diff --git a/fetchmail-fetchmailconf-python3-1of3.patch b/fetchmail-fetchmailconf-python3-1of3.patch new file mode 100644 index 0000000..c9f53a0 --- /dev/null +++ b/fetchmail-fetchmailconf-python3-1of3.patch @@ -0,0 +1,3074 @@ +From 2a23b1b8f3f8d73ba65f2109b0b496bc3d13f59a Mon Sep 17 00:00:00 2001 +From: Samuel Martin +Date: Wed, 8 Jun 2016 21:36:28 +0200 +Subject: [PATCH] fetchmailconf.py: fix tabs/spaces mixup preventing from compiling the pyc module + +This whitespace-only change substitutes all leading tabulations with +the right number of spaces to get the standard 4-space indentation. + +This bug was triggered by the Buildroot farms: + http://autobuild.buildroot.org/results/700/7009445dd116a1c02db82a351d38db44db8dad16/build-end.log + +Signed-off-by: Samuel Martin +Signed-off-by: Matthias Andree +--- + fetchmailconf.py | 2532 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + 1 file changed, 1266 insertions(+), 1266 deletions(-) + +diff --git a/fetchmailconf.py b/fetchmailconf.py +index 2dc02d8..d64556e 100755 +--- a/fetchmailconf.py ++++ b/fetchmailconf.py +@@ -16,416 +16,416 @@ import sys, time, os, string, socket, getopt, tempfile + # + class Configuration: + def __init__(self): +- self.poll_interval = 0 # Normally, run in foreground +- self.logfile = None # No logfile, initially +- self.idfile = os.environ["HOME"] + "/.fetchids" # Default idfile, initially +- 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.servers = [] # List of included sites +- Configuration.typemap = ( +- ('poll_interval', 'Int'), +- ('logfile', 'String'), +- ('idfile', 'String'), +- ('postmaster', 'String'), +- ('bouncemail', 'Boolean'), +- ('spambounce', 'Boolean'), +- ('softbounce', 'Boolean'), +- ('properties', 'String'), +- ('syslog', 'Boolean'), +- ('invisible', 'Boolean')) ++ self.poll_interval = 0 # Normally, run in foreground ++ self.logfile = None # No logfile, initially ++ self.idfile = os.environ["HOME"] + "/.fetchids" # Default idfile, initially ++ 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.servers = [] # List of included sites ++ Configuration.typemap = ( ++ ('poll_interval', 'Int'), ++ ('logfile', 'String'), ++ ('idfile', 'String'), ++ ('postmaster', 'String'), ++ ('bouncemail', 'Boolean'), ++ ('spambounce', 'Boolean'), ++ ('softbounce', 'Boolean'), ++ ('properties', 'String'), ++ ('syslog', 'Boolean'), ++ ('invisible', 'Boolean')) + + def __repr__(self): +- str = ""; +- if self.syslog != ConfigurationDefaults.syslog: +- str = str + ("set syslog\n") +- elif self.logfile: +- str = str + ("set logfile \"%s\"\n" % (self.logfile,)); +- if self.idfile != ConfigurationDefaults.idfile: +- str = str + ("set idfile \"%s\"\n" % (self.idfile,)); +- if self.postmaster != ConfigurationDefaults.postmaster: +- str = str + ("set postmaster \"%s\"\n" % (self.postmaster,)); +- if self.bouncemail: +- str = str + ("set bouncemail\n") +- else: +- str = str + ("set nobouncemail\n") +- if self.spambounce: +- 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 ++ str = ""; ++ if self.syslog != ConfigurationDefaults.syslog: ++ str = str + ("set syslog\n") ++ elif self.logfile: ++ str = str + ("set logfile \"%s\"\n" % (self.logfile,)); ++ if self.idfile != ConfigurationDefaults.idfile: ++ str = str + ("set idfile \"%s\"\n" % (self.idfile,)); ++ if self.postmaster != ConfigurationDefaults.postmaster: ++ str = str + ("set postmaster \"%s\"\n" % (self.postmaster,)); ++ if self.bouncemail: ++ str = str + ("set bouncemail\n") ++ else: ++ str = str + ("set nobouncemail\n") ++ if self.spambounce: ++ 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 + + def __delitem__(self, name): +- for si in range(len(self.servers)): +- if self.servers[si].pollname == name: +- del self.servers[si] +- break ++ for si in range(len(self.servers)): ++ if self.servers[si].pollname == name: ++ del self.servers[si] ++ break + + def __str__(self): +- return "[Configuration: " + repr(self) + "]" ++ return "[Configuration: " + repr(self) + "]" + + class Server: + def __init__(self): +- self.pollname = None # Poll label +- self.via = None # True name of host +- self.active = TRUE # Poll status +- 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.envskip = 0 # Number of envelope headers to skip +- self.qvirtual = None # Name prefix to strip +- self.aka = [] # List of DNS aka names +- self.dns = TRUE # Enable DNS lookup on multidrop +- self.localdomains = [] # Domains to be considered local +- self.interface = None # IP address and range +- self.monitor = None # IP address and range +- self.plugin = None # Plugin command for going to server +- self.plugout = None # Plugin command for going to listener +- self.principal = None # Kerberos principal +- 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'), +- ('via', 'String'), +- ('active', 'Boolean'), +- ('interval', 'Int'), +- ('protocol', 'String'), +- ('service', 'String'), +- ('uidl', 'Boolean'), +- ('auth', 'String'), +- ('timeout', 'Int'), +- ('envelope', 'String'), +- ('envskip', 'Int'), +- ('qvirtual', 'String'), +- # leave aka out +- ('dns', 'Boolean'), +- # leave localdomains out +- ('interface', 'String'), +- ('monitor', 'String'), +- ('plugin', 'String'), +- ('plugout', 'String'), +- ('esmtpname', 'String'), +- ('esmtppassword', 'String'), +- ('principal', 'String'), +- ('tracepolls','Boolean'), +- ('badheader', 'Boolean')) ++ self.pollname = None # Poll label ++ self.via = None # True name of host ++ self.active = TRUE # Poll status ++ 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.envskip = 0 # Number of envelope headers to skip ++ self.qvirtual = None # Name prefix to strip ++ self.aka = [] # List of DNS aka names ++ self.dns = TRUE # Enable DNS lookup on multidrop ++ self.localdomains = [] # Domains to be considered local ++ self.interface = None # IP address and range ++ self.monitor = None # IP address and range ++ self.plugin = None # Plugin command for going to server ++ self.plugout = None # Plugin command for going to listener ++ self.principal = None # Kerberos principal ++ 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'), ++ ('via', 'String'), ++ ('active', 'Boolean'), ++ ('interval', 'Int'), ++ ('protocol', 'String'), ++ ('service', 'String'), ++ ('uidl', 'Boolean'), ++ ('auth', 'String'), ++ ('timeout', 'Int'), ++ ('envelope', 'String'), ++ ('envskip', 'Int'), ++ ('qvirtual', 'String'), ++ # leave aka out ++ ('dns', 'Boolean'), ++ # leave localdomains out ++ ('interface', 'String'), ++ ('monitor', 'String'), ++ ('plugin', 'String'), ++ ('plugout', 'String'), ++ ('esmtpname', 'String'), ++ ('esmtppassword', 'String'), ++ ('principal', 'String'), ++ ('tracepolls','Boolean'), ++ ('badheader', 'Boolean')) + + def dump(self, folded): +- res = "" +- if self.active: res = res + "poll" +- else: res = res + "skip" +- res = res + (" " + self.pollname) +- if self.via: +- res = res + (" via " + str(self.via) + "\n"); +- if self.protocol != ServerDefaults.protocol: +- res = res + " with proto " + 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` +- if self.interval != ServerDefaults.interval: +- res = res + " interval " + `self.interval` +- if self.envelope != ServerDefaults.envelope or self.envskip != ServerDefaults.envskip: +- if self.envskip: +- res = res + " envelope " + `self.envskip` + " " + self.envelope +- else: +- res = res + " envelope " + self.envelope +- if self.qvirtual: +- 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: +- 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 self.aka: +- res = res + "aka" +- for x in self.aka: +- res = res + " " + x +- if self.aka and self.localdomains: res = res + " " +- if self.localdomains: +- res = res + ("localdomains") +- for x in self.localdomains: +- res = res + " " + x +- if (self.aka or self.localdomains): +- if folded: +- res = res + "\n " +- else: +- res = res + " " +- +- if self.tracepolls: +- res = res + "tracepolls\n" +- +- if self.interface: +- res = res + " interface " + str(self.interface) +- if self.monitor: +- res = res + " monitor " + str(self.monitor) +- if self.plugin: +- res = res + " plugin " + `self.plugin` +- if self.plugout: +- res = res + " plugout " + `self.plugout` +- if self.principal: +- res = res + " principal " + `self.principal` +- if self.esmtpname: +- res = res + " esmtpname " + `self.esmtpname` +- 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 res[-1] == " ": res = res[0:-1] +- +- for user in self.users: +- res = res + repr(user) +- res = res + "\n" +- return res; ++ res = "" ++ if self.active: res = res + "poll" ++ else: res = res + "skip" ++ res = res + (" " + self.pollname) ++ if self.via: ++ res = res + (" via " + str(self.via) + "\n"); ++ if self.protocol != ServerDefaults.protocol: ++ res = res + " with proto " + 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` ++ if self.interval != ServerDefaults.interval: ++ res = res + " interval " + `self.interval` ++ if self.envelope != ServerDefaults.envelope or self.envskip != ServerDefaults.envskip: ++ if self.envskip: ++ res = res + " envelope " + `self.envskip` + " " + self.envelope ++ else: ++ res = res + " envelope " + self.envelope ++ if self.qvirtual: ++ 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: ++ 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 self.aka: ++ res = res + "aka" ++ for x in self.aka: ++ res = res + " " + x ++ if self.aka and self.localdomains: res = res + " " ++ if self.localdomains: ++ res = res + ("localdomains") ++ for x in self.localdomains: ++ res = res + " " + x ++ if (self.aka or self.localdomains): ++ if folded: ++ res = res + "\n " ++ else: ++ res = res + " " ++ ++ if self.tracepolls: ++ res = res + "tracepolls\n" ++ ++ if self.interface: ++ res = res + " interface " + str(self.interface) ++ if self.monitor: ++ res = res + " monitor " + str(self.monitor) ++ if self.plugin: ++ res = res + " plugin " + `self.plugin` ++ if self.plugout: ++ res = res + " plugout " + `self.plugout` ++ if self.principal: ++ res = res + " principal " + `self.principal` ++ if self.esmtpname: ++ res = res + " esmtpname " + `self.esmtpname` ++ 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 res[-1] == " ": res = res[0:-1] ++ ++ for user in self.users: ++ res = res + repr(user) ++ res = res + "\n" ++ return res; + + def __delitem__(self, name): +- for ui in range(len(self.users)): +- if self.users[ui].remote == name: +- del self.users[ui] +- break ++ for ui in range(len(self.users)): ++ if self.users[ui].remote == name: ++ del self.users[ui] ++ break + + def __repr__(self): +- return self.dump(TRUE) ++ return self.dump(TRUE) + + def __str__(self): +- return "[Server: " + self.dump(FALSE) + "]" ++ return "[Server: " + self.dump(FALSE) + "]" + + class User: + def __init__(self): +- if os.environ.has_key("USER"): +- self.remote = os.environ["USER"] # Remote username +- elif os.environ.has_key("LOGNAME"): +- self.remote = os.environ["LOGNAME"] +- else: +- print "Can't get your username!" +- sys.exit(1) +- self.localnames = [self.remote,]# Local names +- self.password = None # Password for mail account access +- self.mailboxes = [] # Remote folders to retrieve from +- self.smtphunt = [] # Hosts to forward to +- self.fetchdomains = [] # Domains to fetch from +- self.smtpaddress = None # Append this to MAIL FROM line +- self.smtpname = None # Use this for RCPT TO +- self.preconnect = None # Connection setup +- self.postconnect = None # Connection wrapup +- self.mda = None # Mail Delivery Agent +- self.bsmtp = None # BSMTP output file +- self.lmtp = FALSE # Use LMTP rather than SMTP? +- 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.stripcr = FALSE # Strip CR +- self.pass8bits = FALSE # Force BODY=7BIT +- 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 = 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 = 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.sslkey = None # SSL key filename +- self.sslcert = None # SSL certificate filename +- 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 = ( +- ('remote', 'String'), +- # leave out mailboxes and localnames +- ('password', 'String'), +- # Leave out smtphunt, fetchdomains +- ('smtpaddress', 'String'), +- ('smtpname', 'String'), +- ('preconnect', 'String'), +- ('postconnect', 'String'), +- ('mda', 'String'), +- ('bsmtp', 'String'), +- ('lmtp', 'Boolean'), +- ('antispam', 'String'), +- ('keep', 'Boolean'), +- ('flush', 'Boolean'), +- ('limitflush', 'Boolean'), +- ('fetchall', 'Boolean'), +- ('rewrite', 'Boolean'), +- ('forcecr', 'Boolean'), +- ('stripcr', 'Boolean'), +- ('pass8bits', 'Boolean'), +- ('mimedecode', 'Boolean'), +- ('dropstatus', 'Boolean'), +- ('dropdelivered', 'Boolean'), +- ('idle', 'Boolean'), +- ('limit', 'Int'), +- ('warnings', 'Int'), +- ('fetchlimit', 'Int'), +- ('fetchsizelimit', 'Int'), +- ('fastuidl', 'Int'), +- ('batchlimit', 'Int'), +- ('expunge', 'Int'), +- ('ssl', 'Boolean'), +- ('sslkey', 'String'), +- ('sslcert', 'String'), +- ('sslcertck', 'Boolean'), +- ('sslcertpath', 'String'), +- ('sslcommonname', 'String'), +- ('sslfingerprint', 'String'), +- ('properties', 'String')) ++ if os.environ.has_key("USER"): ++ self.remote = os.environ["USER"] # Remote username ++ elif os.environ.has_key("LOGNAME"): ++ self.remote = os.environ["LOGNAME"] ++ else: ++ print "Can't get your username!" ++ sys.exit(1) ++ self.localnames = [self.remote,]# Local names ++ self.password = None # Password for mail account access ++ self.mailboxes = [] # Remote folders to retrieve from ++ self.smtphunt = [] # Hosts to forward to ++ self.fetchdomains = [] # Domains to fetch from ++ self.smtpaddress = None # Append this to MAIL FROM line ++ self.smtpname = None # Use this for RCPT TO ++ self.preconnect = None # Connection setup ++ self.postconnect = None # Connection wrapup ++ self.mda = None # Mail Delivery Agent ++ self.bsmtp = None # BSMTP output file ++ self.lmtp = FALSE # Use LMTP rather than SMTP? ++ 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.stripcr = FALSE # Strip CR ++ self.pass8bits = FALSE # Force BODY=7BIT ++ 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 = 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 = 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.sslkey = None # SSL key filename ++ self.sslcert = None # SSL certificate filename ++ 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 = ( ++ ('remote', 'String'), ++ # leave out mailboxes and localnames ++ ('password', 'String'), ++ # Leave out smtphunt, fetchdomains ++ ('smtpaddress', 'String'), ++ ('smtpname', 'String'), ++ ('preconnect', 'String'), ++ ('postconnect', 'String'), ++ ('mda', 'String'), ++ ('bsmtp', 'String'), ++ ('lmtp', 'Boolean'), ++ ('antispam', 'String'), ++ ('keep', 'Boolean'), ++ ('flush', 'Boolean'), ++ ('limitflush', 'Boolean'), ++ ('fetchall', 'Boolean'), ++ ('rewrite', 'Boolean'), ++ ('forcecr', 'Boolean'), ++ ('stripcr', 'Boolean'), ++ ('pass8bits', 'Boolean'), ++ ('mimedecode', 'Boolean'), ++ ('dropstatus', 'Boolean'), ++ ('dropdelivered', 'Boolean'), ++ ('idle', 'Boolean'), ++ ('limit', 'Int'), ++ ('warnings', 'Int'), ++ ('fetchlimit', 'Int'), ++ ('fetchsizelimit', 'Int'), ++ ('fastuidl', 'Int'), ++ ('batchlimit', 'Int'), ++ ('expunge', 'Int'), ++ ('ssl', 'Boolean'), ++ ('sslkey', 'String'), ++ ('sslcert', 'String'), ++ ('sslcertck', 'Boolean'), ++ ('sslcertpath', 'String'), ++ ('sslcommonname', 'String'), ++ ('sslfingerprint', 'String'), ++ ('properties', 'String')) + + def __repr__(self): +- res = " " +- res = res + "user " + `self.remote` + " there "; +- if self.password: +- res = res + "with password " + `self.password` + " " +- if self.localnames: +- res = res + "is" +- for x in self.localnames: +- res = res + " " + `x` +- 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.stripcr != UserDefaults.stripcr +- or self.pass8bits != UserDefaults.pass8bits +- or self.mimedecode != UserDefaults.mimedecode +- or self.dropstatus != UserDefaults.dropstatus +- or self.dropdelivered != UserDefaults.dropdelivered +- or self.idle != UserDefaults.idle): +- res = res + " options" +- if self.keep != UserDefaults.keep: +- 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: +- res = res + flag2str(self.rewrite, 'rewrite') +- if self.forcecr != UserDefaults.forcecr: +- res = res + flag2str(self.forcecr, 'forcecr') +- if self.stripcr != UserDefaults.stripcr: +- res = res + flag2str(self.stripcr, 'stripcr') +- if self.pass8bits != UserDefaults.pass8bits: +- res = res + flag2str(self.pass8bits, 'pass8bits') +- if self.mimedecode != UserDefaults.mimedecode: +- res = res + flag2str(self.mimedecode, 'mimedecode') +- if self.dropstatus != UserDefaults.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: +- res = res + " limit " + `self.limit` +- if self.warnings != UserDefaults.warnings: +- res = res + " warnings " + `self.warnings` +- if self.fetchlimit != UserDefaults.fetchlimit: +- res = res + " fetchlimit " + `self.fetchlimit` +- if self.fetchsizelimit != UserDefaults.fetchsizelimit: +- res = res + " fetchsizelimit " + `self.fetchsizelimit` +- if self.fastuidl != UserDefaults.fastuidl: +- res = res + " fastuidl " + `self.fastuidl` +- if self.batchlimit != UserDefaults.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.sslproto and self.sslproto != UserDefaults.sslproto: +- res = res + " sslproto " + `self.sslproto` +- if self.sslcertck and self.sslcertck != UserDefaults.sslcertck: +- 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: +- 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 != []: +- res = res + " smtphost " +- for x in trimmed: +- res = res + " " + x +- res = res + "\n" +- trimmed = self.fetchdomains +- if trimmed != [] and trimmed[len(trimmed) - 1] == hostname: +- trimmed = trimmed[0:len(trimmed) - 1] +- if trimmed != []: +- res = res + " fetchdomains " +- for x in trimmed: +- res = res + " " + x +- res = res + "\n" +- if self.mailboxes: +- res = res + " folder" +- for x in self.mailboxes: +- res = res + ' "%s"' % x +- res = res + "\n" +- for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'): +- if getattr(self, fld): +- res = res + " %s %s\n" % (fld, `getattr(self, fld)`) +- if self.lmtp != UserDefaults.lmtp: +- res = res + flag2str(self.lmtp, 'lmtp') +- if self.antispam != UserDefaults.antispam: +- res = res + " antispam " + self.antispam + "\n" +- return res; ++ res = " " ++ res = res + "user " + `self.remote` + " there "; ++ if self.password: ++ res = res + "with password " + `self.password` + " " ++ if self.localnames: ++ res = res + "is" ++ for x in self.localnames: ++ res = res + " " + `x` ++ 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.stripcr != UserDefaults.stripcr ++ or self.pass8bits != UserDefaults.pass8bits ++ or self.mimedecode != UserDefaults.mimedecode ++ or self.dropstatus != UserDefaults.dropstatus ++ or self.dropdelivered != UserDefaults.dropdelivered ++ or self.idle != UserDefaults.idle): ++ res = res + " options" ++ if self.keep != UserDefaults.keep: ++ 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: ++ res = res + flag2str(self.rewrite, 'rewrite') ++ if self.forcecr != UserDefaults.forcecr: ++ res = res + flag2str(self.forcecr, 'forcecr') ++ if self.stripcr != UserDefaults.stripcr: ++ res = res + flag2str(self.stripcr, 'stripcr') ++ if self.pass8bits != UserDefaults.pass8bits: ++ res = res + flag2str(self.pass8bits, 'pass8bits') ++ if self.mimedecode != UserDefaults.mimedecode: ++ res = res + flag2str(self.mimedecode, 'mimedecode') ++ if self.dropstatus != UserDefaults.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: ++ res = res + " limit " + `self.limit` ++ if self.warnings != UserDefaults.warnings: ++ res = res + " warnings " + `self.warnings` ++ if self.fetchlimit != UserDefaults.fetchlimit: ++ res = res + " fetchlimit " + `self.fetchlimit` ++ if self.fetchsizelimit != UserDefaults.fetchsizelimit: ++ res = res + " fetchsizelimit " + `self.fetchsizelimit` ++ if self.fastuidl != UserDefaults.fastuidl: ++ res = res + " fastuidl " + `self.fastuidl` ++ if self.batchlimit != UserDefaults.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.sslproto and self.sslproto != UserDefaults.sslproto: ++ res = res + " sslproto " + `self.sslproto` ++ if self.sslcertck and self.sslcertck != UserDefaults.sslcertck: ++ 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: ++ 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 != []: ++ res = res + " smtphost " ++ for x in trimmed: ++ res = res + " " + x ++ res = res + "\n" ++ trimmed = self.fetchdomains ++ if trimmed != [] and trimmed[len(trimmed) - 1] == hostname: ++ trimmed = trimmed[0:len(trimmed) - 1] ++ if trimmed != []: ++ res = res + " fetchdomains " ++ for x in trimmed: ++ res = res + " " + x ++ res = res + "\n" ++ if self.mailboxes: ++ res = res + " folder" ++ for x in self.mailboxes: ++ res = res + ' "%s"' % x ++ res = res + "\n" ++ for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'): ++ if getattr(self, fld): ++ res = res + " %s %s\n" % (fld, `getattr(self, fld)`) ++ if self.lmtp != UserDefaults.lmtp: ++ res = res + flag2str(self.lmtp, 'lmtp') ++ if self.antispam != UserDefaults.antispam: ++ res = res + " antispam " + self.antispam + "\n" ++ return res; + + def __str__(self): +- return "[User: " + repr(self) + "]" ++ return "[User: " + repr(self) + "]" + + # + # Helper code +@@ -433,24 +433,24 @@ class User: + + # IANA port assignments and bogus 1109 entry + ianaservices = {"pop2":109, +- "pop3":110, +- "1109":1109, +- "imap":143, +- "smtp":25, +- "odmr":366} ++ "pop3":110, ++ "1109":1109, ++ "imap":143, ++ "smtp":25, ++ "odmr":366} + + # fetchmail protocol to IANA service name + defaultports = {"auto":None, +- "POP2":"pop2", +- "POP3":"pop3", +- "APOP":"pop3", +- "KPOP":"1109", +- "IMAP":"imap", +- "ETRN":"smtp", +- "ODMR":"odmr"} ++ "POP2":"pop2", ++ "POP3":"pop3", ++ "APOP":"pop3", ++ "KPOP":"1109", ++ "IMAP":"imap", ++ "ETRN":"smtp", ++ "ODMR":"odmr"} + + authlist = ("any", "password", "gssapi", "kerberos", "ssh", "otp", +- "msn", "ntlm") ++ "msn", "ntlm") + + listboxhelp = { + 'title' : 'List Selection Help', +@@ -463,23 +463,23 @@ def flag2str(value, string): + # make a string representation of a .fetchmailrc flag or negated flag + str = "" + if value != None: +- str = str + (" ") +- if value == FALSE: str = str + ("no ") +- str = str + string; ++ str = str + (" ") ++ if value == FALSE: str = str + ("no ") ++ str = str + string; + return str + + class LabeledEntry(Frame): + # widget consisting of entry field with caption to left + def bind(self, key, action): +- self.E.bind(key, action) ++ self.E.bind(key, action) + def focus_set(self): +- self.E.focus_set() ++ self.E.focus_set() + def __init__(self, Master, text, textvar, lwidth, ewidth=12): +- Frame.__init__(self, Master) +- self.L = Label(self, {'text':text, 'width':lwidth, 'anchor':'w'}) +- self.E = Entry(self, {'textvar':textvar, 'width':ewidth}) +- self.L.pack({'side':'left'}) +- self.E.pack({'side':'left', 'expand':'1', 'fill':'x'}) ++ Frame.__init__(self, Master) ++ self.L = Label(self, {'text':text, 'width':lwidth, 'anchor':'w'}) ++ self.E = Entry(self, {'textvar':textvar, 'width':ewidth}) ++ self.L.pack({'side':'left'}) ++ self.E.pack({'side':'left', 'expand':'1', 'fill':'x'}) + + def ButtonBar(frame, legend, ref, alternatives, depth, command): + # array of radio buttons, caption to left, picking from a string list +@@ -487,20 +487,20 @@ def ButtonBar(frame, legend, ref, alternatives, depth, command): + width = (len(alternatives)+1) / depth; + Label(bar, text=legend).pack(side=LEFT) + for column in range(width): +- subframe = Frame(bar) +- for row in range(depth): +- ind = width * row + column +- if ind < len(alternatives): +- Radiobutton(subframe, +- {'text':alternatives[ind], +- 'variable':ref, +- 'value':alternatives[ind], +- 'command':command}).pack(side=TOP, anchor=W) +- else: +- # This is just a spacer +- Radiobutton(subframe, +- {'text':" ",'state':DISABLED}).pack(side=TOP, anchor=W) +- subframe.pack(side=LEFT) ++ subframe = Frame(bar) ++ for row in range(depth): ++ ind = width * row + column ++ if ind < len(alternatives): ++ Radiobutton(subframe, ++ {'text':alternatives[ind], ++ 'variable':ref, ++ 'value':alternatives[ind], ++ 'command':command}).pack(side=TOP, anchor=W) ++ else: ++ # This is just a spacer ++ Radiobutton(subframe, ++ {'text':" ",'state':DISABLED}).pack(side=TOP, anchor=W) ++ subframe.pack(side=LEFT) + bar.pack(side=TOP); + return bar + +@@ -520,142 +520,142 @@ def helpwin(helpdict): + scroll.pack(side=RIGHT, fill=BOTH) + helpwin.textwidget.insert(END, helpdict['text']); + Button(helpwin, text='Done', +- command=lambda x=helpwin: x.destroy(), bd=2).pack() ++ command=lambda x=helpwin: x.destroy(), bd=2).pack() + textframe.pack(side=TOP) + + def make_icon_window(base, image): + try: +- # Some older pythons will error out on this +- icon_image = PhotoImage(data=image) +- icon_window = Toplevel() +- Label(icon_window, image=icon_image, bg='black').pack() +- base.master.iconwindow(icon_window) +- # Avoid TkInter brain death. PhotoImage objects go out of +- # scope when the enclosing function returns. Therefore +- # we have to explicitly link them to something. +- base.keepalive.append(icon_image) ++ # Some older pythons will error out on this ++ icon_image = PhotoImage(data=image) ++ icon_window = Toplevel() ++ Label(icon_window, image=icon_image, bg='black').pack() ++ base.master.iconwindow(icon_window) ++ # Avoid TkInter brain death. PhotoImage objects go out of ++ # scope when the enclosing function returns. Therefore ++ # we have to explicitly link them to something. ++ base.keepalive.append(icon_image) + except: +- pass ++ pass + + class ListEdit(Frame): + # edit a list of values (duplicates not allowed) with a supplied editor hook + def __init__(self, newlegend, list, editor, deletor, master, helptxt): +- self.editor = editor +- self.deletor = deletor +- self.list = list +- +- # Set up a widget to accept new elements +- self.newval = StringVar(master) +- newwin = LabeledEntry(master, newlegend, self.newval, '12') +- newwin.bind('', self.handleNew) +- newwin.bind('', self.handleNew) +- newwin.pack(side=TOP, fill=X, anchor=E) +- +- # Edit the existing list +- listframe = Frame(master) +- scroll = Scrollbar(listframe) +- self.listwidget = Listbox(listframe, height=0, selectmode='browse') +- if self.list: +- for x in self.list: +- self.listwidget.insert(END, x) +- listframe.pack(side=TOP, expand=YES, fill=BOTH) +- self.listwidget.config(yscrollcommand=scroll.set) +- self.listwidget.pack(side=LEFT, expand=YES, fill=BOTH) +- scroll.config(command=self.listwidget.yview) +- scroll.pack(side=RIGHT, fill=BOTH) +- self.listwidget.config(selectmode=SINGLE, setgrid=TRUE) +- self.listwidget.bind('', self.handleList); +- self.listwidget.bind('', self.handleList); +- +- bf = Frame(master); +- if self.editor: +- Button(bf, text='Edit', command=self.editItem).pack(side=LEFT) +- Button(bf, text='Delete', command=self.deleteItem).pack(side=LEFT) +- if helptxt: +- self.helptxt = helptxt +- Button(bf, text='Help', fg='blue', +- command=self.help).pack(side=RIGHT) +- bf.pack(fill=X) ++ self.editor = editor ++ self.deletor = deletor ++ self.list = list ++ ++ # Set up a widget to accept new elements ++ self.newval = StringVar(master) ++ newwin = LabeledEntry(master, newlegend, self.newval, '12') ++ newwin.bind('', self.handleNew) ++ newwin.bind('', self.handleNew) ++ newwin.pack(side=TOP, fill=X, anchor=E) ++ ++ # Edit the existing list ++ listframe = Frame(master) ++ scroll = Scrollbar(listframe) ++ self.listwidget = Listbox(listframe, height=0, selectmode='browse') ++ if self.list: ++ for x in self.list: ++ self.listwidget.insert(END, x) ++ listframe.pack(side=TOP, expand=YES, fill=BOTH) ++ self.listwidget.config(yscrollcommand=scroll.set) ++ self.listwidget.pack(side=LEFT, expand=YES, fill=BOTH) ++ scroll.config(command=self.listwidget.yview) ++ scroll.pack(side=RIGHT, fill=BOTH) ++ self.listwidget.config(selectmode=SINGLE, setgrid=TRUE) ++ self.listwidget.bind('', self.handleList); ++ self.listwidget.bind('', self.handleList); ++ ++ bf = Frame(master); ++ if self.editor: ++ Button(bf, text='Edit', command=self.editItem).pack(side=LEFT) ++ Button(bf, text='Delete', command=self.deleteItem).pack(side=LEFT) ++ if helptxt: ++ self.helptxt = helptxt ++ Button(bf, text='Help', fg='blue', ++ command=self.help).pack(side=RIGHT) ++ bf.pack(fill=X) + + def help(self): +- helpwin(self.helptxt) ++ helpwin(self.helptxt) + + def handleList(self, event): +- self.editItem(); ++ self.editItem(); + + def handleNew(self, event): +- item = self.newval.get() +- 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('') ++ item = self.newval.get() ++ 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() +- if not select: +- helpwin(listboxhelp) +- else: +- index = select[0] +- if index and self.editor: +- label = self.listwidget.get(index); +- if self.editor: +- apply(self.editor, (label,)) ++ select = self.listwidget.curselection() ++ if not select: ++ helpwin(listboxhelp) ++ else: ++ index = select[0] ++ if index and self.editor: ++ label = self.listwidget.get(index); ++ if self.editor: ++ apply(self.editor, (label,)) + + def deleteItem(self): +- select = self.listwidget.curselection() +- if not select: +- helpwin(listboxhelp) +- else: +- index = string.atoi(select[0]) +- label = self.listwidget.get(index); +- self.listwidget.delete(index) +- if self.list != None: +- del self.list[index] +- if self.deletor != None: +- apply(self.deletor, (label,)) ++ select = self.listwidget.curselection() ++ if not select: ++ helpwin(listboxhelp) ++ else: ++ index = string.atoi(select[0]) ++ label = self.listwidget.get(index); ++ self.listwidget.delete(index) ++ if self.list != None: ++ del self.list[index] ++ if self.deletor != None: ++ apply(self.deletor, (label,)) + + def ConfirmQuit(frame, context): + ans = Dialog(frame, +- title = 'Quit?', +- text = 'Really quit ' + context + ' without saving?', +- bitmap = 'question', +- strings = ('Yes', 'No'), +- default = 1) ++ title = 'Quit?', ++ text = 'Really quit ' + context + ' without saving?', ++ bitmap = 'question', ++ strings = ('Yes', 'No'), ++ default = 1) + return ans.num == 0 + + def dispose_window(master, legend, help, savelegend='OK'): + dispose = Frame(master, relief=RAISED, bd=5) + Label(dispose, text=legend).pack(side=TOP,pady=10) + Button(dispose, text=savelegend, fg='blue', +- command=master.save).pack(side=LEFT) ++ command=master.save).pack(side=LEFT) + Button(dispose, text='Quit', fg='blue', +- command=master.nosave).pack(side=LEFT) ++ command=master.nosave).pack(side=LEFT) + Button(dispose, text='Help', fg='blue', +- command=lambda x=help: helpwin(x)).pack(side=RIGHT) ++ command=lambda x=help: helpwin(x)).pack(side=RIGHT) + dispose.pack(fill=X) + return dispose + + class MyWidget: + # Common methods for Tkinter widgets -- deals with Tkinter declaration + def post(self, widgetclass, field): +- for x in widgetclass.typemap: +- if x[1] == 'Boolean': +- setattr(self, x[0], BooleanVar(self)) +- elif x[1] == 'String': +- setattr(self, x[0], StringVar(self)) +- elif x[1] == 'Int': +- setattr(self, x[0], IntVar(self)) +- source = getattr(getattr(self, field), x[0]) +- if source: +- getattr(self, x[0]).set(source) ++ for x in widgetclass.typemap: ++ if x[1] == 'Boolean': ++ setattr(self, x[0], BooleanVar(self)) ++ elif x[1] == 'String': ++ setattr(self, x[0], StringVar(self)) ++ elif x[1] == 'Int': ++ setattr(self, x[0], IntVar(self)) ++ source = getattr(getattr(self, field), x[0]) ++ if source: ++ getattr(self, x[0]).set(source) + + def fetch(self, widgetclass, field): +- for x in widgetclass.typemap: +- setattr(getattr(self, field), x[0], getattr(self, x[0]).get()) ++ for x in widgetclass.typemap: ++ setattr(getattr(self, field), x[0], getattr(self, x[0]).get()) + + # + # First, code to set the global fetchmail run controls. +@@ -708,46 +708,46 @@ In the `Run Controls' panel, you can set the following options that + control how fetchmail runs: + + Poll interval +- Number of seconds to wait between polls in the background. +- If zero, fetchmail will run in foreground. ++ Number of seconds to wait between polls in the background. ++ If zero, fetchmail will run in foreground. + + Logfile +- If empty, emit progress and error messages to stderr. +- Otherwise this gives the name of the files to write to. +- This field is ignored if the "Log to syslog?" option is on. ++ If empty, emit progress and error messages to stderr. ++ Otherwise this gives the name of the files to write to. ++ This field is ignored if the "Log to syslog?" option is on. + + Idfile +- If empty, store seen-message IDs in .fetchids under user's home +- directory. If nonempty, use given file name. ++ If empty, store seen-message IDs in .fetchids under user's home ++ directory. If nonempty, use given file name. + + Postmaster +- Who to send multidrop mail to as a last resort if no address can +- be matched. Normally empty; in this case, fetchmail treats the +- invoking user as the address of last resort unless that user is +- root. If that user is root, fetchmail sends to `postmaster'. ++ Who to send multidrop mail to as a last resort if no address can ++ be matched. Normally empty; in this case, fetchmail treats the ++ invoking user as the address of last resort unless that user is ++ root. If that user is root, fetchmail sends to `postmaster'. + + Bounces to sender? +- If this option is on (the default) error mail goes to the sender. +- Otherwise it goes to the postmaster. ++ If this option is on (the default) error mail goes to the sender. ++ Otherwise it goes to the postmaster. + + Send spam bounces? +- If this option is on, spam bounces are sent to the sender or +- postmaster (depending on the "Bounces to sender?" option. Otherwise, +- spam bounces are not sent (the default). ++ If this option is on, spam bounces are sent to the sender or ++ 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. ++ 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. +- If true, fetchmail generates no Received line and HELOs as if it were +- the remote site. ++ If false (the default) fetchmail generates a Received line into ++ each message and generates a HELO from the machine it is running on. ++ If true, fetchmail generates no Received line and HELOs as if it were ++ the remote site. + + In the `Remote Mail Configurations' panel, you can: + +@@ -767,155 +767,155 @@ This will take you to a site configuration dialogue. + + class ConfigurationEdit(Frame, MyWidget): + def __init__(self, configuration, outfile, master, onexit): +- self.subwidgets = {} +- self.configuration = configuration +- self.outfile = outfile +- self.container = master +- self.onexit = onexit +- ConfigurationEdit.mode_to_help = { +- 'novice':configure_novice_help, 'expert':configure_expert_help +- } ++ self.subwidgets = {} ++ self.configuration = configuration ++ self.outfile = outfile ++ self.container = master ++ self.onexit = onexit ++ ConfigurationEdit.mode_to_help = { ++ 'novice':configure_novice_help, 'expert':configure_expert_help ++ } + + def server_edit(self, sitename): +- self.subwidgets[sitename] = ServerEdit(sitename, self).edit(self.mode, Toplevel()) ++ self.subwidgets[sitename] = ServerEdit(sitename, self).edit(self.mode, Toplevel()) + + def server_delete(self, sitename): +- try: +- for user in self.subwidgets.keys(): +- user.destruct() +- del self.configuration[sitename] +- except: +- pass ++ try: ++ for user in self.subwidgets.keys(): ++ user.destruct() ++ del self.configuration[sitename] ++ except: ++ pass + + def edit(self, mode): +- self.mode = mode +- 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_icon) +- Pack.config(self) +- self.post(Configuration, 'configuration') +- +- dispose_window(self, +- 'Configurator ' + self.mode + ' Controls', +- ConfigurationEdit.mode_to_help[self.mode], +- 'Save') +- +- gf = Frame(self, relief=RAISED, bd = 5) +- Label(gf, +- text='Fetchmail Run Controls', +- bd=2).pack(side=TOP, pady=10) +- +- df = Frame(gf) +- +- ff = Frame(df) +- if self.mode != 'novice': +- # Set the postmaster +- log = LabeledEntry(ff, ' Postmaster:', self.postmaster, '14') +- log.pack(side=RIGHT, anchor=E) +- +- # Set the poll interval +- de = LabeledEntry(ff, ' Poll interval:', self.poll_interval, '14') +- de.pack(side=RIGHT, anchor=E) +- ff.pack() +- +- df.pack() +- +- if self.mode != 'novice': +- pf = Frame(gf) +- Checkbutton(pf, +- {'text':'Bounces to sender?', +- 'variable':self.bouncemail, +- 'relief':GROOVE}).pack(side=LEFT, anchor=W) +- pf.pack(fill=X) +- +- sb = Frame(gf) +- Checkbutton(sb, +- {'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?', +- 'variable':self.syslog, +- 'relief':GROOVE}).pack(side=LEFT, anchor=W) +- log = LabeledEntry(sf, ' Logfile:', self.logfile, '14') +- log.pack(side=RIGHT, anchor=E) +- sf.pack(fill=X) +- +- Checkbutton(gf, +- {'text':'Invisible mode?', +- 'variable':self.invisible, +- 'relief':GROOVE}).pack(side=LEFT, anchor=W) +- # Set the idfile +- log = LabeledEntry(gf, ' Idfile:', self.idfile, '14') +- log.pack(side=RIGHT, anchor=E) +- +- gf.pack(fill=X) +- +- # Expert mode allows us to edit multiple sites +- lf = Frame(self, relief=RAISED, bd=5) +- Label(lf, +- text='Remote Mail Server Configurations', +- bd=2).pack(side=TOP, pady=10) +- ListEdit('New Server:', +- map(lambda x: x.pollname, self.configuration.servers), +- lambda site, self=self: self.server_edit(site), +- lambda site, self=self: self.server_delete(site), +- lf, remotehelp) +- lf.pack(fill=X) ++ self.mode = mode ++ 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_icon) ++ Pack.config(self) ++ self.post(Configuration, 'configuration') ++ ++ dispose_window(self, ++ 'Configurator ' + self.mode + ' Controls', ++ ConfigurationEdit.mode_to_help[self.mode], ++ 'Save') ++ ++ gf = Frame(self, relief=RAISED, bd = 5) ++ Label(gf, ++ text='Fetchmail Run Controls', ++ bd=2).pack(side=TOP, pady=10) ++ ++ df = Frame(gf) ++ ++ ff = Frame(df) ++ if self.mode != 'novice': ++ # Set the postmaster ++ log = LabeledEntry(ff, ' Postmaster:', self.postmaster, '14') ++ log.pack(side=RIGHT, anchor=E) ++ ++ # Set the poll interval ++ de = LabeledEntry(ff, ' Poll interval:', self.poll_interval, '14') ++ de.pack(side=RIGHT, anchor=E) ++ ff.pack() ++ ++ df.pack() ++ ++ if self.mode != 'novice': ++ pf = Frame(gf) ++ Checkbutton(pf, ++ {'text':'Bounces to sender?', ++ 'variable':self.bouncemail, ++ 'relief':GROOVE}).pack(side=LEFT, anchor=W) ++ pf.pack(fill=X) ++ ++ sb = Frame(gf) ++ Checkbutton(sb, ++ {'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?', ++ 'variable':self.syslog, ++ 'relief':GROOVE}).pack(side=LEFT, anchor=W) ++ log = LabeledEntry(sf, ' Logfile:', self.logfile, '14') ++ log.pack(side=RIGHT, anchor=E) ++ sf.pack(fill=X) ++ ++ Checkbutton(gf, ++ {'text':'Invisible mode?', ++ 'variable':self.invisible, ++ 'relief':GROOVE}).pack(side=LEFT, anchor=W) ++ # Set the idfile ++ log = LabeledEntry(gf, ' Idfile:', self.idfile, '14') ++ log.pack(side=RIGHT, anchor=E) ++ ++ gf.pack(fill=X) ++ ++ # Expert mode allows us to edit multiple sites ++ lf = Frame(self, relief=RAISED, bd=5) ++ Label(lf, ++ text='Remote Mail Server Configurations', ++ bd=2).pack(side=TOP, pady=10) ++ ListEdit('New Server:', ++ map(lambda x: x.pollname, self.configuration.servers), ++ lambda site, self=self: self.server_edit(site), ++ lambda site, self=self: self.server_delete(site), ++ lf, remotehelp) ++ lf.pack(fill=X) + + def destruct(self): +- for sitename in self.subwidgets.keys(): +- self.subwidgets[sitename].destruct() +- self.master.destroy() +- self.onexit() ++ for sitename in self.subwidgets.keys(): ++ self.subwidgets[sitename].destruct() ++ self.master.destroy() ++ self.onexit() + + def nosave(self): +- if ConfirmQuit(self, self.mode + " configuration editor"): +- self.destruct() ++ if ConfirmQuit(self, self.mode + " configuration editor"): ++ self.destruct() + + def save(self): +- for sitename in self.subwidgets.keys(): +- self.subwidgets[sitename].save() +- self.fetch(Configuration, 'configuration') +- fm = None +- if not self.outfile: +- fm = sys.stdout +- elif not os.path.isfile(self.outfile) or Dialog(self, +- title = 'Overwrite existing run control file?', +- text = 'Really overwrite existing run control file?', +- bitmap = 'question', +- strings = ('Yes', 'No'), +- default = 1).num == 0: +- try: +- os.rename(self.outfile, self.outfile + "~") +- # Pre-1.5.2 compatibility... +- except os.error: +- pass +- oldumask = os.umask(077) +- fm = open(self.outfile, 'w') +- os.umask(oldumask) +- if fm: +- # 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() +- self.destruct() ++ for sitename in self.subwidgets.keys(): ++ self.subwidgets[sitename].save() ++ self.fetch(Configuration, 'configuration') ++ fm = None ++ if not self.outfile: ++ fm = sys.stdout ++ elif not os.path.isfile(self.outfile) or Dialog(self, ++ title = 'Overwrite existing run control file?', ++ text = 'Really overwrite existing run control file?', ++ bitmap = 'question', ++ strings = ('Yes', 'No'), ++ default = 1).num == 0: ++ try: ++ os.rename(self.outfile, self.outfile + "~") ++ # Pre-1.5.2 compatibility... ++ except os.error: ++ pass ++ oldumask = os.umask(077) ++ fm = open(self.outfile, 'w') ++ os.umask(oldumask) ++ if fm: ++ # 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() ++ self.destruct() + + # + # Server editing stuff. +@@ -1063,217 +1063,217 @@ user's options on that site. + + class ServerEdit(Frame, MyWidget): + def __init__(self, host, parent): +- self.parent = parent +- self.server = None +- self.subwidgets = {} +- for site in parent.configuration.servers: +- if site.pollname == host: +- self.server = site +- if (self.server == None): +- self.server = Server() +- self.server.pollname = host +- self.server.via = None +- parent.configuration.servers.append(self.server) ++ self.parent = parent ++ self.server = None ++ self.subwidgets = {} ++ for site in parent.configuration.servers: ++ if site.pollname == host: ++ self.server = site ++ if (self.server == None): ++ self.server = Server() ++ self.server.pollname = host ++ self.server.via = None ++ parent.configuration.servers.append(self.server) + + def edit(self, mode, master=None): +- Frame.__init__(self, master) +- Pack.config(self) +- self.master.title('Fetchmail host ' + self.server.pollname); +- self.master.iconname('Fetchmail host ' + self.server.pollname); +- self.post(Server, 'server') +- self.makeWidgets(self.server.pollname, mode) +- self.keepalive = [] # Use this to anchor the PhotoImage object +- make_icon_window(self, fetchmail_icon) ++ Frame.__init__(self, master) ++ Pack.config(self) ++ self.master.title('Fetchmail host ' + self.server.pollname); ++ self.master.iconname('Fetchmail host ' + self.server.pollname); ++ self.post(Server, 'server') ++ self.makeWidgets(self.server.pollname, mode) ++ self.keepalive = [] # Use this to anchor the PhotoImage object ++ make_icon_window(self, fetchmail_icon) + # self.grab_set() + # self.focus_set() + # self.wait_window() +- return self ++ return self + + def destruct(self): +- for username in self.subwidgets.keys(): +- self.subwidgets[username].destruct() +- del self.parent.subwidgets[self.server.pollname] +- self.master.destroy() ++ for username in self.subwidgets.keys(): ++ self.subwidgets[username].destruct() ++ del self.parent.subwidgets[self.server.pollname] ++ self.master.destroy() + + def nosave(self): +- if ConfirmQuit(self, 'server option editing'): +- self.destruct() ++ if ConfirmQuit(self, 'server option editing'): ++ self.destruct() + + def save(self): +- self.fetch(Server, 'server') +- for username in self.subwidgets.keys(): +- self.subwidgets[username].save() +- self.destruct() ++ self.fetch(Server, 'server') ++ for username in self.subwidgets.keys(): ++ self.subwidgets[username].save() ++ self.destruct() + + def defaultPort(self): +- proto = self.protocol.get() +- # Callback to reset the port number whenever the protocol type changes. +- # We used to only reset the port if it had a default (zero) value. +- # This turns out to be a bad idea especially in Novice mode -- if +- # you set POP3 and then set IMAP, the port invisibly remained 110. +- # Now we reset unconditionally on the theory that if you're setting +- # 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 ++ proto = self.protocol.get() ++ # Callback to reset the port number whenever the protocol type changes. ++ # We used to only reset the port if it had a default (zero) value. ++ # This turns out to be a bad idea especially in Novice mode -- if ++ # you set POP3 and then set IMAP, the port invisibly remained 110. ++ # Now we reset unconditionally on the theory that if you're setting ++ # 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()) ++ self.subwidgets[username] = UserEdit(username, self).edit(mode, Toplevel()) + + def user_delete(self, username): +- if self.subwidgets.has_key(username): +- self.subwidgets[username].destruct() +- del self.server[username] ++ if self.subwidgets.has_key(username): ++ self.subwidgets[username].destruct() ++ del self.server[username] + + def makeWidgets(self, host, mode): +- topwin = dispose_window(self, "Server options for querying " + host, serverhelp) +- +- leftwin = Frame(self); +- leftwidth = '25'; +- +- if mode != 'novice': +- 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:', +- self.interval, leftwidth).pack(side=TOP, fill=X) +- LabeledEntry(ctlwin, 'Server timeout (seconds):', +- self.timeout, leftwidth).pack(side=TOP, fill=X) +- Button(ctlwin, text='Help', fg='blue', +- command=lambda: helpwin(controlhelp)).pack(side=RIGHT) +- ctlwin.pack(fill=X) +- +- # Compute the available protocols from the compile-time options +- protolist = ['auto'] +- if 'pop2' in feature_options: +- protolist.append("POP2") +- if 'pop3' in feature_options: +- protolist = protolist + ["POP3", "APOP", "KPOP"] +- if 'sdps' in feature_options: +- protolist.append("SDPS") +- if 'imap' in feature_options: +- protolist.append("IMAP") +- if 'etrn' in feature_options: +- protolist.append("ETRN") +- if 'odmr' in feature_options: +- protolist.append("ODMR") +- +- protwin = Frame(leftwin, relief=RAISED, bd=5) +- Label(protwin, text="Protocol").pack(side=TOP) +- ButtonBar(protwin, '', +- self.protocol, protolist, 2, +- self.defaultPort) +- if mode != 'novice': +- 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', +- command=lambda: helpwin(protohelp)).pack(side=RIGHT) +- protwin.pack(fill=X) +- +- userwin = Frame(leftwin, relief=RAISED, bd=5) +- Label(userwin, text="User entries for " + host).pack(side=TOP) +- ListEdit("New user: ", +- map(lambda x: x.remote, self.server.users), +- lambda u, m=mode, s=self: s.user_edit(u, m), +- lambda u, s=self: s.user_delete(u), +- userwin, suserhelp) +- userwin.pack(fill=X) +- +- leftwin.pack(side=LEFT, anchor=N, fill=X); +- +- if mode != 'novice': +- rightwin = Frame(self); +- +- mdropwin = Frame(rightwin, relief=RAISED, bd=5) +- Label(mdropwin, text="Multidrop options").pack(side=TOP) +- LabeledEntry(mdropwin, 'Envelope address header:', +- self.envelope, '22').pack(side=TOP, fill=X) +- LabeledEntry(mdropwin, 'Envelope headers to skip:', +- self.envskip, '22').pack(side=TOP, fill=X) +- LabeledEntry(mdropwin, 'Name prefix to strip:', +- self.qvirtual, '22').pack(side=TOP, fill=X) +- Checkbutton(mdropwin, text="Enable multidrop DNS lookup?", +- variable=self.dns).pack(side=TOP) +- Label(mdropwin, text="DNS aliases").pack(side=TOP) +- ListEdit("New alias: ", self.server.aka, None, None, mdropwin, None) +- Label(mdropwin, text="Domains to be considered local").pack(side=TOP) +- ListEdit("New domain: ", +- self.server.localdomains, None, None, mdropwin, multihelp) +- mdropwin.pack(fill=X) +- +- if os_type in ('linux', 'freebsd'): +- 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, 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 'monitor' in dictmembers: +- LabeledEntry(secwin, 'Interface to monitor:', +- self.monitor, leftwidth).pack(side=TOP, fill=X) +- # Someday this should handle Kerberos 5 too +- if 'kerberos' in feature_options: +- LabeledEntry(secwin, 'Principal:', +- self.principal, '12').pack(side=TOP, fill=X) +- # ESMTP authentication +- LabeledEntry(secwin, 'ESMTP name:', +- self.esmtpname, '12').pack(side=TOP, fill=X) +- LabeledEntry(secwin, 'ESMTP password:', +- self.esmtppassword, '12').pack(side=TOP, fill=X) +- Button(secwin, text='Help', fg='blue', +- command=lambda: helpwin(sechelp)).pack(side=RIGHT) +- secwin.pack(fill=X) +- +- rightwin.pack(side=LEFT, anchor=N); ++ topwin = dispose_window(self, "Server options for querying " + host, serverhelp) ++ ++ leftwin = Frame(self); ++ leftwidth = '25'; ++ ++ if mode != 'novice': ++ 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:', ++ self.interval, leftwidth).pack(side=TOP, fill=X) ++ LabeledEntry(ctlwin, 'Server timeout (seconds):', ++ self.timeout, leftwidth).pack(side=TOP, fill=X) ++ Button(ctlwin, text='Help', fg='blue', ++ command=lambda: helpwin(controlhelp)).pack(side=RIGHT) ++ ctlwin.pack(fill=X) ++ ++ # Compute the available protocols from the compile-time options ++ protolist = ['auto'] ++ if 'pop2' in feature_options: ++ protolist.append("POP2") ++ if 'pop3' in feature_options: ++ protolist = protolist + ["POP3", "APOP", "KPOP"] ++ if 'sdps' in feature_options: ++ protolist.append("SDPS") ++ if 'imap' in feature_options: ++ protolist.append("IMAP") ++ if 'etrn' in feature_options: ++ protolist.append("ETRN") ++ if 'odmr' in feature_options: ++ protolist.append("ODMR") ++ ++ protwin = Frame(leftwin, relief=RAISED, bd=5) ++ Label(protwin, text="Protocol").pack(side=TOP) ++ ButtonBar(protwin, '', ++ self.protocol, protolist, 2, ++ self.defaultPort) ++ if mode != 'novice': ++ 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', ++ command=lambda: helpwin(protohelp)).pack(side=RIGHT) ++ protwin.pack(fill=X) ++ ++ userwin = Frame(leftwin, relief=RAISED, bd=5) ++ Label(userwin, text="User entries for " + host).pack(side=TOP) ++ ListEdit("New user: ", ++ map(lambda x: x.remote, self.server.users), ++ lambda u, m=mode, s=self: s.user_edit(u, m), ++ lambda u, s=self: s.user_delete(u), ++ userwin, suserhelp) ++ userwin.pack(fill=X) ++ ++ leftwin.pack(side=LEFT, anchor=N, fill=X); ++ ++ if mode != 'novice': ++ rightwin = Frame(self); ++ ++ mdropwin = Frame(rightwin, relief=RAISED, bd=5) ++ Label(mdropwin, text="Multidrop options").pack(side=TOP) ++ LabeledEntry(mdropwin, 'Envelope address header:', ++ self.envelope, '22').pack(side=TOP, fill=X) ++ LabeledEntry(mdropwin, 'Envelope headers to skip:', ++ self.envskip, '22').pack(side=TOP, fill=X) ++ LabeledEntry(mdropwin, 'Name prefix to strip:', ++ self.qvirtual, '22').pack(side=TOP, fill=X) ++ Checkbutton(mdropwin, text="Enable multidrop DNS lookup?", ++ variable=self.dns).pack(side=TOP) ++ Label(mdropwin, text="DNS aliases").pack(side=TOP) ++ ListEdit("New alias: ", self.server.aka, None, None, mdropwin, None) ++ Label(mdropwin, text="Domains to be considered local").pack(side=TOP) ++ ListEdit("New domain: ", ++ self.server.localdomains, None, None, mdropwin, multihelp) ++ mdropwin.pack(fill=X) ++ ++ if os_type in ('linux', 'freebsd'): ++ 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, 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 'monitor' in dictmembers: ++ LabeledEntry(secwin, 'Interface to monitor:', ++ self.monitor, leftwidth).pack(side=TOP, fill=X) ++ # Someday this should handle Kerberos 5 too ++ if 'kerberos' in feature_options: ++ LabeledEntry(secwin, 'Principal:', ++ self.principal, '12').pack(side=TOP, fill=X) ++ # ESMTP authentication ++ LabeledEntry(secwin, 'ESMTP name:', ++ self.esmtpname, '12').pack(side=TOP, fill=X) ++ LabeledEntry(secwin, 'ESMTP password:', ++ self.esmtppassword, '12').pack(side=TOP, fill=X) ++ Button(secwin, text='Help', fg='blue', ++ command=lambda: helpwin(sechelp)).pack(side=RIGHT) ++ secwin.pack(fill=X) ++ ++ rightwin.pack(side=LEFT, anchor=N); + + def autoprobe(self): +- # Note: this only handles case (1) near fetchmail.c:1032 +- # We're assuming people smart enough to set up ssh tunneling +- # won't need autoprobing. +- if self.server.via: +- realhost = self.server.via +- else: +- realhost = self.server.pollname +- greetline = None +- for protocol in ("IMAP","POP3","POP2"): +- service = defaultports[protocol] +- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +- try: +- sock.connect((realhost, ianaservices[service])) +- greetline = sock.recv(1024) +- sock.close() +- except: +- pass +- else: +- break +- confwin = Toplevel() +- if greetline == None: +- title = "Autoprobe of " + realhost + " failed" +- confirm = """ ++ # Note: this only handles case (1) near fetchmail.c:1032 ++ # We're assuming people smart enough to set up ssh tunneling ++ # won't need autoprobing. ++ if self.server.via: ++ realhost = self.server.via ++ else: ++ realhost = self.server.pollname ++ greetline = None ++ for protocol in ("IMAP","POP3","POP2"): ++ service = defaultports[protocol] ++ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ try: ++ sock.connect((realhost, ianaservices[service])) ++ greetline = sock.recv(1024) ++ sock.close() ++ except: ++ pass ++ else: ++ break ++ confwin = Toplevel() ++ if greetline == None: ++ title = "Autoprobe of " + realhost + " failed" ++ confirm = """ + Fetchmailconf didn't find any mailservers active. + This could mean the host doesn't support any, + or that your Internet connection is down, or + that the host is so slow that the probe timed + out before getting a response. + """ +- else: +- warnings = '' +- # OK, now try to recognize potential problems ++ else: ++ warnings = '' ++ # OK, now try to recognize potential problems + +- if protocol == "POP2": +- warnings = warnings + """ ++ if protocol == "POP2": ++ warnings = warnings + """ + It appears you have somehow found a mailserver running only POP2. + Congratulations. Have you considered a career in archaeology? + +@@ -1286,8 +1286,8 @@ switch --enable-POP2. + + ### POP3 servers start here + +- if string.find(greetline, "1.003") > 0 or string.find(greetline, "1.004") > 0: +- warnings = warnings + """ ++ 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 + on the floor if your connection is interrupted during the session). +@@ -1296,8 +1296,8 @@ It is strongly recommended that you find a better POP3 server. The fetchmail + FAQ includes pointers to good ones. + + """ +- if string.find(greetline, "comcast.net") > 0: +- warnings = warnings + """ ++ if string.find(greetline, "comcast.net") > 0: ++ warnings = warnings + """ + The Comcast Maillennium POP3 server only returns the first 80K of a long + message retrieved with TOP. Its response to RETR is normal, so use the + `fetchall' option. +@@ -1321,8 +1321,8 @@ message retrieved with TOP. Its response to RETR is normal, so use the + # + # +OK Cubic Circle's v1.31 1998/05/13 POP3 ready <6229000062f95036@wakko> + # +- if string.find(greetline, "Cubic Circle") > 0: +- warnings = warnings + """ ++ 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 +@@ -1332,8 +1332,8 @@ Also, some versions of cucipop don't assert an exclusive lock on your + mailbox when it's being queried. This means that if you have more than + one fetchmail query running against the same mailbox, bad things can happen. + """ +- if string.find(greetline, "David POP3 Server") > 0: +- warnings = warnings + """ ++ if string.find(greetline, "David POP3 Server") > 0: ++ warnings = warnings + """ + This POP3 server is badly broken. You should get rid of it -- and the + brain-dead Microsoft operating system it rode in on. + +@@ -1341,20 +1341,20 @@ brain-dead Microsoft operating system it rode in on. + # 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 + """ ++ 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, " geonet.de") > 0: +- warnings = warnings + """ ++ if string.find(greetline, " geonet.de") > 0: ++ warnings = warnings + """ + You appear to be using geonet. As of late 2002, the TOP command on + geonet's POP3 is broken. Use the fetchall option. + + """ +- if string.find(greetline, "OpenMail") > 0: +- warnings = warnings + """ ++ 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 +@@ -1362,16 +1362,16 @@ around this bug, turn on `fetchall' on all user entries associated with + this server. + + """ +- if string.find(greetline, "Escape character is") > 0: +- warnings = warnings + """ ++ if string.find(greetline, "Escape character is") > 0: ++ warnings = warnings + """ + Your greeting line looks like it was written by a fetid pile of + camel dung identified to me as `popa3d written by Solar Designer'. + Beware! The UIDL support in this thing is known to be completely broken, + and other things probably are too. + + """ +- if string.find(greetline, "MercuryP/NLM v1.48") > 0: +- warnings = warnings + """ ++ if string.find(greetline, "MercuryP/NLM v1.48") > 0: ++ warnings = warnings + """ + This is not a POP3 server. It has delusions of being one, but after + RETR all messages are automatically marked to be deleted. The only + way to prevent this is to issue an RSET before leaving the server. +@@ -1379,8 +1379,8 @@ Fetchmail does this, but we suspect this is probably broken in lots + of other ways, too. + + """ +- if string.find(greetline, "POP-Max") > 0: +- warnings = warnings + """ ++ 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 +@@ -1388,14 +1388,14 @@ 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 + """ ++ 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 + """ ++ 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. However, be aware that the 2.53 version of + qpopper does something odd that causes fetchmail to hang with a socket +@@ -1404,16 +1404,16 @@ 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 + """ ++ 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 + """ ++ 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 +@@ -1421,8 +1421,8 @@ this bug, turn on `fetchall' on all user entries associated with this + server. + + """ +- if string.find(greetline, " spray.se") > 0: +- warnings = warnings + """ ++ 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 +@@ -1430,8 +1430,8 @@ this bug, turn on `fetchall' on all user entries associated with this + server. + + """ +- if string.find(greetline, " usa.net") > 0: +- warnings = warnings + """ ++ 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 +@@ -1444,15 +1444,15 @@ 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 + """ ++ 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. + + """ +- if string.find(greetline, " IMS POP3") > 0: +- warnings = warnings + """ ++ if string.find(greetline, " IMS POP3") > 0: ++ warnings = warnings + """ + Some servers issuing the greeting line 'IMS POP3' have been known to + do byte-stuffing incorrectly. This means that if a message you receive + has a . (period) at start of line, fetchmail will become confused and +@@ -1462,8 +1462,8 @@ probably wedge itself. (This bug was recorded on IMS POP3 0.86.) + + ### IMAP servers start here + +- if string.find(greetline, "GroupWise") > 0: +- warnings = warnings + """ ++ 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 +@@ -1475,8 +1475,8 @@ with code as shoddy as GroupWise seems to be, you will probably pay + for it with other problems.

+ + """ +- if string.find(greetline, "InterChange") > 0: +- warnings = warnings + """ ++ if string.find(greetline, "InterChange") > 0: ++ warnings = warnings + """ + + The InterChange IMAP server at release levels below 3.61.08 screws up + on mail with attachments. It doesn't fetch them if you give it a +@@ -1487,16 +1487,16 @@ Exchange (quite legally under RFC2062) rejectsit. The InterChange + folks claim to have fixed this bug in 3.61.08. + + """ +- if string.find(greetline, "Imail") > 0: +- warnings = warnings + """ ++ 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 + """ ++ 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 +@@ -1507,16 +1507,16 @@ 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 + """ ++ closebrak = string.find(greetline, ">") ++ if closebrak > 0 and greetline[closebrak+1] == "\r": ++ warnings = warnings + """ + 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, "IMAP2bis") > 0: +- warnings = warnings + """ ++ 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. +@@ -1529,30 +1529,30 @@ 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 + """ + 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 + """ ++ if warnings == '': ++ warnings = warnings + """ + Fetchmail doesn't know anything special about this server type. + + """ + +- # Display success window with warnings +- 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() +- Message(confwin, text=confirm, width=600).pack() +- Button(confwin, text='Done', +- command=lambda x=confwin: x.destroy(), bd=2).pack() ++ # Display success window with warnings ++ 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() ++ Message(confwin, text=confirm, width=600).pack() ++ Button(confwin, text='Done', ++ command=lambda x=confwin: x.destroy(), bd=2).pack() + + # + # User editing stuff +@@ -1597,193 +1597,193 @@ of sending it to your local system. + + class UserEdit(Frame, MyWidget): + def __init__(self, username, parent): +- self.parent = parent +- self.user = None +- for user in parent.server.users: +- if user.remote == username: +- self.user = user +- if self.user == None: +- self.user = User() +- self.user.remote = username +- self.user.localnames = [username] +- parent.server.users.append(self.user) ++ self.parent = parent ++ self.user = None ++ for user in parent.server.users: ++ if user.remote == username: ++ self.user = user ++ if self.user == None: ++ self.user = User() ++ self.user.remote = username ++ self.user.localnames = [username] ++ parent.server.users.append(self.user) + + def edit(self, mode, master=None): +- Frame.__init__(self, master) +- Pack.config(self) +- self.master.title('Fetchmail user ' + self.user.remote +- + ' querying ' + self.parent.server.pollname); +- self.master.iconname('Fetchmail user ' + self.user.remote); +- 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_icon) ++ Frame.__init__(self, master) ++ Pack.config(self) ++ self.master.title('Fetchmail user ' + self.user.remote ++ + ' querying ' + self.parent.server.pollname); ++ self.master.iconname('Fetchmail user ' + self.user.remote); ++ 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_icon) + # self.grab_set() + # self.focus_set() + # self.wait_window() +- return self ++ return self + + def destruct(self): +- # 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] +- self.master.destroy() ++ # 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] ++ self.master.destroy() + + def nosave(self): +- if ConfirmQuit(self, 'user option editing'): +- self.destruct() ++ if ConfirmQuit(self, 'user option editing'): ++ self.destruct() + + def save(self): +- ok = 0 +- for x in self.user.localnames: ok = ok + (string.find(x, '@') != -1) +- if ok == 0 or Dialog(self, +- title = "Really accept an embedded '@' ?", +- text = "Local names with an embedded '@', such as in foo@bar " +- "might result in your mail being sent to foo@bar.com " +- "instead of your local system.\n Are you sure you want " +- "a local user name with an '@' in it?", +- bitmap = 'question', +- strings = ('Yes', 'No'), +- default = 1).num == 0: +- self.fetch(User, 'user') +- self.destruct() ++ ok = 0 ++ for x in self.user.localnames: ok = ok + (string.find(x, '@') != -1) ++ if ok == 0 or Dialog(self, ++ title = "Really accept an embedded '@' ?", ++ text = "Local names with an embedded '@', such as in foo@bar " ++ "might result in your mail being sent to foo@bar.com " ++ "instead of your local system.\n Are you sure you want " ++ "a local user name with an '@' in it?", ++ bitmap = 'question', ++ strings = ('Yes', 'No'), ++ default = 1).num == 0: ++ self.fetch(User, 'user') ++ self.destruct() + + def makeWidgets(self, mode, servername): +- dispose_window(self, +- "User options for " + self.user.remote + " querying " + servername, +- userhelp) +- +- if mode != 'novice': +- leftwin = Frame(self); +- else: +- leftwin = self +- +- secwin = Frame(leftwin, relief=RAISED, bd=5) +- Label(secwin, text="Authentication").pack(side=TOP) +- LabeledEntry(secwin, 'Password:', +- 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) +- Checkbutton(sslwin, text="Check server SSL certificate?", +- 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) +- +- names = Frame(leftwin, relief=RAISED, bd=5) +- Label(names, text="Local names").pack(side=TOP) +- ListEdit("New name: ", +- self.user.localnames, None, None, names, localhelp) +- names.pack(fill=X, anchor=N) +- +- if mode != 'novice': +- targwin = Frame(leftwin, relief=RAISED, bd=5) +- Label(targwin, text="Forwarding Options").pack(side=TOP) +- Label(targwin, text="Listeners to forward to").pack(side=TOP) +- ListEdit("New listener:", +- self.user.smtphunt, 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, 'Use domain on RCPT TO line:', +- self.smtpaddress, '26').pack(side=TOP, fill=X) +- 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) +- LabeledEntry(targwin, 'Connection wrapup command:', +- self.postconnect, '26').pack(side=TOP, fill=X) +- LabeledEntry(targwin, 'Local delivery agent:', +- self.mda, '26').pack(side=TOP, fill=X) +- LabeledEntry(targwin, 'BSMTP output file:', +- self.bsmtp, '26').pack(side=TOP, fill=X) +- LabeledEntry(targwin, 'Listener spam-block codes:', +- self.antispam, '26').pack(side=TOP, fill=X) +- LabeledEntry(targwin, 'Pass-through properties:', +- self.properties, '26').pack(side=TOP, fill=X) +- Checkbutton(targwin, text="Use LMTP?", +- variable=self.lmtp).pack(side=TOP, fill=X) +- targwin.pack(fill=X, anchor=N) +- +- if mode != 'novice': +- leftwin.pack(side=LEFT, fill=X, anchor=N) +- rightwin = Frame(self) +- else: +- rightwin = self +- +- optwin = Frame(rightwin, relief=RAISED, bd=5) +- Label(optwin, text="Processing Options").pack(side=TOP) +- Checkbutton(optwin, text="Suppress deletion of messages after reading", +- variable=self.keep).pack(side=TOP, anchor=W) +- Checkbutton(optwin, text="Fetch old messages as well as new", +- variable=self.fetchall).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", +- variable=self.forcecr).pack(side=TOP, anchor=W) +- Checkbutton(optwin, text="Strip CR from end of each line", +- variable=self.stripcr).pack(side=TOP, anchor=W) +- Checkbutton(optwin, text="Pass 8 bits even though SMTP says 7BIT", +- variable=self.pass8bits).pack(side=TOP, anchor=W) +- Checkbutton(optwin, text="Undo MIME armoring on header and body", +- 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': +- limwin = Frame(rightwin, relief=RAISED, bd=5) +- Label(limwin, text="Resource Limits").pack(side=TOP) +- LabeledEntry(limwin, 'Message size limit:', +- self.limit, '30').pack(side=TOP, fill=X) +- LabeledEntry(limwin, 'Size warning interval:', +- self.warnings, '30').pack(side=TOP, fill=X) +- LabeledEntry(limwin, 'Max messages to fetch per poll:', +- self.fetchlimit, '30').pack(side=TOP, fill=X) +- LabeledEntry(limwin, 'Max message sizes to fetch per transaction:', +- self.fetchsizelimit, '30').pack(side=TOP, fill=X) +- if self.parent.server.protocol not in ('ETRN', 'ODMR'): +- LabeledEntry(limwin, 'Use fast UIDL:', +- self.fastuidl, '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 not in ('ETRN', 'ODMR'): +- 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 == 'IMAP': +- foldwin = Frame(rightwin, relief=RAISED, bd=5) +- Label(foldwin, text="Remote folders (IMAP only)").pack(side=TOP) +- ListEdit("New folder:", self.user.mailboxes, +- None, None, foldwin, None) +- foldwin.pack(fill=X, anchor=N) +- +- if mode != 'novice': +- rightwin.pack(side=LEFT) +- else: +- self.pack() ++ dispose_window(self, ++ "User options for " + self.user.remote + " querying " + servername, ++ userhelp) ++ ++ if mode != 'novice': ++ leftwin = Frame(self); ++ else: ++ leftwin = self ++ ++ secwin = Frame(leftwin, relief=RAISED, bd=5) ++ Label(secwin, text="Authentication").pack(side=TOP) ++ LabeledEntry(secwin, 'Password:', ++ 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) ++ Checkbutton(sslwin, text="Check server SSL certificate?", ++ 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) ++ ++ names = Frame(leftwin, relief=RAISED, bd=5) ++ Label(names, text="Local names").pack(side=TOP) ++ ListEdit("New name: ", ++ self.user.localnames, None, None, names, localhelp) ++ names.pack(fill=X, anchor=N) ++ ++ if mode != 'novice': ++ targwin = Frame(leftwin, relief=RAISED, bd=5) ++ Label(targwin, text="Forwarding Options").pack(side=TOP) ++ Label(targwin, text="Listeners to forward to").pack(side=TOP) ++ ListEdit("New listener:", ++ self.user.smtphunt, 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, 'Use domain on RCPT TO line:', ++ self.smtpaddress, '26').pack(side=TOP, fill=X) ++ 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) ++ LabeledEntry(targwin, 'Connection wrapup command:', ++ self.postconnect, '26').pack(side=TOP, fill=X) ++ LabeledEntry(targwin, 'Local delivery agent:', ++ self.mda, '26').pack(side=TOP, fill=X) ++ LabeledEntry(targwin, 'BSMTP output file:', ++ self.bsmtp, '26').pack(side=TOP, fill=X) ++ LabeledEntry(targwin, 'Listener spam-block codes:', ++ self.antispam, '26').pack(side=TOP, fill=X) ++ LabeledEntry(targwin, 'Pass-through properties:', ++ self.properties, '26').pack(side=TOP, fill=X) ++ Checkbutton(targwin, text="Use LMTP?", ++ variable=self.lmtp).pack(side=TOP, fill=X) ++ targwin.pack(fill=X, anchor=N) ++ ++ if mode != 'novice': ++ leftwin.pack(side=LEFT, fill=X, anchor=N) ++ rightwin = Frame(self) ++ else: ++ rightwin = self ++ ++ optwin = Frame(rightwin, relief=RAISED, bd=5) ++ Label(optwin, text="Processing Options").pack(side=TOP) ++ Checkbutton(optwin, text="Suppress deletion of messages after reading", ++ variable=self.keep).pack(side=TOP, anchor=W) ++ Checkbutton(optwin, text="Fetch old messages as well as new", ++ variable=self.fetchall).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", ++ variable=self.forcecr).pack(side=TOP, anchor=W) ++ Checkbutton(optwin, text="Strip CR from end of each line", ++ variable=self.stripcr).pack(side=TOP, anchor=W) ++ Checkbutton(optwin, text="Pass 8 bits even though SMTP says 7BIT", ++ variable=self.pass8bits).pack(side=TOP, anchor=W) ++ Checkbutton(optwin, text="Undo MIME armoring on header and body", ++ 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': ++ limwin = Frame(rightwin, relief=RAISED, bd=5) ++ Label(limwin, text="Resource Limits").pack(side=TOP) ++ LabeledEntry(limwin, 'Message size limit:', ++ self.limit, '30').pack(side=TOP, fill=X) ++ LabeledEntry(limwin, 'Size warning interval:', ++ self.warnings, '30').pack(side=TOP, fill=X) ++ LabeledEntry(limwin, 'Max messages to fetch per poll:', ++ self.fetchlimit, '30').pack(side=TOP, fill=X) ++ LabeledEntry(limwin, 'Max message sizes to fetch per transaction:', ++ self.fetchsizelimit, '30').pack(side=TOP, fill=X) ++ if self.parent.server.protocol not in ('ETRN', 'ODMR'): ++ LabeledEntry(limwin, 'Use fast UIDL:', ++ self.fastuidl, '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 not in ('ETRN', 'ODMR'): ++ 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 == 'IMAP': ++ foldwin = Frame(rightwin, relief=RAISED, bd=5) ++ Label(foldwin, text="Remote folders (IMAP only)").pack(side=TOP) ++ ListEdit("New folder:", self.user.mailboxes, ++ None, None, foldwin, None) ++ foldwin.pack(fill=X, anchor=N) ++ ++ if mode != 'novice': ++ rightwin.pack(side=LEFT) ++ else: ++ self.pack() + + + # +@@ -1793,162 +1793,162 @@ class UserEdit(Frame, MyWidget): + + class Configurator(Frame): + def __init__(self, outfile, master, onexit, parent): +- Frame.__init__(self, master) +- self.outfile = outfile +- self.onexit = onexit +- self.parent = parent +- self.master.title('fetchmail configurator'); +- self.master.iconname('fetchmail configurator'); +- Pack.config(self) +- self.keepalive = [] # Use this to anchor the PhotoImage object +- make_icon_window(self, fetchmail_icon) +- +- Message(self, text=""" ++ Frame.__init__(self, master) ++ self.outfile = outfile ++ self.onexit = onexit ++ self.parent = parent ++ self.master.title('fetchmail configurator'); ++ self.master.iconname('fetchmail configurator'); ++ Pack.config(self) ++ self.keepalive = [] # Use this to anchor the PhotoImage object ++ make_icon_window(self, fetchmail_icon) ++ ++ Message(self, text=""" + Use `Novice Configuration' for basic fetchmail setup; + with this, you can easily set up a single-drop connection + to one remote mail server. + """, width=600).pack(side=TOP) +- Button(self, text='Novice Configuration', +- fg='blue', command=self.novice).pack() ++ Button(self, text='Novice Configuration', ++ fg='blue', command=self.novice).pack() + +- Message(self, text=""" ++ Message(self, text=""" + Use `Expert Configuration' for advanced fetchmail setup, + including multiple-site or multidrop connections. + """, width=600).pack(side=TOP) +- Button(self, text='Expert Configuration', +- fg='blue', command=self.expert).pack() ++ Button(self, text='Expert Configuration', ++ fg='blue', command=self.expert).pack() + +- Message(self, text=""" ++ Message(self, text=""" + 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) ++ Button(self, text='Quit', fg='blue', command=self.leave).pack() ++ master.protocol("WM_DELETE_WINDOW", self.leave) + + def novice(self): +- self.master.destroy() +- ConfigurationEdit(Fetchmailrc, self.outfile, Toplevel(), self.onexit).edit('novice') ++ self.master.destroy() ++ ConfigurationEdit(Fetchmailrc, self.outfile, Toplevel(), self.onexit).edit('novice') + + def expert(self): +- self.master.destroy() +- ConfigurationEdit(Fetchmailrc, self.outfile, Toplevel(), self.onexit).edit('expert') ++ self.master.destroy() ++ ConfigurationEdit(Fetchmailrc, self.outfile, Toplevel(), self.onexit).edit('expert') + + def leave(self): +- self.master.destroy() +- self.onexit() ++ self.master.destroy() ++ self.onexit() + + # Run a command in a scrolling text widget, displaying its output + + class RunWindow(Frame): + def __init__(self, command, master, parent): +- Frame.__init__(self, master) +- self.master = master +- self.master.title('fetchmail run window'); +- self.master.iconname('fetchmail run window'); +- Pack.config(self) +- Label(self, +- text="Running "+command, +- bd=2).pack(side=TOP, pady=10) +- self.keepalive = [] # Use this to anchor the PhotoImage object +- make_icon_window(self, fetchmail_icon) +- +- # This is a scrolling text window +- textframe = Frame(self) +- scroll = Scrollbar(textframe) +- self.textwidget = Text(textframe, setgrid=TRUE) +- textframe.pack(side=TOP, expand=YES, fill=BOTH) +- self.textwidget.config(yscrollcommand=scroll.set) +- self.textwidget.pack(side=LEFT, expand=YES, fill=BOTH) +- scroll.config(command=self.textwidget.yview) +- scroll.pack(side=RIGHT, fill=BOTH) +- textframe.pack(side=TOP) +- +- Button(self, text='Quit', fg='blue', command=self.leave).pack() +- +- self.update() # Draw widget before executing fetchmail +- +- # Always look for a runnable command in the directory we're running in +- # 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 &1 " + tmpfile ++ cmd = "umask 077 && fetchmail " + tmpfile + else: +- cmd = "umask 077 && fetchmail " + tmpfile ++ cmd = "umask 077 && fetchmail " + tmpfile + + try: +- s = os.system(cmd) +- if s != 0: +- print "`" + cmd + "' run failure, status " + `s` +- raise SystemExit ++ s = os.system(cmd) ++ if s != 0: ++ print "`" + cmd + "' run failure, status " + `s` ++ raise SystemExit + except: +- print "Unknown error while running fetchmail --configdump" +- os.remove(tmpfile) +- sys.exit(1) ++ print "Unknown error while running fetchmail --configdump" ++ os.remove(tmpfile) ++ sys.exit(1) + + try: +- execfile(tmpfile) ++ execfile(tmpfile) + except: +- print "Can't read configuration output of fetchmail --configdump." +- os.remove(tmpfile) +- sys.exit(1) ++ print "Can't read configuration output of fetchmail --configdump." ++ os.remove(tmpfile) ++ sys.exit(1) + + os.remove(tmpfile) + +@@ -2145,23 +2145,23 @@ COPYING in the source or documentation directory for details.""" + copy_instance(Fetchmailrc, fetchmailrc) + Fetchmailrc.servers = []; + for server in fetchmailrc['servers']: +- Newsite = Server() +- copy_instance(Newsite, server) +- Fetchmailrc.servers.append(Newsite) +- Newsite.users = []; +- for user in server['users']: +- Newuser = User() +- copy_instance(Newuser, user) +- Newsite.users.append(Newuser) ++ Newsite = Server() ++ copy_instance(Newsite, server) ++ Fetchmailrc.servers.append(Newsite) ++ Newsite.users = []; ++ for user in server['users']: ++ Newuser = User() ++ copy_instance(Newuser, user) ++ Newsite.users.append(Newuser) + + # We may want to display the configuration and quit + if dump: +- print "This is a dump of the configuration we read:\n"+`Fetchmailrc` ++ print "This is a dump of the configuration we read:\n"+`Fetchmailrc` + + # The theory here is that -f alone sets the rcfile location, + # but -d and -f together mean the new configuration should go to stdout. + if not rcfile and not dump: +- rcfile = os.environ["HOME"] + "/.fetchmailrc" ++ rcfile = os.environ["HOME"] + "/.fetchmailrc" + + # OK, now run the configuration edit + root = MainWindow(rcfile) +-- +libgit2 0.26.0 + diff --git a/fetchmail-fetchmailconf-python3-2of3.patch b/fetchmail-fetchmailconf-python3-2of3.patch new file mode 100644 index 0000000..37157fd --- /dev/null +++ b/fetchmail-fetchmailconf-python3-2of3.patch @@ -0,0 +1,280 @@ +From ff279a5697992730bc885ddd171456c06c09fb10 Mon Sep 17 00:00:00 2001 +From: Samuel Martin +Date: Wed, 8 Jun 2016 21:36:29 +0200 +Subject: [PATCH] fetchmailconf.py: make fetchmailconf.py python{2, 3}-compliant + +This change does: +- use repr(...) instead of `...` (see [1]); +- fix print call; +- fix octal numbers. + +[1] https://docs.python.org/release/3.0.1/whatsnew/3.0.html#removed-syntax + +Signed-off-by: Samuel Martin +Signed-off-by: Matthias Andree +--- + fetchmailconf.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------- + 1 file changed, 48 insertions(+), 46 deletions(-) + +diff --git a/fetchmailconf.py b/fetchmailconf.py +index d64556e..697e4f7 100755 +--- a/fetchmailconf.py ++++ b/fetchmailconf.py +@@ -5,6 +5,8 @@ + # Matthias Andree + # Requires Python with Tkinter, and the following OS-dependent services: + # posix, posixpath, socket ++from __future__ import print_function ++ + version = "1.57" + + from Tkinter import * +@@ -64,7 +66,7 @@ class Configuration: + 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" ++ str = str + "set daemon " + repr(self.poll_interval) + "\n" + if self.invisible: + str = str + ("set invisible\n") + for site in self.servers: +@@ -145,12 +147,12 @@ class Server: + 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 + " timeout " + repr(self.timeout) + if self.interval != ServerDefaults.interval: +- res = res + " interval " + `self.interval` ++ res = res + " interval " + repr(self.interval) + if self.envelope != ServerDefaults.envelope or self.envskip != ServerDefaults.envskip: + if self.envskip: +- res = res + " envelope " + `self.envskip` + " " + self.envelope ++ res = res + " envelope " + repr(self.envskip) + " " + self.envelope + else: + res = res + " envelope " + self.envelope + if self.qvirtual: +@@ -189,15 +191,15 @@ class Server: + if self.monitor: + res = res + " monitor " + str(self.monitor) + if self.plugin: +- res = res + " plugin " + `self.plugin` ++ res = res + " plugin " + repr(self.plugin) + if self.plugout: +- res = res + " plugout " + `self.plugout` ++ res = res + " plugout " + repr(self.plugout) + if self.principal: +- res = res + " principal " + `self.principal` ++ res = res + " principal " + repr(self.principal) + if self.esmtpname: +- res = res + " esmtpname " + `self.esmtpname` ++ res = res + " esmtpname " + repr(self.esmtpname) + if self.esmtppassword: +- res = res + " esmtppassword " + `self.esmtppassword` ++ res = res + " esmtppassword " + repr(self.esmtppassword) + if self.interface or self.monitor or self.principal or self.plugin or self.plugout: + if folded: + res = res + "\n" +@@ -230,7 +232,7 @@ class User: + elif os.environ.has_key("LOGNAME"): + self.remote = os.environ["LOGNAME"] + else: +- print "Can't get your username!" ++ print("Can't get your username!") + sys.exit(1) + self.localnames = [self.remote,]# Local names + self.password = None # Password for mail account access +@@ -316,13 +318,13 @@ class User: + + def __repr__(self): + res = " " +- res = res + "user " + `self.remote` + " there "; ++ res = res + "user " + repr(self.remote) + " there "; + if self.password: +- res = res + "with password " + `self.password` + " " ++ res = res + "with password " + repr(self.password) + " " + if self.localnames: + res = res + "is" + for x in self.localnames: +- res = res + " " + `x` ++ res = res + " " + repr(x) + res = res + " here" + if (self.keep != UserDefaults.keep + or self.flush != UserDefaults.flush +@@ -362,35 +364,35 @@ class User: + if self.idle != UserDefaults.idle: + res = res + flag2str(self.idle, 'idle') + if self.limit != UserDefaults.limit: +- res = res + " limit " + `self.limit` ++ res = res + " limit " + repr(self.limit) + if self.warnings != UserDefaults.warnings: +- res = res + " warnings " + `self.warnings` ++ res = res + " warnings " + repr(self.warnings) + if self.fetchlimit != UserDefaults.fetchlimit: +- res = res + " fetchlimit " + `self.fetchlimit` ++ res = res + " fetchlimit " + repr(self.fetchlimit) + if self.fetchsizelimit != UserDefaults.fetchsizelimit: +- res = res + " fetchsizelimit " + `self.fetchsizelimit` ++ res = res + " fetchsizelimit " + repr(self.fetchsizelimit) + if self.fastuidl != UserDefaults.fastuidl: +- res = res + " fastuidl " + `self.fastuidl` ++ res = res + " fastuidl " + repr(self.fastuidl) + if self.batchlimit != UserDefaults.batchlimit: +- res = res + " batchlimit " + `self.batchlimit` ++ res = res + " batchlimit " + repr(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` ++ res = res + " sslkey " + repr(self.sslkey) + if self.sslcert and self.sslcert != UserDefaults.sslcert: +- res = res + " sslcert " + `self.sslcert` ++ res = res + " sslcert " + repr(self.sslcert) + if self.sslproto and self.sslproto != UserDefaults.sslproto: +- res = res + " sslproto " + `self.sslproto` ++ res = res + " sslproto " + repr(self.sslproto) + if self.sslcertck and self.sslcertck != UserDefaults.sslcertck: + res = res + flag2str(self.sslcertck, 'sslcertck') + if self.sslcertpath and self.sslcertpath != UserDefaults.sslcertpath: +- res = res + " sslcertpath " + `self.sslcertpath` ++ res = res + " sslcertpath " + repr(self.sslcertpath) + if self.sslcommonname and self.sslcommonname != UserDefaults.sslcommonname: +- res = res + " sslcommonname " + `self.sslcommonname` ++ res = res + " sslcommonname " + repr(self.sslcommonname) + if self.sslfingerprint and self.sslfingerprint != UserDefaults.sslfingerprint: +- res = res + " sslfingerprint " + `self.sslfingerprint` ++ res = res + " sslfingerprint " + repr(self.sslfingerprint) + if self.expunge != UserDefaults.expunge: +- res = res + " expunge " + `self.expunge` ++ res = res + " expunge " + repr(self.expunge) + res = res + "\n" + trimmed = self.smtphunt; + if trimmed != [] and trimmed[len(trimmed) - 1] == "localhost": +@@ -417,7 +419,7 @@ class User: + res = res + "\n" + for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'): + if getattr(self, fld): +- res = res + " %s %s\n" % (fld, `getattr(self, fld)`) ++ res = res + " %s %s\n" % (fld, repr(getattr(self, fld))) + if self.lmtp != UserDefaults.lmtp: + res = res + flag2str(self.lmtp, 'lmtp') + if self.antispam != UserDefaults.antispam: +@@ -904,15 +906,15 @@ class ConfigurationEdit(Frame, MyWidget): + # Pre-1.5.2 compatibility... + except os.error: + pass +- oldumask = os.umask(077) ++ oldumask = os.umask(0o77) + fm = open(self.outfile, 'w') + os.umask(oldumask) + if fm: + # be paranoid + if fm != sys.stdout: +- os.chmod(self.outfile, 0600) ++ os.chmod(self.outfile, 0o600) + fm.write("# Configuration created %s by fetchmailconf %s\n" % (time.ctime(time.time()), version)) +- fm.write(`self.configuration`) ++ fm.write(repr(self.configuration)) + if self.outfile: + fm.close() + self.destruct() +@@ -1988,15 +1990,15 @@ def copy_instance(toclass, fromdict): + if 'typemap' in class_sig: + class_sig.remove('typemap') + if tuple(class_sig) != tuple(dict_keys): +- print "Fields don't match what fetchmailconf expected:" +-# print "Class signature: " + `class_sig` +-# print "Dictionary keys: " + `dict_keys` ++ print("Fields don't match what fetchmailconf expected:") ++# print("Class signature: " + repr(class_sig)) ++# print("Dictionary keys: " + repr(dict_keys)) + diff = setdiff(class_sig, common) + if diff: +- print "Not matched in class `" + toclass.__class__.__name__ + "' signature: " + `diff` ++ print("Not matched in class `" + toclass.__class__.__name__ + "' signature: " + repr(diff)) + diff = setdiff(dict_keys, common) + if diff: +- print "Not matched in dictionary keys: " + `diff` ++ print("Not matched in dictionary keys: " + repr(diff)) + sys.exit(1) + else: + for x in fromdict.keys(): +@@ -2028,7 +2030,7 @@ def copy_instance(toclass, fromdict): + if __name__ == '__main__': + + if not os.environ.has_key("DISPLAY"): +- print "fetchmailconf must be run under X" ++ print("fetchmailconf must be run under X") + sys.exit(1) + + fetchmail_icon = """ +@@ -2068,7 +2070,7 @@ gUSiYASJpMEHhilJTEnhAlGoQqYAZQ1AiqEMZ0jDGtqQImhwwA13yMMevoQAGvGhEAWHGMOAAAA7 + # The base64 data in the string above was generated by the following procedure: + # + # import base64 +-# print base64.encodestring(open("fetchmail.gif", "rb").read()) ++# print(base64.encodestring(open("fetchmail.gif", "rb").read())) + # + + # Process options +@@ -2081,22 +2083,22 @@ gUSiYASJpMEHhilJTEnhAlGoQqYAZQ1AiqEMZ0jDGtqQImhwwA13yMMevoQAGvGhEAWHGMOAAAA7 + elif (switch == '-f'): + rcfile = val + elif (switch == '-h' or switch == '--help'): +- print """ ++ print(""" + 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) + elif (switch == '-V' or switch == '--version'): +- print "fetchmailconf %s" % version +- print """ ++ 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.""" ++COPYING in the source or documentation directory for details.""") + sys.exit(0) + + # Get client host's FQDN +@@ -2119,17 +2121,17 @@ COPYING in the source or documentation directory for details.""" + try: + s = os.system(cmd) + if s != 0: +- print "`" + cmd + "' run failure, status " + `s` ++ print("`" + cmd + "' run failure, status " + repr(s)) + raise SystemExit + except: +- print "Unknown error while running fetchmail --configdump" ++ print("Unknown error while running fetchmail --configdump") + os.remove(tmpfile) + sys.exit(1) + + try: + execfile(tmpfile) + except: +- print "Can't read configuration output of fetchmail --configdump." ++ print("Can't read configuration output of fetchmail --configdump.") + os.remove(tmpfile) + sys.exit(1) + +@@ -2156,7 +2158,7 @@ COPYING in the source or documentation directory for details.""" + + # We may want to display the configuration and quit + if dump: +- print "This is a dump of the configuration we read:\n"+`Fetchmailrc` ++ print("This is a dump of the configuration we read:\n" + repr(Fetchmailrc)) + + # The theory here is that -f alone sets the rcfile location, + # but -d and -f together mean the new configuration should go to stdout. +-- +libgit2 0.26.0 + diff --git a/fetchmail-fetchmailconf-python3-3of3.patch b/fetchmail-fetchmailconf-python3-3of3.patch new file mode 100644 index 0000000..025bac8 --- /dev/null +++ b/fetchmail-fetchmailconf-python3-3of3.patch @@ -0,0 +1,86 @@ +From 1a405368c25f76db054fd3befa7fb72e7a5e1f2e Mon Sep 17 00:00:00 2001 +From: Matthias Andree +Date: Wed, 8 Jun 2016 22:34:23 +0200 +Subject: [PATCH] A few Python 3 compatibility fixes. + +Still needs 2to3 to be run under Python 3. +--- + fetchmailconf.py | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/fetchmailconf.py b/fetchmailconf.py +index 697e4f7..5c0b8ed 100755 +--- a/fetchmailconf.py ++++ b/fetchmailconf.py +@@ -5,12 +5,17 @@ + # Matthias Andree + # Requires Python with Tkinter, and the following OS-dependent services: + # posix, posixpath, socket ++ ++# WARNING: this needs to be updated for fetchmail 6.4's SSL options, ++# and other recent new options; ++# WARNING: to be compatible with Python 3, needs to be run thru 2to3.py. + from __future__ import print_function + +-version = "1.57" ++version = "1.58" + + from Tkinter import * + from Dialog import * ++ + import sys, time, os, string, socket, getopt, tempfile + + # +@@ -227,9 +232,9 @@ class Server: + + class User: + def __init__(self): +- if os.environ.has_key("USER"): ++ if "USER" in os.environ: + self.remote = os.environ["USER"] # Remote username +- elif os.environ.has_key("LOGNAME"): ++ elif "LOGNAME" in os.environ: + self.remote = os.environ["LOGNAME"] + else: + print("Can't get your username!") +@@ -1123,7 +1128,7 @@ class ServerEdit(Frame, MyWidget): + self.subwidgets[username] = UserEdit(username, self).edit(mode, Toplevel()) + + def user_delete(self, username): +- if self.subwidgets.has_key(username): ++ if username in self.subwidgets: + self.subwidgets[username].destruct() + del self.server[username] + +@@ -1627,7 +1632,7 @@ class UserEdit(Frame, MyWidget): + + def destruct(self): + # Yes, this test can fail -- if you delete the parent window. +- if self.parent.subwidgets.has_key(self.user.remote): ++ if self.user.remote in self.parent.subwidgets: + del self.parent.subwidgets[self.user.remote] + self.master.destroy() + +@@ -2029,7 +2034,7 @@ def copy_instance(toclass, fromdict): + + if __name__ == '__main__': + +- if not os.environ.has_key("DISPLAY"): ++ if "DISPLAY" not in os.environ: + print("fetchmailconf must be run under X") + sys.exit(1) + +@@ -2130,8 +2135,9 @@ COPYING in the source or documentation directory for details.""") + + try: + execfile(tmpfile) +- except: ++ except Exception as e: + print("Can't read configuration output of fetchmail --configdump.") ++ print(repr(e)) + os.remove(tmpfile) + sys.exit(1) + +-- +libgit2 0.26.0 + diff --git a/fetchmail.changes b/fetchmail.changes index fa944be..690ac8e 100644 --- a/fetchmail.changes +++ b/fetchmail.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Thu Mar 15 17:12:10 UTC 2018 - pmonrealgonzalez@suse.com + +- Fix fetchmailconf to compile with python{2,3} [bsc#1082694] + ------------------------------------------------------------------- Fri Mar 2 19:32:52 UTC 2018 - pmonrealgonzalez@suse.com diff --git a/fetchmail.spec b/fetchmail.spec index ca0c2db..e8c1c50 100644 --- a/fetchmail.spec +++ b/fetchmail.spec @@ -38,6 +38,10 @@ Source7: %{name}.tmpfiles Source8: %{name}.exec Patch0: fetchmail-6.3.8-smtp_errors.patch Patch1: fetchmail-openssl11.patch +# PATCH-FIX-UPSTREAM bsc#1082694 Fix fetchmailconf to be able to compile with python{2,3} +Patch2: fetchmail-fetchmailconf-python3-1of3.patch +Patch3: fetchmail-fetchmailconf-python3-2of3.patch +Patch4: fetchmail-fetchmailconf-python3-3of3.patch BuildRequires: automake BuildRequires: krb5-devel BuildRequires: openssl-devel @@ -85,6 +89,9 @@ files (.fetchmailrc). %setup -q %patch0 -p1 %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 cp -a %{SOURCE2} %{SOURCE3} . ACLOCAL="aclocal -I m4 -I m4-local" autoreconf -fvi