X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;ds=sidebyside;f=fetchmailconf;h=15ccc2fbf02234e060d0a15ecbd43983ae4d6a71;hb=1c7ab650bf7acfdd94ee386c84dccc8d5cb157b6;hp=c5b6113112725ddeff53da52a81a7159d8de1431;hpb=3bdd4142f91c3f76a654879e2b616cc81ad119d5;p=~andy%2Ffetchmail diff --git a/fetchmailconf b/fetchmailconf index c5b61131..15ccc2fb 100755 --- a/fetchmailconf +++ b/fetchmailconf @@ -4,7 +4,7 @@ # by Eric S. Raymond, . # Requires Python with Tkinter, and the following OS-dependent services: # posix, posixpath, socket -version = "1.15" +version = "1.28" from Tkinter import * from Dialog import * @@ -74,7 +74,7 @@ class Server: self.protocol = 'auto' # Default to auto protocol self.port = 0 # Port number to use self.uidl = FALSE # Don't use RFC1725 UIDLs by default - self.auth = 'password' # Default to password authentication + self.preauth = 'password' # Default to password authentication self.timeout = 300 # 5-minute timeout self.envelope = 'Received' # Envelope-address header self.envskip = 0 # Number of envelope headers to skip @@ -96,7 +96,7 @@ class Server: ('protocol', 'String'), ('port', 'Int'), ('uidl', 'Boolean'), - ('auth', 'String'), + ('preauth', 'String'), ('timeout', 'Int'), ('envelope', 'String'), ('envskip', 'Int'), @@ -111,69 +111,69 @@ class Server: ('netsec', 'String')) def dump(self, folded): - str = "" - if self.active: str = str + "poll" - else: str = str + "skip" - str = str + (" " + self.pollname) + res = "" + if self.active: res = res + "poll" + else: res = res + "skip" + res = res + (" " + self.pollname) if self.via: - str = str + (" via \"%s\"\n" % (self.via,)); + res = res + (" via " + str(self.via) + "\n"); if self.protocol != ServerDefaults.protocol: - str = str + " with proto " + self.protocol + res = res + " with proto " + self.protocol if self.port != defaultports[self.protocol] and self.port != 0: - str = str + " port " + `self.port` + res = res + " port " + `self.port` if self.timeout != ServerDefaults.timeout: - str = str + " timeout " + `self.timeout` + res = res + " timeout " + `self.timeout` if self.interval != ServerDefaults.interval: - str = str + " interval " + `self.interval` + res = res + " interval " + `self.interval` if self.envelope != ServerDefaults.envelope or self.envskip != ServerDefaults.envskip: if self.envskip: - str = str + " envelope " + self.envskip + " " + self.envelope + res = res + " envelope " + `self.envskip` + " " + self.envelope else: - str = str + " envelope " + self.envelope + res = res + " envelope " + self.envelope if self.qvirtual: - str = str + (" qvirtual \"%s\"\n" % (self.qvirtual,)); - if self.auth != ServerDefaults.auth: - str = str + " auth " + self.auth + res = res + (" qvirtual " + str(self.qvirtual) + "\n"); + if self.preauth != ServerDefaults.preauth: + res = res + " preauth " + self.preauth if self.dns != ServerDefaults.dns or self.uidl != ServerDefaults.uidl: - str = str + " and options" + res = res + " and options" if self.dns != ServerDefaults.dns: - str = str + flag2str(self.dns, 'dns') + res = res + flag2str(self.dns, 'dns') if self.uidl != ServerDefaults.uidl: - str = str + flag2str(self.uidl, 'uidl') - if folded: str = str + "\n " - else: str = str + " " + res = res + flag2str(self.uidl, 'uidl') + if folded: res = res + "\n " + else: res = res + " " if self.aka: - str = str + "aka" + res = res + "aka" for x in self.aka: - str = str + " " + x - if self.aka and self.localdomains: str = str + " " + res = res + " " + x + if self.aka and self.localdomains: res = res + " " if self.localdomains: - str = str + ("localdomains") + res = res + ("localdomains") for x in self.localdomains: - str = str + " " + x + res = res + " " + x if (self.aka or self.localdomains): if folded: - str = str + "\n " + res = res + "\n " else: - str = str + " " + res = res + " " if self.interface: - str = str + "interface \"" + self.interface + "\"" + res = res + "interface " + str(self.interface) if self.monitor: - str = str + "monitor \"" + self.monitor + "\"" + res = res + "monitor " + str(self.monitor) if self.netsec: - str = str + "netsec \"" + self.netsec + "\"" + res = res + "netsec " + str(self.netsec) if self.interface or self.monitor or self.netsec: if folded: - str = str + "\n" + res = res + "\n" - if str[-1] == " ": str = str[0:-1] + if res[-1] == " ": res = res[0:-1] for user in self.users: - str = str + repr(user) - str = str + "\n" - return str; + res = res + repr(user) + res = res + "\n" + return res; def __delitem__(self, name): for ui in range(len(self.users)): @@ -214,13 +214,18 @@ class User: self.forcecr = FALSE # Force LF -> CR/LF self.stripcr = FALSE # Strip CR self.pass8bits = FALSE # Force BODY=7BIT - self.mimedecode = TRUE # Undo MIME armoring + self.mimedecode = FALSE # Undo MIME armoring self.dropstatus = FALSE # Drop incoming Status lines + self.dropdelivered = FALSE # Drop incoming Delivered-To lines + self.idle = FALSE # IDLE after poll self.limit = 0 # Message size limit self.warnings = 0 # Size warning interval self.fetchlimit = 0 # Max messages fetched per batch self.batchlimit = 0 # Max message forwarded per batch self.expunge = 0 # Interval between expunges (IMAP) + self.ssl = 0 # Enable Seccure Socket Layer + self.sslkey = None # SSL key filename + self.sslcert = None # SSL certificate filename self.properties = None # Extension properties User.typemap = ( ('remote', 'String'), @@ -243,23 +248,28 @@ class User: ('pass8bits', 'Boolean'), ('mimedecode', 'Boolean'), ('dropstatus', 'Boolean'), + ('dropdelivered', 'Boolean'), + ('idle', 'Boolean'), ('limit', 'Int'), ('warnings', 'Int'), ('fetchlimit', 'Int'), ('batchlimit', 'Int'), ('expunge', 'Int'), - ('properties', 'String')) + ('ssl', 'Boolean'), + ('sslkey', 'String'), + ('sslcert', 'String'), + ('properties', 'String')) def __repr__(self): - str = " " - str = str + "user \"" + self.remote + "\" there "; + res = " " + res = res + "user " + `self.remote` + " there "; if self.password: - str = str + "with password \"" + self.password + '" ' + res = res + "with password " + `self.password` + " " if self.localnames: - str = str + "is" + res = res + "is" for x in self.localnames: - str = str + " " + x - str = str + " here" + res = res + " " + x + res = res + " here" if (self.keep != UserDefaults.keep or self.flush != UserDefaults.flush or self.fetchall != UserDefaults.fetchall @@ -268,60 +278,72 @@ class User: or self.stripcr != UserDefaults.stripcr or self.pass8bits != UserDefaults.pass8bits or self.mimedecode != UserDefaults.mimedecode - or self.dropstatus != UserDefaults.dropstatus): - str = str + " options" + or self.dropstatus != UserDefaults.dropstatus + or self.dropdelivered != UserDefaults.dropdelivered + or self.idle != UserDefaults.idle): + res = res + " options" if self.keep != UserDefaults.keep: - str = str + flag2str(self.keep, 'keep') + res = res + flag2str(self.keep, 'keep') if self.flush != UserDefaults.flush: - str = str + flag2str(self.flush, 'flush') + res = res + flag2str(self.flush, 'flush') if self.fetchall != UserDefaults.fetchall: - str = str + flag2str(self.fetchall, 'fetchall') + res = res + flag2str(self.fetchall, 'fetchall') if self.rewrite != UserDefaults.rewrite: - str = str + flag2str(self.rewrite, 'rewrite') + res = res + flag2str(self.rewrite, 'rewrite') if self.forcecr != UserDefaults.forcecr: - str = str + flag2str(self.forcecr, 'forcecr') + res = res + flag2str(self.forcecr, 'forcecr') if self.stripcr != UserDefaults.stripcr: - str = str + flag2str(self.stripcr, 'stripcr') + res = res + flag2str(self.stripcr, 'stripcr') if self.pass8bits != UserDefaults.pass8bits: - str = str + flag2str(self.pass8bits, 'pass8bits') + res = res + flag2str(self.pass8bits, 'pass8bits') if self.mimedecode != UserDefaults.mimedecode: - str = str + flag2str(self.mimedecode, 'mimedecode') + res = res + flag2str(self.mimedecode, 'mimedecode') if self.dropstatus != UserDefaults.dropstatus: - str = str + flag2str(self.dropstatus, 'dropstatus') + res = res + flag2str(self.dropstatus, 'dropstatus') + if self.dropdelivered != UserDefaults.dropdelivered: + res = res + flag2str(self.dropdelivered, 'dropdelivered') + if self.idle != UserDefaults.idle: + res = res + flag2str(self.idle, 'idle') if self.limit != UserDefaults.limit: - str = str + " limit " + `self.limit` + res = res + " limit " + `self.limit` if self.warnings != UserDefaults.warnings: - str = str + " warnings " + `self.warnings` + res = res + " warnings " + `self.warnings` if self.fetchlimit != UserDefaults.fetchlimit: - str = str + " fetchlimit " + `self.fetchlimit` + res = res + " fetchlimit " + `self.fetchlimit` if self.batchlimit != UserDefaults.batchlimit: - str = str + " batchlimit " + `self.batchlimit` + res = res + " batchlimit " + `self.batchlimit` + if self.ssl and self.ssl != UserDefaults.ssl: + res = res + flag2str(self.ssl, 'ssl') + if self.sslkey and self.sslkey != UserDefaults.sslkey: + res = res + " sslkey " + `self.sslkey` + if self.sslcert and self.sslcert != UserDefaults.sslcert: + res = res + " sslcert " + `self.sslcert` if self.expunge != UserDefaults.expunge: - str = str + " expunge " + `self.expunge` - str = str + "\n" + res = res + " expunge " + `self.expunge` + res = res + "\n" trimmed = self.smtphunt; if trimmed != [] and trimmed[len(trimmed) - 1] == "localhost": trimmed = trimmed[0:len(trimmed) - 1] if trimmed != [] and trimmed[len(trimmed) - 1] == hostname: trimmed = trimmed[0:len(trimmed) - 1] if trimmed != []: - str = str + " smtphost " + res = res + " smtphost " for x in trimmed: - str = str + " " + x - str = str + "\n" + res = res + " " + x + res = res + "\n" if self.mailboxes: - str = str + " folder" + res = res + " folder" for x in self.mailboxes: - str = str + " " + x - str = str + "\n" + res = res + " " + x + res = res + "\n" for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'): if getattr(self, fld): - str = str + " %s %s\n" % (fld, `getattr(self, fld)`) + res = res + " %s %s\n" % (fld, `getattr(self, fld)`) if self.lmtp != UserDefaults.lmtp: - str = str + flag2str(self.lmtp, 'lmtp') + res = res + flag2str(self.lmtp, 'lmtp') if self.antispam != UserDefaults.antispam: - str = str + " antispam " + self.antispam + "\n" - return str; + res = res + " antispam " + self.antispam + "\n" + return res; def __str__(self): return "[User: " + repr(self) + "]" @@ -340,7 +362,7 @@ defaultports = {"auto":0, "IMAP-K4":143, "ETRN":25} -authlist = ("password", "kerberos") +preauthlist = ("password", "kerberos", "ssh") listboxhelp = { 'title' : 'List Selection Help', @@ -395,10 +417,18 @@ def helpwin(helpdict): helpwin.title(helpdict['title']) helpwin.iconname(helpdict['title']) Label(helpwin, text=helpdict['banner']).pack() - textwin = Message(helpwin, text=helpdict['text'], width=600) - textwin.pack() + textframe = Frame(helpwin) + scroll = Scrollbar(textframe) + helpwin.textwidget = Text(textframe, setgrid=TRUE) + textframe.pack(side=TOP, expand=YES, fill=BOTH) + helpwin.textwidget.config(yscrollcommand=scroll.set) + helpwin.textwidget.pack(side=LEFT, expand=YES, fill=BOTH) + scroll.config(command=helpwin.textwidget.yview) + scroll.pack(side=RIGHT, fill=BOTH) + helpwin.textwidget.insert(END, helpdict['text']); Button(helpwin, text='Done', command=lambda x=helpwin: Widget.destroy(x), bd=2).pack() + textframe.pack(side=TOP) def make_icon_window(base, image): try: @@ -458,15 +488,18 @@ class ListEdit(Frame): helpwin(self.helptxt) def handleList(self, event): - self.editItem(); + self.editItem(); def handleNew(self, event): item = self.newval.get() - entire = self.listwidget.get(0, self.listwidget.index('end')); - if item and (not entire) or (not item in self.listwidget.get(0, self.listwidget.index('end'))): - self.listwidget.insert('end', item) - if self.list != None: self.list.append(item) - self.newval.set('') + if item: + entire = self.listwidget.get(0, self.listwidget.index('end')); + if item and (not entire) or (not item in self.listwidget.get(0, self.listwidget.index('end'))): + self.listwidget.insert('end', item) + if self.list != None: self.list.append(item) + if self.editor: + apply(self.editor, (item,)) + self.newval.set('') def editItem(self): select = self.listwidget.curselection() @@ -476,7 +509,8 @@ class ListEdit(Frame): index = select[0] if index and self.editor: label = self.listwidget.get(index); - apply(self.editor, (label,)) + if self.editor: + apply(self.editor, (label,)) def deleteItem(self): select = self.listwidget.curselection() @@ -638,6 +672,8 @@ class ConfigurationEdit(Frame, MyWidget): def server_delete(self, sitename): try: + for user in self.subwidgets.keys(): + user.destruct() del self.configuration[sitename] except: pass @@ -647,8 +683,9 @@ class ConfigurationEdit(Frame, MyWidget): Frame.__init__(self, self.container) self.master.title('fetchmail ' + self.mode + ' configurator'); self.master.iconname('fetchmail ' + self.mode + ' configurator'); + self.master.protocol('WM_DELETE_WINDOW', self.nosave) self.keepalive = [] # Use this to anchor the PhotoImage object - make_icon_window(self, fetchmail_gif) + make_icon_window(self, fetchmail_icon) Pack.config(self) self.post(Configuration, 'configuration') @@ -854,6 +891,10 @@ The `interface' and `monitor' options are available only for Linux and freeBSD systems. See the fetchmail manual page for details on these. +The ssl option enables SSL communication with a mailserver +supporting Secure Sockets Layer. The sslkey and sslcert options +declare key and certificate files for use with SSL. + The `netsec' option will be configurable only if fetchmail was compiled with IPV6 support. If you need to use it, you probably know what to do. @@ -904,7 +945,7 @@ class ServerEdit(Frame, MyWidget): self.post(Server, 'server') self.makeWidgets(self.server.pollname, mode) self.keepalive = [] # Use this to anchor the PhotoImage object - make_icon_window(self, fetchmail_gif) + make_icon_window(self, fetchmail_icon) # self.grab_set() # self.focus_set() # self.wait_window() @@ -937,7 +978,7 @@ class ServerEdit(Frame, MyWidget): def user_delete(self, username): if self.subwidgets.has_key(username): - del self.subwidgets[username] + self.subwidgets[username].destruct() del self.server[username] def makeWidgets(self, host, mode): @@ -1030,8 +1071,8 @@ class ServerEdit(Frame, MyWidget): secwin = Frame(rightwin, relief=RAISED, bd=5) Label(secwin, text="Security").pack(side=TOP) # Don't actually let users set this. KPOP sets it implicitly - # ButtonBar(secwin, 'Authorization mode:', - # self.auth, authlist, 1, None).pack(side=TOP) + # ButtonBar(secwin, 'Preauthorization mode:', + # self.preauth, preauthlist, 1, None).pack(side=TOP) if os_type == 'linux' or os_type == 'freebsd' or 'interface' in dictmembers: LabeledEntry(secwin, 'IP range to check before poll:', self.interface, leftwidth).pack(side=TOP, fill=X) @@ -1091,7 +1132,10 @@ you'll have to build it from sources yourself with the configure switch --enable-POP2. """ - if string.find(greetline, "1.003") > 0 or string.find(greetline, "1.004") > 0: + +### POP3 servers start here + + if string.find(greetline, "1.003") > 0 or string.find(greetline, "1.004") > 0: warnings = warnings + """ This appears to be an old version of the UC Davis POP server. These are dangerously unreliable (among other problems, they may drop your mailbox @@ -1101,29 +1145,6 @@ It is strongly recommended that you find a better POP3 server. The fetchmail FAQ includes pointers to good ones. """ - if string.find(greetline, "usa.net") > 0: - warnings = warnings + """ -You appear to be using USA.NET's free mail service. Their POP3 servers -(at least as of the 2.2 version in use mid-1998) are quite flaky, but -fetchmail can compensate. They seem to require that fetchall be switched on -(otherwise you won't necessarily see all your mail, not even new mail). -They also botch the TOP command the fetchmail normally uses for retrieval -(it only retrieves about 10 lines rather than the number specified). -Turning on fetchall will disable the use of TOP. - -Therefore, it is strongly recommended that you turn on `fetchall' on all -user entries associated with this server. - -""" - if string.find(greetline, "sprynet.com") > 0: - warnings = warnings + """ -You appear to be using a SpryNet server. In mid-1999 it was reported that -the SpryNet TOP command marks messages seen. Therefore, for proper error -recovery in the event of a line drop, it is strongly recommended that you -turn on `fetchall' on all user entries associated with this server. - -""" - # Steve VanDevender writes: # The only system I have seen this happen with is cucipop-1.31 # under SunOS 4.1.4. cucipop-1.31 runs fine on at least Solaris @@ -1142,19 +1163,163 @@ turn on `fetchall' on all user entries associated with this server. # # +OK Cubic Circle's v1.31 1998/05/13 POP3 ready <6229000062f95036@wakko> # - if string.find(greetline, "Cubic Circle") > 0: + if string.find(greetline, "Cubic Circle") > 0: warnings = warnings + """ I see your server is running cucipop. Better make sure the server box isn't a SunOS 4.1.4 machine; cucipop tickles a bug in SunOS realloc() under that version, and doesn't cope with the result gracefully. Newer SunOS and Solaris machines run cucipop OK. + +""" + if string.find(greetline, "David POP3 Server") > 0: + warnings = warnings + """ +This POP3 serrver is badly broken. You should get rid of it -- and the +brain-dead NT operating system it rode in on. + """ - if string.find(greetline, "QPOP") > 0: +# The greeting line on the server known to be buggy is: +# +OK POP3 server ready (running FTGate V2, 2, 1, 0 Jun 21 1999 09:55:01) +# + if string.find(greetline, "FTGate") > 0: + warnings = warnings + """ +This POP server has a weird bug; it says OK twice in response to TOP. +Its response to RETR is normal, so use the `fetchall' option. + +""" + if string.find(greetline, "OpenMail") > 0: + warnings = warnings + """ +You appear to be using some version of HP OpenMail. Many versions of +OpenMail do not process the "TOP" command correctly; the symptom is that +only the header and first line of each message is retrieved. To work +around this bug, turn on `fetchall' on all user entries associated with +this server. + +""" + if string.find(greetline, "POP-Max") > 0: + warnings = warnings + """ +The Mail Max POP3 server screws up on mail with attachments. It +reports the message size with attachments included, but doesn't +download them on a RETR or TOP (this violates the IMAP RFCs). It also +doesn't implement TOP correctly. You should get rid of it -- and the +brain-dead NT server it rode in on. + +""" + if string.find(greetline, "POP3 Server Ready") > 0: + warnings = warnings + """ +Some server that uses this greeting line has been observed to choke on +TOP %d 99999999. Use the fetchall option. if necessary, to force RETR. + +""" + if string.find(greetline, "QPOP") > 0: warnings = warnings + """ This appears to be a version of Eudora qpopper. That's good. Fetchmail -knows all about qpopper. +knows all about qpopper. However, be aware that the 2.53 version of +qpopper does something odd that causes fetchmail to hang with a socket +error on very large messages. This is probably not a fetchmail bug, as +it has been observed with fetchpop. The fix is to upgrade to qpopper +3.0beta or a more recent version. Better yet, switch to IMAP. + +""" + if string.find(greetline, " sprynet.com") > 0: + warnings = warnings + """ +You appear to be using a SpryNet server. In mid-1999 it was reported that +the SpryNet TOP command marks messages seen. Therefore, for proper error +recovery in the event of a line drop, it is strongly recommended that you +turn on `fetchall' on all user entries associated with this server. """ + if string.find(greetline, "TEMS POP3") > 0: + warnings = warnings + """ +Your POP3 server has "TEMS" in its header line. At least one such +server does not process the "TOP" command correctly; the symptom is +that fetchmail hangs when trying to retrieve mail. To work around +this bug, turn on `fetchall' on all user entries associated with this +server. + +""" + if string.find(greetline, " spray.se") > 0: + warnings = warnings + """ +Your POP3 server has "spray.se" in its header line. In May 2000 at +least one such server did not process the "TOP" command correctly; the +symptom is that messages are treated as headerless. To work around +this bug, turn on `fetchall' on all user entries associated with this +server. + +""" + if string.find(greetline, " usa.net") > 0: + warnings = warnings + """ +You appear to be using USA.NET's free mail service. Their POP3 servers +(at least as of the 2.2 version in use mid-1998) are quite flaky, but +fetchmail can compensate. They seem to require that fetchall be switched on +(otherwise you won't necessarily see all your mail, not even new mail). +They also botch the TOP command the fetchmail normally uses for retrieval +(it only retrieves about 10 lines rather than the number specified). +Turning on fetchall will disable the use of TOP. + +Therefore, it is strongly recommended that you turn on `fetchall' on all +user entries associated with this server. + +""" + if string.find(greetline, " Novonyx POP3") > 0: + warnings = warnings + """ +Your mailserver is running Novonyx POP3. This server, at least as of +version 2.17, seems to have problems handling and reporting seen bits. +You may have to use the fetchall option. + +""" + +### IMAP servers start here + + if string.find(greetline, "GroupWise") > 0: + warnings = warnings + """ +The Novell GroupWise IMAP server would be better named GroupFoolish; +it is (according to the designer of IMAP) unusably broken. Among +other things, it doesn't include a required content length in its +BODY[TEXT] response.

+ +Fetchmail works around this problem, but we strongly recommend voting +with your dollars for a server that isn't brain-dead. If you stick +with code as shoddy as GroupWise seems to be, you will probably pay +for it with other problems.

+ +""" + if string.find(greetline, "Netscape IMAP4rev1 Service 3.6") > 0: + warnings = warnings + """ +This server violates the RFC2060 requirement that a BODY[TEXT] fetch should +set the messages's Seen flag. As a result, if you use the keep option the +same messages will be downloaded over and over. + +""" + if string.find(greetline, "InterChange") > 0: + warnings = warnings + """ +The InterChange IMAP server screws up on mail with attachments. It +doesn't fetch them if you give it a BODY[TEXT] request, though it +does if you request RFC822.TEXT. According to the IMAP RFCs and their +maintainer these should be equivalent -- and we can't drop the +BODY[TEXT] form because M$ Exchange (quite legally under RFC2062) +rejects it. + +""" + if string.find(greetline, "Imail") > 0: + warnings = warnings + """ +We've seen a bug report indicating that this IMAP server (at least as of +version 5.0.7) returns an invalid body size for messages with MIME +attachments; the effect is to drop the attachments on the floor. We +recommend you upgrade to a non-broken IMAP server. + +""" + if string.find(greetline, "Domino IMAP4") > 0: + warnings = warnings + """ +Your IMAP server appears to be Lotus Domino. This server, at least up +to version 4.6.2a, has a bug in its generation of MIME boundaries (see +the details in the fetchmail FAQ). As a result, even MIME aware MUAs +will see attachments as part of the message text. If your Domino server's +POP3 facility is enabled, we recommend you fall back on it. + +""" + +### Checks for protocol variants start here + closebrak = string.find(greetline, ">") if closebrak > 0 and greetline[closebrak+1] == "\r": warnings = warnings + """ @@ -1162,14 +1327,6 @@ It looks like you could use APOP on this server and avoid sending it your password in clear. You should talk to the mailserver administrator about this. -""" - if string.find(greetline, "csi.com") > 0: - warnings = warnings + """ -It appears you're talking to CompuServe. You can use their special RPA -service for authentication, but only if your fetchmail -V output's first -line contains the string "RPA". This is not included in stock fetchmail -binaries; to compile it in, rebuild from sources with the configure -option --enable-RPA. """ if string.find(greetline, "IMAP2bis") > 0: warnings = warnings + """ @@ -1181,21 +1338,21 @@ To work around this, it is recommended that you set the `fetchall' option on all user entries associated with this server, so any stuck mail will be retrieved next time around. -""" - if string.find(greetline, "POP3 Server Ready") > 0: - warnings = warnings + """ -Some server that uses this greeting line has been observed to choke on -TOP %d 99999999. Use the fetchall option. if necessary, to force RETR. +To fix this bug, upgrade to an IMAP4 server. The fetchmail FAQ includes +a pointer to an open-source implementation. + """ if string.find(greetline, "IMAP4rev1") > 0: warnings = warnings + """ I see an IMAP4rev1 server. Excellent. This is (a) the best kind of remote-mail server, and (b) the one the fetchmail author uses. Fetchmail has therefore been extremely well tested with this class of server. + """ if warnings == '': warnings = warnings + """ Fetchmail doesn't know anything special about this server type. + """ # Display success window with warnings @@ -1267,14 +1424,16 @@ class UserEdit(Frame, MyWidget): self.post(User, 'user') self.makeWidgets(mode, self.parent.server.pollname) self.keepalive = [] # Use this to anchor the PhotoImage object - make_icon_window(self, fetchmail_gif) + make_icon_window(self, fetchmail_icon) # self.grab_set() # self.focus_set() # self.wait_window() return self def destruct(self): - del self.parent.subwidgets[self.user.remote] + # Yes, this test can fail -- if you delete the parent window. + if self.parent.subwidgets.has_key(self.user.remote): + del self.parent.subwidgets[self.user.remote] Widget.destroy(self.master) def nosave(self): @@ -1301,6 +1460,16 @@ class UserEdit(Frame, MyWidget): self.password, '12').pack(side=TOP, fill=X) secwin.pack(fill=X, anchor=N) + if 'ssl' in feature_options or 'ssl' in dictmembers: + sslwin = Frame(leftwin, relief=RAISED, bd=5) + Checkbutton(sslwin, text="Use SSL?", + variable=self.ssl).pack(side=TOP, fill=X) + LabeledEntry(sslwin, 'SSL key:', + self.sslkey, '14').pack(side=TOP, fill=X) + LabeledEntry(sslwin, 'SSL certificate:', + self.sslcert, '14').pack(side=TOP, fill=X) + sslwin.pack(fill=X, anchor=N) + names = Frame(leftwin, relief=RAISED, bd=5) Label(names, text="Local names").pack(side=TOP) ListEdit("New name: ", @@ -1358,6 +1527,8 @@ class UserEdit(Frame, MyWidget): variable=self.mimedecode).pack(side=TOP, anchor=W) Checkbutton(optwin, text="Drop Status lines from forwarded messages", variable=self.dropstatus).pack(side=TOP, anchor=W) + Checkbutton(optwin, text="Drop Delivered-To lines from forwarded messages", + variable=self.dropdelivered).pack(side=TOP, anchor=W) optwin.pack(fill=X) if mode != 'novice': @@ -1371,9 +1542,11 @@ class UserEdit(Frame, MyWidget): self.fetchlimit, '30').pack(side=TOP, fill=X) LabeledEntry(limwin, 'Max messages to forward per poll:', self.batchlimit, '30').pack(side=TOP, fill=X) - if self.parent.server.protocol in ('IMAP', 'IMAP-K4', 'IMAP-GSS'): - LabeledEntry(limwin, 'Interval between expunges (IMAP):', + if self.parent.server.protocol != 'ETRN': + LabeledEntry(limwin, 'Interval between expunges:', self.expunge, '30').pack(side=TOP, fill=X) + Checkbutton(limwin, text="Idle after each poll (IMAP only)", + variable=self.idle).pack(side=TOP, anchor=W) limwin.pack(fill=X) if self.parent.server.protocol in ('IMAP', 'IMAP-K4', 'IMAP-GSS'): @@ -1404,7 +1577,7 @@ class Configurator(Frame): self.master.iconname('fetchmail configurator'); Pack.config(self) self.keepalive = [] # Use this to anchor the PhotoImage object - make_icon_window(self, fetchmail_gif) + make_icon_window(self, fetchmail_icon) Message(self, text=""" Use `Novice Configuration' for basic fetchmail setup; @@ -1426,6 +1599,7 @@ Or you can just select `Quit' to leave the configurator now and return to the main panel. """, width=600).pack(side=TOP) Button(self, text='Quit', fg='blue', command=self.leave).pack() + master.protocol("WM_DELETE_WINDOW", self.leave) def novice(self): self.master.destroy() @@ -1439,7 +1613,7 @@ return to the main panel. self.master.destroy() self.onexit() -# Run a command an a scrolling text widget, displaying its output +# Run a command in a scrolling text widget, displaying its output class RunWindow(Frame): def __init__(self, command, master, parent): @@ -1452,7 +1626,7 @@ class RunWindow(Frame): text="Running "+command, bd=2).pack(side=TOP, pady=10) self.keepalive = [] # Use this to anchor the PhotoImage object - make_icon_window(self, fetchmail_gif) + make_icon_window(self, fetchmail_icon) # This is a scrolling text window textframe = Frame(self) @@ -1494,9 +1668,14 @@ class MainWindow(Frame): text='Fetchmailconf ' + version, bd=2).pack(side=TOP, pady=10) self.keepalive = [] # Use this to anchor the PhotoImage object - make_icon_window(self, fetchmail_gif) + make_icon_window(self, fetchmail_icon) self.debug = 0 + ## Test icon display with the following: + # icon_image = PhotoImage(data=fetchmail_icon) + # Label(self, image=icon_image).pack(side=TOP, pady=10) + # self.keepalive.append(icon_image) + Message(self, text=""" Use `Configure fetchmail' to tell fetchmail about the remote servers it should poll (the host name, your username there, @@ -1528,7 +1707,6 @@ Or you can just select `Quit' to exit the launcher now. Configurator(self.outfile, Toplevel(), lambda self=self: self.configbutton.configure(state=NORMAL), self) - def test(self): RunWindow("fetchmail -d0 -v --nosyslog", Toplevel(), self) @@ -1564,7 +1742,7 @@ def copy_instance(toclass, fromdict): # The `optional' fields are the ones we can ignore for purposes of # conformability checking; they'll still get copied if they are # present in the dictionary. - optional = ('interface', 'monitor', 'netsec') + optional = ('interface', 'monitor', 'netsec', 'ssl', 'sslkey', 'sslcert') class_sig = setdiff(toclass.__dict__.keys(), optional) class_sig.sort() dict_keys = setdiff(fromdict.keys(), optional) @@ -1612,7 +1790,11 @@ def copy_instance(toclass, fromdict): if __name__ == '__main__': - fetchmail_gif = """ + if not os.environ.has_key("DISPLAY"): + print "fetchmailconf must be run under X" + sys.exit(1) + + fetchmail_icon = """ R0lGODdhPAAoAPcAAP///wgICBAQEISEhIyMjJSUlKWlpa2trbW1tcbGxs7Ozufn5+/v7//39yEY GNa9tUoxKZyEe1o5KTEQAN7OxpyMhIRjUvfn3pxSKYQ5EO/Wxv/WvWtSQrVzSmtCKWspAMatnP/e xu+1jIxSKaV7Wt6ca5xSGK2EY8aUa72MY86UY617UsaMWrV7SpRjOaVrOZRaKYxSIXNCGGs5EIRC @@ -1646,12 +1828,10 @@ OtO0k84+7KjzBjzplMJOOOOoo8846/ATxqJWinkkGUyEkMAaIezABQM3bMAEK1xEsUMDGjARRxhY xEGGHfPjEcccca6BRxhyuEMY7FCHMNDhf9140r2qRiVvdENQ3liUArzREW/0qRsRVIAGFfBADnLw gUSiYASJpMEHhilJTEnhAlGoQqYAZQ1AiqEMZ0jDGtqQImhwwA13yMMevoQAGvGhEAWHGMOAAAA7 """ -# Note on making icons: the above was generated by the following procedure: +# The base64 data in the string above was generated by the following procedure: # # import base64 -# data = open("fetchmail.gif", "rb").read() -# print "fetchmail_gif =\\" -# print repr(base64.encodestring(data)) +# print base64.encodestring(open("fetchmail.gif", "rb").read()) # # Process options @@ -1671,12 +1851,14 @@ gUSiYASJpMEHhilJTEnhAlGoQqYAZQ1AiqEMZ0jDGtqQImhwwA13yMMevoQAGvGhEAWHGMOAAAA7 ServerDefaults = Server() UserDefaults = User() - # Read the existing configuration + # Read the existing configuration. We set the umask to 077 to make sure + # that group & other read/write permissions are shut off -- we wouldn't + # want crackers to snoop password information out of the tempfile. tmpfile = "/tmp/fetchmailconf." + `os.getpid()` if rcfile: - cmd = "fetchmail -f " + rcfile + " --configdump --nosyslog >" + tmpfile + cmd = "umask 077; fetchmail -f " + rcfile + " --configdump --nosyslog >" + tmpfile else: - cmd = "fetchmail --configdump --nosyslog >" + tmpfile + cmd = "umask 077; fetchmail --configdump --nosyslog >" + tmpfile try: s = os.system(cmd) @@ -1701,7 +1883,7 @@ gUSiYASJpMEHhilJTEnhAlGoQqYAZQ1AiqEMZ0jDGtqQImhwwA13yMMevoQAGvGhEAWHGMOAAAA7 # `Configuration' is the top level of the object tree we're going to mung. # The dictmembers list is used to track the set of fields the dictionary # contains; in particular, we can use it to tell whether things like the - # monitor, interface, and netsec fields are present. + # monitor, interface, netsec, ssl, sslkey, or sslcert fields are present. dictmembers = [] Fetchmailrc = Configuration() copy_instance(Fetchmailrc, fetchmailrc)