X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=fetchmailconf.py;h=2dc02d875995b088dd49e2e84a89ae434e085074;hb=49268a95ee78bc179fd3439b3f06e9a06c993c92;hp=83e9ed7ae7037c7a9b2abe12363e87298419a160;hpb=cabbd0c9ca318c55e45af5a9aa0d01fce936ccd4;p=~andy%2Ffetchmail diff --git a/fetchmailconf.py b/fetchmailconf.py index 83e9ed7a..2dc02d87 100755 --- a/fetchmailconf.py +++ b/fetchmailconf.py @@ -5,7 +5,7 @@ # Matthias Andree # Requires Python with Tkinter, and the following OS-dependent services: # posix, posixpath, socket -version = "1.46" +version = "1.57" from Tkinter import * from Dialog import * @@ -22,6 +22,7 @@ class Configuration: self.postmaster = None # No last-resort address, initially self.bouncemail = TRUE # Bounce errors to users self.spambounce = FALSE # Bounce spam errors + self.softbounce = TRUE # Treat permanent error as temporary self.properties = None # No exiguous properties self.invisible = FALSE # Suppress Received line & spoof? self.syslog = FALSE # Use syslogd for logging? @@ -33,6 +34,7 @@ class Configuration: ('postmaster', 'String'), ('bouncemail', 'Boolean'), ('spambounce', 'Boolean'), + ('softbounce', 'Boolean'), ('properties', 'String'), ('syslog', 'Boolean'), ('invisible', 'Boolean')) @@ -55,10 +57,16 @@ class Configuration: str = str + ("set spambounce\n") else: str = str + ("set no spambounce\n") + if self.softbounce: + str = str + ("set softbounce\n") + else: + str = str + ("set no softbounce\n") if self.properties != ConfigurationDefaults.properties: str = str + ("set properties \"%s\"\n" % (self.properties,)); if self.poll_interval > 0: str = str + "set daemon " + `self.poll_interval` + "\n" + if self.invisible: + str = str + ("set invisible\n") for site in self.servers: str = str + repr(site) return str @@ -97,6 +105,7 @@ class Server: self.esmtpname = None # ESMTP 2554 name self.esmtppassword = None # ESMTP 2554 password self.tracepolls = FALSE # Add trace-poll info to headers + self.badheader = FALSE # Pass messages with bad headers on? self.users = [] # List of user entries for site Server.typemap = ( ('pollname', 'String'), @@ -121,7 +130,8 @@ class Server: ('esmtpname', 'String'), ('esmtppassword', 'String'), ('principal', 'String'), - ('tracepolls','Boolean')) + ('tracepolls','Boolean'), + ('badheader', 'Boolean')) def dump(self, folded): res = "" @@ -132,7 +142,7 @@ class Server: res = res + (" via " + str(self.via) + "\n"); if self.protocol != ServerDefaults.protocol: res = res + " with proto " + self.protocol - if self.service and self.service != defaultports[self.protocol] and self.service != ianaservices[defaultports[self.protocol]]: + if self.service and self.protocol and self.service != defaultports[self.protocol] and defaultports[self.protocol] and self.service != ianaservices[defaultports[self.protocol]]: res = res + " service " + self.service if self.timeout != ServerDefaults.timeout: res = res + " timeout " + `self.timeout` @@ -191,6 +201,8 @@ class Server: if self.interface or self.monitor or self.principal or self.plugin or self.plugout: if folded: res = res + "\n" + if self.badheader: + res = res + "bad-header accept " if res[-1] == " ": res = res[0:-1] @@ -235,6 +247,7 @@ class User: self.antispam = "" # Listener's spam-block code self.keep = FALSE # Keep messages self.flush = FALSE # Flush messages + self.limitflush = FALSE # Flush oversized messages self.fetchall = FALSE # Fetch old messages self.rewrite = TRUE # Rewrite message headers self.forcecr = FALSE # Force LF -> CR/LF @@ -248,7 +261,7 @@ class User: self.warnings = 3600 # Size warning interval (see tunable.h) self.fetchlimit = 0 # Max messages fetched per batch self.fetchsizelimit = 100 # Max message sizes fetched per transaction - self.fastuidl = 10 # Do fast uidl 9 out of 10 times + self.fastuidl = 4 # Do fast uidl 3 out of 4 times self.batchlimit = 0 # Max message forwarded per batch self.expunge = 0 # Interval between expunges (IMAP) self.ssl = 0 # Enable Seccure Socket Layer @@ -257,6 +270,7 @@ class User: self.sslproto = None # Force SSL? self.sslcertck = 0 # Enable strict SSL cert checking self.sslcertpath = None # Path to trusted certificates + self.sslcommonname = None # SSL CommonName to expect self.sslfingerprint = None # SSL key fingerprint to check self.properties = None # Extension properties User.typemap = ( @@ -274,6 +288,7 @@ class User: ('antispam', 'String'), ('keep', 'Boolean'), ('flush', 'Boolean'), + ('limitflush', 'Boolean'), ('fetchall', 'Boolean'), ('rewrite', 'Boolean'), ('forcecr', 'Boolean'), @@ -295,6 +310,7 @@ class User: ('sslcert', 'String'), ('sslcertck', 'Boolean'), ('sslcertpath', 'String'), + ('sslcommonname', 'String'), ('sslfingerprint', 'String'), ('properties', 'String')) @@ -310,6 +326,7 @@ class User: res = res + " here" if (self.keep != UserDefaults.keep or self.flush != UserDefaults.flush + or self.limitflush != UserDefaults.limitflush or self.fetchall != UserDefaults.fetchall or self.rewrite != UserDefaults.rewrite or self.forcecr != UserDefaults.forcecr @@ -324,6 +341,8 @@ class User: res = res + flag2str(self.keep, 'keep') if self.flush != UserDefaults.flush: res = res + flag2str(self.flush, 'flush') + if self.limitflush != UserDefaults.limitflush: + res = res + flag2str(self.limitflush, 'limitflush') if self.fetchall != UserDefaults.fetchall: res = res + flag2str(self.fetchall, 'fetchall') if self.rewrite != UserDefaults.rewrite: @@ -366,6 +385,8 @@ class User: res = res + flag2str(self.sslcertck, 'sslcertck') if self.sslcertpath and self.sslcertpath != UserDefaults.sslcertpath: res = res + " sslcertpath " + `self.sslcertpath` + if self.sslcommonname and self.sslcommonname != UserDefaults.sslcommonname: + res = res + " sslcommonname " + `self.sslcommonname` if self.sslfingerprint and self.sslfingerprint != UserDefaults.sslfingerprint: res = res + " sslfingerprint " + `self.sslfingerprint` if self.expunge != UserDefaults.expunge: @@ -392,7 +413,7 @@ class User: if self.mailboxes: res = res + " folder" for x in self.mailboxes: - res = res + " " + x + res = res + ' "%s"' % x res = res + "\n" for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'): if getattr(self, fld): @@ -428,7 +449,8 @@ defaultports = {"auto":None, "ETRN":"smtp", "ODMR":"odmr"} -authlist = ("any", "password", "gssapi", "kerberos", "ssh", "otp") +authlist = ("any", "password", "gssapi", "kerberos", "ssh", "otp", + "msn", "ntlm") listboxhelp = { 'title' : 'List Selection Help', @@ -660,9 +682,12 @@ needed to create a simple fetchmail setup. These include: 4. A protocol to use (POP, IMAP, ETRN, etc.) -5. A polling interval. +5. A poll interval in seconds. + If 0, fetchmail will run in the foreground once when started. + If > 0, fetchmail will run in the background and start a new poll + cycle after the interval has elapsed. -6. Options to fetch old messages as well as new, uor to suppress +6. Options to fetch old messages as well as new, or to suppress deletion of fetched message. The novice-configuration code will assume that you want to forward mail @@ -710,6 +735,14 @@ Send spam bounces? postmaster (depending on the "Bounces to sender?" option. Otherwise, spam bounces are not sent (the default). +Use soft bounces? + If this option is on, permanent delivery errors are treated as + temporary, i. e. mail is kept on the upstream server. Useful + during testing and after configuration changes, and on by + default. + If this option is off, permanent delivery errors delete + undeliverable mail from the upstream. + Invisible If false (the default) fetchmail generates a Received line into each message and generates a HELO from the machine it is running on. @@ -800,11 +833,18 @@ class ConfigurationEdit(Frame, MyWidget): sb = Frame(gf) Checkbutton(sb, - {'text':'send spam bounces?', + {'text':'Send spam bounces?', 'variable':self.spambounce, 'relief':GROOVE}).pack(side=LEFT, anchor=W) sb.pack(fill=X) + sb = Frame(gf) + Checkbutton(sb, + {'text':'Treat permanent errors as temporary?', + 'variable':self.softbounce, + 'relief':GROOVE}).pack(side=LEFT, anchor=W) + sb.pack(fill=X) + sf = Frame(gf) Checkbutton(sf, {'text':'Log to syslog?', @@ -864,14 +904,17 @@ class ConfigurationEdit(Frame, MyWidget): # Pre-1.5.2 compatibility... except os.error: pass + oldumask = os.umask(077) fm = open(self.outfile, 'w') + os.umask(oldumask) if fm: - fm.write("# Configuration created %s by fetchmailconf\n" % time.ctime(time.time())) + # be paranoid + if fm != sys.stdout: + os.chmod(self.outfile, 0600) + fm.write("# Configuration created %s by fetchmailconf %s\n" % (time.ctime(time.time()), version)) fm.write(`self.configuration`) if self.outfile: fm.close() - if fm != sys.stdout: - os.chmod(self.outfile, 0600) self.destruct() # @@ -962,7 +1005,12 @@ sechelp = { 'title' : 'Security option help', 'banner': 'Security', 'text' : """ -The `interface' option allows you to specify a range +The 'authorization mode' allows you to choose the +mode that fetchmail uses to log in to your server. You +can usually leave this at 'any', but you will have to pick +'NTLM' and 'MSN' manually for the nonce. + +The 'interface' option allows you to specify a range of IP addresses to monitor for activity. If these addresses are not active, fetchmail will not poll. Specifying this may protect you from a spoofing attack @@ -983,8 +1031,10 @@ 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 sslcertck option enables strict checking of SSL server -certificates (and sslcertpath gives trusted certificate -directory). With sslfingerprint, you can specify a finger- +certificates (and sslcertpath gives the trusted certificate +directory). The sslcommonname option helps if the server is +misconfigured and returning "Server CommonName mismatch" +warnings. With sslfingerprint, you can specify a finger- print the server's key is checked against. """} @@ -1085,6 +1135,8 @@ class ServerEdit(Frame, MyWidget): ctlwin = Frame(leftwin, relief=RAISED, bd=5) Label(ctlwin, text="Run Controls").pack(side=TOP) Checkbutton(ctlwin, text='Poll ' + host + ' normally?', variable=self.active).pack(side=TOP) + Checkbutton(ctlwin, text='Pass messages with bad headers?', + variable=self.badheader).pack(side=TOP) LabeledEntry(ctlwin, 'True name of ' + host + ':', self.via, leftwidth).pack(side=TOP, fill=X) LabeledEntry(ctlwin, 'Cycles to skip between polls:', @@ -1163,8 +1215,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, 'Authorization mode:', + self.auth, authlist, 2, 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) @@ -1422,13 +1474,6 @@ 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 + """ @@ -1501,6 +1546,7 @@ Fetchmail doesn't know anything special about this server type. title = "Autoprobe of " + realhost + " succeeded" confirm = "The " + protocol + " server said:\n\n" + greetline + warnings self.protocol.set(protocol) + self.service.set(defaultports[protocol]) confwin.title(title) confwin.iconname(title) Label(confwin, text=title).pack() @@ -1630,6 +1676,8 @@ class UserEdit(Frame, MyWidget): variable=self.sslcertck).pack(side=TOP, fill=X) LabeledEntry(sslwin, 'SSL trusted certificate directory:', self.sslcertpath, '14').pack(side=TOP, fill=X) + LabeledEntry(sslwin, 'SSL CommonName:', + self.sslcommonname, '14').pack(side=TOP, fill=X) LabeledEntry(sslwin, 'SSL key fingerprint:', self.sslfingerprint, '14').pack(side=TOP, fill=X) sslwin.pack(fill=X, anchor=N) @@ -1649,9 +1697,9 @@ class UserEdit(Frame, MyWidget): Label(targwin, text="Domains to fetch from (ODMR/ETRN only)").pack(side=TOP) ListEdit("Domains:", self.user.fetchdomains, None, None, targwin, None) - LabeledEntry(targwin, 'Append to MAIL FROM line:', + LabeledEntry(targwin, 'Use domain on RCPT TO line:', self.smtpaddress, '26').pack(side=TOP, fill=X) - LabeledEntry(targwin, 'Set RCPT To address:', + LabeledEntry(targwin, 'Set fixed RCPT TO address:', self.smtpname, '26').pack(side=TOP, fill=X) LabeledEntry(targwin, 'Connection setup command:', self.preconnect, '26').pack(side=TOP, fill=X) @@ -1684,6 +1732,8 @@ class UserEdit(Frame, MyWidget): if mode != 'novice': Checkbutton(optwin, text="Flush seen messages before retrieval", variable=self.flush).pack(side=TOP, anchor=W) + Checkbutton(optwin, text="Flush oversized messages before retrieval", + variable=self.limitflush).pack(side=TOP, anchor=W) Checkbutton(optwin, text="Rewrite To/Cc/Bcc messages to enable reply", variable=self.rewrite).pack(side=TOP, anchor=W) Checkbutton(optwin, text="Force CR/LF at end of each line", @@ -1821,7 +1871,7 @@ class RunWindow(Frame): # first. This avoids some obscure version-skew errors that can occur # if you pick up an old fetchmail from the standard system locations. os.environ["PATH"] = os.path.dirname(sys.argv[0]) + ":" + os.environ["PATH"] - child_stdout = os.popen(command + " 2>&1", "r") + child_stdout = os.popen(command + " 2>&1 " + tmpfile + cmd = "umask 077 && fetchmail " + tmpfile else: - cmd = "umask 077 && fetchmail --configdump --nosyslog >" + tmpfile + cmd = "umask 077 && fetchmail " + tmpfile try: s = os.system(cmd)