2 * driver.c -- generic driver for mail fetch method protocols
4 * Copyright 1996 by Eric S. Raymond
6 * For license terms, see the file COPYING in this directory.
13 #if defined(STDC_HEADERS)
17 #if defined(HAVE_UNISTD_H)
20 #if defined(HAVE_STDARG_H)
28 #ifdef HAVE_GETHOSTBYNAME
31 #endif /* HAVE_GETHOSTBYNAME */
36 #include <netinet/in.h> /* must be included before "socket.h".*/
38 #endif /* KERBEROS_V4 */
40 #include "fetchmail.h"
43 #define SMTP_PORT 25 /* standard SMTP service port */
45 static const struct method *protocol;
46 static jmp_buf restart;
50 #define GENSYM (sprintf(tag, "a%04d", ++tagnum), tag)
52 static char *shroud; /* string to shroud in debug output, if non-NULL */
54 static int strcrlf(dst, src, count)
55 /* replace LFs with CR-LF; return length of string with replacements */
56 char *dst; /* new string with CR-LFs */
57 char *src; /* original string with LFs */
58 int count; /* length of src */
75 static void alarm_handler (int signal)
76 /* handle server-timeout signal */
81 static void reply_hack(buf, host)
82 /* hack message headers so replies will work properly */
83 char *buf; /* header to be hacked */
84 const char *host; /* server hostname */
87 int parendepth, state = 0, tokencount = 0;
88 char mycopy[POPBUFSIZE+1];
90 if (strncmp("From: ", buf, 6)
91 && strncmp("To: ", buf, 4)
92 && strncmp("Reply-", buf, 6)
93 && strncmp("Cc: ", buf, 4)
94 && strncmp("Bcc: ", buf, 5)) {
99 for (from = mycopy; *from; from++)
103 case 0: /* before header colon */
108 case 1: /* we've seen the colon, we're looking for addresses */
111 else if (*from == '(')
116 else if (*from == '<' || isalnum(*from))
118 else if (isspace(*from))
120 else if (*from == ',')
124 case 2: /* found a token boundary -- reset without copying */
125 if (*from != ' ' && *from != '\t')
133 case 3: /* we're in a quoted human name, copy and ignore */
138 case 4: /* we're in a parenthesized human name, copy and ignore */
141 else if (*from == ')')
147 case 5: /* the real work gets done here */
149 * We're in something that might be an address part,
150 * either a bare unquoted/unparenthesized text or text
151 * enclosed in <> as per RFC822.
153 /* if the address part contains an @, don't mess with it */
157 /* If the address token is not properly terminated, ignore it. */
158 else if (*from == ' ' || *from == '\t')
163 * The only lookahead case. If we're looking at space or tab,
164 * we might be looking at a local name immediately followed
167 for (cp = from; isspace(*cp); cp++)
179 * On proper termination with no @, insert hostname.
180 * Case '>' catches <>-enclosed mail IDs. Case ',' catches
181 * comma-separated bare IDs.
183 else if (strchr(">,", *from))
191 /* a single local name alone on the line */
192 else if (*from == '\n' && tokencount == 0)
200 /* everything else, including alphanumerics, just passes through */
203 case 6: /* we're in a remote mail ID, no need to append hostname */
204 if (*from == '>' || *from == ',' || isspace(*from))
209 /* all characters from the old buffer get copied to the new one */
215 static char *nxtaddr(hdr)
216 /* parse addresses in succession out of a specified RFC822 header */
217 char *hdr; /* header line to be parsed, NUL to continue in previous hdr */
219 static char *hp, *tp, address[POPBUFSIZE+1];
224 * Note 1: RFC822 escaping with \ is *not* handled. Note 2: it is
225 * important that this routine not stop on \r, since we use \r as
226 * a marker for RFC822 continuations below.
239 case 0: /* before header colon */
249 case 1: /* we've seen the colon, now grab the address */
250 if (*hp == '\n') /* end of address list */
256 else if (*hp == ',') /* end of address */
261 else if (*hp == '"') /* quoted string */
266 else if (*hp == '(') /* address comment -- ignore */
271 else if (*hp == '<') /* begin <address> */
276 else if (isspace(*hp)) /* ignore space */
278 else /* just take it */
285 case 2: /* we're in a quoted string, copy verbatim */
297 case 3: /* we're in a parenthesized comment, ignore */
308 case 4: /* possible <>-enclosed address */
309 if (*hp == '>') /* end of address */
315 else if (*hp == '<') /* nested <> */
317 else if (*hp == '"') /* quoted address */
322 else /* just copy address */
326 case 5: /* we're in a quoted address, copy verbatim */
327 if (*hp == '\n') /* mismatched quotes */
329 if (*hp != '"') /* just copy it if it isn't a quote */
331 else if (*hp == '"') /* end of quoted string */
347 #ifdef HAVE_GETHOSTBYNAME
350 static int is_host_alias(name, ctl)
351 /* determine whether name is a DNS alias of the hostname */
359 * The first two checks are optimizations that will catch a good
360 * many cases. First, check against the hostname the user specified.
361 * Odds are good this will either be the mailserver's FQDN or a
362 * suffix of it with the mailserver's domain's default host name
363 * omitted. Next, check against the mailserver's FQDN, in case
364 * it's not the same as the declared hostname.
366 * Either of these on a mail address is definitive. Only if the
367 * name doesn't match either is it time to call the bind library.
368 * If this happens odds are good we're looking at an MX name.
370 if (strcmp(name, ctl->servername) == 0)
372 else if (strcmp(name, ctl->canonical_name) == 0)
376 * We treat DNS lookup failure as a negative on the theory that
377 * the mailserver's DNS server is `nearby' and should be able
378 * to respond quickly and reliably. Ergo if we get failure,
379 * the name isn't a mailserver alias.
381 else if ((he = gethostbyname(name)) && strcmp(ctl->canonical_name, he->h_name) == 0)
385 * Search for a name match on MX records pointing to the server
386 * site. These may live far away, so allow a couple of retries.
388 for (i = 0; i < MX_RETRIES; i++)
390 struct mxentry *mxrecords, *mxp;
392 mxrecords = getmxrecords(name);
394 if (mxrecords == (struct mxentry *)NULL)
395 if (h_errno == TRY_AGAIN)
403 for (mxp = mxrecords; mxp->name; mxp++)
404 if (strcmp(name, mxp->name) == 0)
411 void find_server_names(hdr, ctl, xmit_names)
412 /* parse names out of a RFC822 header into an ID list */
413 const char *hdr; /* RFC822 header in question */
414 struct query *ctl; /* list of permissible aliases */
415 struct idlist **xmit_names; /* list of recipient names parsed out */
417 if (hdr == (char *)NULL)
423 if ((cp = nxtaddr(hdr)) != (char *)NULL)
425 char *atsign = strchr(cp, '@');
432 if (!is_host_alias(atsign+1, ctl))
436 lname = idpair_find(&ctl->localnames, cp);
437 if (lname != (char *)NULL)
439 if (outlevel == O_VERBOSE)
441 "fetchmail: mapped %s to local %s\n",
443 save_uid(xmit_names, -1, lname);
446 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
449 #endif /* HAVE_GETHOSTBYNAME */
451 static int smtp_open(ctl)
452 /* try to open a socket to the appropriate SMTP server for this query */
455 ctl = ctl->leader; /* go to the SMTP leader for this query */
457 /* if no socket to this host is already set up, try to open one */
458 if (ctl->smtp_socket == -1)
460 if ((ctl->smtp_socket = Socket(ctl->smtphost, SMTP_PORT)) == -1)
462 else if (SMTP_ok(ctl->smtp_socket, NULL) != SM_OK
463 || SMTP_helo(ctl->smtp_socket, ctl->servername) != SM_OK)
465 close(ctl->smtp_socket);
466 ctl->smtp_socket = -1;
470 return(ctl->smtp_socket);
473 static int gen_readmsg (socket, len, delimited, ctl)
474 /* read message content and ship to SMTP or MDA */
475 int socket; /* to which the server is connected */
476 long len; /* length of message */
477 int delimited; /* does the protocol use a message delimiter? */
478 struct query *ctl; /* query control record */
480 char buf [MSGBUFSIZE+1];
481 char *bufp, *headers, *fromhdr, *tohdr, *cchdr, *bcchdr;
482 int n, oldlen, mboxfd;
483 int inheaders,lines,sizeticker;
485 /* read the message content from the server */
487 headers = fromhdr = tohdr = cchdr = bcchdr = NULL;
491 while (delimited || len > 0)
493 if ((n = SockGets(socket,buf,sizeof(buf))) < 0)
496 /* write the message size dots */
500 while (sizeticker >= SIZETICKER)
502 if (outlevel > O_SILENT)
504 sizeticker -= SIZETICKER;
509 if (buf[0] == '\0' || buf[0] == '\r' || buf[0] == '\n')
511 if (delimited && *bufp == '.') {
514 break; /* end of message */
521 reply_hack(bufp, ctl->servername);
525 oldlen = strlen(bufp);
526 headers = malloc(oldlen + 1);
529 (void) strcpy(headers, bufp);
537 * We deal with RFC822 continuation lines here.
538 * Replace previous '\n' with '\r' so nxtaddr
539 * and reply_hack will be able to see past it.
540 * (We know this is safe because SocketGets stripped
541 * out all carriage returns in the read loop above
542 * and we haven't reintroduced any since then.)
543 * We'll undo this before writing the header.
545 if (isspace(bufp[0]))
546 headers[oldlen-1] = '\r';
548 newlen = oldlen + strlen(bufp);
549 headers = realloc(headers, newlen + 1);
552 strcpy(headers + oldlen, bufp);
553 bufp = headers + oldlen;
557 if (!strncasecmp("From:", bufp, 5))
559 else if (!strncasecmp("To:", bufp, 3))
561 else if (!strncasecmp("Cc:", bufp, 3))
563 else if (!strncasecmp("Bcc:", bufp, 4))
568 else if (headers) /* OK, we're at end of headers now */
571 struct idlist *idp, *xmit_names;
573 /* cons up a list of local recipients */
574 xmit_names = (struct idlist *)NULL;
575 #ifdef HAVE_GETHOSTBYNAME
576 /* is this a multidrop box? */
579 /* compute the local address list */
580 find_server_names(tohdr, ctl, &xmit_names);
581 find_server_names(cchdr, ctl, &xmit_names);
582 find_server_names(bcchdr, ctl, &xmit_names);
584 else /* it's a single-drop box, use first localname */
585 #endif /* HAVE_GETHOSTBYNAME */
588 save_uid(&xmit_names, -1, ctl->localnames->id);
591 /* if nothing supplied localnames, default appropriately */
594 save_uid(&xmit_names, -1, ctl->remotename);
596 save_uid(&xmit_names, -1, user);
598 /* time to address the message */
599 if (ctl->mda[0]) /* we have a declared MDA */
605 * We go through this in order to be able to handle very
606 * long lists of users.
608 for (idp = xmit_names; idp; idp = idp->next)
610 sp = sargv = (char **)alloca(ctl->mda_argcount+nlocals+2);
611 for (i = 0; i < ctl->mda_argcount; i++)
612 *sp++ = ctl->mda_argv[i];
613 for (idp = xmit_names; idp; idp = idp->next)
619 * Arrange to run with user's permissions if we're root.
620 * This will initialize the ownership of any files the
621 * MDA creates properly. (The seteuid call is available
622 * under all BSDs and Linux)
625 #endif /* HAVE_SETEUID */
627 mboxfd = openmailpipe(sargv);
630 /* this will fail quietly if we didn't start as root */
632 #endif /* HAVE_SETEUID */
636 fprintf(stderr, "fetchmail: MDA open failed\n");
642 if (ctl->mda[0] == '\0' && ((mboxfd = smtp_open(ctl)) < 0))
644 free_uid_list(&xmit_names);
645 fprintf(stderr, "fetchmail: SMTP connect failed\n");
649 if (SMTP_from(mboxfd, nxtaddr(fromhdr)) != SM_OK)
651 fprintf(stderr, "fetchmail: SMTP listener is confused\n");
655 for (idp = xmit_names; idp; idp = idp->next)
656 if (SMTP_rcpt(mboxfd, idp->id) != SM_OK)
658 fprintf(stderr, "fetchmail: SMTP listener is upset\n");
663 if (outlevel == O_VERBOSE)
664 fputs("SMTP> ", stderr);
666 free_uid_list(&xmit_names);
668 /* change continuation markers back to regular newlines */
669 for (cp = headers; cp < headers + oldlen; cp++)
673 /* replace all LFs with CR-LF before sending to the SMTP server */
676 char *newheaders = malloc(1 + oldlen * 2);
678 if (newheaders == NULL)
680 oldlen = strcrlf(newheaders, headers, oldlen);
682 headers = newheaders;
684 if (write(mboxfd,headers,oldlen) < 0)
688 perror("fetchmail: writing RFC822 headers");
691 else if (outlevel == O_VERBOSE)
697 /* SMTP byte-stuffing */
698 if (*bufp == '.' && ctl->mda[0] == 0)
699 write(mboxfd, ".", 1);
701 /* write this line to the file after replacing all LFs with CR-LF */
704 char *newbufp = malloc(1 + strlen(bufp) * 2);
708 strcrlf(newbufp, bufp, strlen(bufp));
711 n = write(mboxfd,bufp,strlen(bufp));
716 perror("fetchmail: writing message text");
719 else if (outlevel == O_VERBOSE)
728 /* close the delivery pipe, we'll reopen before next message */
729 if (closemailpipe(mboxfd))
734 /* write message terminator */
735 if (SMTP_eom(mboxfd) != SM_OK)
737 fputs("fetchmail: SMTP listener refused delivery\n", stderr);
747 kerberos_auth (socket, canonical)
748 /* authenticate to the server host using Kerberos V4 */
749 int socket; /* socket to server host */
750 char *canonical; /* server name */
756 Key_schedule schedule;
759 ticket = ((KTEXT) (malloc (sizeof (KTEXT_ST))));
760 rem = (krb_sendauth (0L, socket, ticket, "pop",
762 ((char *) (krb_realmofhost (canonical))),
767 ((struct sockaddr_in *) 0),
768 ((struct sockaddr_in *) 0),
773 fprintf (stderr, "fetchmail: kerberos error %s\n", (krb_get_err_text (rem)));
778 #endif /* KERBEROS_V4 */
780 int do_protocol(ctl, proto)
781 /* retrieve messages from server using given protocol method table */
782 struct query *ctl; /* parsed options with merged-in defaults */
783 const struct method *proto; /* protocol method table */
789 if (ctl->authenticate == A_KERBEROS)
791 fputs("fetchmail: Kerberos support not linked.\n", stderr);
794 #endif /* KERBEROS_V4 */
796 /* lacking methods, there are some options that may fail */
799 /* check for unsupported options */
802 "Option --flush is not supported with %s\n",
806 else if (ctl->fetchall) {
808 "Option --all is not supported with %s\n",
813 if (!proto->getsizes && ctl->limit)
816 "Option --limit is not supported with %s\n",
823 tag[0] = '\0'; /* nuke any tag hanging out from previous query */
826 if (setjmp(restart) == 1)
828 "fetchmail: timeout after %d seconds waiting for %s.\n",
829 ctl->timeout, ctl->servername);
832 char buf [POPBUFSIZE+1];
833 int *msgsizes, socket, len, num, count, new, deletions = 0;
835 /* set up the server-nonresponse timeout */
836 sigsave = signal(SIGALRM, alarm_handler);
839 /* open a socket to the mail server */
840 if ((socket = Socket(ctl->servername,
841 ctl->port ? ctl->port : protocol->port))<0)
843 perror("fetchmail, connecting to host");
849 if (ctl->authenticate == A_KERBEROS)
851 ok = (kerberos_auth (socket, ctl->canonical_name));
855 #endif /* KERBEROS_V4 */
857 /* accept greeting message from mail server */
858 ok = (protocol->parse_response)(socket, buf);
862 /* try to get authorized to fetch mail */
863 shroud = ctl->password;
864 ok = (protocol->getauth)(socket, ctl, buf);
865 shroud = (char *)NULL;
871 /* compute number of messages and number of new messages waiting */
872 if ((protocol->getrange)(socket, ctl, &count, &new) != 0)
875 /* show user how many messages we downloaded */
876 if (outlevel > O_SILENT)
878 fprintf(stderr, "No mail from %s@%s\n",
883 fprintf(stderr, "%d message%s", count, count > 1 ? "s" : "");
884 if (new != -1 && (count - new) > 0)
885 fprintf(stderr, " (%d seen)", count-new);
892 /* we may need to get sizes in order to check message limits */
893 msgsizes = (int *)NULL;
894 if (!ctl->fetchall && proto->getsizes && ctl->limit)
896 msgsizes = (int *)alloca(sizeof(int) * count);
898 if ((ok = (proto->getsizes)(socket, count, msgsizes)) != 0)
904 if (new == -1 || ctl->fetchall)
906 ok = ((new > 0) ? PS_SUCCESS : PS_NOMAIL);
911 /* read, forward, and delete messages */
912 for (num = 1; num <= count; num++)
914 int toolarge = msgsizes && msgsizes[num-1]>ctl->limit;
915 int fetch_it = ctl->fetchall ||
916 (!(protocol->is_old && (protocol->is_old)(socket,ctl,num)) && !toolarge);
918 /* we may want to reject this message if it's old */
921 if (outlevel > O_SILENT)
923 fprintf(stderr, "skipping message %d", num);
925 fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
930 /* request a message */
931 (protocol->fetch)(socket, num, &len);
933 if (outlevel > O_SILENT)
935 fprintf(stderr, "reading message %d", num);
937 fprintf(stderr, " (%d bytes)", len);
938 if (outlevel == O_VERBOSE)
944 /* read the message and ship it to the output sink */
945 ok = gen_readmsg(socket,
952 /* tell the server we got it OK and resynchronize */
954 (protocol->trail)(socket, ctl, num);
958 * At this point in flow of control, either we've bombed
959 * on a protocol error or had delivery refused by the SMTP
960 * server (unlikely -- I've never seen it) or we've seen
961 * `accepted for delivery' and the message is shipped.
962 * It's safe to mark the message seen and delete it on the
966 /* maybe we delete this message now? */
968 && (fetch_it ? !ctl->keep : ctl->flush))
971 if (outlevel > O_SILENT)
972 fprintf(stderr, " flushed\n");
973 ok = (protocol->delete)(socket, ctl, num);
977 else if (outlevel > O_SILENT)
979 /* nuke it from the unseen-messages list */
980 delete_uid(&ctl->newsaved, num);
981 fprintf(stderr, " not flushed\n");
985 /* remove all messages flagged for deletion */
986 if (protocol->expunge_cmd && deletions > 0)
988 ok = gen_transact(socket, protocol->expunge_cmd);
993 ok = gen_transact(socket, protocol->exit_cmd);
1000 ok = gen_transact(socket, protocol->exit_cmd);
1008 if (ok != 0 && ok != PS_SOCKET)
1010 gen_transact(socket, protocol->exit_cmd);
1016 signal(SIGALRM, sigsave);
1022 #if defined(HAVE_STDARG_H)
1023 void gen_send(int socket, char *fmt, ... )
1024 /* assemble command in printf(3) style and send to the server */
1027 void gen_send(socket, fmt, va_alist)
1028 /* assemble command in printf(3) style and send to the server */
1029 int socket; /* socket to which server is connected */
1030 const char *fmt; /* printf-style format */
1034 char buf [POPBUFSIZE+1];
1037 if (protocol->tagged)
1038 (void) sprintf(buf, "%s ", GENSYM);
1042 #if defined(HAVE_STDARG_H)
1047 vsprintf(buf + strlen(buf), fmt, ap);
1050 SockPuts(socket, buf);
1052 if (outlevel == O_VERBOSE)
1056 if (shroud && (cp = strstr(buf, shroud)))
1057 memset(cp, '*', strlen(shroud));
1058 fprintf(stderr,"> %s\n", buf);
1062 #if defined(HAVE_STDARG_H)
1063 int gen_transact(int socket, char *fmt, ... )
1064 /* assemble command in printf(3) style, send to server, accept a response */
1067 int gen_transact(socket, fmt, va_alist)
1068 /* assemble command in printf(3) style, send to server, accept a response */
1069 int socket; /* socket to which server is connected */
1070 const char *fmt; /* printf-style format */
1075 char buf [POPBUFSIZE+1];
1078 if (protocol->tagged)
1079 (void) sprintf(buf, "%s ", GENSYM);
1083 #if defined(HAVE_STDARG_H)
1088 vsprintf(buf + strlen(buf), fmt, ap);
1091 SockPuts(socket, buf);
1092 if (outlevel == O_VERBOSE)
1096 if (shroud && (cp = strstr(buf, shroud)))
1097 memset(cp, '*', strlen(shroud));
1098 fprintf(stderr,"> %s\n", buf);
1101 /* we presume this does its own response echoing */
1102 ok = (protocol->parse_response)(socket, buf);
1107 /* driver.c ends here */