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. First, check against the hostname the user specified.
108 * Odds are good this will either be the mailserver's FQDN or a
109 * suffix of it with the mailserver's domain's default host name
110 * omitted. Next, check against the mailserver's FQDN, in case
111 * it's not the same as the declared hostname.
113 * Either of these on a mail address is definitive. Only if the
114 * name doesn't match either is it time to call the bind library.
115 * If this happens odds are good we're looking at an MX name.
117 if (strcmp(name, ctl->servername) == 0)
119 else if (strcmp(name, ctl->canonical_name) == 0)
123 * Is it in the `also known as' cache accumulated by previous DNS checks?
124 * This cache is primed by the aka list option.
126 else if (uid_in_list(&ctl->lead_server->aka, name))
130 * We know DNS service was up at the beginning of this poll cycle.
131 * If it's down, our nameserver has crashed. We don't want to try
132 * delivering the current message or anything else from this
133 * mailbox until it's back up.
135 else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
137 if (strcmp(ctl->canonical_name, he->h_name) == 0)
145 case HOST_NOT_FOUND: /* specified host is unknown */
146 case NO_ADDRESS: /* valid, but does not have an IP address */
149 case NO_RECOVERY: /* non-recoverable name server error */
150 case TRY_AGAIN: /* temporary error on authoritative server */
152 if (outlevel != O_SILENT)
153 putchar('\n'); /* terminate the progress message */
155 "fetchmail: nameserver failure while looking for `%s' during poll of %s.\n",
156 name, ctl->servername);
158 longjmp(restart, 2); /* try again next poll cycle */
163 * We're only here if DNS was OK but the gethostbyname() failed
164 * with a HOST_NOT_FOUND or NO_ADDRESS error.
165 * Search for a name match on MX records pointing to the server.
168 if ((mxrecords = getmxrecords(name)) == (struct mxentry *)NULL)
171 case HOST_NOT_FOUND: /* specified host is unknown */
174 case NO_ADDRESS: /* valid, but does not have an IP address */
175 for (mxp = mxrecords; mxp->name; mxp++)
176 if (strcmp(name, mxp->name) == 0)
180 case NO_RECOVERY: /* non-recoverable name server error */
181 case TRY_AGAIN: /* temporary error on authoritative server */
184 "fetchmail: nameserver failure while looking for `%s' during poll of %s.\n",
185 name, ctl->servername);
187 longjmp(restart, 2); /* try again next poll cycle */
194 /* add this name to relevant server's `also known as' list */
195 save_uid(&ctl->lead_server->aka, -1, name);
199 static void map_name(name, ctl, xmit_names)
200 /* add given name to xmit_names if it matches declared localnames */
201 const char *name; /* name to map */
202 struct query *ctl; /* list of permissible aliases */
203 struct idlist **xmit_names; /* list of recipient names parsed out */
207 lname = idpair_find(&ctl->localnames, name);
208 if (!lname && ctl->wildcard)
211 if (lname != (char *)NULL)
213 if (outlevel == O_VERBOSE)
215 "fetchmail: mapped %s to local %s\n",
217 save_uid(xmit_names, -1, lname);
221 void find_server_names(hdr, ctl, xmit_names)
222 /* parse names out of a RFC822 header into an ID list */
223 const char *hdr; /* RFC822 header in question */
224 struct query *ctl; /* list of permissible aliases */
225 struct idlist **xmit_names; /* list of recipient names parsed out */
227 if (hdr == (char *)NULL)
233 if ((cp = nxtaddr(hdr)) != (char *)NULL)
237 if ((atsign = strchr(cp, '@')))
240 * Address has an @. Check to see if the right-hand part
241 * is an alias or MX equivalent of the mailserver. If it's
242 * not, skip this name. If it is, we'll keep going and try
243 * to find a mapping to a client name.
245 if (!is_host_alias(atsign+1, ctl))
250 map_name(cp, ctl, xmit_names);
252 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
255 #endif /* HAVE_RES_SEARCH */
257 static FILE *smtp_open(struct query *ctl)
258 /* try to open a socket to the appropriate SMTP server for this query */
260 ctl = ctl->lead_smtp; /* go to the SMTP leader for this query */
262 /* maybe it's time to close the socket in order to force delivery */
263 if (batchlimit && ctl->smtp_sockfp && batchcount++ == batchlimit)
265 fclose(ctl->smtp_sockfp);
266 ctl->smtp_sockfp = (FILE *)NULL;
270 /* if no socket to this host is already set up, try to open one */
271 if (ctl->smtp_sockfp == (FILE *)NULL)
273 if ((ctl->smtp_sockfp = Socket(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL)
274 return((FILE *)NULL);
275 else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK
276 || SMTP_helo(ctl->smtp_sockfp, ctl->servername) != SM_OK)
278 fclose(ctl->smtp_sockfp);
279 ctl->smtp_sockfp = (FILE *)NULL;
283 return(ctl->smtp_sockfp);
286 static int gen_readmsg (sockfp, len, delimited, ctl)
287 /* read message content and ship to SMTP or MDA */
288 FILE *sockfp; /* to which the server is connected */
289 long len; /* length of message */
290 int delimited; /* does the protocol use a message delimiter? */
291 struct query *ctl; /* query control record */
293 char buf [MSGBUFSIZE+1];
294 char *bufp, *headers, *fromhdr,*tohdr,*cchdr,*bcchdr,*received_for,*envto;
295 int n, oldlen, mboxfd;
296 int inheaders,lines,sizeticker;
298 #ifdef HAVE_GETHOSTBYNAME
299 char rbuf[HOSTLEN + USERNAMELEN + 4];
300 #endif /* HAVE_GETHOSTBYNAME */
302 /* read the message content from the server */
304 headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = NULL;
308 while (delimited || len > 0)
310 if ((n = SockGets(buf,sizeof(buf),sockfp)) < 0)
312 vtalarm(ctl->timeout);
314 /* write the message size dots */
318 while (sizeticker >= SIZETICKER)
320 if (outlevel > O_SILENT)
322 sizeticker -= SIZETICKER;
327 if (buf[0] == '\0' || buf[0] == '\r' || buf[0] == '\n')
329 if (delimited && *bufp == '.') {
332 break; /* end of message */
339 reply_hack(bufp, ctl->servername);
343 oldlen = strlen(bufp);
344 headers = xmalloc(oldlen + 1);
345 (void) strcpy(headers, bufp);
353 * We deal with RFC822 continuation lines here.
354 * Replace previous '\n' with '\r' so nxtaddr
355 * and reply_hack will be able to see past it.
356 * (We know this is safe because SocketGets stripped
357 * out all carriage returns in the read loop above
358 * and we haven't reintroduced any since then.)
359 * We'll undo this before writing the header.
361 if (isspace(bufp[0]))
362 headers[oldlen-1] = '\r';
364 newlen = oldlen + strlen(bufp);
365 headers = realloc(headers, newlen + 1);
368 strcpy(headers + oldlen, bufp);
369 bufp = headers + oldlen;
373 if (!strncasecmp("From:", bufp, 5))
375 else if (!fromhdr && !strncasecmp("Resent-From:", bufp, 12))
377 else if (!fromhdr && !strncasecmp("Apparently-From:", bufp, 16))
379 else if (!strncasecmp("To:", bufp, 3))
381 else if (!strncasecmp("Apparently-To:", bufp, 14))
383 else if (!strncasecmp("X-Envelope-To:", bufp, 14))
385 else if (!strncasecmp("Cc:", bufp, 3))
387 else if (!strncasecmp("Bcc:", bufp, 4))
389 #ifdef HAVE_GETHOSTBYNAME
390 else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9))
395 * Try to extract the real envelope addressee. We look here
396 * specifically for the mailserver's Received line.
397 * Note: this will only work for sendmail, or an MTA that
398 * shares sendmail's convention of embedding the envelope
399 * address in the Received line.
402 strcat(rbuf, ctl->canonical_name);
403 if ((ok = strstr(bufp, rbuf)))
404 ok = strstr(ok, "for <");
415 while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
420 /* uh oh -- whitespace here can't be right! */
429 received_for = alloca(strlen(rbuf)+1);
430 strcpy(received_for, rbuf);
431 if (outlevel == O_VERBOSE)
433 "fetchmail: found Received address `%s'\n",
437 #endif /* HAVE_GETHOSTBYNAME */
441 else if (headers) /* OK, we're at end of headers now */
444 struct idlist *idp, *xmit_names;
445 int good_addresses, bad_addresses;
446 #ifdef HAVE_RES_SEARCH
447 int no_local_matches = FALSE;
448 #endif /* HAVE_RES_SEARCH */
450 /* cons up a list of local recipients */
451 xmit_names = (struct idlist *)NULL;
452 bad_addresses = good_addresses = 0;
453 #ifdef HAVE_RES_SEARCH
454 /* is this a multidrop box? */
457 if (envto) /* We have the actual envelope addressee */
458 find_server_names(envto, ctl, &xmit_names);
459 else if (received_for)
461 * We have the Received for addressee.
462 * It has to be a mailserver address, or we
463 * wouldn't have got here.
465 map_name(received_for, ctl, &xmit_names);
469 * We haven't extracted the envelope address.
470 * So check all the header addresses.
472 find_server_names(tohdr, ctl, &xmit_names);
473 find_server_names(cchdr, ctl, &xmit_names);
474 find_server_names(bcchdr, ctl, &xmit_names);
478 no_local_matches = TRUE;
479 save_uid(&xmit_names, -1, user);
480 if (outlevel == O_VERBOSE)
482 "fetchmail: no local matches, forwarding to %s\n",
486 else /* it's a single-drop box, use first localname */
487 #endif /* HAVE_RES_SEARCH */
488 save_uid(&xmit_names, -1, ctl->localnames->id);
490 /* time to address the message */
491 if (ctl->mda[0]) /* we have a declared MDA */
497 * We go through this in order to be able to handle very
498 * long lists of users and (re)implement %s.
500 for (idp = xmit_names; idp; idp = idp->next)
502 sp = sargv = (char **)alloca(sizeof(char **) * ctl->mda_argcount+nlocals+2);
503 for (i = 0; i < ctl->mda_argcount; i++)
504 if (strcmp("%s", ctl->mda_argv[i]))
505 *sp++ = ctl->mda_argv[i];
507 for (idp = xmit_names; idp; idp = idp->next)
513 * Arrange to run with user's permissions if we're root.
514 * This will initialize the ownership of any files the
515 * MDA creates properly. (The seteuid call is available
516 * under all BSDs and Linux)
519 #endif /* HAVE_SETEUID */
521 mboxfd = openmailpipe(sargv);
524 /* this will fail quietly if we didn't start as root */
526 #endif /* HAVE_SETEUID */
530 fprintf(stderr, "fetchmail: MDA open failed\n");
538 /* build a connection to the SMTP listener */
539 if (ctl->mda[0] == '\0' && ((sinkfp = smtp_open(ctl)) == NULL))
541 free_uid_list(&xmit_names);
542 fprintf(stderr, "fetchmail: SMTP connect failed\n");
547 * Try to get the SMTP listener to take the header
548 * From address as MAIL FROM (this makes the logging
549 * nicer). If it won't, fall back on the calling-user
550 * ID. This won't affect replies, which use the header
551 * From address anyway.
553 if (!fromhdr || !(ap = nxtaddr(fromhdr))
554 || SMTP_from(sinkfp, ap) != SM_OK)
555 if (SMTP_from(sinkfp, user) != SM_OK)
556 return(PS_SMTP); /* should never happen */
558 /* now list the recipient addressees */
559 for (idp = xmit_names; idp; idp = idp->next)
560 if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
567 "fetchmail: SMTP listener doesn't like recipient address `%s'\n", idp->id);
569 if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK)
572 "fetchmail: can't even send to calling user!\n");
576 /* tell it we're ready to send data */
578 if (outlevel == O_VERBOSE)
579 fputs("SMTP> ", stderr);
582 /* change continuation markers back to regular newlines */
583 for (cp = headers; cp < headers + oldlen; cp++)
587 /* replace all LFs with CR-LF before sending to the SMTP server */
590 char *newheaders = xmalloc(1 + oldlen * 2);
592 oldlen = strcrlf(newheaders, headers, oldlen);
594 headers = newheaders;
597 /* write all the headers */
599 n = write(mboxfd,headers,oldlen);
601 n = SockWrite(headers, oldlen, sinkfp);
607 perror("fetchmail: writing RFC822 headers");
610 else if (outlevel == O_VERBOSE)
615 /* write error notifications */
616 #ifdef HAVE_RES_SEARCH
617 if (no_local_matches || bad_addresses)
620 #endif /* HAVE_RES_SEARCH */
623 char errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
626 (void) strcpy(errhd, "X-Fetchmail-Warning: ");
627 #ifdef HAVE_RES_SEARCH
628 if (no_local_matches)
630 strcat(errhd, "no recipient addresses matched declared local names");
634 #endif /* HAVE_RES_SEARCH */
638 strcat(errhd, "SMTP listener rejected local recipient addresses: ");
639 errlen = strlen(errhd);
640 for (idp = xmit_names; idp; idp = idp->next)
642 errlen += strlen(idp->id) + 2;
644 errmsg = alloca(errlen+3);
645 (void) strcpy(errmsg, errhd);
646 for (idp = xmit_names; idp; idp = idp->next)
649 strcat(errmsg, idp->id);
651 strcat(errmsg, ", ");
655 strcat(errmsg, "\n");
658 write(mboxfd, errmsg, strlen(errmsg));
660 SockWrite(errmsg, strlen(errmsg), sinkfp);
663 free_uid_list(&xmit_names);
666 /* SMTP byte-stuffing */
667 if (*bufp == '.' && ctl->mda[0] == 0)
668 SockWrite(".", 1, sinkfp);
670 /* replace all LFs with CR-LF in the line */
673 char *newbufp = xmalloc(1 + strlen(bufp) * 2);
675 strcrlf(newbufp, bufp, strlen(bufp));
679 /* ship out the text line */
681 n = write(mboxfd,bufp,strlen(bufp));
683 n = SockWrite(bufp, strlen(bufp), sinkfp);
689 perror("fetchmail: writing message text");
692 else if (outlevel == O_VERBOSE)
701 /* close the delivery pipe, we'll reopen before next message */
702 if (closemailpipe(mboxfd))
707 /* write message terminator */
708 if (SMTP_eom(sinkfp) != SM_OK)
710 fputs("fetchmail: SMTP listener refused delivery\n", stderr);
720 kerberos_auth (socket, canonical)
721 /* authenticate to the server host using Kerberos V4 */
722 int socket; /* socket to server host */
723 const char *canonical; /* server name */
729 Key_schedule schedule;
732 ticket = ((KTEXT) (malloc (sizeof (KTEXT_ST))));
733 rem = (krb_sendauth (0L, socket, ticket, "pop",
735 ((char *) (krb_realmofhost (canonical))),
740 ((struct sockaddr_in *) 0),
741 ((struct sockaddr_in *) 0),
746 fprintf (stderr, "fetchmail: kerberos error %s\n", (krb_get_err_text (rem)));
751 #endif /* KERBEROS_V4 */
753 int do_protocol(ctl, proto)
754 /* retrieve messages from server using given protocol method table */
755 struct query *ctl; /* parsed options with merged-in defaults */
756 const struct method *proto; /* protocol method table */
762 if (ctl->authenticate == A_KERBEROS)
764 fputs("fetchmail: Kerberos support not linked.\n", stderr);
767 #endif /* KERBEROS_V4 */
769 /* lacking methods, there are some options that may fail */
772 /* check for unsupported options */
775 "Option --flush is not supported with %s\n",
779 else if (ctl->fetchall) {
781 "Option --all is not supported with %s\n",
786 if (!proto->getsizes && ctl->limit)
789 "Option --limit is not supported with %s\n",
796 tag[0] = '\0'; /* nuke any tag hanging out from previous query */
799 /* set up the server-nonresponse timeout */
800 sigsave = signal(SIGVTALRM, vtalarm_handler);
801 vtalarm(mytimeout = ctl->timeout);
803 if ((js = setjmp(restart)) == 1)
806 "fetchmail: timeout after %d seconds waiting for %s.\n",
807 ctl->timeout, ctl->servername);
812 /* error message printed at point of longjmp */
817 char buf [POPBUFSIZE+1];
818 int *msgsizes, len, num, count, new, deletions = 0;
821 /* open a socket to the mail server */
822 if ((sockfp = Socket(ctl->servername,
823 ctl->port ? ctl->port : protocol->port)) == NULL)
825 perror("fetchmail, connecting to host");
831 if (ctl->authenticate == A_KERBEROS)
833 ok = (kerberos_auth (fileno(sockfp), ctl->canonical_name));
834 vtalarm(ctl->timeout);
838 #endif /* KERBEROS_V4 */
840 /* accept greeting message from mail server */
841 ok = (protocol->parse_response)(sockfp, buf);
842 vtalarm(ctl->timeout);
846 /* try to get authorized to fetch mail */
847 shroud = ctl->password;
848 ok = (protocol->getauth)(sockfp, ctl, buf);
849 vtalarm(ctl->timeout);
850 shroud = (char *)NULL;
856 /* compute number of messages and number of new messages waiting */
857 if ((protocol->getrange)(sockfp, ctl, &count, &new) != 0)
859 vtalarm(ctl->timeout);
861 /* show user how many messages we downloaded */
862 if (outlevel > O_SILENT)
864 fprintf(stderr, "No mail from %s@%s\n",
869 fprintf(stderr, "%d message%s", count, count > 1 ? "s" : "");
870 if (new != -1 && (count - new) > 0)
871 fprintf(stderr, " (%d seen)", count-new);
878 /* we may need to get sizes in order to check message limits */
879 msgsizes = (int *)NULL;
880 if (!ctl->fetchall && proto->getsizes && ctl->limit)
882 msgsizes = (int *)alloca(sizeof(int) * count);
884 if ((ok = (proto->getsizes)(sockfp, count, msgsizes)) != 0)
891 if (new == -1 || ctl->fetchall)
893 ok = ((new > 0) ? PS_SUCCESS : PS_NOMAIL);
899 * What forces this code is that in POP3 you can't fetch a
900 * message without having it marked `seen'.
902 * The result is that if there's any kind of transient error
903 * (DNS lookup failure, or sendmail refusing delivery due to
904 * process-table limits) the message will be marked "seen" on
905 * the server without having been delivered. This is not a
906 * big problem if fetchmail is running in foreground, because
907 * the user will see a "skipped" message when it next runs and
910 * But in daemon mode this leads to the message being silently
911 * ignored forever. This is not acceptable.
913 * We compensate for this by checking the error count from the
914 * previous pass and forcing all messages to be considered new
917 int force_retrieval = (ctl->errcount > 0);
921 /* read, forward, and delete messages */
922 for (num = 1; num <= count; num++)
924 int toolarge = msgsizes && (msgsizes[num-1] > ctl->limit);
925 int fetch_it = ctl->fetchall ||
926 (!toolarge && (force_retrieval || !(protocol->is_old && (protocol->is_old)(sockfp,ctl,num))));
928 /* we may want to reject this message if it's old */
931 if (outlevel > O_SILENT)
933 fprintf(stderr, "skipping message %d", num);
935 fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
940 /* request a message */
941 (protocol->fetch)(sockfp, num, &len);
942 vtalarm(ctl->timeout);
944 if (outlevel > O_SILENT)
946 fprintf(stderr, "reading message %d", num);
948 fprintf(stderr, " (%d bytes)", len);
949 if (outlevel == O_VERBOSE)
955 /* read the message and ship it to the output sink */
956 ok = gen_readmsg(sockfp,
960 vtalarm(ctl->timeout);
964 /* tell the server we got it OK and resynchronize */
966 (protocol->trail)(sockfp, ctl, num);
970 * At this point in flow of control, either we've bombed
971 * on a protocol error or had delivery refused by the SMTP
972 * server (unlikely -- I've never seen it) or we've seen
973 * `accepted for delivery' and the message is shipped.
974 * It's safe to mark the message seen and delete it on the
978 /* maybe we delete this message now? */
980 && (fetch_it ? !ctl->keep : ctl->flush))
983 if (outlevel > O_SILENT)
984 fprintf(stderr, " flushed\n");
985 ok = (protocol->delete)(sockfp, ctl, num);
986 vtalarm(ctl->timeout);
989 delete_uid(&ctl->newsaved, num);
991 else if (outlevel > O_SILENT)
992 fprintf(stderr, " not flushed\n");
995 /* remove all messages flagged for deletion */
996 if (protocol->expunge_cmd && deletions > 0)
998 ok = gen_transact(sockfp, protocol->expunge_cmd);
1003 ok = gen_transact(sockfp, protocol->exit_cmd);
1010 ok = gen_transact(sockfp, protocol->exit_cmd);
1018 if (ok != 0 && ok != PS_SOCKET)
1020 gen_transact(sockfp, protocol->exit_cmd);
1028 fputs("fetchmail: socket", stderr);
1031 fputs("fetchmail: authorization", stderr);
1034 fputs("fetchmail: missing or bad RFC822 header", stderr);
1037 fputs("fetchmail: MDA", stderr);
1040 fputs("fetchmail: client/server synchronization", stderr);
1043 fputs("fetchmail: client/server protocol", stderr);
1046 fputs("fetchmail: SMTP transaction", stderr);
1049 fputs("fetchmail: undefined", stderr);
1052 if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX || ok==PS_IOERR
1053 || ok==PS_ERROR || ok==PS_PROTOCOL || ok==PS_SMTP)
1054 fprintf(stderr, " error while talking to %s\n", ctl->servername);
1057 signal(SIGVTALRM, sigsave);
1061 #if defined(HAVE_STDARG_H)
1062 void gen_send(FILE *sockfp, char *fmt, ... )
1063 /* assemble command in printf(3) style and send to the server */
1066 void gen_send(sockfp, fmt, va_alist)
1067 /* assemble command in printf(3) style and send to the server */
1068 FILE *sockfp; /* socket to which server is connected */
1069 const char *fmt; /* printf-style format */
1073 char buf [POPBUFSIZE+1];
1076 if (protocol->tagged)
1077 (void) sprintf(buf, "%s ", GENSYM);
1081 #if defined(HAVE_STDARG_H)
1086 vsprintf(buf + strlen(buf), fmt, ap);
1089 strcat(buf, "\r\n");
1090 SockWrite(buf, strlen(buf), sockfp);
1092 if (outlevel == O_VERBOSE)
1096 if (shroud && (cp = strstr(buf, shroud)))
1097 memset(cp, '*', strlen(shroud));
1098 fprintf(stderr,"> %s", buf);
1102 #if defined(HAVE_STDARG_H)
1103 int gen_transact(FILE *sockfp, char *fmt, ... )
1104 /* assemble command in printf(3) style, send to server, accept a response */
1107 int gen_transact(sockfp, fmt, va_alist)
1108 /* assemble command in printf(3) style, send to server, accept a response */
1109 FILE *sockfp; /* socket to which server is connected */
1110 const char *fmt; /* printf-style format */
1115 char buf [POPBUFSIZE+1];
1118 if (protocol->tagged)
1119 (void) sprintf(buf, "%s ", GENSYM);
1123 #if defined(HAVE_STDARG_H)
1128 vsprintf(buf + strlen(buf), fmt, ap);
1131 strcat(buf, "\r\n");
1132 SockWrite(buf, strlen(buf), sockfp);
1133 if (outlevel == O_VERBOSE)
1137 if (shroud && (cp = strstr(buf, shroud)))
1138 memset(cp, '*', strlen(shroud));
1139 fprintf(stderr,"> %s", buf);
1142 /* we presume this does its own response echoing */
1143 ok = (protocol->parse_response)(sockfp, buf);
1149 /* driver.c ends here */