]> Pileus Git - ~andy/fetchmail/blobdiff - driver.c
Initial revision
[~andy/fetchmail] / driver.c
index 9c8c61597ca167345394ae5ed644cdfb8f78be0b..ee4d3e5fa33d0ac8cc74b86acd9adc0c1ff4db33 100644 (file)
--- a/driver.c
+++ b/driver.c
 #include  <sys/time.h>
 #include  <signal.h>
 
+#ifdef HAVE_NET_SOCKET_H
+#include <net/socket.h>
+#endif
+
 #ifdef HAVE_RES_SEARCH
 #include <netdb.h>
 #include "mx.h"
@@ -82,6 +86,8 @@ flag peek_capable;    /* can we peek for better error recovery? */
 int pass;              /* how many times have we re-polled? */
 int stage;             /* where are we? */
 int phase;             /* where are we, for error-logging purposes? */
+int mytimeout;         /* value of nonreponse timeout */
+int suppress_tags;     /* emit tags? */
 
 static const struct method *protocol;
 static jmp_buf restart;
@@ -91,14 +97,13 @@ static int tagnum;
 #define GENSYM (sprintf(tag, "A%04d", ++tagnum % TAGMOD), tag)
 
 static char shroud[PASSWORDLEN];       /* string to shroud in debug output */
-static int mytimeout;                  /* value of nonreponse timeout */
 static int timeoutcount;               /* count consecutive timeouts */
 static int msglen;                     /* actual message length */
 
 void set_timeout(int timeleft)
 /* reset the nonresponse-timeout */
 {
-#ifndef __EMX__
+#if !defined(__EMX__) && !defined(__BEOS__) 
     struct itimerval ntimeout;
 
     if (timeleft == 0)
@@ -430,7 +435,7 @@ static int readheaders(int sock,
     int                        from_offs, reply_to_offs, resent_from_offs;
     int                        app_from_offs, sender_offs, resent_sender_offs;
     int                        env_offs;
-    char               *received_for, *rcv, *cp;
+    char               *received_for, *rcv, *cp, *delivered_to;
     int                n, linelen, oldlen, ch, remaining, skipcount;
     struct idlist      *idp;
     flag               no_local_matches = FALSE;
@@ -444,7 +449,17 @@ static int readheaders(int sock,
 
     /* read message headers */
     msgblk.reallen = reallen;
-    msgblk.headers = received_for = NULL;
+
+    /*
+     * We used to free the header block unconditionally at the end of 
+     * readheaders, but it turns out that if close_sink() hits an error
+     * condition the code for sending bouncemail will actually look
+     * at the freed storage and coredump...
+     */
+    if (msgblk.headers)
+       free(msgblk.headers);
+
+    msgblk.headers = received_for = delivered_to = NULL;
     from_offs = reply_to_offs = resent_from_offs = app_from_offs = 
        sender_offs = resent_sender_offs = env_offs = -1;
     oldlen = 0;
@@ -465,6 +480,7 @@ static int readheaders(int sock,
                set_timeout(0);
                free(line);
                free(msgblk.headers);
+               msgblk.headers = NULL;
                return(PS_SOCKET);
            }
            set_timeout(0);
@@ -516,6 +532,21 @@ static int readheaders(int sock,
                goto process_headers;
            }
 
+           /*
+            * At least one brain-dead website (netmind.com) is known to
+            * send out robotmail that's missing the RFC822 delimiter blank
+            * line before the body! Without this check fetchmail segfaults.
+            * With it, we treat such messages as though they had the missing
+            * blank line.
+            */
+           if (!isspace(line[0]) && !strchr(line, ':'))
+           {
+               headers_ok = TRUE;
+               free(line);
+               has_nuls = (linelen != strlen(line));
+               goto process_headers;
+           }
+
            /* check for RFC822 continuations */
            set_timeout(mytimeout);
            ch = SockPeek(sock);
@@ -529,7 +560,7 @@ static int readheaders(int sock,
            sizeticker += linelen;
            while (sizeticker >= SIZETICKER)
            {
-               if (!run.use_syslog && isatty(1))
+               if ((!run.use_syslog && !isafile(1)) || run.showdots)
                {
                    fputc('.', stdout);
                    fflush(stdout);
@@ -546,20 +577,32 @@ static int readheaders(int sock,
         * addressed to multiple people on the client machine, there
         * will be one copy left in the box for each recipient.  Thus,
         * if the mail is addressed to N people, each recipient will
-        * get N copies.
+        * get N copies.  This is bad when N > 1.
         *
         * Foil this by suppressing all but one copy of a message with
-        * a given Message-ID.  Note: This implementation only catches
-        * runs of successive identical messages, but that should be
-        * good enough. 
+        * a given Message-ID.  The accept_count test ensures that
+        * multiple pieces of email with the same Message-ID, each
+        * with a *single* addressee (the N == 1 case), won't be 
+        * suppressed.
+        *
+        * Note: This implementation only catches runs of successive
+        * messages with the same ID, but that should be good
+        * enough. A more general implementation would have to store
+        * ever-growing lists of seen message-IDs; in a long-running
+        * daemon this would turn into a memory leak even if the 
+        * implementation were perfect.
         * 
-        * The accept_count test ensures that multiple pieces of identical 
-        * email, each with a *single* addressee, won't be suppressed.
+        * Don't mess with this code casually.  It would be way too easy
+        * to break it in a way that blackholed mail.  Better to pass
+        * the occasional duplicate than to do that...
         */
-       if (MULTIDROP(ctl) && accept_count > 1 && !strncasecmp(line, "Message-ID:", 11))
+       if (MULTIDROP(ctl) && !strncasecmp(line, "Message-ID:", 11))
        {
            if (ctl->lastid && !strcasecmp(ctl->lastid, line))
-               return(PS_REFUSED);
+           {
+               if (accept_count > 1)
+                   return(PS_REFUSED);
+           }
            else
            {
                if (ctl->lastid)
@@ -591,6 +634,7 @@ static int readheaders(int sock,
            if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
                free(line);
                free(msgblk.headers);
+               msgblk.headers = NULL;
                return(PS_RETAINED);
            }
 
@@ -621,6 +665,21 @@ static int readheaders(int sock,
            continue;
        }
 
+       /*
+        * We remove all Delivered-To: headers.
+        * 
+        * This is to avoid false mail loops messages when delivering
+        * local messages to and from a Postfix/qmail mailserver. 
+        */
+       if (ctl->dropdelivered && !strncasecmp(line, "Delivered-To:", 13)) 
+       {
+           if (delivered_to)
+               free(line);
+           else 
+               delivered_to = line;
+           continue;
+       }
+
        /*
         * If we see a Status line, it may have been inserted by an MUA
         * on the mail host, or it may have been inserted by the server
@@ -698,14 +757,16 @@ static int readheaders(int sock,
        }
        else
        {
+           char *newhdrs;
            int newlen;
 
            newlen = oldlen + strlen(line);
-           msgblk.headers = (char *) realloc(msgblk.headers, newlen + 1);
-           if (msgblk.headers == NULL) {
+           newhdrs = (char *) realloc(msgblk.headers, newlen + 1);
+           if (newhdrs == NULL) {
                free(line);
                return(PS_IOERR);
            }
+           msgblk.headers = newhdrs;
            strcpy(msgblk.headers + oldlen, line);
            free(line);
            line = msgblk.headers + oldlen;
@@ -726,14 +787,14 @@ static int readheaders(int sock,
            resent_sender_offs = (line - msgblk.headers);
 
 #ifdef __UNUSED__
-       else if (!strncasecmp("Message-Id:", buf, 11))
+       else if (!strncasecmp("Message-Id:", line, 11))
        {
            if (ctl->server.uidl)
            {
                char id[IDLEN+1];
 
-               buf[IDLEN+12] = 0;              /* prevent stack overflow */
-               sscanf(buf+12, "%s", id);
+               line[IDLEN+12] = 0;             /* prevent stack overflow */
+               sscanf(line+12, "%s", id);
                if (!str_find( &ctl->newsaved, num))
                {
                    struct idlist *new = save_str(&ctl->newsaved,id,UID_SEEN);
@@ -885,6 +946,12 @@ static int readheaders(int sock,
 #endif /* SDPS_ENABLE */ 
        if (env_offs > -1)          /* We have the actual envelope addressee */
            find_server_names(msgblk.headers + env_offs, ctl, &msgblk.recipients);
+       else if (delivered_to && ctl->server.envelope != STRING_DISABLED &&
+      ctl->server.envelope && !strcasecmp(ctl->server.envelope, "Delivered-To"))
+   {
+           find_server_names(delivered_to, ctl, &msgblk.recipients);
+       free(delivered_to);
+   }
        else if (received_for)
            /*
             * We have the Received for addressee.  
@@ -946,6 +1013,7 @@ static int readheaders(int sock,
            report(stdout,
                   _("forwarding and deletion suppressed due to DNS errors\n"));
        free(msgblk.headers);
+       msgblk.headers = NULL;
        free_str_list(&msgblk.recipients);
        return(PS_TRANSIENT);
     }
@@ -956,6 +1024,7 @@ static int readheaders(int sock,
                           &good_addresses, &bad_addresses)) != PS_SUCCESS)
        {
            free(msgblk.headers);
+           msgblk.headers = NULL;
            free_str_list(&msgblk.recipients);
            return(n);
        }
@@ -983,7 +1052,16 @@ static int readheaders(int sock,
     if (!run.invisible && n != -1)
     {
        /* utter any per-message Received information we need here */
-       sprintf(buf, "Received: from %s\r\n", ctl->server.truename);
+        if (ctl->server.trueaddr) {
+           sprintf(buf, "Received: from %s [%u.%u.%u.%u]\r\n", 
+                   ctl->server.truename,
+                   (unsigned char)ctl->server.trueaddr[0],
+                   (unsigned char)ctl->server.trueaddr[1],
+                   (unsigned char)ctl->server.trueaddr[2],
+                   (unsigned char)ctl->server.trueaddr[3]);
+       } else {
+         sprintf(buf, "Received: from %s\r\n", ctl->server.truename);
+       }
        n = stuffline(ctl, buf);
        if (n != -1)
        {
@@ -1044,10 +1122,11 @@ static int readheaders(int sock,
        report(stdout, _("writing RFC822 msgblk.headers\n"));
        release_sink(ctl);
        free(msgblk.headers);
+       msgblk.headers = NULL;
        free_str_list(&msgblk.recipients);
        return(PS_IOERR);
     }
-    else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE && isatty(2))
+    else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE && !isafile(2))
        fputs("#", stderr);
 
     /* write error notifications */
@@ -1113,7 +1192,7 @@ static int readheaders(int sock,
     *cp++ = '\0';
     stuffline(ctl, buf);
 
-    free(msgblk.headers);
+/*    free(msgblk.headers); */
     free_str_list(&msgblk.recipients);
     return(headers_ok ? PS_SUCCESS : PS_TRUNCATED);
 }
@@ -1157,7 +1236,7 @@ static int readbody(int sock, struct query *ctl, flag forward, int len)
            sizeticker += linelen;
            while (sizeticker >= SIZETICKER)
            {
-               if ((run.poll_interval == 0 || nodetach) && outlevel > O_SILENT && isatty(1))
+               if (outlevel > O_SILENT && (((run.poll_interval == 0 || nodetach) && !isafile(1)) || run.showdots))
                {
                    fputc('.', stdout);
                    fflush(stdout);
@@ -1215,7 +1294,7 @@ static int readbody(int sock, struct query *ctl, flag forward, int len)
                release_sink(ctl);
                return(PS_IOERR);
            }
-           else if (outlevel >= O_VERBOSE && isatty(1))
+           else if (outlevel >= O_VERBOSE && !isafile(1))
            {
                fputc('*', stdout);
                fflush(stdout);
@@ -1228,14 +1307,11 @@ static int readbody(int sock, struct query *ctl, flag forward, int len)
 
 #ifdef KERBEROS_V4
 int
-kerberos_auth (socket, canonical) 
+kerberos_auth (socket, canonical, principal
 /* authenticate to the server host using Kerberos V4 */
 int socket;            /* socket to server host */
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
 char *canonical;       /* server name */
-#else
-const char *canonical; /* server name */
-#endif
+char *principal;
 {
     char * host_primary;
     KTEXT ticket;
@@ -1243,11 +1319,36 @@ const char *canonical;  /* server name */
     CREDENTIALS cred;
     Key_schedule schedule;
     int rem;
+    char * prin_copy = (char *) NULL;
+    char * prin = (char *) NULL;
+    char * inst = (char *) NULL;
+    char * realm = (char *) NULL;
+
+    if (principal != (char *)NULL && *principal)
+    {
+        char *cp;
+        prin = prin_copy = xstrdup(principal);
+       for (cp = prin_copy; *cp && *cp != '.'; ++cp)
+           ;
+       if (*cp)
+       {
+           *cp++ = '\0';
+           inst = cp;
+           while (*cp && *cp != '@')
+               ++cp;
+           if (*cp)
+           {
+               *cp++ = '\0';
+               realm = cp;
+           }
+       }
+    }
   
     xalloca(ticket, KTEXT, sizeof (KTEXT_ST));
-    rem = (krb_sendauth (0L, socket, ticket, "pop",
-                        canonical,
-                        ((char *) (krb_realmofhost (canonical))),
+    rem = (krb_sendauth (0L, socket, ticket,
+                        prin ? prin : "pop",
+                        inst ? inst : canonical,
+                        realm ? realm : ((char *) (krb_realmofhost (canonical))),
                         ((unsigned long) 0),
                         (&msg_data),
                         (&cred),
@@ -1255,6 +1356,10 @@ const char *canonical;   /* server name */
                         ((struct sockaddr_in *) 0),
                         ((struct sockaddr_in *) 0),
                         "KPOPV0.1"));
+    if (prin_copy)
+    {
+        free(prin_copy);
+    }
     if (rem != KSUCCESS)
     {
        report(stderr, _("kerberos error %s\n"), (krb_get_err_text (rem)));
@@ -1382,7 +1487,6 @@ static void send_size_warnings(struct query *ctl)
     int msg_to_send = FALSE;
     struct idlist *head=NULL, *current=NULL;
     int max_warning_poll_count;
-#define OVERHD "Subject: Fetchmail oversized-messages warning.\r\n\r\nThe following oversized messages remain on the mail server %s:"
 
     head = ctl->skipped;
     if (!head)
@@ -1402,7 +1506,11 @@ static void send_size_warnings(struct query *ctl)
      */
     if (open_warning_by_mail(ctl, (struct msgblk *)NULL))
        return;
-    stuff_warning(ctl, OVERHD, ctl->server.pollname);
+    stuff_warning(ctl,
+          _("Subject: Fetchmail oversized-messages warning.\r\n"
+            "\r\n"
+            "The following oversized messages remain on the mail server %s:"),
+                 ctl->server.pollname);
  
     if (run.poll_interval == 0)
        max_warning_poll_count = 0;
@@ -1428,7 +1536,6 @@ static void send_size_warnings(struct query *ctl)
     }
 
     close_warning_by_mail(ctl, (struct msgblk *)NULL);
-#undef OVERHD
 }
 
 static int do_session(ctl, proto, maxfetch)
@@ -1483,6 +1590,7 @@ const int maxfetch;               /* maximum number of messages to fetch */
 
        if (js == THROW_SIGPIPE)
        {
+           signal(SIGPIPE, SIG_IGN);
            report(stdout,
                   _("SIGPIPE thrown from an MDA or a stream socket error\n"));
            ok = PS_SOCKET;
@@ -1513,6 +1621,8 @@ const int maxfetch;               /* maximum number of messages to fetch */
            /*
             * If we've exceeded our threshold for consecutive timeouts, 
             * try to notify the user, then mark the connection wedged.
+            * Don't do this if the connection can idle, though; idle
+            * timeouts just mean the frequency of mail is low.
             */
            if (timeoutcount > MAX_TIMEOUTS 
                && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
@@ -1582,7 +1692,7 @@ const int maxfetch;               /* maximum number of messages to fetch */
            (void)sleep(1);
 #if INET6_ENABLE
        if ((mailserver_socket = SockOpen(realhost, 
-                            ctl->server.service ? ctl->server.service : protocol->service,
+                            ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? protocol->sslservice : protocol->service ),
                             ctl->server.netsec, ctl->server.plugin)) == -1)
 #else /* INET6_ENABLE */
        if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
@@ -1610,8 +1720,10 @@ const int maxfetch;              /* maximum number of messages to fetch */
                {
                    if (h_errno == HOST_NOT_FOUND)
                        strcpy(errbuf, _("host is unknown."));
+#ifndef __BEOS__
                    else if (h_errno == NO_ADDRESS)
                        strcpy(errbuf, _("name is valid but has no IP address."));
+#endif
                    else if (h_errno == NO_RECOVERY)
                        strcpy(errbuf, _("unrecoverable name server error."));
                    else if (h_errno == TRY_AGAIN)
@@ -1634,11 +1746,13 @@ const int maxfetch;             /* maximum number of messages to fetch */
                /* warn the system administrator */
                if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
                {
-#define OPENFAIL       "Subject: Fetchmail unreachable-server warning.\r\n\r\nFetchmail could not reach the mail server %s:"
-                   stuff_warning(ctl, OPENFAIL, ctl->server.pollname);
+                   stuff_warning(ctl,
+                        _("Subject: Fetchmail unreachable-server warning.\r\n"
+                          "\r\n"
+                          "Fetchmail could not reach the mail server %s:")
+                                 ctl->server.pollname);
                    stuff_warning(ctl, errbuf, ctl->server.pollname);
                    close_warning_by_mail(ctl, (struct msgblk *)NULL);
-#undef OPENFAIL
                }
 #endif
            }
@@ -1657,7 +1771,7 @@ const int maxfetch;               /* maximum number of messages to fetch */
                verification.  We may want to make this configurable */
        if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslkey,ctl->sslcert,realhost) == -1) 
        {
-           report(stderr, "SSL connection failed.");
+           report(stderr, _("SSL connection failed.\n"));
            goto closeUp;
        }
 #endif
@@ -1666,7 +1780,8 @@ const int maxfetch;               /* maximum number of messages to fetch */
        if (ctl->server.preauthenticate == A_KERBEROS_V4)
        {
            set_timeout(mytimeout);
-           ok = kerberos_auth(mailserver_socket, ctl->server.truename);
+           ok = kerberos_auth(mailserver_socket, ctl->server.truename,
+                              ctl->server.principal);
            set_timeout(0);
            if (ok != 0)
                goto cleanUp;
@@ -1716,9 +1831,12 @@ const int maxfetch;              /* maximum number of messages to fetch */
                     * calling user a heads-up about the authentication 
                     * failure once it looks like this isn't a fluke 
                     * due to the server being temporarily inaccessible.
+                    * When we get third failure, we notify the user.  After
+                    * that, once we get authorization we let the user know
+                    * service is restored.
                     */
                    if (run.poll_interval
-                       && ctl->authfailcount++ > MAX_AUTHFAILS 
+                       && ++ctl->authfailcount == 3
                        && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
                    {
                        stuff_warning(ctl,
@@ -1727,13 +1845,16 @@ const int maxfetch;             /* maximum number of messages to fetch */
                            _("Fetchmail could not get mail from %s@%s.\r\n"), 
                            ctl->remotename,
                            ctl->server.truename);
-                       stuff_warning(ctl, 
-    _("The attempt to get authorization failed.\r\n" \
-    "This probably means your password is invalid, but POP3 servers have\r\n" \
-    "other failure modes that fetchmail cannot distinguish from this\r\n" \
-    "because they don't send useful error messages on login failure.\r\n"));
+                       stuff_warning(ctl, _("\
+The attempt to get authorization failed.\r\n\
+This probably means your password is invalid, but some servers have\r\n\
+other failure modes that fetchmail cannot distinguish from this\r\n\
+because they don't send useful error messages on login failure.\r\n\
+\r\n\
+The fetchmail daemon will continue running and attempt to connect\r\n\
+at each cycle.  No future notifications will be sent until service\r\n\
+is restored."));
                        close_warning_by_mail(ctl, (struct msgblk *)NULL);
-                       ctl->wedged = TRUE;
                    }
                }
                else
@@ -1743,6 +1864,30 @@ const int maxfetch;              /* maximum number of messages to fetch */
                    
                goto cleanUp;
            }
+           else
+           {
+               if (ctl->authfailcount >= 3)
+               {
+                   report(stderr,
+                          _("Authorization OK on %s@%s\n"),
+                          ctl->remotename,
+                          ctl->server.truename);
+                   if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
+                   {
+                       stuff_warning(ctl,
+                           _("Subject: fetchmail authentication OK\r\n"));
+                       stuff_warning(ctl,
+                           _("Fetchmail was able to log into %s@%s.\r\n"), 
+                           ctl->remotename,
+                           ctl->server.truename);
+                       stuff_warning(ctl, 
+                           _("Service has been restored.\r\n"));
+                       close_warning_by_mail(ctl, (struct msgblk *)NULL);
+                   
+                   }
+                   ctl->authfailcount = 0;
+               }
+           }
        }
 
        ctl->errcount = fetches = 0;
@@ -1755,6 +1900,9 @@ const int maxfetch;               /* maximum number of messages to fetch */
                dispatches = 0;
                ++pass;
 
+               /* reset timeout, in case we did an IDLE */
+               mytimeout = ctl->server.timeout;
+
                if (outlevel >= O_DEBUG)
                {
                    if (idp->id)
@@ -1813,7 +1961,12 @@ const int maxfetch;              /* maximum number of messages to fetch */
                    if (new == -1 || ctl->fetchall)
                        new = count;
                    fetches = new;      /* set error status ccorrectly */
-                   goto no_error;
+                   /*
+                    * There used to be a `got noerror' here, but this
+                    * prevneted checking of multiple folders.  This
+                    * comment is a reminder in case I introduced some
+                    * subtle bug by removing it...
+                    */
                }
                else if (count > 0)
                {    
@@ -1917,7 +2070,9 @@ const int maxfetch;               /* maximum number of messages to fetch */
                        {
                            if (outlevel > O_SILENT)
                            {
-                               report_build(stdout, _("skipping message %d"), num);
+                               report_build(stdout, 
+                                    _("skipping message %d (%d octets)"),
+                                    num, msgsizes[num-1]);
                                if (toolarge && !check_only) 
                                {
                                    char size[32];
@@ -2024,7 +2179,7 @@ const int maxfetch;               /* maximum number of messages to fetch */
                             */
                            if (protocol->fetch_body && !suppress_readbody) 
                            {
-                               if (outlevel >= O_VERBOSE && isatty(1))
+                               if (outlevel >= O_VERBOSE && !isafile(1))
                                {
                                    fputc('\n', stdout);
                                    fflush(stdout);
@@ -2078,7 +2233,7 @@ const int maxfetch;               /* maximum number of messages to fetch */
                                /* tell server we got it OK and resynchronize */
                                if (protocol->trail)
                                {
-                                   if (outlevel >= O_VERBOSE && isatty(1))
+                                   if (outlevel >= O_VERBOSE && !isafile(1))
                                    {
                                        fputc('\n', stdout);
                                        fflush(stdout);
@@ -2150,7 +2305,8 @@ const int maxfetch;               /* maximum number of messages to fetch */
                            struct idlist       *sdp;
 
                            for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
-                               if (sdp->val.status.num == num)
+                               if ((sdp->val.status.num == num)
+                                               && (!toolarge || oldmsg))
                                    sdp->val.status.mark = UID_SEEN;
                        }
 
@@ -2196,14 +2352,14 @@ const int maxfetch;             /* maximum number of messages to fetch */
                }
            } while
                  /*
-                  * Only re-poll if we had some actual forwards, allowed
-                  * deletions and had no errors.
+                  * Only re-poll if we either had some actual forwards and 
+                  * either allowed deletions and had no errors.
                   * Otherwise it is far too easy to get into infinite loops.
                   */
                  (dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
        }
 
-   no_error:
+    /* no_error: */
        /* ordinary termination with no errors -- officially log out */
        ok = (protocol->logout_cmd)(mailserver_socket, ctl);
        /*
@@ -2231,9 +2387,6 @@ const int maxfetch;               /* maximum number of messages to fetch */
     case PS_SOCKET:
        msg = _("socket");
        break;
-    case PS_AUTHFAIL:
-       msg = _("authorization");
-       break;
     case PS_SYNTAX:
        msg = _("missing or bad RFC822 header");
        break;
@@ -2259,8 +2412,8 @@ const int maxfetch;               /* maximum number of messages to fetch */
        report(stderr, _("undefined error\n"));
        break;
     }
-    /* no report on PS_MAXFETCH or PS_UNDEFINED */
-    if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX 
+    /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
+    if (ok==PS_SOCKET || ok==PS_SYNTAX
                || ok==PS_IOERR || ok==PS_ERROR || ok==PS_PROTOCOL 
                || ok==PS_LOCKBUSY || ok==PS_SMTP || ok==PS_DNS)
        report(stderr, _("%s error while fetching from %s\n"), msg, ctl->server.pollname);
@@ -2385,7 +2538,7 @@ va_dcl
     char buf [MSGBUFSIZE+1];
     va_list ap;
 
-    if (protocol->tagged)
+    if (protocol->tagged && !suppress_tags)
        (void) sprintf(buf, "%s ", GENSYM);
     else
        buf[0] = '\0';
@@ -2471,7 +2624,7 @@ va_dcl
 
     phase = SERVER_WAIT;
 
-    if (protocol->tagged)
+    if (protocol->tagged && !suppress_tags)
        (void) sprintf(buf, "%s ", GENSYM);
     else
        buf[0] = '\0';