]> Pileus Git - ~andy/fetchmail/blobdiff - driver.c
STEP 9: Eliminate the static buffer in the socket library.
[~andy/fetchmail] / driver.c
index f4f3b1103d6996daa1ba8c652d1ad6e8ece95ae7..dee11f45b0b673e019b2286e4578ac5f779ef941 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -50,6 +50,7 @@ static int tagnum;
 #define GENSYM (sprintf(tag, "a%04d", ++tagnum), tag)
 
 static char *shroud;   /* string to shroud in debug output, if  non-NULL */
+static int mytimeout;  /* value of nonreponse timeout */
 
 static int strcrlf(dst, src, count)
 /* replace LFs with CR-LF; return length of string with replacements */
@@ -72,8 +73,20 @@ int count;   /* length of src */
   return len;
 }
 
-static void alarm_handler (int signal)
-/* handle server-timeout signal */
+static void vtalarm(timeleft)
+/* reset the nonresponse-timeout */
+int    timeleft;
+{
+    struct itimerval ntimeout;
+
+    ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_sec = 0;
+    ntimeout.it_value.tv_sec  = timeleft;
+    ntimeout.it_value.tv_usec = 0;
+    setitimer(ITIMER_VIRTUAL, &ntimeout, (struct itimerval *)NULL);
+}
+
+static void vtalarm_handler (int signal)
+/* handle server-timeout SIGVTALARM signal */
 {
     longjmp(restart, 1);
 }
@@ -117,8 +130,6 @@ const char *host;   /* server hostname */
                state = 5;
            else if (isspace(*from))
                state = 2;
-           else if (*from == ',')
-               tokencount = 0;
            break;
 
        case 2:     /* found a token boundary -- reset without copying */
@@ -185,11 +196,12 @@ const char *host; /* server hostname */
                strcpy(buf, "@");
                strcat(buf, host);
                buf += strlen(buf);
+               tokencount = 0;
                state = 1;
            }
 
            /* a single local name alone on the line */
-           else if (*from == '\n' && tokencount == 0)
+           else if (*from == '\n' && tokencount == 1)
            {
                strcpy(buf, "@");
                strcat(buf, host);
@@ -422,17 +434,21 @@ struct idlist **xmit_names;       /* list of recipient names parsed out */
 
        if ((cp = nxtaddr(hdr)) != (char *)NULL)
            do {
-               char    *atsign = strchr(cp, '@');
+               char    *atsign;
 
-               if (atsign)
-                   if (ctl->norewrite)
+               if ((atsign = strchr(cp, '@')))
+               {
+                   /*
+                    * Address has an @. Check to see if the right-hand part
+                    * is an alias or MX equivalent of the mailserver.  If it's
+                    * not, skip this name.  If it is, we'll keep going and try
+                    * to find a mapping to a client name.
+                    */
+                   if (!is_host_alias(atsign+1, ctl))
                        continue;
-                   else
-                   {
-                       if (!is_host_alias(atsign+1, ctl))
-                           continue;
-                       atsign[0] = '\0';
-                   }
+                   atsign[0] = '\0';
+               }
+
                lname = idpair_find(&ctl->localnames, cp);
                if (lname != (char *)NULL)
                {
@@ -448,31 +464,31 @@ struct idlist **xmit_names;       /* list of recipient names parsed out */
 }
 #endif /* HAVE_GETHOSTBYNAME */
 
-static int smtp_open(ctl)
+static FILE *smtp_open(ctl)
 /* try to open a socket to the appropriate SMTP server for this query */ 
 struct query *ctl;
 {
     ctl = ctl->leader; /* go to the SMTP leader for this query */
 
     /* if no socket to this host is already set up, try to open one */
-    if (ctl->smtp_socket == -1)
+    if (ctl->smtp_sockfp == (FILE *)NULL)
     {
-       if ((ctl->smtp_socket = Socket(ctl->smtphost, SMTP_PORT)) == -1)
-           return(-1);
-       else if (SMTP_ok(ctl->smtp_socket, NULL) != SM_OK
-                || SMTP_helo(ctl->smtp_socket, ctl->servername) != SM_OK)
+       if ((ctl->smtp_sockfp = Socket(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL)
+           return((FILE *)NULL);
+       else if (SMTP_ok(ctl->smtp_sockfp, NULL) != SM_OK
+                || SMTP_helo(ctl->smtp_sockfp, ctl->servername) != SM_OK)
        {
-           close(ctl->smtp_socket);
-           ctl->smtp_socket = -1;
+           fclose(ctl->smtp_sockfp);
+           ctl->smtp_sockfp = (FILE *)NULL;
        }
     }
 
-    return(ctl->smtp_socket);
+    return(ctl->smtp_sockfp);
 }
 
-static int gen_readmsg (socket, len, delimited, ctl)
+static int gen_readmsg (sockfp, len, delimited, ctl)
 /* read message content and ship to SMTP or MDA */
-int socket;    /* to which the server is connected */
+FILE *sockfp;  /* to which the server is connected */
 long len;      /* length of message */
 int delimited; /* does the protocol use a message delimiter? */
 struct query *ctl;     /* query control record */
@@ -481,6 +497,7 @@ struct query *ctl;  /* query control record */
     char *bufp, *headers, *fromhdr, *tohdr, *cchdr, *bcchdr;
     int n, oldlen, mboxfd;
     int inheaders,lines,sizeticker;
+    FILE *sinkfp;
 
     /* read the message content from the server */
     inheaders = 1;
@@ -490,8 +507,9 @@ struct query *ctl;  /* query control record */
     oldlen = 0;
     while (delimited || len > 0)
     {
-       if ((n = SockGets(socket,buf,sizeof(buf))) < 0)
+       if ((n = SockGets(buf,sizeof(buf),sockfp)) < 0)
            return(PS_SOCKET);
+       vtalarm(ctl->timeout);
 
        /* write the message size dots */
        if (n > 0)
@@ -607,7 +625,7 @@ struct query *ctl;  /* query control record */
                 */
                for (idp = xmit_names; idp; idp = idp->next)
                    nlocals++;
-               sp = sargv = (char **)alloca(ctl->mda_argcount+nlocals+2);
+               sp = sargv = (char **)alloca(sizeof(char **) * ctl->mda_argcount+nlocals+2);
                for (i = 0; i < ctl->mda_argcount; i++)
                    *sp++ = ctl->mda_argv[i];
                for (idp = xmit_names; idp; idp = idp->next)
@@ -639,36 +657,37 @@ struct query *ctl;        /* query control record */
            }
            else
            {
-               if (ctl->mda[0] == '\0' && ((mboxfd = smtp_open(ctl)) < 0))
+               if (ctl->mda[0] == '\0' && ((sinkfp = smtp_open(ctl)) < 0))
                {
                    free_uid_list(&xmit_names);
                    fprintf(stderr, "fetchmail: SMTP connect failed\n");
                    return(PS_SMTP);
                }
 
-               if (SMTP_from(mboxfd, nxtaddr(fromhdr)) != SM_OK)
+               if (SMTP_from(sinkfp, nxtaddr(fromhdr)) != SM_OK)
                {
                    fprintf(stderr, "fetchmail: SMTP listener is confused\n");
                    return(PS_SMTP);
                }
 
                for (idp = xmit_names; idp; idp = idp->next)
-                   if (SMTP_rcpt(mboxfd, idp->id) != SM_OK)
+                   if (SMTP_rcpt(sinkfp, idp->id) != SM_OK)
                    {
                        fprintf(stderr, "fetchmail: SMTP listener is upset\n");
                        return(PS_SMTP);
                    }
 
-               SMTP_data(mboxfd);
+               SMTP_data(sinkfp);
                if (outlevel == O_VERBOSE)
                    fputs("SMTP> ", stderr);
            }
            free_uid_list(&xmit_names);
 
            /* change continuation markers back to regular newlines */
-           for (cp = headers; cp < headers +  oldlen; cp++)
+           for (cp = headers; cp < headers + oldlen; cp++)
                if (*cp == '\r')
                    *cp = '\n';
+           headers[oldlen++] = '\0';
 
            /* replace all LFs with CR-LF before sending to the SMTP server */
            if (!ctl->mda[0])
@@ -681,7 +700,14 @@ struct query *ctl; /* query control record */
                free(headers);
                headers = newheaders;
            }
-           if (write(mboxfd,headers,oldlen) < 0)
+
+           /* write all the headers */
+           if (ctl->mda[0])
+               n = write(mboxfd,headers,oldlen);
+           else
+               n = SockWrite(headers, oldlen, sinkfp);
+
+           if (n < 0)
            {
                free(headers);
                headers = NULL;
@@ -696,9 +722,9 @@ struct query *ctl;  /* query control record */
 
        /* SMTP byte-stuffing */
        if (*bufp == '.' && ctl->mda[0] == 0)
-           write(mboxfd, ".", 1);
+           SockWrite(".", 1, sinkfp);
 
-       /* write this line to the file after replacing all LFs with CR-LF */
+       /* replace all LFs with CR-LF  in the line */
        if (!ctl->mda[0])
        {
            char *newbufp = malloc(1 + strlen(bufp) * 2);
@@ -708,7 +734,13 @@ struct query *ctl; /* query control record */
            strcrlf(newbufp, bufp, strlen(bufp));
            bufp = newbufp;
        }
-       n = write(mboxfd,bufp,strlen(bufp));
+
+       /* ship out the text line */
+       if (ctl->mda[0])
+           n = write(mboxfd,bufp,strlen(bufp));
+       else
+           n = SockWrite(bufp, strlen(bufp), sinkfp);
+
        if (!ctl->mda[0])
            free(bufp);
        if (n < 0)
@@ -732,7 +764,7 @@ struct query *ctl;  /* query control record */
     else
     {
        /* write message terminator */
-       if (SMTP_eom(mboxfd) != SM_OK)
+       if (SMTP_eom(sinkfp) != SM_OK)
        {
            fputs("fetchmail: SMTP listener refused delivery\n", stderr);
            return(PS_SMTP);
@@ -823,6 +855,10 @@ const struct method *proto;        /* protocol method table */
     tag[0] = '\0';     /* nuke any tag hanging out from previous query */
     ok = 0;
 
+    /* set up the server-nonresponse timeout */
+    sigsave = signal(SIGVTALRM, vtalarm_handler);
+    vtalarm(mytimeout = ctl->timeout);
+
     if (setjmp(restart) == 1)
        fprintf(stderr,
                "fetchmail: timeout after %d seconds waiting for %s.\n",
@@ -830,14 +866,11 @@ const struct method *proto;       /* protocol method table */
     else
     {
        char buf [POPBUFSIZE+1];
-       int *msgsizes, socket, len, num, count, new, deletions = 0;
-
-       /* set up the server-nonresponse timeout */
-       sigsave = signal(SIGALRM, alarm_handler);
-       alarm(ctl->timeout);
+       int *msgsizes, len, num, count, new, deletions = 0;
+       FILE *sockfp;
 
        /* open a socket to the mail server */
-       if ((socket = Socket(ctl->servername,
+       if ((sockfp = Socket(ctl->servername,
                             ctl->port ? ctl->port : protocol->port))<0)
        {
            perror("fetchmail, connecting to host");
@@ -848,20 +881,23 @@ const struct method *proto;       /* protocol method table */
 #ifdef KERBEROS_V4
        if (ctl->authenticate == A_KERBEROS)
        {
-           ok = (kerberos_auth (socket, ctl->canonical_name));
-           if (ok != 0)
+           ok = (kerberos_auth (fileno(sockfp), ctl->canonical_name));
+           vtalarm(ctl->timeout);
+           if (ok != 0)
                goto cleanUp;
        }
 #endif /* KERBEROS_V4 */
 
        /* accept greeting message from mail server */
-       ok = (protocol->parse_response)(socket, buf);
+       ok = (protocol->parse_response)(sockfp, buf);
+       vtalarm(ctl->timeout);
        if (ok != 0)
            goto cleanUp;
 
        /* try to get authorized to fetch mail */
        shroud = ctl->password;
-       ok = (protocol->getauth)(socket, ctl, buf);
+       ok = (protocol->getauth)(sockfp, ctl, buf);
+       vtalarm(ctl->timeout);
        shroud = (char *)NULL;
        if (ok == PS_ERROR)
            ok = PS_AUTHFAIL;
@@ -869,8 +905,9 @@ const struct method *proto; /* protocol method table */
            goto cleanUp;
 
        /* compute number of messages and number of new messages waiting */
-       if ((protocol->getrange)(socket, ctl, &count, &new) != 0)
+       if ((protocol->getrange)(sockfp, ctl, &count, &new) != 0)
            goto cleanUp;
+       vtalarm(ctl->timeout);
 
        /* show user how many messages we downloaded */
        if (outlevel > O_SILENT)
@@ -895,7 +932,7 @@ const struct method *proto; /* protocol method table */
        {
            msgsizes = (int *)alloca(sizeof(int) * count);
 
-           if ((ok = (proto->getsizes)(socket, count, msgsizes)) != 0)
+           if ((ok = (proto->getsizes)(sockfp, count, msgsizes)) != 0)
                return(PS_ERROR);
        }
 
@@ -913,7 +950,7 @@ const struct method *proto; /* protocol method table */
            {
                int     toolarge = msgsizes && msgsizes[num-1]>ctl->limit;
                int     fetch_it = ctl->fetchall ||
-                   (!(protocol->is_old && (protocol->is_old)(socket,ctl,num)) && !toolarge);
+                   (!(protocol->is_old && (protocol->is_old)(sockfp,ctl,num)) && !toolarge);
 
                /* we may want to reject this message if it's old */
                if (!fetch_it)
@@ -928,7 +965,8 @@ const struct method *proto; /* protocol method table */
                else
                {
                    /* request a message */
-                   (protocol->fetch)(socket, num, &len);
+                   (protocol->fetch)(sockfp, num, &len);
+                   vtalarm(ctl->timeout);
 
                    if (outlevel > O_SILENT)
                    {
@@ -942,16 +980,17 @@ const struct method *proto;       /* protocol method table */
                    }
 
                    /* read the message and ship it to the output sink */
-                   ok = gen_readmsg(socket,
+                   ok = gen_readmsg(sockfp,
                                     len, 
                                     protocol->delimited,
                                     ctl);
+                   vtalarm(ctl->timeout);
                    if (ok != 0)
                        goto cleanUp;
 
                    /* tell the server we got it OK and resynchronize */
                    if (protocol->trail)
-                       (protocol->trail)(socket, ctl, num);
+                       (protocol->trail)(sockfp, ctl, num);
                }
 
                /*
@@ -970,7 +1009,8 @@ const struct method *proto;        /* protocol method table */
                    deletions++;
                    if (outlevel > O_SILENT) 
                        fprintf(stderr, " flushed\n");
-                   ok = (protocol->delete)(socket, ctl, num);
+                   ok = (protocol->delete)(sockfp, ctl, num);
+                   vtalarm(ctl->timeout);
                    if (ok != 0)
                        goto cleanUp;
                }
@@ -985,57 +1025,47 @@ const struct method *proto;      /* protocol method table */
            /* remove all messages flagged for deletion */
            if (protocol->expunge_cmd && deletions > 0)
            {
-               ok = gen_transact(socket, protocol->expunge_cmd);
+               ok = gen_transact(sockfp, protocol->expunge_cmd);
                if (ok != 0)
                    goto cleanUp;
            }
 
-           ok = gen_transact(socket, protocol->exit_cmd);
+           ok = gen_transact(sockfp, protocol->exit_cmd);
            if (ok == 0)
                ok = PS_SUCCESS;
-           close(socket);
+           fclose(sockfp);
            goto closeUp;
        }
        else {
-           ok = gen_transact(socket, protocol->exit_cmd);
+           ok = gen_transact(sockfp, protocol->exit_cmd);
            if (ok == 0)
                ok = PS_NOMAIL;
-           close(socket);
+           fclose(sockfp);
            goto closeUp;
        }
 
     cleanUp:
        if (ok != 0 && ok != PS_SOCKET)
        {
-           gen_transact(socket, protocol->exit_cmd);
-           close(socket);
+           gen_transact(sockfp, protocol->exit_cmd);
+           fclose(sockfp);
        }
     }
 
-    alarm(0);
-    signal(SIGALRM, sigsave);
+    signal(SIGVTALRM, sigsave);
 
 closeUp:
     return(ok);
 }
 
-void smtp_close(mboxfd)
-/* close the current SMTP connection */
-int    mboxfd;
-{
-    if (mboxfd != -1)
-    {
-       close(mboxfd);
-    }
-}
 #if defined(HAVE_STDARG_H)
-void gen_send(int socket, char *fmt, ... )
+void gen_send(FILE *sockfp, char *fmt, ... )
 /* assemble command in printf(3) style and send to the server */
 {
 #else
-void gen_send(socket, fmt, va_alist)
+void gen_send(sockfp, fmt, va_alist)
 /* assemble command in printf(3) style and send to the server */
-int socket;            /* socket to which server is connected */
+FILE *sockfp;          /* socket to which server is connected */
 const char *fmt;       /* printf-style format */
 va_dcl {
 #endif
@@ -1056,7 +1086,8 @@ va_dcl {
     vsprintf(buf + strlen(buf), fmt, ap);
     va_end(ap);
 
-    SockPuts(socket, buf);
+    strcat(buf, "\r\n");
+    SockWrite(buf, strlen(buf), sockfp);
 
     if (outlevel == O_VERBOSE)
     {
@@ -1064,18 +1095,18 @@ va_dcl {
 
        if (shroud && (cp = strstr(buf, shroud)))
            memset(cp, '*', strlen(shroud));
-       fprintf(stderr,"> %s\n", buf);
+       fprintf(stderr,"> %s", buf);
     }
 }
 
 #if defined(HAVE_STDARG_H)
-int gen_transact(int socket, char *fmt, ... )
+int gen_transact(FILE *sockfp, char *fmt, ... )
 /* assemble command in printf(3) style, send to server, accept a response */
 {
 #else
-int gen_transact(socket, fmt, va_alist)
+int gen_transact(sockfp, fmt, va_alist)
 /* assemble command in printf(3) style, send to server, accept a response */
-int socket;            /* socket to which server is connected */
+FILE *sockfp;          /* socket to which server is connected */
 const char *fmt;       /* printf-style format */
 va_dcl {
 #endif
@@ -1097,18 +1128,20 @@ va_dcl {
   vsprintf(buf + strlen(buf), fmt, ap);
   va_end(ap);
 
-  SockPuts(socket, buf);
+  strcat(buf, "\r\n");
+  SockWrite(buf, strlen(buf), sockfp);
   if (outlevel == O_VERBOSE)
   {
       char *cp;
 
       if (shroud && (cp = strstr(buf, shroud)))
          memset(cp, '*', strlen(shroud));
-      fprintf(stderr,"> %s\n", buf);
+      fprintf(stderr,"> %s", buf);
   }
 
   /* we presume this does its own response echoing */
-  ok = (protocol->parse_response)(socket, buf);
+  ok = (protocol->parse_response)(sockfp, buf);
+  vtalarm(mytimeout);
 
   return(ok);
 }