]> Pileus Git - ~andy/fetchmail/commitdiff
Feature: bad-header {reject|pass}
authorMatthias Andree <matthias.andree@gmx.de>
Wed, 24 Feb 2010 00:54:22 +0000 (01:54 +0100)
committerMatthias Andree <matthias.andree@gmx.de>
Wed, 24 Feb 2010 00:54:22 +0000 (01:54 +0100)
NEWS
conf.c
fetchmail.c
fetchmail.h
fetchmail.man
fetchmailconf.py
options.c
rcfile_l.l
rcfile_y.y
transact.c

diff --git a/NEWS b/NEWS
index 44cba4041fd08d005e1d10608e288e250e93e245..7ae09a7d1ee9b160a02319dfb9051e416a67ce74 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -49,6 +49,12 @@ removed from a 6.4.0 or newer release.)
 
 fetchmail 6.3.15 (not yet released):
 
+# FEATURE
+* Fetchmail now supports a bad-header command line or rcfile option that takes
+  exactly one argument, pass or reject (default).  If set to pass, fetchmail
+  will pass messages with bad headers on.  This has been rejected for a long
+  time, and the right behaviour was disputed for too long.
+
 # CHANGES
 * The repository has been converted and moved from the Subversion (SVN) format
   kindly hosted by Graham Wilson over the past years to Git format hosted on
diff --git a/conf.c b/conf.c
index 60eb3ebbb9fc0d0f140cd52085fffdfed132da1c..5b5d877908a879506bb0b6c8a6ae5f8e5331fb14 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -312,6 +312,13 @@ void dump_config(struct runctl *runp, struct query *querylist)
            if (ctl->server.esmtp_password)
                stringdump("esmtppassword",ctl->server.esmtp_password);
            booldump("tracepolls", ctl->server.tracepolls);
+           indent(0);
+           switch(ctl->server.badheader) {
+               /* this is a hack - we map this to a boolean option for
+                * fetchmailconf purposes */
+               case BHREJECT: puts("'badheader': FALSE,"); break;
+               case BHPASS:   puts("'badheader': TRUE,"); break;
+           }
 
            indent(0);
            fputs("'users': ", stdout);
index cb1bc9003fee72671cf8d23ebd04b1b7b878ebc3..5d02a289058161e4addbb97c2aebf9b7dcd74c20 100644 (file)
@@ -944,6 +944,7 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(server.plugin);
     FLAG_MERGE(server.plugout);
     FLAG_MERGE(server.tracepolls);
+    FLAG_MERGE(server.badheader);
 
     FLAG_MERGE(wildcard);
     FLAG_MERGE(remotename);
@@ -1012,6 +1013,7 @@ static int load_params(int argc, char **argv, int optind)
     def_opts.server.protocol = P_AUTO;
     def_opts.server.timeout = CLIENT_TIMEOUT;
     def_opts.server.esmtp_name = user;
+    def_opts.server.badheader = BHREJECT;
     def_opts.warnings = WARNING_INTERVAL;
     def_opts.remotename = user;
     def_opts.listener = SMTP_MODE;
@@ -1949,6 +1951,16 @@ static void dump_params (struct runctl *runp,
         else if (outlevel >= O_VERBOSE)
             printf(GT_("  No poll trace information will be added to the Received header.\n.\n"));
 
+       switch (ctl->server.badheader) {
+           case BHREJECT:
+               if (outlevel >= O_VERBOSE)
+                   printf(GT_("  Messages with bad headers will be rejected.\n"));
+               break;
+           case BHPASS:
+               printf(GT_("  Messages with bad headers will be passed on.\n"));
+               break;
+       }
+
        if (ctl->properties)
            printf(GT_("  Pass-through properties \"%s\".\n"),
                   visbuf(ctl->properties));
index d09913868d09ba0de6a682c5bb4557f82948d8f8..88f7dd33ae495ed2b2de9ccd18f492a0a9dbf46e 100644 (file)
@@ -245,6 +245,8 @@ struct method               /* describe methods for protocol state machine */
     flag retry;                        /* can getrange poll for new messages? */
 };
 
+enum badheader { BHREJECT = 0, BHPASS };
+
 struct hostdata                /* shared among all user connections to given server */
 {
     /* rc file data */
@@ -270,6 +272,7 @@ struct hostdata             /* shared among all user connections to given server */
     flag tracepolls;                   /* if TRUE, add poll trace info to Received */
     char *principal;                   /* Kerberos principal for mail service */
     char *esmtp_name, *esmtp_password; /* ESMTP AUTH information */
+    enum badheader badheader;          /* bad-header {pass|reject} */
 
 #if defined(linux) || defined(__FreeBSD__)
 #define CAN_MONITOR
index d2b5119769a62c2db97f563a160e60ae9a6ab1b6..f63f381f57853a9a7c7665e8e535a03499ccc1a6 100644 (file)
@@ -699,6 +699,15 @@ to be written to standard output.  Note that fetchmail's
 reconstruction of MAIL FROM and RCPT TO lines is not guaranteed
 correct; the caveats discussed under THE USE AND ABUSE OF MULTIDROP
 MAILBOXES below apply.
+.TP
+.B \-\-bad\-header {reject|pass}
+(Keyword: bad\-header; since v6.3.15)
+.br
+Specify how fetchmail is supposed to treat messages with bad headers,
+i. e. headers with bad syntax. Traditionally, fetchmail has rejected such
+messages, but some distributors modified fetchmail to pass them. You can now
+configure fetchmail's behaviour per server.
+
 .SS Resource Limit Control Options
 .TP
 .B \-l <maxbytes> | \-\-limit <maxbytes>
@@ -1749,6 +1758,9 @@ T}
 esmtppassword  \&      \&      T{
 Set password for RFC2554 authentication to the ESMTP server.
 T}
+bad-header     \&      \&      T{
+How to treat messages with a bad header. Can be reject (default) or pass.
+T}
 .TE
 
 Here are the legal user descriptions and options:
index 90a2dea5223bd7cf86b89edecdec7d736dae20fa..4aae48f8a5de064fbb59a1bce6e8488b68ac558b 100755 (executable)
@@ -5,7 +5,7 @@
 # Matthias Andree <matthias.andree@gmx.de>
 # Requires Python with Tkinter, and the following OS-dependent services:
 #      posix, posixpath, socket
-version = "1.56 $Revision$"
+version = "1.57"
 
 from Tkinter import *
 from Dialog import *
@@ -103,6 +103,7 @@ class Server:
        self.esmtpname = None           # ESMTP 2554 name
        self.esmtppassword = None       # ESMTP 2554 password
        self.tracepolls = FALSE         # Add trace-poll info to headers
+       self.badheader = FALSE          # Pass messages with bad headers on?
        self.users = []                 # List of user entries for site
        Server.typemap = (
            ('pollname',  'String'),
@@ -127,7 +128,8 @@ class Server:
            ('esmtpname', 'String'),
            ('esmtppassword', 'String'),
            ('principal', 'String'),
-           ('tracepolls','Boolean'))
+           ('tracepolls','Boolean'),
+           ('badheader', 'Boolean'))
 
     def dump(self, folded):
        res = ""
@@ -197,6 +199,8 @@ class Server:
        if self.interface or self.monitor or self.principal or self.plugin or self.plugout:
            if folded:
                res = res + "\n"
+       if self.badheader:
+               res = res + "bad-header pass "
 
        if res[-1] == " ": res = res[0:-1]
 
@@ -1129,6 +1133,8 @@ class ServerEdit(Frame, MyWidget):
            ctlwin = Frame(leftwin, relief=RAISED, bd=5)
            Label(ctlwin, text="Run Controls").pack(side=TOP)
            Checkbutton(ctlwin, text='Poll ' + host + ' normally?', variable=self.active).pack(side=TOP)
+           Checkbutton(ctlwin, text='Pass messages with bad headers?',
+                   variable=self.badheader).pack(side=TOP)
            LabeledEntry(ctlwin, 'True name of ' + host + ':',
                      self.via, leftwidth).pack(side=TOP, fill=X)
            LabeledEntry(ctlwin, 'Cycles to skip between polls:',
index e85682d56dfcdf4f3d16843afa9bfa3ab63ab96d..066a8ab0df02d37f032d7f0cf58a15e2b7166e98 100644 (file)
--- a/options.c
+++ b/options.c
@@ -53,7 +53,8 @@ enum {
     LA_LIMITFLUSH,
     LA_IDLE,
     LA_NOSOFTBOUNCE,
-    LA_SOFTBOUNCE
+    LA_SOFTBOUNCE,
+    LA_BADHEADER
 };
 
 /* options still left: CgGhHjJoORTWxXYz */
@@ -93,6 +94,7 @@ static const struct option longoptions[] = {
   {"timeout",  required_argument, (int *) 0, 't' },
   {"envelope", required_argument, (int *) 0, 'E' },
   {"qvirtual", required_argument, (int *) 0, 'Q' },
+  {"bad-header",required_argument, (int *) 0, LA_BADHEADER},
 
   {"user",     required_argument, (int *) 0, 'u' },
   {"username", required_argument, (int *) 0, 'u' },
@@ -310,6 +312,17 @@ int parsecmdline (int argc /** argument count */,
        case LA_SOFTBOUNCE:
            run.softbounce = TRUE;
            break;
+       case LA_BADHEADER:
+           if (strcasecmp(optarg,"pass") == 0) {
+               ctl->server.badheader = BHPASS;
+           } else if (strcasecmp(optarg,"reject") == 0) {
+               ctl->server.badheader = BHREJECT;
+           } else {
+               fprintf(stderr,GT_("Invalid bad-header policy `%s' specified.\n"), optarg);
+               errflag++;
+           }
+           break;
+
        case 'p':
            /* XXX -- should probably use a table lookup here */
            if (strcasecmp(optarg,"auto") == 0)
@@ -635,6 +648,8 @@ int parsecmdline (int argc /** argument count */,
 #endif
        P(GT_("      --plugin      specify external command to open connection\n"));
        P(GT_("      --plugout     specify external command to open smtp connection\n"));
+       P(GT_("      --bad-header {reject|pass}\n"
+             "                    specify policy for handling messages with bad headers\n"));
 
        P(GT_("  -p, --protocol    specify retrieval protocol (see man page)\n"));
        P(GT_("  -U, --uidl        force the use of UIDLs (pop3 only)\n"));
index 67317a6bad7bf7088a2287e39dcd9006e82a40d7..679a5b4e891b64cf96050213ee2e8d3a3c3c8d8f 100644 (file)
@@ -113,7 +113,9 @@ qvirtual    { return QVIRTUAL; }
 principal      { return PRINCIPAL; }
 esmtpname      { return ESMTPNAME; }
 esmtppassword  { return ESMTPPASSWORD; }
-
+bad-header     { return BADHEADER; }
+pass           { return PASS; }
+reject         { return REJECT_; }
 
 user(name)?    {SETSTATE(NAME); return USERNAME; }
 <INITIAL,NAME>pass(word)?      {SETSTATE(NAME); return PASSWORD; }
index e57973b6f400ec64c15342b0c63c7f892e00469b..b5765d7703c19c055dd1f3a308bccd49050bcdc5 100644 (file)
@@ -70,6 +70,7 @@ extern char * yytext;
 %token BATCHLIMIT FETCHLIMIT FETCHSIZELIMIT FASTUIDL EXPUNGE PROPERTIES
 %token SET LOGFILE DAEMON SYSLOG IDFILE PIDFILE INVISIBLE POSTMASTER BOUNCEMAIL
 %token SPAMBOUNCE SOFTBOUNCE SHOWDOTS
+%token BADHEADER PASS REJECT_
 %token <proto> PROTO AUTHTYPE
 %token <sval>  STRING
 %token <number> NUMBER
@@ -231,6 +232,8 @@ serv_option : AKA alias_list
                | NO ENVELOPE           {current.server.envelope = STRING_DISABLED;}
                | TRACEPOLLS            {current.server.tracepolls = FLAG_TRUE;}
                | NO TRACEPOLLS         {current.server.tracepolls = FLAG_FALSE;}
+               | BADHEADER PASS        {current.server.badheader = BHPASS;}
+               | BADHEADER REJECT_     {current.server.badheader = BHREJECT;}
                ;
 
 userspecs      : user1opts             {record_current(); user_reset();}
index c6ea7e354b7f2ed5d8f565f842e8aab5c12e4870..9d151607e2a0c93f0e2bd7fb7c924854b265f52c 100644 (file)
@@ -583,7 +583,10 @@ eoh:
             * message/rfc822 attachment and forward to postmaster (Rob
             * MacGregor)
             */
-           if (!refuse_mail && !isspace((unsigned char)line[0]) && !strchr(line, ':'))
+           if (!refuse_mail
+               && !ctl->server.badheader == BHPASS
+               && !isspace((unsigned char)line[0])
+               && !strchr(line, ':'))
            {
                if (linelen != strlen (line))
                    has_nuls = TRUE;