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.
14 #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 int batchlimit; /* how often to tear down the delivery connection */
46 int batchcount; /* count of messages sent in current batch */
48 static const struct method *protocol;
49 static jmp_buf restart;
53 #define GENSYM (sprintf(tag, "a%04d", ++tagnum), tag)
55 static char *shroud; /* string to shroud in debug output, if non-NULL */
56 static int mytimeout; /* value of nonreponse timeout */
58 static int strcrlf(dst, src, count)
59 /* replace LFs with CR-LF; return length of string with replacements */
60 char *dst; /* new string with CR-LFs */
61 char *src; /* original string with LFs */
62 int count; /* length of src */
79 static void vtalarm(int timeleft)
80 /* reset the nonresponse-timeout */
82 struct itimerval ntimeout;
84 ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
85 ntimeout.it_value.tv_sec = timeleft;
86 ntimeout.it_value.tv_usec = 0;
87 setitimer(ITIMER_VIRTUAL, &ntimeout, (struct itimerval *)NULL);
90 static void vtalarm_handler (int signal)
91 /* handle server-timeout SIGVTALARM signal */
96 #ifdef HAVE_RES_SEARCH
99 static int is_host_alias(const char *name, struct query *ctl)
100 /* determine whether name is a DNS alias of the hostname */
103 struct mxentry *mxp, *mxrecords;
106 * The first two checks are optimizations that will catch a good
107 * many cases. (1) check against the hostname the user
108 * specified. Odds are good this will either be the mailserver's
109 * FQDN or a suffix of it with the mailserver's domain's default
110 * host name omitted. Then check the rest of the `also known as'
111 * cache accumulated by previous DNS checks. This cache is primed
112 * by the aka list option.
114 * (2) check against the mailserver's FQDN, in case
115 * it's not the same as the declared hostname.
117 * Either of these on a mail address is definitive. Only if the
118 * name doesn't match either is it time to call the bind library.
119 * If this happens odds are good we're looking at an MX name.
121 if (str_in_list(&ctl->lead_server->servernames, name))
123 else if (strcmp(name, ctl->canonical_name) == 0)
127 * We know DNS service was up at the beginning of this poll cycle.
128 * If it's down, our nameserver has crashed. We don't want to try
129 * delivering the current message or anything else from this
130 * mailbox until it's back up.
132 else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
134 if (strcmp(ctl->canonical_name, he->h_name) == 0)
142 case HOST_NOT_FOUND: /* specified host is unknown */
143 case NO_ADDRESS: /* valid, but does not have an IP address */
146 case NO_RECOVERY: /* non-recoverable name server error */
147 case TRY_AGAIN: /* temporary error on authoritative server */
149 if (outlevel != O_SILENT)
150 putchar('\n'); /* terminate the progress message */
152 "fetchmail: nameserver failure while looking for `%s' during poll of %s.\n",
153 name, ctl->servernames->id);
155 longjmp(restart, 2); /* try again next poll cycle */
160 * We're only here if DNS was OK but the gethostbyname() failed
161 * with a HOST_NOT_FOUND or NO_ADDRESS error.
162 * Search for a name match on MX records pointing to the server.
165 if ((mxrecords = getmxrecords(name)) == (struct mxentry *)NULL)
168 case HOST_NOT_FOUND: /* specified host is unknown */
171 case NO_ADDRESS: /* valid, but does not have an IP address */
172 for (mxp = mxrecords; mxp->name; mxp++)
173 if (strcmp(name, mxp->name) == 0)
177 case NO_RECOVERY: /* non-recoverable name server error */
178 case TRY_AGAIN: /* temporary error on authoritative server */
181 "fetchmail: nameserver failure while looking for `%s' during poll of %s.\n",
182 name, ctl->servernames->id);
184 longjmp(restart, 2); /* try again next poll cycle */
191 /* add this name to relevant server's `also known as' list */
192 save_str(&ctl->lead_server->servernames, -1, name);
196 static void map_name(name, ctl, xmit_names)
197 /* add given name to xmit_names if it matches declared localnames */
198 const char *name; /* name to map */
199 struct query *ctl; /* list of permissible aliases */
200 struct idlist **xmit_names; /* list of recipient names parsed out */
204 lname = idpair_find(&ctl->localnames, name);
205 if (!lname && ctl->wildcard)
208 if (lname != (char *)NULL)
210 if (outlevel == O_VERBOSE)
212 "fetchmail: mapped %s to local %s\n",
214 save_str(xmit_names, -1, lname);
218 void find_server_names(hdr, ctl, xmit_names)
219 /* parse names out of a RFC822 header into an ID list */
220 const char *hdr; /* RFC822 header in question */
221 struct query *ctl; /* list of permissible aliases */
222 struct idlist **xmit_names; /* list of recipient names parsed out */
224 if (hdr == (char *)NULL)
230 if ((cp = nxtaddr(hdr)) != (char *)NULL)
234 if ((atsign = strchr(cp, '@')))
237 * Address has an @. Check to see if the right-hand part
238 * is an alias or MX equivalent of the mailserver. If it's
239 * not, skip this name. If it is, we'll keep going and try
240 * to find a mapping to a client name.
242 if (!is_host_alias(atsign+1, ctl))
247 map_name(cp, ctl, xmit_names);
249 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
252 #endif /* HAVE_RES_SEARCH */
254 static FILE *smtp_open(struct query *ctl)
255 /* try to open a socket to the appropriate SMTP server for this query */
257 ctl = ctl->lead_smtp; /* go to the SMTP leader for this query */
259 /* maybe it's time to close the socket in order to force delivery */
260 if (batchlimit && ctl->smtp_sockfp && batchcount++ == batchlimit)
262 fclose(ctl->smtp_sockfp);
263 ctl->smtp_sockfp = (FILE *)NULL;
267 /* if no socket to this host is already set up, try to open one */
268 if (ctl->smtp_sockfp == (FILE *)NULL)
270 if ((ctl->smtp_sockfp = Socket(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL)
271 return((FILE *)NULL);
272 else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK
273 || SMTP_helo(ctl->smtp_sockfp, ctl->servernames->id) != SM_OK)
275 fclose(ctl->smtp_sockfp);
276 ctl->smtp_sockfp = (FILE *)NULL;
280 return(ctl->smtp_sockfp);
283 static int gen_readmsg (sockfp, len, delimited, ctl)
284 /* read message content and ship to SMTP or MDA */
285 FILE *sockfp; /* to which the server is connected */
286 long len; /* length of message */
287 int delimited; /* does the protocol use a message delimiter? */
288 struct query *ctl; /* query control record */
290 char buf [MSGBUFSIZE+1];
291 char *bufp, *headers, *fromhdr,*tohdr,*cchdr,*bcchdr,*received_for,*envto;
292 int n, oldlen, mboxfd;
293 int inheaders,lines,sizeticker;
295 #ifdef HAVE_GETHOSTBYNAME
296 char rbuf[HOSTLEN + USERNAMELEN + 4];
297 #endif /* HAVE_GETHOSTBYNAME */
299 /* read the message content from the server */
301 headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = NULL;
305 while (delimited || len > 0)
307 if ((n = SockGets(buf,sizeof(buf),sockfp)) < 0)
309 vtalarm(ctl->timeout);
311 /* write the message size dots */
315 while (sizeticker >= SIZETICKER)
317 if (outlevel > O_SILENT)
319 sizeticker -= SIZETICKER;
324 if (buf[0] == '\0' || buf[0] == '\r' || buf[0] == '\n')
326 if (delimited && *bufp == '.') {
329 break; /* end of message */
336 reply_hack(bufp, ctl->servernames->id);
340 oldlen = strlen(bufp);
341 headers = xmalloc(oldlen + 1);
342 (void) strcpy(headers, bufp);
350 * We deal with RFC822 continuation lines here.
351 * Replace previous '\n' with '\r' so nxtaddr
352 * and reply_hack will be able to see past it.
353 * (We know this is safe because SocketGets stripped
354 * out all carriage returns in the read loop above
355 * and we haven't reintroduced any since then.)
356 * We'll undo this before writing the header.
358 if (isspace(bufp[0]))
359 headers[oldlen-1] = '\r';
361 newlen = oldlen + strlen(bufp);
362 headers = realloc(headers, newlen + 1);
365 strcpy(headers + oldlen, bufp);
366 bufp = headers + oldlen;
370 if (!strncasecmp("From:", bufp, 5))
372 else if (!fromhdr && !strncasecmp("Resent-From:", bufp, 12))
374 else if (!fromhdr && !strncasecmp("Apparently-From:", bufp, 16))
376 else if (!strncasecmp("To:", bufp, 3))
378 else if (!strncasecmp("Apparently-To:", bufp, 14))
380 else if (!strncasecmp("X-Envelope-To:", bufp, 14))
382 else if (!strncasecmp("Cc:", bufp, 3))
384 else if (!strncasecmp("Bcc:", bufp, 4))
386 #ifdef HAVE_GETHOSTBYNAME
387 else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9))
392 * Try to extract the real envelope addressee. We look here
393 * specifically for the mailserver's Received line.
394 * Note: this will only work for sendmail, or an MTA that
395 * shares sendmail's convention of embedding the envelope
396 * address in the Received line.
399 strcat(rbuf, ctl->canonical_name);
400 if ((ok = strstr(bufp, rbuf)))
401 ok = strstr(ok, "for <");
412 while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
417 /* uh oh -- whitespace here can't be right! */
426 received_for = alloca(strlen(rbuf)+1);
427 strcpy(received_for, rbuf);
428 if (outlevel == O_VERBOSE)
430 "fetchmail: found Received address `%s'\n",
434 #endif /* HAVE_GETHOSTBYNAME */
438 else if (headers) /* OK, we're at end of headers now */
441 struct idlist *idp, *xmit_names;
442 int good_addresses, bad_addresses;
443 #ifdef HAVE_RES_SEARCH
444 int no_local_matches = FALSE;
445 #endif /* HAVE_RES_SEARCH */
447 /* cons up a list of local recipients */
448 xmit_names = (struct idlist *)NULL;
449 bad_addresses = good_addresses = 0;
450 #ifdef HAVE_RES_SEARCH
451 /* is this a multidrop box? */
454 if (envto) /* We have the actual envelope addressee */
455 find_server_names(envto, ctl, &xmit_names);
456 else if (received_for)
458 * We have the Received for addressee.
459 * It has to be a mailserver address, or we
460 * wouldn't have got here.
462 map_name(received_for, ctl, &xmit_names);
466 * We haven't extracted the envelope address.
467 * So check all the header addresses.
469 find_server_names(tohdr, ctl, &xmit_names);
470 find_server_names(cchdr, ctl, &xmit_names);
471 find_server_names(bcchdr, ctl, &xmit_names);
475 no_local_matches = TRUE;
476 save_str(&xmit_names, -1, user);
477 if (outlevel == O_VERBOSE)
479 "fetchmail: no local matches, forwarding to %s\n",
483 else /* it's a single-drop box, use first localname */
484 #endif /* HAVE_RES_SEARCH */
485 save_str(&xmit_names, -1, ctl->localnames->id);
487 /* time to address the message */
488 if (ctl->mda[0]) /* we have a declared MDA */
494 * We go through this in order to be able to handle very
495 * long lists of users and (re)implement %s.
497 for (idp = xmit_names; idp; idp = idp->next)
499 sp = sargv = (char **)alloca(sizeof(char **) * ctl->mda_argcount+nlocals+2);
500 for (i = 0; i < ctl->mda_argcount; i++)
501 if (strcmp("%s", ctl->mda_argv[i]))
502 *sp++ = ctl->mda_argv[i];
504 for (idp = xmit_names; idp; idp = idp->next)
510 * Arrange to run with user's permissions if we're root.
511 * This will initialize the ownership of any files the
512 * MDA creates properly. (The seteuid call is available
513 * under all BSDs and Linux)
516 #endif /* HAVE_SETEUID */
518 mboxfd = openmailpipe(sargv);
521 /* this will fail quietly if we didn't start as root */
523 #endif /* HAVE_SETEUID */
527 fprintf(stderr, "fetchmail: MDA open failed\n");
535 /* build a connection to the SMTP listener */
536 if (ctl->mda[0] == '\0' && ((sinkfp = smtp_open(ctl)) == NULL))
538 free_str_list(&xmit_names);
539 fprintf(stderr, "fetchmail: SMTP connect failed\n");
544 * Try to get the SMTP listener to take the header
545 * From address as MAIL FROM (this makes the logging
546 * nicer). If it won't, fall back on the calling-user
547 * ID. This won't affect replies, which use the header
548 * From address anyway.
550 if (!fromhdr || !(ap = nxtaddr(fromhdr))
551 || SMTP_from(sinkfp, ap) != SM_OK)
552 if (SMTP_from(sinkfp, user) != SM_OK)
553 return(PS_SMTP); /* should never happen */
555 /* now list the recipient addressees */
556 for (idp = xmit_names; idp; idp = idp->next)
557 if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
564 "fetchmail: SMTP listener doesn't like recipient address `%s'\n", idp->id);
566 if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK)
569 "fetchmail: can't even send to calling user!\n");
573 /* tell it we're ready to send data */
575 if (outlevel == O_VERBOSE)
576 fputs("SMTP> ", stderr);
579 /* change continuation markers back to regular newlines */
580 for (cp = headers; cp < headers + oldlen; cp++)
584 /* replace all LFs with CR-LF before sending to the SMTP server */
587 char *newheaders = xmalloc(1 + oldlen * 2);
589 oldlen = strcrlf(newheaders, headers, oldlen);
591 headers = newheaders;
594 /* write all the headers */
596 n = write(mboxfd,headers,oldlen);
598 n = SockWrite(headers, oldlen, sinkfp);
604 perror("fetchmail: writing RFC822 headers");
607 else if (outlevel == O_VERBOSE)
612 /* write error notifications */
613 #ifdef HAVE_RES_SEARCH
614 if (no_local_matches || bad_addresses)
617 #endif /* HAVE_RES_SEARCH */
620 char errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
623 (void) strcpy(errhd, "X-Fetchmail-Warning: ");
624 #ifdef HAVE_RES_SEARCH
625 if (no_local_matches)
627 strcat(errhd, "no recipient addresses matched declared local names");
631 #endif /* HAVE_RES_SEARCH */
635 strcat(errhd, "SMTP listener rejected local recipient addresses: ");
636 errlen = strlen(errhd);
637 for (idp = xmit_names; idp; idp = idp->next)
639 errlen += strlen(idp->id) + 2;
641 errmsg = alloca(errlen+3);
642 (void) strcpy(errmsg, errhd);
643 for (idp = xmit_names; idp; idp = idp->next)
646 strcat(errmsg, idp->id);
648 strcat(errmsg, ", ");
652 strcat(errmsg, "\n");
655 write(mboxfd, errmsg, strlen(errmsg));
657 SockWrite(errmsg, strlen(errmsg), sinkfp);
660 free_str_list(&xmit_names);
663 /* SMTP byte-stuffing */
664 if (*bufp == '.' && ctl->mda[0] == 0)
665 SockWrite(".", 1, sinkfp);
667 /* replace all LFs with CR-LF in the line */
670 char *newbufp = xmalloc(1 + strlen(bufp) * 2);
672 strcrlf(newbufp, bufp, strlen(bufp));
676 /* ship out the text line */
678 n = write(mboxfd,bufp,strlen(bufp));
680 n = SockWrite(bufp, strlen(bufp), sinkfp);
686 perror("fetchmail: writing message text");
689 else if (outlevel == O_VERBOSE)
698 /* close the delivery pipe, we'll reopen before next message */
699 if (closemailpipe(mboxfd))
704 /* write message terminator */
705 if (SMTP_eom(sinkfp) != SM_OK)
707 fputs("fetchmail: SMTP listener refused delivery\n", stderr);
717 kerberos_auth (socket, canonical)
718 /* authenticate to the server host using Kerberos V4 */
719 int socket; /* socket to server host */
720 const char *canonical; /* server name */
726 Key_schedule schedule;
729 ticket = ((KTEXT) (malloc (sizeof (KTEXT_ST))));
730 rem = (krb_sendauth (0L, socket, ticket, "pop",
732 ((char *) (krb_realmofhost (canonical))),
737 ((struct sockaddr_in *) 0),
738 ((struct sockaddr_in *) 0),
743 fprintf (stderr, "fetchmail: kerberos error %s\n", (krb_get_err_text (rem)));
748 #endif /* KERBEROS_V4 */
750 int do_protocol(ctl, proto)
751 /* retrieve messages from server using given protocol method table */
752 struct query *ctl; /* parsed options with merged-in defaults */
753 const struct method *proto; /* protocol method table */
759 if (ctl->authenticate == A_KERBEROS)
761 fputs("fetchmail: Kerberos support not linked.\n", stderr);
764 #endif /* KERBEROS_V4 */
766 /* lacking methods, there are some options that may fail */
769 /* check for unsupported options */
772 "Option --flush is not supported with %s\n",
776 else if (ctl->fetchall) {
778 "Option --all is not supported with %s\n",
783 if (!proto->getsizes && ctl->limit)
786 "Option --limit is not supported with %s\n",
793 tag[0] = '\0'; /* nuke any tag hanging out from previous query */
796 /* set up the server-nonresponse timeout */
797 sigsave = signal(SIGVTALRM, vtalarm_handler);
798 vtalarm(mytimeout = ctl->timeout);
800 if ((js = setjmp(restart)) == 1)
803 "fetchmail: timeout after %d seconds waiting for %s.\n",
804 ctl->timeout, ctl->servernames->id);
809 /* error message printed at point of longjmp */
814 char buf [POPBUFSIZE+1];
815 int *msgsizes, len, num, count, new, deletions = 0;
818 /* open a socket to the mail server */
819 if ((sockfp = Socket(ctl->servernames->id,
820 ctl->port ? ctl->port : protocol->port)) == NULL)
822 perror("fetchmail, connecting to host");
828 if (ctl->authenticate == A_KERBEROS)
830 ok = (kerberos_auth (fileno(sockfp), ctl->canonical_name));
831 vtalarm(ctl->timeout);
835 #endif /* KERBEROS_V4 */
837 /* accept greeting message from mail server */
838 ok = (protocol->parse_response)(sockfp, buf);
839 vtalarm(ctl->timeout);
843 /* try to get authorized to fetch mail */
844 shroud = ctl->password;
845 ok = (protocol->getauth)(sockfp, ctl, buf);
846 vtalarm(ctl->timeout);
847 shroud = (char *)NULL;
853 /* compute number of messages and number of new messages waiting */
854 if ((protocol->getrange)(sockfp, ctl, &count, &new) != 0)
856 vtalarm(ctl->timeout);
858 /* show user how many messages we downloaded */
859 if (outlevel > O_SILENT)
861 fprintf(stderr, "No mail from %s@%s\n",
863 ctl->servernames->id);
866 fprintf(stderr, "%d message%s", count, count > 1 ? "s" : "");
867 if (new != -1 && (count - new) > 0)
868 fprintf(stderr, " (%d seen)", count-new);
872 ctl->servernames->id);
875 /* we may need to get sizes in order to check message limits */
876 msgsizes = (int *)NULL;
877 if (!ctl->fetchall && proto->getsizes && ctl->limit)
879 msgsizes = (int *)alloca(sizeof(int) * count);
881 if ((ok = (proto->getsizes)(sockfp, count, msgsizes)) != 0)
888 if (new == -1 || ctl->fetchall)
890 ok = ((new > 0) ? PS_SUCCESS : PS_NOMAIL);
896 * What forces this code is that in POP3 you can't fetch a
897 * message without having it marked `seen'.
899 * The result is that if there's any kind of transient error
900 * (DNS lookup failure, or sendmail refusing delivery due to
901 * process-table limits) the message will be marked "seen" on
902 * the server without having been delivered. This is not a
903 * big problem if fetchmail is running in foreground, because
904 * the user will see a "skipped" message when it next runs and
907 * But in daemon mode this leads to the message being silently
908 * ignored forever. This is not acceptable.
910 * We compensate for this by checking the error count from the
911 * previous pass and forcing all messages to be considered new
914 int force_retrieval = (ctl->errcount > 0);
918 /* read, forward, and delete messages */
919 for (num = 1; num <= count; num++)
921 int toolarge = msgsizes && (msgsizes[num-1] > ctl->limit);
922 int fetch_it = ctl->fetchall ||
923 (!toolarge && (force_retrieval || !(protocol->is_old && (protocol->is_old)(sockfp,ctl,num))));
925 /* we may want to reject this message if it's old */
928 if (outlevel > O_SILENT)
930 fprintf(stderr, "skipping message %d", num);
932 fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
937 /* request a message */
938 (protocol->fetch)(sockfp, num, &len);
939 vtalarm(ctl->timeout);
941 if (outlevel > O_SILENT)
943 fprintf(stderr, "reading message %d", num);
945 fprintf(stderr, " (%d bytes)", len);
946 if (outlevel == O_VERBOSE)
952 /* read the message and ship it to the output sink */
953 ok = gen_readmsg(sockfp,
957 vtalarm(ctl->timeout);
961 /* tell the server we got it OK and resynchronize */
963 (protocol->trail)(sockfp, ctl, num);
967 * At this point in flow of control, either we've bombed
968 * on a protocol error or had delivery refused by the SMTP
969 * server (unlikely -- I've never seen it) or we've seen
970 * `accepted for delivery' and the message is shipped.
971 * It's safe to mark the message seen and delete it on the
975 /* maybe we delete this message now? */
977 && (fetch_it ? !ctl->keep : ctl->flush))
980 if (outlevel > O_SILENT)
981 fprintf(stderr, " flushed\n");
982 ok = (protocol->delete)(sockfp, ctl, num);
983 vtalarm(ctl->timeout);
986 delete_str(&ctl->newsaved, num);
988 else if (outlevel > O_SILENT)
989 fprintf(stderr, " not flushed\n");
992 /* remove all messages flagged for deletion */
993 if (protocol->expunge_cmd && deletions > 0)
995 ok = gen_transact(sockfp, protocol->expunge_cmd);
1000 ok = gen_transact(sockfp, protocol->exit_cmd);
1007 ok = gen_transact(sockfp, protocol->exit_cmd);
1015 if (ok != 0 && ok != PS_SOCKET)
1017 gen_transact(sockfp, protocol->exit_cmd);
1025 fputs("fetchmail: socket", stderr);
1028 fputs("fetchmail: authorization", stderr);
1031 fputs("fetchmail: missing or bad RFC822 header", stderr);
1034 fputs("fetchmail: MDA", stderr);
1037 fputs("fetchmail: client/server synchronization", stderr);
1040 fputs("fetchmail: client/server protocol", stderr);
1043 fputs("fetchmail: SMTP transaction", stderr);
1046 fputs("fetchmail: undefined", stderr);
1049 if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX || ok==PS_IOERR
1050 || ok==PS_ERROR || ok==PS_PROTOCOL || ok==PS_SMTP)
1051 fprintf(stderr, " error while talking to %s\n", ctl->servernames->id);
1054 signal(SIGVTALRM, sigsave);
1058 #if defined(HAVE_STDARG_H)
1059 void gen_send(FILE *sockfp, char *fmt, ... )
1060 /* assemble command in printf(3) style and send to the server */
1063 void gen_send(sockfp, fmt, va_alist)
1064 /* assemble command in printf(3) style and send to the server */
1065 FILE *sockfp; /* socket to which server is connected */
1066 const char *fmt; /* printf-style format */
1070 char buf [POPBUFSIZE+1];
1073 if (protocol->tagged)
1074 (void) sprintf(buf, "%s ", GENSYM);
1078 #if defined(HAVE_STDARG_H)
1083 vsprintf(buf + strlen(buf), fmt, ap);
1086 strcat(buf, "\r\n");
1087 SockWrite(buf, strlen(buf), sockfp);
1089 if (outlevel == O_VERBOSE)
1093 if (shroud && (cp = strstr(buf, shroud)))
1094 memset(cp, '*', strlen(shroud));
1095 fprintf(stderr,"> %s", buf);
1099 #if defined(HAVE_STDARG_H)
1100 int gen_transact(FILE *sockfp, char *fmt, ... )
1101 /* assemble command in printf(3) style, send to server, accept a response */
1104 int gen_transact(sockfp, fmt, va_alist)
1105 /* assemble command in printf(3) style, send to server, accept a response */
1106 FILE *sockfp; /* socket to which server is connected */
1107 const char *fmt; /* printf-style format */
1112 char buf [POPBUFSIZE+1];
1115 if (protocol->tagged)
1116 (void) sprintf(buf, "%s ", GENSYM);
1120 #if defined(HAVE_STDARG_H)
1125 vsprintf(buf + strlen(buf), fmt, ap);
1128 strcat(buf, "\r\n");
1129 SockWrite(buf, strlen(buf), sockfp);
1130 if (outlevel == O_VERBOSE)
1134 if (shroud && (cp = strstr(buf, shroud)))
1135 memset(cp, '*', strlen(shroud));
1136 fprintf(stderr,"> %s", buf);
1139 /* we presume this does its own response echoing */
1140 ok = (protocol->parse_response)(sockfp, buf);
1146 /* driver.c ends here */