]> Pileus Git - ~andy/fetchmail/blobdiff - fetchmailconf.py
Fix typo repsonsible -> responsible.
[~andy/fetchmail] / fetchmailconf.py
index ce493627e1df0d6100b179fde5b27dcab10a1133..b4b0a1ae7facd4431a39b776e39cefb071b9ab5e 100755 (executable)
@@ -5,7 +5,7 @@
 # Matthias Andree <matthias.andree@gmx.de>
 # Requires Python with Tkinter, and the following OS-dependent services:
 #      posix, posixpath, socket
 # Matthias Andree <matthias.andree@gmx.de>
 # Requires Python with Tkinter, and the following OS-dependent services:
 #      posix, posixpath, socket
-version = "1.46"
+version = "1.58"
 
 from Tkinter import *
 from Dialog import *
 
 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.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?
        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'),
            ('postmaster',      'String'),
            ('bouncemail',      'Boolean'),
            ('spambounce',      'Boolean'),
+           ('softbounce',      'Boolean'),
            ('properties',      'String'),
            ('syslog',    'Boolean'),
            ('invisible',       '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")
            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.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
        for site in self.servers:
            str = str + repr(site)
        return str
@@ -80,7 +88,6 @@ class Server:
        self.interval = 0               # Skip interval
        self.protocol = 'auto'          # Default to auto protocol
        self.service = None             # Service name to use
        self.interval = 0               # Skip interval
        self.protocol = 'auto'          # Default to auto protocol
        self.service = None             # Service name to use
-       self.uidl = FALSE               # Don't use RFC1725 UIDLs by default
        self.auth = 'any'               # Default to password authentication
        self.timeout = 300              # 5-minute timeout
        self.envelope = 'Received'      # Envelope-address header
        self.auth = 'any'               # Default to password authentication
        self.timeout = 300              # 5-minute timeout
        self.envelope = 'Received'      # Envelope-address header
@@ -97,6 +104,8 @@ class Server:
        self.esmtpname = None           # ESMTP 2554 name
        self.esmtppassword = None       # ESMTP 2554 password
        self.tracepolls = FALSE         # Add trace-poll info to headers
        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.retrieveerror = 'abort'    # Policy when message retrieval errors encountered
        self.users = []                 # List of user entries for site
        Server.typemap = (
            ('pollname',  'String'),
        self.users = []                 # List of user entries for site
        Server.typemap = (
            ('pollname',  'String'),
@@ -105,7 +114,6 @@ class Server:
            ('interval',  'Int'),
            ('protocol',  'String'),
            ('service',   'String'),
            ('interval',  'Int'),
            ('protocol',  'String'),
            ('service',   'String'),
-           ('uidl',      'Boolean'),
            ('auth',      'String'),
            ('timeout',   'Int'),
            ('envelope',  'String'),
            ('auth',      'String'),
            ('timeout',   'Int'),
            ('envelope',  'String'),
@@ -121,7 +129,9 @@ class Server:
            ('esmtpname', 'String'),
            ('esmtppassword', 'String'),
            ('principal', 'String'),
            ('esmtpname', 'String'),
            ('esmtppassword', 'String'),
            ('principal', 'String'),
-           ('tracepolls','Boolean'))
+           ('tracepolls','Boolean'),
+           ('badheader', 'Boolean'),
+           ('retrieveerror', 'String'))
 
     def dump(self, folded):
        res = ""
 
     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
            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`
            res = res + " service " + self.service
        if self.timeout != ServerDefaults.timeout:
            res = res + " timeout " + `self.timeout`
@@ -147,12 +157,9 @@ class Server:
            res = res + (" qvirtual " + str(self.qvirtual) + "\n");
        if self.auth != ServerDefaults.auth:
            res = res + " auth " + self.auth
            res = res + (" qvirtual " + str(self.qvirtual) + "\n");
        if self.auth != ServerDefaults.auth:
            res = res + " auth " + self.auth
-       if self.dns != ServerDefaults.dns or self.uidl != ServerDefaults.uidl:
-           res = res + " and options"
        if self.dns != ServerDefaults.dns:
        if self.dns != ServerDefaults.dns:
+           res = res + " and options"
            res = res + flag2str(self.dns, 'dns')
            res = res + flag2str(self.dns, 'dns')
-       if self.uidl != ServerDefaults.uidl:
-           res = res + flag2str(self.uidl, 'uidl')
        if folded:      res = res + "\n    "
        else:        res = res + " "
 
        if folded:      res = res + "\n    "
        else:        res = res + " "
 
@@ -189,6 +196,16 @@ class Server:
        if self.esmtppassword:
            res = res + " esmtppassword " + `self.esmtppassword`
        if self.interface or self.monitor or self.principal or self.plugin or self.plugout:
        if self.esmtppassword:
            res = res + " esmtppassword " + `self.esmtppassword`
        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 self.retrieveerror == 'continue':
+               res = res + "retrieve-error continue "
+       if self.retrieveerror == 'markseen':
+               res = res + "retrieve-error markseen "
+       if self.badheader or self.retrieveerror != ServerDefaults.retrieveerror:
            if folded:
                res = res + "\n"
 
            if folded:
                res = res + "\n"
 
@@ -235,6 +252,7 @@ class User:
        self.antispam = ""      # Listener's spam-block code
        self.keep = FALSE       # Keep messages
        self.flush = FALSE      # Flush messages
        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
        self.fetchall = FALSE   # Fetch old messages
        self.rewrite = TRUE     # Rewrite message headers
        self.forcecr = FALSE    # Force LF -> CR/LF
@@ -248,7 +266,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.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
        self.batchlimit = 0     # Max message forwarded per batch
        self.expunge = 0        # Interval between expunges (IMAP)
        self.ssl = 0            # Enable Seccure Socket Layer
@@ -257,6 +275,7 @@ class User:
        self.sslproto = None    # Force SSL?
        self.sslcertck = 0      # Enable strict SSL cert checking
        self.sslcertpath = None # Path to trusted certificates
        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 = (
        self.sslfingerprint = None      # SSL key fingerprint to check
        self.properties = None  # Extension properties
        User.typemap = (
@@ -274,6 +293,7 @@ class User:
            ('antispam',    'String'),
            ('keep',    'Boolean'),
            ('flush',       'Boolean'),
            ('antispam',    'String'),
            ('keep',    'Boolean'),
            ('flush',       'Boolean'),
+           ('limitflush',  'Boolean'),
            ('fetchall',    'Boolean'),
            ('rewrite',     'Boolean'),
            ('forcecr',     'Boolean'),
            ('fetchall',    'Boolean'),
            ('rewrite',     'Boolean'),
            ('forcecr',     'Boolean'),
@@ -295,6 +315,7 @@ class User:
            ('sslcert',     'String'),
            ('sslcertck',   'Boolean'),
            ('sslcertpath', 'String'),
            ('sslcert',     'String'),
            ('sslcertck',   'Boolean'),
            ('sslcertpath', 'String'),
+           ('sslcommonname', 'String'),
            ('sslfingerprint', 'String'),
            ('properties',  'String'))
 
            ('sslfingerprint', 'String'),
            ('properties',  'String'))
 
@@ -310,6 +331,7 @@ class User:
            res = res + " here"
        if (self.keep != UserDefaults.keep
                or self.flush != UserDefaults.flush
            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
                or self.fetchall != UserDefaults.fetchall
                or self.rewrite != UserDefaults.rewrite
                or self.forcecr != UserDefaults.forcecr
@@ -324,6 +346,8 @@ class User:
            res = res + flag2str(self.keep, 'keep')
        if self.flush != UserDefaults.flush:
            res = res + flag2str(self.flush, 'flush')
            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:
        if self.fetchall != UserDefaults.fetchall:
            res = res + flag2str(self.fetchall, 'fetchall')
        if self.rewrite != UserDefaults.rewrite:
@@ -366,6 +390,8 @@ class User:
            res = res +  flag2str(self.sslcertck, 'sslcertck')
        if self.sslcertpath and self.sslcertpath != UserDefaults.sslcertpath:
            res = res + " sslcertpath " + `self.sslcertpath`
            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:
        if self.sslfingerprint and self.sslfingerprint != UserDefaults.sslfingerprint:
            res = res + " sslfingerprint " + `self.sslfingerprint`
        if self.expunge != UserDefaults.expunge:
@@ -392,7 +418,7 @@ class User:
        if self.mailboxes:
             res = res + "    folder"
             for x in self.mailboxes:
        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):
             res = res + "\n"
        for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'):
            if getattr(self, fld):
@@ -411,8 +437,7 @@ class User:
 #
 
 # IANA port assignments and bogus 1109 entry
 #
 
 # IANA port assignments and bogus 1109 entry
-ianaservices = {"pop2":109,
-               "pop3":110,
+ianaservices = {"pop3":110,
                "1109":1109,
                "imap":143,
                "smtp":25,
                "1109":1109,
                "imap":143,
                "smtp":25,
@@ -420,15 +445,14 @@ ianaservices = {"pop2":109,
 
 # fetchmail protocol to IANA service name
 defaultports = {"auto":None,
 
 # fetchmail protocol to IANA service name
 defaultports = {"auto":None,
-               "POP2":"pop2",
                "POP3":"pop3",
                "POP3":"pop3",
-               "APOP":"pop3",
                "KPOP":"1109",
                "IMAP":"imap",
                "ETRN":"smtp",
                "ODMR":"odmr"}
 
                "KPOP":"1109",
                "IMAP":"imap",
                "ETRN":"smtp",
                "ODMR":"odmr"}
 
-authlist = ("any", "password", "gssapi", "kerberos", "ssh", "otp")
+authlist = ("any", "password", "gssapi", "kerberos", "ssh", "otp",
+           "msn", "ntlm", "apop", "cram-md5")
 
 listboxhelp = {
     'title' : 'List Selection Help',
 
 listboxhelp = {
     'title' : 'List Selection Help',
@@ -660,9 +684,12 @@ needed to create a simple fetchmail setup.  These include:
 
 4. A protocol to use (POP, IMAP, ETRN, etc.)
 
 
 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
    deletion of fetched message.
 
 The novice-configuration code will assume that you want to forward mail
@@ -710,6 +737,14 @@ Send spam bounces?
        postmaster (depending on the "Bounces to sender?" option.  Otherwise,
        spam bounces are not sent (the default).
 
        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.
 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 +835,18 @@ class ConfigurationEdit(Frame, MyWidget):
 
            sb = Frame(gf)
            Checkbutton(sb,
 
            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)
 
                '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?',
            sf = Frame(gf)
            Checkbutton(sf,
                {'text':'Log to syslog?',
@@ -864,14 +906,17 @@ class ConfigurationEdit(Frame, MyWidget):
            # Pre-1.5.2 compatibility...
            except os.error:
                pass
            # Pre-1.5.2 compatibility...
            except os.error:
                pass
+           oldumask = os.umask(077)
            fm = open(self.outfile, 'w')
            fm = open(self.outfile, 'w')
+           os.umask(oldumask)
        if fm:
        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()
            fm.write(`self.configuration`)
            if self.outfile:
                fm.close()
-           if fm != sys.stdout:
-               os.chmod(self.outfile, 0600)
            self.destruct()
 
 #
            self.destruct()
 
 #
@@ -917,6 +962,13 @@ the normal operation of fetchmail when it is run with no arguments.
 If it is off, fetchmail will only query this host when it is given as
 a command-line argument.
 
 If it is off, fetchmail will only query this host when it is given as
 a command-line argument.
 
+The `Retrieve Error Policy' specifies how server errors during
+message retrieval are handled.  The default behaviour is to abort the
+current session.  Both the continue and markseen options will skip
+the message with the error, but continue the session allowing for 
+downloading of subsequent messages.  Additionally, the markseen
+option will mark the skipped message as seen.
 The `True name of server' box should specify the actual DNS name
 to query. By default this is the same as the poll name.
 
 The `True name of server' box should specify the actual DNS name
 to query. By default this is the same as the poll name.
 
@@ -962,7 +1014,12 @@ sechelp = {
     'title' : 'Security option help',
     'banner': 'Security',
     'text' : """
     '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
 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 +1040,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
 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.
 """}
 
 print the server's key is checked against.
 """}
 
@@ -1065,7 +1124,6 @@ class ServerEdit(Frame, MyWidget):
        # a custom port number you should be in expert mode and playing
        # close enough attention to notice this...
        self.service.set(defaultports[proto])
        # a custom port number you should be in expert mode and playing
        # close enough attention to notice this...
        self.service.set(defaultports[proto])
-       if not proto in ("POP3", "APOP", "KPOP"): self.uidl.state = DISABLED
 
     def user_edit(self, username, mode):
        self.subwidgets[username] = UserEdit(username, self).edit(mode, Toplevel())
 
     def user_edit(self, username, mode):
        self.subwidgets[username] = UserEdit(username, self).edit(mode, Toplevel())
@@ -1085,6 +1143,11 @@ 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)
            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)
+            retrieveerrorlist = ['abort', 'continue', 'markseen']
+            Label(ctlwin, text="Retrieve Error Policy").pack(side=TOP)
+            ButtonBar(ctlwin, '', self.retrieveerror, retrieveerrorlist, 1, None)
            LabeledEntry(ctlwin, 'True name of ' + host + ':',
                      self.via, leftwidth).pack(side=TOP, fill=X)
            LabeledEntry(ctlwin, 'Cycles to skip between polls:',
            LabeledEntry(ctlwin, 'True name of ' + host + ':',
                      self.via, leftwidth).pack(side=TOP, fill=X)
            LabeledEntry(ctlwin, 'Cycles to skip between polls:',
@@ -1097,10 +1160,8 @@ class ServerEdit(Frame, MyWidget):
 
        # Compute the available protocols from the compile-time options
        protolist = ['auto']
 
        # Compute the available protocols from the compile-time options
        protolist = ['auto']
-       if 'pop2' in feature_options:
-           protolist.append("POP2")
        if 'pop3' in feature_options:
        if 'pop3' in feature_options:
-           protolist = protolist + ["POP3", "APOP", "KPOP"]
+           protolist = protolist + ["POP3", "KPOP"]
        if 'sdps' in feature_options:
            protolist.append("SDPS")
        if 'imap' in feature_options:
        if 'sdps' in feature_options:
            protolist.append("SDPS")
        if 'imap' in feature_options:
@@ -1119,9 +1180,6 @@ class ServerEdit(Frame, MyWidget):
            LabeledEntry(protwin, 'On server TCP/IP service:',
                      self.service, leftwidth).pack(side=TOP, fill=X)
            self.defaultPort()
            LabeledEntry(protwin, 'On server TCP/IP service:',
                      self.service, leftwidth).pack(side=TOP, fill=X)
            self.defaultPort()
-           Checkbutton(protwin,
-               text="POP3: track `seen' with client-side UIDLs?",
-               variable=self.uidl).pack(side=TOP)
        Button(protwin, text='Probe for supported protocols', fg='blue',
               command=self.autoprobe).pack(side=LEFT)
        Button(protwin, text='Help', fg='blue',
        Button(protwin, text='Probe for supported protocols', fg='blue',
               command=self.autoprobe).pack(side=LEFT)
        Button(protwin, text='Help', fg='blue',
@@ -1163,8 +1221,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
                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)
                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)
@@ -1195,7 +1253,7 @@ class ServerEdit(Frame, MyWidget):
        else:
            realhost = self.server.pollname
        greetline = None
        else:
            realhost = self.server.pollname
        greetline = None
-       for protocol in ("IMAP","POP3","POP2"):
+       for protocol in ("IMAP","POP3"):
            service = defaultports[protocol]
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
            service = defaultports[protocol]
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
@@ -1220,18 +1278,6 @@ out before getting a response.
            warnings = ''
            # OK, now try to recognize potential problems
 
            warnings = ''
            # OK, now try to recognize potential problems
 
-           if protocol == "POP2":
-               warnings = warnings + """
-It appears you have somehow found a mailserver running only POP2.
-Congratulations.  Have you considered a career in archaeology?
-
-Unfortunately, stock fetchmail binaries don't include POP2 support anymore.
-Unless the first line of your fetchmail -V output includes the string "POP2",
-you'll have to build it from sources yourself with the configure
-switch --enable-POP2.
-
-"""
-
 ### POP3 servers start here
 
            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:
@@ -1422,13 +1468,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.<p>
 
 with code as shoddy as GroupWise seems to be, you will probably pay
 for it with other problems.<p>
 
-"""
-           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 + """
 """
            if string.find(greetline, "InterChange") > 0:
                warnings = warnings + """
@@ -1453,7 +1492,7 @@ 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
            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
+to version 5.0.2, 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.
 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.
@@ -1469,20 +1508,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.
 
 password in clear.  You should talk to the mailserver administrator about
 this.
 
-"""
-           if string.find(greetline, "IMAP2bis") > 0:
-               warnings = warnings + """
-IMAP2bis servers have a minor problem; they can't peek at messages without
-marking them seen.  If you take a line hit during the retrieval, the
-interrupted message may get left on the server, marked seen.
-
-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.
-
-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 + """
 """
            if string.find(greetline, "IMAP4rev1") > 0:
                warnings = warnings + """
@@ -1501,6 +1526,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)
            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()
        confwin.title(title)
        confwin.iconname(title)
        Label(confwin, text=title).pack()
@@ -1630,6 +1656,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)
                        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)
            LabeledEntry(sslwin, 'SSL key fingerprint:',
                         self.sslfingerprint, '14').pack(side=TOP, fill=X)
            sslwin.pack(fill=X, anchor=N)
@@ -1649,9 +1677,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)
            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)
                     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)
                     self.smtpname, '26').pack(side=TOP, fill=X)
            LabeledEntry(targwin, 'Connection setup command:',
                     self.preconnect, '26').pack(side=TOP, fill=X)
@@ -1684,6 +1712,8 @@ class UserEdit(Frame, MyWidget):
        if mode != 'novice':
            Checkbutton(optwin, text="Flush seen messages before retrieval",
                    variable=self.flush).pack(side=TOP, anchor=W)
        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",
            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 +1851,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"]
        # 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 </dev/null", "r")
        while 1:
            ch = child_stdout.read(1)
            if not ch:
        while 1:
            ch = child_stdout.read(1)
            if not ch:
@@ -1886,10 +1916,16 @@ Or you can just select `Quit' to exit the launcher now.
                     lambda self=self: self.configbutton.configure(state=NORMAL),
                     self)
     def test(self):
                     lambda self=self: self.configbutton.configure(state=NORMAL),
                     self)
     def test(self):
-       RunWindow("fetchmail -d0 -v --nosyslog", Toplevel(), self)
+       cmd = "fetchmail -N -d0 --nosyslog -v"
+       if rcfile:
+           cmd = cmd + " -f " + rcfile
+       RunWindow(cmd, Toplevel(), self)
 
     def run(self):
 
     def run(self):
-       RunWindow("fetchmail -d0", Toplevel(), self)
+       cmd = "fetchmail -N -d0"
+       if rcfile:
+           cmd = cmd + " -f " + rcfile
+       RunWindow(cmd, Toplevel(), self)
 
     def leave(self):
        self.quit()
 
     def leave(self):
        self.quit()
@@ -1923,7 +1959,7 @@ def copy_instance(toclass, fromdict):
     optional = ('interface', 'monitor',
                'esmtpname', 'esmtppassword',
                'ssl', 'sslkey', 'sslcert', 'sslproto', 'sslcertck',
     optional = ('interface', 'monitor',
                'esmtpname', 'esmtppassword',
                'ssl', 'sslkey', 'sslcert', 'sslproto', 'sslcertck',
-               'sslcertpath', 'sslfingerprint', 'showdots')
+               'sslcertpath', 'sslcommonname', 'sslfingerprint', 'showdots')
     class_sig = setdiff(toclass.__dict__.keys(), optional)
     class_sig.sort()
     dict_keys = setdiff(fromdict.keys(), optional)
     class_sig = setdiff(toclass.__dict__.keys(), optional)
     class_sig.sort()
     dict_keys = setdiff(fromdict.keys(), optional)
@@ -2016,20 +2052,32 @@ gUSiYASJpMEHhilJTEnhAlGoQqYAZQ1AiqEMZ0jDGtqQImhwwA13yMMevoQAGvGhEAWHGMOAAAA7
 #
 
     # Process options
 #
 
     # Process options
-    (options, arguments) = getopt.getopt(sys.argv[1:], "df:h")
+    (options, arguments) = getopt.getopt(sys.argv[1:], "df:hV", ["help",
+           "version"])
     dump = rcfile = None;
     for (switch, val) in options:
        if (switch == '-d'):
            dump = TRUE
        elif (switch == '-f'):
            rcfile = val
     dump = rcfile = None;
     for (switch, val) in options:
        if (switch == '-d'):
            dump = TRUE
        elif (switch == '-f'):
            rcfile = val
-       elif (switch == '-h'):
+       elif (switch == '-h' or switch == '--help'):
            print """
            print """
-Usage: fetchmailconf [-d] [-f fetchmailrc]
--d       - dump configuration (for debugging)
--f fmrc  - read alternate fetchmailrc file
+Usage: fetchmailconf {[-d] [-f fetchmailrc]|-h|--help|-V|--version}
+           -d      - dump configuration (for debugging)
+           -f fmrc - read alternate fetchmailrc file
+--help,    -h      - print this help text and quit
+--version, -V      - print fetchmailconf version and quit
 """
            sys.exit(0)
 """
            sys.exit(0)
+       elif (switch == '-V' or switch == '--version'):
+           print "fetchmailconf %s" % version
+           print """
+Copyright (C) 1997 - 2003 Eric S. Raymond
+Copyright (C) 2005, 2006, 2008, 2009 Matthias Andree
+fetchmailconf comes with ABSOLUTELY NO WARRANTY.  This is free software, you are
+welcome to redistribute it under certain conditions.  Please see the file
+COPYING in the source or documentation directory for details."""
+           sys.exit(0)
 
     # Get client host's FQDN
     hostname = socket.gethostbyaddr(socket.gethostname())[0]
 
     # Get client host's FQDN
     hostname = socket.gethostbyaddr(socket.gethostname())[0]
@@ -2044,9 +2092,9 @@ Usage: fetchmailconf [-d] [-f fetchmailrc]
     # want crackers to snoop password information out of the tempfile.
     tmpfile = tempfile.mktemp()
     if rcfile:
     # want crackers to snoop password information out of the tempfile.
     tmpfile = tempfile.mktemp()
     if rcfile:
-       cmd = "umask 077; fetchmail -f " + rcfile + " --configdump --nosyslog >" + tmpfile
+       cmd = "umask 077 && fetchmail </dev/null -f " + rcfile + " --configdump --nosyslog >" + tmpfile
     else:
     else:
-       cmd = "umask 077; fetchmail --configdump --nosyslog >" + tmpfile
+       cmd = "umask 077 && fetchmail </dev/null --configdump --nosyslog >" + tmpfile
 
     try:
        s = os.system(cmd)
 
     try:
        s = os.system(cmd)