aboutsummaryrefslogtreecommitdiffstats
path: root/fetchmail.py
diff options
context:
space:
mode:
Diffstat (limited to 'fetchmail.py')
-rwxr-xr-xfetchmail.py899
1 files changed, 0 insertions, 899 deletions
diff --git a/fetchmail.py b/fetchmail.py
deleted file mode 100755
index 844d538d..00000000
--- a/fetchmail.py
+++ /dev/null
@@ -1,899 +0,0 @@
-#!/usr/bin/env python2
-#
-# Python translation of fetchmail.
-# Reads configuration from .fetchmailpyrc rather than .fetchmailrc
-#
-# Features removed:
-# 1. Support for multiple usernames per UID.
-# 2. Repolling on a changed rc file.
-# 3. It's no longer possible to specify site parameters from the command line.
-# 4. OPIE support -- use STLS instead..
-
-VERSION = "X0.1"
-
-import os, sys, getpass, pwd, getopt, stat
-
-# fetchmail return status codes
-PS_SUCCESS = 0 # successful receipt of messages
-PS_NOMAIL = 1 # no mail available
-PS_SOCKET = 2 # socket I/O woes
-PS_AUTHFAIL = 3 # user authorization failed
-PS_PROTOCOL = 4 # protocol violation
-PS_SYNTAX = 5 # command-line syntax error
-PS_IOERR = 6 # bad permissions on rc file
-PS_ERROR = 7 # protocol error
-PS_EXCLUDE = 8 # client-side exclusion error
-PS_LOCKBUSY = 9 # server responded lock busy
-PS_SMTP = 10 # SMTP error
-PS_DNS = 11 # fatal DNS error
-PS_BSMTP = 12 # output batch could not be opened
-PS_MAXFETCH = 13 # poll ended by fetch limit
-PS_SERVBUSY = 14 # server is busy
-PS_IDLETIMEOUT = 15 # timeout on imap IDLE
-# leave space for more codes
-PS_UNDEFINED = 23 # something I hadn't thought of
-PS_TRANSIENT = 24 # transient failure (internal use)
-PS_REFUSED = 25 # mail refused (internal use)
-PS_RETAINED = 26 # message retained (internal use)
-PS_TRUNCATED = 27 # headers incomplete (internal use)
-
-# output noise level
-O_SILENT = 0 # mute, max squelch, etc.
-O_NORMAL = 1 # user-friendly
-O_VERBOSE = 2 # chatty
-O_DEBUG = 3 # prolix
-O_MONITOR = O_VERBOSE
-
-# magic port numbers
-SMTP_PORT = 25
-KPOP_PORT = 1109
-SIMAP_PORT = 993
-SPOP3_PORT = 995
-
-# response hooks can use this to identify the query stage
-STAGE_GETAUTH = 0
-STAGE_GETRANGE = 1
-STAGE_GETSIZES = 2
-STAGE_FETCH = 3
-STAGE_IDLE = 4
-STAGE_LOGOUT = 5
-
-
-def DOTLINE(s):
- return (s[0] == '.' and (s[1]=='\r' or s[1]=='\n' or s[1]=='\0'))
-
-# Error classes
-class FetchError(Exception):
- def __init__(self, err):
- self.error = err
-
-class proto_pop2:
- "POP2 protocol methods"
- def __init__(self, ctl):
- self.name = 'POP2'
- self.service = 'pop2'
- self.sslservice = 'pop2'
- self.port = 109
- self.sslport = 109
- self.peek_capable = False
- self.tagged = False
- self.delimited = False
- self.repoll = False
- # Internal
- self.pound_arg = -1
- self.equal_arg = -1
-
- def ok(sock):
- st = 0
- self.pound_arg = self.equal_arg = -1
- buf = gen_recv(sock)
- if buf[0] == "+":
- pass
- elif buf[0] == "#":
- self.pound_arg = int(buf[1:])
- elif buf[0] == '=':
- self.equal_arg = int(buf[1:])
- elif buf[0] == '-':
- raise FetchError(PS_ERROR)
- else:
- raise FetchError(PS_PROTOCOL)
- return buf
-
- def getauth(sock, ctl):
- return gen_transact(sock,
- "HELO %s %s" % (ctl.remotename, ctl.password),
- ctl.password)
-
- def getrange(sock, ctl, folder):
- if folder:
- ok = gen_transact(sock, "FOLD %s" % folder)
- if pound_arg == -1:
- raise FetchError(PS_ERROR)
- else:
- # We should have picked up a count of messages in the user's
- # default inbox from the pop2_getauth() response.
- #
- # Note: this logic only works because there is no way to select
- # both the unnamed folder and named folders within a single
- # fetchmail run. If that assumption ever becomes invalid, the
- # pop2_getauth code will have to stash the pound response away
- # explicitly in case it gets stepped on.
- if pound_arg == -1:
- raise FetchError(PS_ERROR)
- return(pound_arg, -1, -1)
-
- def fetch(sock, ctl, number):
- # request nth message
- gen_transact(sock, "READ %d", number);
- gen_send(sock, "RETR");
- return equal_arg;
-
- def trail(sock, ctl, number):
- # send acknowledgement for message data
- if ctl.keep:
- return gen_transact(sock, "ACKS")
- else:
- return gen_transact(sock, "ACKD")
-
- def logout(sock, ctl):
- # send logout command
- return gen_transact(sock, "QUIT")
-
-class proto_pop3:
- "POP3 protocol methods"
- def __init__(self, ctl):
- name = 'POP3'
- service = 'pop2'
- sslservice = 'pop2'
- port = 110
- sslport = 995
- peek_capable = not ctl.fetchall
- tagged = False
- delimited = True
- retry = False
- # Internal
- self.stage = 0
- has_gssapi = FALSE
- has_kerberos = FALSE
- has_cram = FALSE
- has_otp = FALSE
- has_ssl = FALSE
-
- def ok(sock):
- buf = gen_recv(sock)
- if buf.beginswith("+OK"):
- return buf[3:]
- elif outlevel >= O_VERBOSE:
- stderr.write(buf + "\n")
- if buf.beginswith('-ERR'):
- buf = buf[4:]
- if self.stage == STAGE_FETCH:
- raise FetchError(PS_TRANSIENT)
- elif self.stage > STAGE_GETAUTH:
- raise FetchError(PS_PROTOCOL)
- # We're checking for "lock busy", "unable to lock",
- # "already locked", "wait a few minutes" etc. here.
- # This indicates that we have to wait for the server to
- # unwedge itself before we can poll again.
- #
- # PS_LOCKBUSY check empirically verified with two recent
- # versions of the Berkeley popper; QPOP (version 2.2) and
- # QUALCOMM Pop server derived from UCB (version 2.1.4-R3)
- # These are caught by the case-indifferent "lock" check.
- # The "wait" catches "mail storage services unavailable,
- # wait a few minutes and try again" on the InterMail server.
- #
- # [IN-USE] and [LOGIN-DELAY] are blessed by RFC 2449.
- #
- # If these aren't picked up on correctly, fetchmail will
- # think there is an authentication failure and wedge the
- # connection in order to prevent futile polls.
- #
- # Gad, what a kluge.
- elif buf.lower().find("lock") > -1 or buf.find("wait") > -1
- or buf.find("[IN-USE]") > -1
- or buf.find("[LOGIN-DELAY]") > -1:
- # We always want to pass the user lock-busy messages, because
- # they're red flags. Other stuff (like AUTH failures on non-
- # RFC1734 servers) only if we're debugging.
- if outlevel < O_VERBOSE:
- stderr.write(buf + "\n")
- raise FetchError(PS_LOCKBUSY)
- elif buf.find("ervice") > -1 and buf.find("unavailable") > -1:
- raise FetchError(PS_AUTHFAIL)
- else:
- raise FetchError(PS_PROTOCOL)
-
- def getauth(sock, ctl):
- did_stls = has_gssapi = has_kerberos = has_cram = has_ssl = False
- if ctl.server.authenticate == A_SSH:
- return
-
-
- def getrange(sock, ctl, folder):
-
- def fetch(sock, ctl, number):
-
- def trail(sock, ctl, number):
-
- def logout(sock, ctl):
- return gen_transact(sock, "QUIT")
-
-
-class hostdata:
- "Per-mailserver control data."
-
- # rc file data
- pollname = None # poll label of host
- via = None # "true" server name if non-NULL
- akalist = [] # server name first, then akas
- localdomains = [] # list of pass-through domains
- protocol = None # protocol type
- netsec = None # IPv6 security request
- port = None # TCP/IP service port number (name in IPV6)
- interval = 0 # cycles to skip between polls
- authenticate = 'password' # authentication mode to try
- timeout = 300 # inactivity timout in seconds
- envelope = None # envelope address list header
- envskip = 0 # skip to numbered envelope header
- qvirtual = None # prefix removed from local user id
- skip = False # suppress poll in implicit mode?
- dns = True # do DNS lookup on multidrop?
- uidl = False # use RFC1725 UIDLs?
- sdps = False # use Demon Internet SDPS *ENV
- checkalias = False # resolve aliases by comparing IPs?
- principal = None # Kerberos principal for mail service
- esmtp_name = None # ESMTP AUTH information
- esmtp_password = None
-
- # Only used under Linux
- interface = None
- monitor = None
- monitor_io = 0
- #struct interface_pair_s *interface_pair
-
- plugin = None
- plugout = None
-
- # computed for internal use
- base_protocol = None # relevant protocol method table
- poll_count = 0 # count of polls so far
- queryname = None # name to attempt DNS lookup on
- truename = None # "true name" of server host
- trueaddr = None # IP address of truename, as char
- lead_server = None # ptr to lead query for this server
- esmtp_options = [] # ESMTP option list
-
- def is_mailbox_protocol(self):
- # We need to distinguish between mailbox and mailbag protocols.
- # Under a mailbox protocol we're pulling mail for a speecific user.
- # Under a mailbag protocol we're fetching mail for an entire domain.
- return self.protocol != proto_etrn
-
-class query:
- "All the parameters of a fetchmail query."
- # mailserver connection controls
- server = None
-
- # per-user data
- localnames = [] # including calling user's name
- wildcard = False # should unmatched names be passed through
- remotename = None # remote login name to use
- password = None # remote password to use
- mailboxes = [] # list of mailboxes to check
-
- # per-forwarding-target data
- smtphunt = [] # list of SMTP hosts to try forwarding to
- domainlist = [] # domainlist to fetch from
- smtpaddress = None # address to force in RCPT TO
- smtpname = None # full RCPT TO name, including domain
- antispam = [] # list of listener's antispam response
- mda = None # local MDA to pass mail to
- bsmtp = None # BSMTP output file
- listener = 'SMTP' # what's the listener's wire protocol?
- preconnect = None # pre-connection command to execute
- postconnect = None # post-connection command to execute
-
- # per-user control flags
- keep = False # if TRUE, leave messages undeleted
- fetchall = False # if TRUE, fetch all (not just unseen)
- flush = False # if TRUE, delete messages already seen
- rewrite = False # if TRUE, canonicalize recipient addresses
- stripcr = False # if TRUE, strip CRs in text
- forcecr = False # if TRUE, force CRs before LFs in text
- pass8bits = False # if TRUE, ignore Content-Transfer-Encoding
- dropstatus = False # if TRUE, drop Status lines in mail
- dropdelivered = False # if TRUE, drop Delivered-To lines in mail
- mimedecode = False # if TRUE, decode MIME-armored messages
- idle = False # if TRUE, idle after each poll
- limit = 0 # limit size of retrieved messages
- warnings = 3600 # size warning interval
- fetchlimit = 0 # max # msgs to get in single poll
- batchlimit = 0 # max # msgs to pass in single SMTP session
- expunge = 1 # max # msgs to pass between expunges
- use_ssl = False # use SSL encrypted session
- sslkey = None # optional SSL private key file
- sslcert = None # optional SSL certificate file
- sslproto = None # force usage of protocol (ssl2|ssl3|tls1) - defaults to ssl23
- sslcertpath = None # Trusted certificate directory for checking the server cert
- sslcertck = False # Strictly check the server cert.
- sslfingerprint = None # Fingerprint to check against
- properties = [] # passthrough properties for extensions
- tracepolls = False # if TRUE, add poll trace info to Received
-
- # internal use -- per-poll state
- active = False # should we actually poll this server?
- destaddr = None # destination host for this query
- errcount = 0 # count transient errors in last pass
- authfailcount = 0 # count of authorization failures
- wehaveauthed = 0 # We've managed to logon at least once!
- wehavesentauthnote = 0 # We've sent an authorization failure note
- wedged = 0 # wedged by auth failures or timeouts?
- smtphost = None # actual SMTP host we connected to
- smtp_socket = -1 # socket descriptor for SMTP connection
- uid = 0 # UID of user to deliver to
- skipped = [] # messages skipped on the mail server
- oldsaved = []
- newsaved = []
- oldsavedend = []
- lastid = None # last Message-ID seen on this connection
- thisid = None # Message-ID of current message
-
- # internal use -- per-message state
- mimemsg = 0 # bitmask indicating MIME body-type
- digest = None
-
- def dump(self):
- print "Options for retrieving from %s@%s:" \
- % (self.remotename, self.server.pollname)
- if self.server.via and self.server.server.is_mailbox_protocol():
- print " Mail will be retrieved via %s" % self.server.via
- if self.server.interval:
- print " Poll of this server will occur every %d intervals." \
- % self.server.interval;
- if self.server.truename:
- print " True name of server is %s." % self.server.truename
- if self.server.skip || outlevel >= O_VERBOSE:
- if self.server.skip:
- print " Will not be queried when no host is specified."
- else:
- print " Will not be queried when no host is specified."
- if self.server.authenticate not in ('KERBEROS', 'GSSAPI', 'SSH'):
- if not self.password:
- print " Password will be prompted for."
- else if outlevel >= O_VERBOSE:
- if self.server.protocol == proto_apop:
- print " APOP secret = \"%s\"." % self.password
- elif self.server.protocol == proto_rpop:
- print " RPOP id = \"%s\"." % self.password
- else
- print " Password = \"%s\"." % self.password
-
- if self.server.protocol == proto_pop3 \
- and self.server.port == KPOP_PORT \
- and self.server.authenticate.startswith("Kerberos"):
- sys.stdout.write(" Protocol is KPOP with %s authentication" \
- % self.server.authenticate)
- else
- sys.stdout.write(" Protocol is %s" % self.server.protocol.name)
- if ipv6:
- if self.server.port:
- sys.stdout.write(" (using service %s)" % self.server.port)
- if (self.server.netsec)
- sys.stdout.write(" (using network security options %s)" % self.server.netsec)
- else:
- if self.server.port:
- sys.stdout.write(" (using port %d)" % self.server.port)
- else if outlevel >= O_VERBOSE:
- sys.stdout.write(" (using default port)")
- if self.server.uidl and self.server.is_mailbox.protocol())
- sys.stdout.write(" (forcing UIDL use)")
- sys.stdout.write("\n")
- print {
- None : " All available authentication methods will be tried.",
- 'password' : " Password authentication will be forced.",
- 'NTLM' : " NTLM authentication will be forced.",
- 'OTP' : " OTP authentication will be forced.",
- 'CRAM-MD5' " CRAM-MD5 authentication will be forced.",
- 'GSSAPI' : " GSSAPI authentication will be forced.",
- 'Kerberos V4' : " Kerberos V4 authentication will be forced.",
- 'Kerberos V5' : " Kerberos V5 authentication will be forced.",
- 'ssh' : " End-to-end encryption will be assumed.",
- }[self.server.authenticate]
-
- if self.server.principal:
- print " Mail service principal is: %s" % self.server.principal
- if self.use_ssl:
- print " SSL encrypted sessions enabled."
- if self.sslproto:
- print " SSL protocol: %s." % self.sslproto;
- if self.sslcertck:
- print " SSL server certificate checking enabled."
- if self.sslcertpath:
- print " SSL trusted certificate directory: %s" % self.sslcertpath;
- if self.sslfingerprint:
- print " SSL key fingerprint (checked against the server key): %s" % self.sslfingerprint;
- if self.server.timeout > 0:
- print " Server nonresponse timeout is %d seconds" % self.server.timeout;
- if self.server.is_mailbox_protocol():
- if not self.mailboxes.id:
- print " Default mailbox selected."
- else
- print " Selected mailboxes are: ", ", ".join(self.mailboxes)
- flagarray = (
- ('fetchall',
- "%s messages will be retrieved (--all %s)."
- "All", "Only new")
- ('keep',
- " Fetched messages %s be kept on the server (--keep %s)."
- "will", "will not")
- ('flush',
- " Old messages %s be flushed before message retrieval (--flush %s).",
- "will", "will not")
- ('rewrite',
- " Rewrite of server-local addresses is %s (norewrite %s).",
- "enabled", "disabled")
- ('stripcr',
- " Carriage-return stripping is %s (stripcr %s).",
- "enabled", "disabled")
- ('forcecr',
- " Carriage-return forcing is %s (forcecr %s).",
- "enabled", "disabled")
- ('pass8bits',
- " Interpretation of Content-Transfer-Encoding is %s (pass8bits %s).",
- "enabled", "disabled")
- ('mimedecode',
- " MIME decoding is %s (mimedecode %s).",
- "enabled", "disabled")
- ('idle',
- " Idle after poll is %s (idle %s).",
- "enabled", "disabled")
- ('dropstatus',
- " Nonempty Status lines will be %s (dropstatus %s)",
- "discarded", "kept")
- ('dropdelivered',
- " Delivered-To lines will be %s (dropdelivered %s)",
- "discarded", "kept")
- )
- for (attr, template, on, off) in flagarray:
- flag = getattr(self, att)
- if flag:
- onoff1 = on
- onoff2 = "on"
- else:
- onoff1 = off
- onoff2 = "off"
- print template % (onoff1, onoff2)
- if self.limit:
- {
- if NUM_NONZERO(self.limit):
- print " Message size limit is %d octets (--limit %d)." %
- self.limit, self.limit);
- else if outlevel >= O_VERBOSE:
- print " No message size limit (--limit 0)."
- if run.poll_interval > 0:
- print " Message size warning interval is %d seconds (--warnings %d)." %
- self.warnings, self.warnings);
- else if outlevel >= O_VERBOSE:
- print " Size warnings on every poll (--warnings 0)."
- }
- if NUM_NONZERO(self.fetchlimit):
- print " Received-message limit is %d (--fetchlimit %d)."),
- self.fetchlimit, self.fetchlimit);
- else if outlevel >= O_VERBOSE:
- print " No received-message limit (--fetchlimit 0)."
- if NUM_NONZERO(self.batchlimit):
- print " SMTP message batch limit is %d." % self.batchlimit);
- else if outlevel >= O_VERBOSE:
- print " No SMTP message batch limit (--batchlimit 0)."
- if MAILBOX_PROTOCOL(ctl):
- {
- if NUM_NONZERO(self.expunge):
- print " Deletion interval between expunges forced to %d (--expunge %d)." % self.expunge, self.expunge);
- else if outlevel >= O_VERBOSE:
- print " No forced expunges (--expunge 0)."
- }
- }
- else /* ODMR or ETRN */
- {
- struct idlist *idp;
-
- print " Domains for which mail will be fetched are:"
- for (idp = self.domainlist; idp; idp = idp.next:
- {
- printf(" %s", idp.id);
- if not idp.val.status.mark:
- print " (default)"
- }
- printf("");
- }
- if self.bsmtp:
- print " Messages will be appended to %s as BSMTP" % visbuf(self.bsmtp
- else if self.mda and MAILBOX_PROTOCOL(ctl):
- print " Messages will be delivered with \"%s\"." % visbuf(self.mda
- else
- {
- struct idlist *idp;
-
- if self.smtphunt:
- {
- print " Messages will be %cMTP-forwarded to:" %
- self.listener);
- for (idp = self.smtphunt; idp; idp = idp.next:
- {
- printf(" %s", idp.id);
- if not idp.val.status.mark:
- print " (default)"
- }
- printf("");
- }
- if self.smtpaddress:
- print " Host part of MAIL FROM line will be %s"),
- self.smtpaddress);
- if self.smtpname:
- print " Address to be put in RCPT TO lines shipped to SMTP will be %s"),
- self.smtpname);
- }
- if MAILBOX_PROTOCOL(ctl):
- {
- if self.antispam != (struct idlist *)NULL:
- {
- struct idlist *idp;
-
- print " Recognized listener spam block responses are:"
- for (idp = self.antispam; idp; idp = idp.next:
- printf(" %d", idp.val.status.num);
- printf("");
- }
- else if outlevel >= O_VERBOSE:
- print " Spam-blocking disabled"
- }
- if self.preconnect:
- print " Server connection will be brought up with \"%s\"."),
- visbuf(self.preconnect
- else if outlevel >= O_VERBOSE:
- print " No pre-connection command."
- if self.postconnect:
- print " Server connection will be taken down with \"%s\"."),
- visbuf(self.postconnect
- else if outlevel >= O_VERBOSE:
- print " No post-connection command."
- if MAILBOX_PROTOCOL(ctl)) {
- if !self.localnames:
- print " No localnames declared for this host."
- else
- {
- struct idlist *idp;
- int count = 0;
-
- for (idp = self.localnames; idp; idp = idp.next:
- ++count;
-
- if count > 1 || self.wildcard:
- print " Multi-drop mode: "
- else
- print " Single-drop mode: "
-
- print "%d local name(s) recognized." % count);
- if outlevel >= O_VERBOSE:
- {
- for (idp = self.localnames; idp; idp = idp.next:
- if idp.val.id2:
- printf("\t%s . %s", idp.id, idp.val.id2);
- else
- printf("\t%s", idp.id);
- if self.wildcard:
- fputs("\t*", stdout);
- }
-
- if count > 1 || self.wildcard:
- {
- print " DNS lookup for multidrop addresses is %s."),
- self.server.dns ? GT_("enabled") : GT_("disabled"
- if self.server.dns:
- {
- print " Server aliases will be compared with multidrop addresses by "
- if self.server.checkalias:
- print "IP address."
- else
- print "name."
- }
- if self.server.envelope == STRING_DISABLED:
- print " Envelope-address routing is disabled"
- else
- {
- print " Envelope header is assumed to be: %s"),
- self.server.envelope ? self.server.envelope:GT_("Received"
- if self.server.envskip > 1 || outlevel >= O_VERBOSE:
- print " Number of envelope header to be parsed: %d"),
- self.server.envskip);
- if self.server.qvirtual:
- print " Prefix %s will be removed from user id"),
- self.server.qvirtual);
- else if outlevel >= O_VERBOSE)
- print " No prefix stripping"
- }
-
- if self.server.akalist:
- {
- struct idlist *idp;
-
- print " Predeclared mailserver aliases:"
- for (idp = self.server.akalist; idp; idp = idp.next:
- printf(" %s", idp.id);
- putchar('');
- }
- if self.server.localdomains:
- {
- struct idlist *idp;
-
- print " Local domains:"
- for (idp = self.server.localdomains; idp; idp = idp.next:
- printf(" %s", idp.id);
- putchar('');
- }
- }
- }
- }
-#if defined(linux) || defined(__FreeBSD__:
- if self.server.interface:
- print " Connection must be through interface %s." % self.server.interface);
- else if outlevel >= O_VERBOSE:
- print " No interface requirement specified."
- if self.server.monitor:
- print " Polling loop will monitor %s." % self.server.monitor);
- else if outlevel >= O_VERBOSE:
- print " No monitor interface specified."
-#endif
-
- if self.server.plugin:
- print " Server connections will be made via plugin %s (--plugin %s)." % self.server.plugin, self.server.plugin);
- else if outlevel >= O_VERBOSE:
- print " No plugin command specified."
- if self.server.plugout:
- print " Listener connections will be made via plugout %s (--plugout %s)." % self.server.plugout, self.server.plugout);
- else if outlevel >= O_VERBOSE:
- print " No plugout command specified."
-
- if self.server.protocol > P_POP2 and MAILBOX_PROTOCOL(ctl):
- {
- if !self.oldsaved:
- print " No UIDs saved from this host."
- else
- {
- struct idlist *idp;
- int count = 0;
-
- for (idp = self.oldsaved; idp; idp = idp.next:
- ++count;
-
- print " %d UIDs saved." % count);
- if outlevel >= O_VERBOSE:
- for (idp = self.oldsaved; idp; idp = idp.next:
- printf("\t%s", idp.id);
- }
- }
-
- if self.tracepolls:
- print " Poll trace information will be added to the Received header."
- else if outlevel >= O_VERBOSE:
- print " No poll trace information will be added to the Received header.."
-
- if self.properties:
- print " Pass-through properties \"%s\"." % self.properties
-
-
-
-if __name__ == '__main__':
- # C version queried FETCHMAILUSER, then USER, then LOGNAME.
- # Order here is FETCHMAILUSER, LOGNAME, USER, LNAME and USERNAME.
- user = os.getenv("FETCHMAILUSER") or getpass.getuser()
- for injector in ("QMAILINJECT", "NULLMAILER_FLAGS"):
- if os.getenv(injector):
- print >>sys.stderr, \
- ("fetchmail: The %s environment variable is set.\n"
- "This is dangerous, as it can make qmail-inject or qmail's\n"
- "sendmail wrapper tamper with your From or Message-ID "
- "headers.\n"
- "Try 'env %s= fetchmail YOUR ARGUMENTS HERE'\n") % (injector, injector)
- sys.exit(PS_UNDEFINED)
-
- # Figure out who calling user is and where the run-control file is.
- # C version handled multiple usernames per PID; this doesn't.
- try:
- pwp = pwd.getpwuid(os.getuid())
- except:
- print >>sys.stderr, "You don't exist. Go away."
- sys.exit(PS_UNDEFINED)
- home = os.getenv("HOME") or pwp.pw_dir
- fmhome = os.getenv("FETCHMAILHOME") or home
- rcfile = os.path.join(fmhome, ".fetchmailpyrc")
- idfile = os.path.join(fmhome, ".fetchids")
-
- cmdhelp = \
- "usage: fetchmail [options] [server ...]\n" \
- " Options are as follows:\n" \
- " -?, --help display this option help\n" \
- " -V, --version display version info\n" \
- " -c, --check check for messages without fetching\n" \
- " -s, --silent work silently\n" \
- " -v, --verbose work noisily (diagnostic output)\n" \
- " -d, --daemon run as a daemon once per n seconds\n" \
- " -N, --nodetach don't detach daemon process\n" \
- " -q, --quit kill daemon process\n" \
- " -f, --fetchmailrc specify alternate run control file\n" \
- " -a, --all retrieve old and new messages\n" \
- " -k, --keep save new messages after retrieval\n" \
- " -F, --flush delete old messages from server\n"
-
- # Now time to parse the command line
- try:
- (options, arguments) = getopt.getopt(sys.argv[1:],
- "?Vcsvd:NqfakF",
- ("help",
- "version",
- "check",
- "silent",
- "verbose",
- "daemon",
- "nodetach",
- "quit",
- "fetchmailrc",
- "all",
- "keep",
- "flush",
- ))
- except getopt.GetoptError:
- print cmdhelp
- sys.exit(PS_SYNTAX)
- versioninfo = checkonly = silent = nodetach = quitmode = False
- fetchall = keep = flutch = False
- outlevel = O_NORMAL
- poll_interval = -1
- for (switch, val) in options:
- if switch in ("-?", "--help"):
- print cmdhelp
- sys.exit(0)
- elif switch in ("-V", "--version"):
- versioninfo = True
- elif switch in ("-c", "--check"):
- checkonly = True
- elif switch in ("-s", "--silent"):
- outlevel = O_SILENT
- elif switch in ("-v", "--verbose"):
- if outlevel == O_VERBOSE:
- outlevel = O_DEBUG
- else:
- outlevel = O_VERBOSE
- elif switch in ("-d", "--daemon"):
- poll_interval = int(val)
- elif switch in ("-N", "--nodetach"):
- outlevel = O_SILENT
- elif switch in ("-q", "--quitmode"):
- quitmode = True
- elif switch in ("-f", "--fetchmailrc"):
- rcfile = val
- elif switch in ("-a", "--all"):
- fetchall = True
- elif switch in ("-k", "--keep"):
- keep = True
- elif switch in ("-F", "--flush"):
- flush = True
-
- if versioninfo:
- print "This is fetchmail release", VERSION
- os.system("uname -a")
-
- # avoid parsing the config file if all we're doing is killing a daemon
- fetchmailrc = {}
- if not quitmode or len(sys.argv) != 2:
- # user probably supplied a configuration file, check security
- if os.path.exists(rcfile):
- # the run control file must have the same uid as the
- # REAL uid of this process, it must have permissions
- # no greater than 600, and it must not be a symbolic
- # link. We check these conditions here.
- try:
- st = os.lstat(rcfile)
- except IOError:
- sys.exit(PS_IOERR)
- if not versioninfo:
- if not stat.S_ISREG(st.st_mode):
- print >>sys.stderr, \
- "File %s must be a regular file." % pathname;
- sys.exit(PS_IOERR);
-
- if st.st_mode & 0067:
- print >>sys.stderr, \
- "File %s must have no more than -rwx--x--- (0710) permissions." % pathname;
- sys.exit(PS_IOERR);
- # time to read the configuration
- if rcfile == '-':
- ifp = sys.stdin
- elif os.path.exists(rcfile):
- ifp = file(rcfile)
- try:
- exec ifp in globals()
- except SyntaxError:
- print >>sys.stderr, \
- "File %s is ill-formed." % pathname;
- sys.exit(PS_SYNTAX);
- ifp.close()
- # generate a default configuration if user did not supply one
- if not fetchmailrc:
- fetchmailrc = {
- 'poll_interval': 300,
- "logfile": None,
- "idfile": idfile,
- "postmaster": "esr",
- 'bouncemail': True,
- 'spambounce': False,
- "properties": "",
- 'invisible': False,
- 'showdots': False,
- 'syslog': False,
- 'servers': []
- }
- for site in arguments:
- fetchmailrc['servers'].append({
- "pollname" : site,
- 'active' : False,
- "via" : None,
- "protocol" : "IMAP",
- 'port' : 0,
- 'timeout' : 300,
- 'interval' : 0,
- "envelope" : "Received",
- 'envskip' : 0,
- "qvirtual" : None,
- "auth" : "any",
- 'dns' : True,
- 'uidl' : False,
- "aka" : [],
- "localdomains" : [],
- "interface" : None,
- "monitor" : None,
- "plugin" : None,
- "plugout" : None,
- "principal" : None,
- 'tracepolls' : False,
- 'users' : [
- {
- "remote" : user,
- "password" : None,
- 'localnames' : [user],
- 'fetchall' : False,
- 'keep' : False,
- 'flush' : False,
- 'rewrite' : True,
- 'stripcr' : True,
- 'forcecr' : False,
- 'pass8bits' : False,
- 'dropstatus' : False,
- 'dropdelivered' : False,
- 'mimedecode' : False,
- 'idle' : False,
- "mda" : "/usr/bin/procmail -d %T",
- "bsmtp" : None,
- 'lmtp' : False,
- "preconnect" : None,
- "postconnect" : None,
- 'limit' : 0,
- 'warnings' : 3600,
- 'fetchlimit' : 0,
- 'batchlimit' : 0,
- 'expunge' : 0,
- "properties" : None,
- "smtphunt" : ["localhost"],
- "fetchdomains" : [],
- "smtpaddress" : None,
- "smtpname" : None,
- 'antispam' : '',
- "mailboxes" : [],
- }
- ]
- })
- if poll_interval != -1:
- fetchmailrc['poll_interval'] = poll_interval
- # now turn the configuration into control structures
-