]> Pileus Git - ~andy/fetchmail/blob - driver.c
Avoid that core-dump!
[~andy/fetchmail] / driver.c
1 /*
2  * driver.c -- generic driver for mail fetch method protocols
3  *
4  * Copyright 1996 by Eric S. Raymond
5  * All rights reserved.
6  * For license terms, see the file COPYING in this directory.
7  */
8
9 #include  <config.h>
10 #include  <stdio.h>
11 #include  <setjmp.h>
12 #include  <errno.h>
13 #include  <ctype.h>
14 #include  <string.h>
15 #if defined(STDC_HEADERS)
16 #include  <stdlib.h>
17 #endif
18 #if defined(HAVE_UNISTD_H)
19 #include <unistd.h>
20 #endif
21 #if defined(HAVE_STDARG_H)
22 #include  <stdarg.h>
23 #else
24 #include  <varargs.h>
25 #endif
26 #if defined(HAVE_ALLOCA_H)
27 #include <alloca.h>
28 #endif
29 #include  <sys/time.h>
30 #include  <signal.h>
31
32 #ifdef HAVE_GETHOSTBYNAME
33 #include <netdb.h>
34 #include "mx.h"
35 #endif /* HAVE_GETHOSTBYNAME */
36
37 #ifdef KERBEROS_V4
38 #include <krb.h>
39 #include <des.h>
40 #include <netinet/in.h>
41 #include <netdb.h>
42 #endif /* KERBEROS_V4 */
43 #include  "socket.h"
44 #include  "fetchmail.h"
45 #include  "socket.h"
46 #include  "smtp.h"
47
48 /* BSD portability hack...I know, this is an ugly place to put it */
49 #if !defined(SIGCHLD) && defined(SIGCLD)
50 #define SIGCHLD SIGCLD
51 #endif
52
53 #define SMTP_PORT       25      /* standard SMTP service port */
54
55 extern char *strstr();  /* needed on sysV68 R3V7.1. */
56
57 int batchlimit;         /* how often to tear down the delivery connection */
58 int fetchlimit;         /* how often to tear down the server connection */
59 int batchcount;         /* count of messages sent in current batch */
60 int peek_capable;       /* can we peek for better error recovery? */
61
62 static const struct method *protocol;
63 static jmp_buf  restart;
64
65 char tag[TAGLEN];
66 static int tagnum;
67 #define GENSYM  (sprintf(tag, "a%04d", ++tagnum), tag)
68
69 static char *shroud;    /* string to shroud in debug output, if  non-NULL */
70 static int mytimeout;   /* value of nonreponse timeout */
71
72 static void vtalarm(int timeleft)
73 /* reset the nonresponse-timeout */
74 {
75     struct itimerval ntimeout;
76
77     ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
78     ntimeout.it_value.tv_sec  = timeleft;
79     ntimeout.it_value.tv_usec = 0;
80     setitimer(ITIMER_VIRTUAL, &ntimeout, (struct itimerval *)NULL);
81 }
82
83 static void vtalarm_handler (int signal)
84 /* handle server-timeout SIGVTALARM signal */
85 {
86     longjmp(restart, 1);
87 }
88
89 #ifdef HAVE_RES_SEARCH
90 #define MX_RETRIES      3
91
92 static int is_host_alias(const char *name, struct query *ctl)
93 /* determine whether name is a DNS alias of the hostname */
94 {
95     struct hostent      *he;
96     struct mxentry      *mxp, *mxrecords;
97
98     /*
99      * The first two checks are optimizations that will catch a good
100      * many cases.  (1) check against the hostname the user
101      * specified.  Odds are good this will either be the mailserver's
102      * FQDN or a suffix of it with the mailserver's domain's default
103      * host name omitted.  Then check the rest of the `also known as'
104      * cache accumulated by previous DNS checks.  This cache is primed
105      * by the aka list option.
106      *
107      * (2) check against the mailserver's FQDN, in case
108      * it's not the same as the declared hostname.
109      *
110      * Either of these on a mail address is definitive.  Only if the
111      * name doesn't match either is it time to call the bind library.
112      * If this happens odds are good we're looking at an MX name.
113      */
114     if (str_in_list(&ctl->server.lead_server->names, name))
115         return(TRUE);
116     else if (strcmp(name, ctl->server.canonical_name) == 0)
117         return(TRUE);
118     else if (ctl->server.no_dns)
119         return(FALSE);
120
121     /*
122      * We know DNS service was up at the beginning of this poll cycle.
123      * If it's down, our nameserver has crashed.  We don't want to try
124      * delivering the current message or anything else from this
125      * mailbox until it's back up.
126      */
127     else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
128     {
129         if (strcmp(ctl->server.canonical_name, he->h_name) == 0)
130             goto match;
131         else
132             return(FALSE);
133     }
134     else
135         switch (h_errno)
136         {
137         case HOST_NOT_FOUND:    /* specified host is unknown */
138         case NO_ADDRESS:        /* valid, but does not have an IP address */
139             break;
140
141         case NO_RECOVERY:       /* non-recoverable name server error */
142         case TRY_AGAIN:         /* temporary error on authoritative server */
143         default:
144             if (outlevel != O_SILENT)
145                 putchar('\n');  /* terminate the progress message */
146             error(0, 0,
147                 "nameserver failure while looking for `%s' during poll of %s.",
148                 name, ctl->server.names->id);
149             ctl->errcount++;
150             longjmp(restart, 2);        /* try again next poll cycle */
151             break;
152         }
153
154     /*
155      * We're only here if DNS was OK but the gethostbyname() failed
156      * with a HOST_NOT_FOUND or NO_ADDRESS error.
157      * Search for a name match on MX records pointing to the server.
158      */
159     h_errno = 0;
160     if ((mxrecords = getmxrecords(name)) == (struct mxentry *)NULL)
161     {
162         switch (h_errno)
163         {
164         case HOST_NOT_FOUND:    /* specified host is unknown */
165         case NO_ADDRESS:        /* valid, but does not have an IP address */
166             return(FALSE);
167             break;
168
169         case NO_RECOVERY:       /* non-recoverable name server error */
170         case TRY_AGAIN:         /* temporary error on authoritative server */
171         default:
172             error(0, 0,
173                 "nameserver failure while looking for `%s' during poll of %s.",
174                 name, ctl->server.names->id);
175             ctl->errcount++;
176             longjmp(restart, 2);        /* try again next poll cycle */
177             break;
178         }
179     }
180     else
181     {
182         for (mxp = mxrecords; mxp->name; mxp++)
183             if (strcmp(ctl->server.canonical_name, mxp->name) == 0)
184                 goto match;
185         return(FALSE);
186     match:;
187     }
188
189     /* add this name to relevant server's `also known as' list */
190     save_str(&ctl->server.lead_server->names, -1, name);
191     return(TRUE);
192 }
193
194 static void map_name(name, ctl, xmit_names)
195 /* add given name to xmit_names if it matches declared localnames */
196 const char *name;               /* name to map */
197 struct query *ctl;              /* list of permissible aliases */
198 struct idlist **xmit_names;     /* list of recipient names parsed out */
199 {
200     const char  *lname;
201
202     lname = idpair_find(&ctl->localnames, name);
203     if (!lname && ctl->wildcard)
204         lname = name;
205
206     if (lname != (char *)NULL)
207     {
208         if (outlevel == O_VERBOSE)
209             error(0, 0, "mapped %s to local %s", name, lname);
210         save_str(xmit_names, -1, lname);
211     }
212 }
213
214 void find_server_names(hdr, ctl, xmit_names)
215 /* parse names out of a RFC822 header into an ID list */
216 const char *hdr;                /* RFC822 header in question */
217 struct query *ctl;              /* list of permissible aliases */
218 struct idlist **xmit_names;     /* list of recipient names parsed out */
219 {
220     if (hdr == (char *)NULL)
221         return;
222     else
223     {
224         char    *cp, *lname;
225
226         if ((cp = nxtaddr(hdr)) != (char *)NULL)
227             do {
228                 char    *atsign;
229
230                 if ((atsign = strchr(cp, '@')))
231                 {
232                     struct idlist       *idp;
233
234                     /*
235                      * Does a trailing segment of the hostname match something
236                      * on the localdomains list?  If so, save the whole name
237                      * and keep going.
238                      */
239                     for (idp = ctl->server.localdomains; idp; idp = idp->next)
240                     {
241                         char    *rhs;
242
243                         rhs = atsign + 1 + (strlen(atsign) - strlen(idp->id));
244                         if ((rhs[-1] == '.' || rhs[-1] == '@')
245                                         && strcmp(rhs, idp->id) == 0)
246                         {
247                             if (outlevel == O_VERBOSE)
248                                 error(0, 0, "passed through %s matching %s", 
249                                       cp, idp->id);
250                             save_str(xmit_names, -1, cp);
251                             continue;
252                         }
253                     }
254
255                     /*
256                      * Check to see if the right-hand part is an alias
257                      * or MX equivalent of the mailserver.  If it's
258                      * not, skip this name.  If it is, we'll keep
259                      * going and try to find a mapping to a client name.
260                      */
261                     if (!is_host_alias(atsign+1, ctl))
262                         continue;
263                     atsign[0] = '\0';
264                 }
265
266                 map_name(cp, ctl, xmit_names);
267             } while
268                 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
269     }
270 }
271
272 char *parse_received(struct query *ctl, char *bufp)
273 /* try to extract */
274 {
275     char *ok;
276     static char rbuf[HOSTLEN + USERNAMELEN + 4]; 
277
278     /*
279      * Try to extract the real envelope addressee.  We look here
280      * specifically for the mailserver's Received line.
281      * Note: this will only work for sendmail, or an MTA that
282      * shares sendmail's convention for embedding the envelope
283      * address in the Received line.  Sendmail itself only
284      * does this when the mail has a single recipient.
285      */
286     if ((ok = strstr(bufp, "by ")) == (char *)NULL)
287         ok = (char *)NULL;
288     else
289     {
290         char    *sp, *tp;
291
292         /* extract space-delimited token after "by " */
293         for (sp = ok + 3; isspace(*sp); sp++)
294             continue;
295         tp = rbuf;
296         for (; !isspace(*sp); sp++)
297             *tp++ = *sp;
298         *tp = '\0';
299
300         /*
301          * If it's a DNS name of the mail server, look for the
302          * recipient name after a following "for".  Otherwise
303          * punt.
304          */
305         if (is_host_alias(rbuf, ctl))
306             ok = strstr(sp, "for ");
307         else
308             ok = (char *)NULL;
309     }
310
311     if (ok != 0)
312     {
313         char    *sp, *tp;
314
315         tp = rbuf;
316         sp = ok + 4;
317         if (*sp == '<')
318             sp++;
319         while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
320             if (!isspace(*sp))
321                 *tp++ = *sp++;
322             else
323             {
324                 /* uh oh -- whitespace here can't be right! */
325                 ok = (char *)NULL;
326                 break;
327             }
328         *tp = '\0';
329     }
330
331     if (!ok)
332         return(NULL);
333     else
334     {
335         if (outlevel == O_VERBOSE)
336             error(0, 0, "found Received address `%s'", rbuf);
337         return(rbuf);
338     }
339 }
340 #endif /* HAVE_RES_SEARCH */
341
342 static FILE *smtp_open(struct query *ctl)
343 /* try to open a socket to the appropriate SMTP server for this query */ 
344 {
345     struct query *lead;
346
347     lead = ctl->lead_smtp; /* go to the SMTP leader for this query */
348
349     /* maybe it's time to close the socket in order to force delivery */
350     if (batchlimit && lead->smtp_sockfp && batchcount++ == batchlimit)
351     {
352         fclose(lead->smtp_sockfp);
353         lead->smtp_sockfp = (FILE *)NULL;
354         batchcount = 0;
355     }
356
357     /* 
358      * RFC 1123 requires that the domain name in HELO address is a
359      * "valid principal domain name" for the client host.  We
360      * violate this with malice aforethought in order to make the
361      * Received headers and logging look right.
362      *
363      * In fact this code relies on the RFC1123 requirement that the
364      * SMTP listener must accept messages even if verification of the
365      * HELO name fails (RFC1123 section 5.2.5, paragraph 2).
366      */
367
368     /* if no socket to this host is already set up, try to open ESMTP */
369     if (lead->smtp_sockfp == (FILE *)NULL)
370     {
371         if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL)
372             return((FILE *)NULL);
373         else if (SMTP_ok(lead->smtp_sockfp) != SM_OK
374                  || SMTP_ehlo(lead->smtp_sockfp, 
375                               ctl->server.names->id,
376                               &lead->server.esmtp_options) != SM_OK)
377         {
378             /*
379              * RFC 1869 warns that some listeners hang up on a failed EHLO,
380              * so it's safest not to assume the socket will still be good.
381              */
382             fclose(lead->smtp_sockfp);
383             lead->smtp_sockfp = (FILE *)NULL;
384         }
385     }
386
387     /* if opening for ESMTP failed, try SMTP */
388     if (lead->smtp_sockfp == (FILE *)NULL)
389     {
390         if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL)
391             return((FILE *)NULL);
392         else if (SMTP_ok(lead->smtp_sockfp) != SM_OK
393                  || SMTP_helo(lead->smtp_sockfp, ctl->server.names->id) != SM_OK)
394         {
395             fclose(lead->smtp_sockfp);
396             lead->smtp_sockfp = (FILE *)NULL;
397         }
398     }
399
400     return(lead->smtp_sockfp);
401 }
402
403 static int gen_readmsg(sockfp, len, delimited, ctl, realname)
404 /* read message content and ship to SMTP or MDA */
405 FILE *sockfp;           /* to which the server is connected */
406 long len;               /* length of message */
407 int delimited;          /* does the protocol use a message delimiter? */
408 struct query *ctl;      /* query control record */
409 char *realname;         /* real name of host */
410 {
411     char buf [MSGBUFSIZE+1]; 
412     int from_offs, to_offs, cc_offs, bcc_offs, ctt_offs, env_offs;
413     char *headers, *received_for;
414     int n, oldlen, ch, sizeticker, delete_ok;
415     FILE *sinkfp;
416     RETSIGTYPE (*sigchld)();
417 #ifdef HAVE_GETHOSTBYNAME
418     char rbuf[HOSTLEN + USERNAMELEN + 4]; 
419 #endif /* HAVE_GETHOSTBYNAME */
420     char                *cp;
421     struct idlist       *idp, *xmit_names;
422     int                 good_addresses, bad_addresses;
423 #ifdef HAVE_RES_SEARCH
424     int                 no_local_matches = FALSE;
425 #endif /* HAVE_RES_SEARCH */
426
427     sizeticker = 0;
428     delete_ok = TRUE;
429
430     /* read message headers */
431     headers = received_for = NULL;
432     from_offs = to_offs = cc_offs = bcc_offs = ctt_offs = env_offs = -1;
433     oldlen = 0;
434     for (;;)
435     {
436         char *bufp, *line;
437
438         line = xmalloc(sizeof(buf));
439         line[0] = '\0';
440         do {
441             if (!SockGets(buf, sizeof(buf)-1, sockfp))
442                 return(PS_SOCKET);
443             vtalarm(ctl->server.timeout);
444             /* leave extra room for reply_hack to play with */
445             line = realloc(line, strlen(line) + strlen(buf) + HOSTLEN + 1);
446             strcat(line, buf);
447         } while
448             /* we may need to grab RFC822 continuations */
449             ((ch = SockPeek(sockfp)) == ' ' || ch == '\t');
450
451         /* write the message size dots */
452         if ((n = strlen(line)) > 0)
453         {
454             sizeticker += n;
455             while (sizeticker >= SIZETICKER)
456             {
457                 if (outlevel > O_SILENT)
458                     error_build(".");
459                 sizeticker -= SIZETICKER;
460             }
461         }
462         len -= n;
463
464         /* check for end of headers; don't save terminating line */
465         if (line[0] == '\r' && line[1] == '\n')
466         {
467             free(line);
468             break;
469         }
470      
471         if (!ctl->no_rewrite)
472             reply_hack(line, realname);
473
474         bufp = line;
475         if (!headers)
476         {
477             oldlen = strlen(bufp);
478             headers = xmalloc(oldlen + 1);
479             (void) strcpy(headers, bufp);
480             bufp = headers;
481         }
482         else
483         {
484             int newlen;
485
486             newlen = oldlen + strlen(bufp);
487             headers = realloc(headers, newlen + 1);
488             if (headers == NULL)
489                 return(PS_IOERR);
490             strcpy(headers + oldlen, bufp);
491             bufp = headers + oldlen;
492             oldlen = newlen;
493         }
494         free(line);
495
496         if (from_offs == -1 && !strncasecmp("From:", bufp, 5))
497             from_offs = (bufp - headers);
498         else if (from_offs == -1 && !strncasecmp("Resent-From:", bufp, 12))
499             from_offs = (bufp - headers);
500         else if (from_offs == -1 && !strncasecmp("Apparently-From:", bufp, 16))
501             from_offs = (bufp - headers);
502
503         else if (!strncasecmp("To:", bufp, 3))
504             to_offs = (bufp - headers);
505
506         else if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
507                                                 bufp,
508                                                 strlen(ctl->server.envelope)))
509             env_offs = (bufp - headers);
510
511         else if (!strncasecmp("Cc:", bufp, 3))
512             cc_offs = (bufp - headers);
513
514         else if (!strncasecmp("Bcc:", bufp, 4))
515             bcc_offs = (bufp - headers);
516
517         else if (!strncasecmp("Content-Transfer-Encoding:", bufp, 26))
518             ctt_offs = (bufp - headers);
519
520 #ifdef HAVE_RES_SEARCH
521         else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9))
522             received_for = parse_received(ctl, bufp);
523 #endif /* HAVE_RES_SEARCH */
524     }
525
526     /*
527      * We can now process message headers before reading the text.
528      * In fact we have to, as this will tell us where to forward to.
529      */
530
531     /* cons up a list of local recipients */
532     xmit_names = (struct idlist *)NULL;
533     bad_addresses = good_addresses = 0;
534 #ifdef HAVE_RES_SEARCH
535     /* is this a multidrop box? */
536     if (MULTIDROP(ctl))
537     {
538         if (env_offs > -1)          /* We have the actual envelope addressee */
539             find_server_names(headers + env_offs, ctl, &xmit_names);
540         else if (received_for)
541             /*
542              * We have the Received for addressee.  
543              * It has to be a mailserver address, or we
544              * wouldn't have got here.
545              */
546             map_name(received_for, ctl, &xmit_names);
547         else
548         {
549             /*
550              * We haven't extracted the envelope address.
551              * So check all the header addresses.
552              */
553             if (to_offs > -1)
554                 find_server_names(headers + to_offs,  ctl, &xmit_names);
555             if (cc_offs > -1)
556                 find_server_names(headers + cc_offs,  ctl, &xmit_names);
557             if (bcc_offs > -1)
558                 find_server_names(headers + bcc_offs, ctl, &xmit_names);
559         }
560         if (!xmit_names)
561         {
562             no_local_matches = TRUE;
563             save_str(&xmit_names, -1, user);
564             if (outlevel == O_VERBOSE)
565                 error(0, 0, 
566                       "no local matches, forwarding to %s",
567                       user);
568         }
569     }
570     else        /* it's a single-drop box, use first localname */
571 #endif /* HAVE_RES_SEARCH */
572         save_str(&xmit_names, -1, ctl->localnames->id);
573
574     /* time to address the message */
575     if (ctl->mda)       /* we have a declared MDA */
576     {
577         int     length = 0;
578         char    *names, *cmd;
579
580         /*
581          * We go through this in order to be able to handle very
582          * long lists of users and (re)implement %s.
583          */
584         for (idp = xmit_names; idp; idp = idp->next)
585             length += (strlen(idp->id) + 1);
586         names = (char *)alloca(length);
587         names[0] = '\0';
588         for (idp = xmit_names; idp; idp = idp->next)
589         {
590             strcat(names, idp->id);
591             strcat(names, " ");
592         }
593         cmd = (char *)alloca(strlen(ctl->mda) + length);
594         sprintf(cmd, ctl->mda, names);
595         if (outlevel == O_VERBOSE)
596             error(0, 0, "about to deliver with: %s", cmd);
597
598 #ifdef HAVE_SETEUID
599         /*
600          * Arrange to run with user's permissions if we're root.
601          * This will initialize the ownership of any files the
602          * MDA creates properly.  (The seteuid call is available
603          * under all BSDs and Linux)
604          */
605         seteuid(ctl->uid);
606 #endif /* HAVE_SETEUID */
607
608         sinkfp = popen(cmd, "w");
609
610 #ifdef HAVE_SETEUID
611         /* this will fail quietly if we didn't start as root */
612         seteuid(0);
613 #endif /* HAVE_SETEUID */
614
615         if (!sinkfp)
616         {
617             error(0, 0, "MDA open failed");
618             return(PS_IOERR);
619         }
620
621         sigchld = signal(SIGCHLD, SIG_DFL);
622     }
623     else
624     {
625         char    *ap, *ctt, options[MSGBUFSIZE];
626         int     smtperr;
627
628         /* build a connection to the SMTP listener */
629         if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL))
630         {
631             free_str_list(&xmit_names);
632             error(0, 0, "SMTP connect failed");
633             return(PS_SMTP);
634         }
635
636         /*
637          * Compute ESMTP options.  It's a kluge to use nxtaddr()
638          * here because the contents of the Content-Transfer-Encoding
639          * headers isn't semantically an address.  But it has the
640          * desired tokenizing effect.
641          */
642         options[0] = '\0';
643         if ((ctl->server.esmtp_options & ESMTP_8BITMIME)
644             && (ctt_offs >= 0)
645             && (ctt = nxtaddr(headers + ctt_offs)))
646             if (!strcasecmp(ctt,"7BIT"))
647                 sprintf(options, " BODY=7BIT", ctt);
648             else if (!strcasecmp(ctt,"8BIT"))
649                 sprintf(options, " BODY=8BITMIME", ctt);
650         if ((ctl->server.esmtp_options & ESMTP_SIZE) && !delimited)
651             sprintf(options + strlen(options), " SIZE=%d", len);
652
653         /*
654          * Try to get the SMTP listener to take the header
655          * From address as MAIL FROM (this makes the logging
656          * nicer).  If it won't, fall back on the calling-user
657          * ID.  This won't affect replies, which use the header
658          * From address anyway.
659          *
660          * RFC 1123 requires that the domain name part of the
661          * MAIL FROM address be "canonicalized", that is a
662          * FQDN or MX but not a CNAME.  We'll assume the From
663          * header is already in this form here (it certainly
664          * is if rewrite is on).  RFC 1123 is silent on whether
665          * a nonexistent hostname part is considered canonical.
666          *
667          * This is a potential problem if the MTAs further
668          * upstream didn't pass canonicalized From lines, *and*
669          * the local SMTP listener insists on them.
670          */
671         if (from_offs == -1 || !(ap = nxtaddr(headers + from_offs)))
672             ap = user;
673         if (SMTP_from(sinkfp, ap, options) != SM_OK)
674         {
675             int smtperr = atoi(smtp_response);
676
677             if (smtperr >= 400)
678                 error(0, 0, "SMTP error: %s", smtp_response);
679
680             /*
681              * There'a one problem with this flow of control;
682              * there's no way to avoid reading the whole message
683              * off the server, even if the MAIL FROM response 
684              * tells us that it's just to be discarded.  We could
685              * fix this under IMAP by reading headers first, then
686              * trying to issue the MAIL FROM, and *then* reading
687              * the body...but POP3 can't do this.
688              */
689
690             switch (smtperr)
691             {
692             case 571: /* unsolicited email refused */
693                 /*
694                  * SMTP listener explicitly refuses to deliver
695                  * mail coming from this address, probably due
696                  * to an anti-spam domain exclusion.  Respect
697                  * this.  Don't try to ship the message, and
698                  * don't prevent it from being deleted.
699                  */
700                 sinkfp = (FILE *)NULL;
701                 goto skiptext;
702
703             case 452: /* insufficient system storage */
704                 /*
705                  * Temporary out-of-queue-space condition on the
706                  * ESMTP server.  Don't try to ship the message, 
707                  * and suppress deletion so it can be retried on
708                  * a future retrieval cycle.
709                  */
710                 delete_ok = FALSE;
711                 sinkfp = (FILE *)NULL;
712                 SMTP_rset(sockfp);      /* required by RFC1870 */
713                 goto skiptext;
714
715             case 552: /* message exceeds fixed maximum message size */
716                 /*
717                  * Permanent no-go condition on the
718                  * ESMTP server.  Don't try to ship the message, 
719                  * and allow it to be deleted.
720                  */
721                 sinkfp = (FILE *)NULL;
722                 SMTP_rset(sockfp);      /* required by RFC1870 */
723                 goto skiptext;
724
725             default:    /* retry with invoking user's address */
726                 if (SMTP_from(sinkfp, user, options) != SM_OK)
727                 {
728                     error(0,0,"SMTP error: %s", smtp_response);
729                     return(PS_SMTP);    /* should never happen */
730                 }
731             }
732         }
733
734         /*
735          * Now list the recipient addressees
736          *
737          * RFC 1123 requires that the domain name part of the
738          * RCPT TO address be "canonicalized", that is a FQDN
739          * or MX but not a CNAME.  RFC1123 doesn't say whether
740          * the FQDN part can be null (as it frequently will be
741          * here), but it's hard to see how this could cause a
742          * problem.
743          */
744         for (idp = xmit_names; idp; idp = idp->next)
745             if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
746                 good_addresses++;
747             else
748             {
749                 bad_addresses++;
750                 idp->val.num = 0;
751                 error(0, 0, 
752                       "SMTP listener doesn't like recipient address `%s'", idp->id);
753             }
754         if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK)
755         {
756             error(0, 0, 
757                   "can't even send to calling user!");
758             return(PS_SMTP);
759         }
760
761         /* tell it we're ready to send data */
762         SMTP_data(sinkfp);
763
764     skiptext:;
765     }
766
767     /* write all the headers */
768     if (sinkfp)
769     {
770         if (ctl->mda)
771         {
772             char        *sp, *tp;
773
774             for (sp = tp = headers; *sp; sp++)
775                 if (*sp != '\r')
776                     *tp++ =  *sp;
777             *tp = '\0';
778
779             n = fwrite(headers, 1, oldlen, sinkfp);
780         }
781         else
782             n = SockWrite(headers, 1, oldlen, sinkfp);
783
784         if (n < 0)
785         {
786             free(headers);
787             headers = NULL;
788             error(0, errno, "writing RFC822 headers");
789             if (ctl->mda)
790             {
791                 pclose(sinkfp);
792                 signal(SIGCHLD, sigchld);
793             }
794             return(PS_IOERR);
795         }
796         else if (outlevel == O_VERBOSE)
797             fputs("#", stderr);
798     }
799     free(headers);
800     headers = NULL;
801
802     /* write error notifications */
803 #ifdef HAVE_RES_SEARCH
804     if (no_local_matches || bad_addresses)
805 #else
806     if (bad_addresses)
807 #endif /* HAVE_RES_SEARCH */
808     {
809         int     errlen = 0;
810         char    errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
811
812         errmsg = errhd;
813         (void) strcpy(errhd, "X-Fetchmail-Warning: ");
814 #ifdef HAVE_RES_SEARCH
815         if (no_local_matches)
816         {
817             strcat(errhd, "no recipient addresses matched declared local names");
818             if (bad_addresses)
819                 strcat(errhd, "; ");
820         }
821 #endif /* HAVE_RES_SEARCH */
822
823         if (bad_addresses)
824         {
825             strcat(errhd, "SMTP listener rejected local recipient addresses: ");
826             errlen = strlen(errhd);
827             for (idp = xmit_names; idp; idp = idp->next)
828                 if (!idp->val.num)
829                     errlen += strlen(idp->id) + 2;
830
831             errmsg = alloca(errlen+3);
832             (void) strcpy(errmsg, errhd);
833             for (idp = xmit_names; idp; idp = idp->next)
834                 if (!idp->val.num)
835                 {
836                     strcat(errmsg, idp->id);
837                     if (idp->next)
838                         strcat(errmsg, ", ");
839                 }
840         }
841
842         strcat(errmsg, "\n");
843
844         /* ship out the error line */
845         if (sinkfp)
846         {
847             if (ctl->mda)
848             {
849                 char    *sp, *tp;
850
851                 for (sp = tp = errmsg; *sp; sp++)
852                     if (*sp != '\r')
853                         *tp++ =  *sp;
854                 *tp = '\0';
855                 fwrite(errmsg, 1, strlen(errmsg), sinkfp);
856             }
857             else
858                 SockWrite(errmsg, 1, strlen(errmsg), sinkfp);
859         }
860     }
861
862     free_str_list(&xmit_names);
863
864     /* issue the delimiter line */
865     if (sinkfp)
866     {
867         if (ctl->mda)
868             fputc('\n', sinkfp);
869         else
870             SockWrite("\r\n", 1, 2, sinkfp);
871     }
872
873     /*
874      *  Body processing starts here
875      */
876
877     /* pass through the text lines */
878     while (delimited || len > 0)
879     {
880         if (!SockGets(buf, sizeof(buf)-1, sockfp))
881             return(PS_SOCKET);
882         vtalarm(ctl->server.timeout);
883
884         /* write the message size dots */
885         if ((n = strlen(buf)) > 0)
886         {
887             sizeticker += n;
888             while (sizeticker >= SIZETICKER)
889             {
890                 if (outlevel > O_SILENT)
891                     error_build(".");
892                 sizeticker -= SIZETICKER;
893             }
894         }
895         len -= n;
896
897         /* check for end of message */
898         if (delimited && *buf == '.')
899             if (buf[1] == '\r' && buf[2] == '\n')
900                 break;
901
902         /* ship out the text line */
903         if (sinkfp)
904         {
905             /* SMTP byte-stuffing */
906             if (*buf == '.')
907                 if (ctl->mda)
908                     fputs(".", sinkfp);
909                 else
910                     SockWrite(buf, 1, 1, sinkfp);
911
912             if (ctl->mda)
913             {
914                 char    *sp, *tp;
915
916                 for (sp = tp = buf; *sp; sp++)
917                     if (*sp != '\r')
918                         *tp++ =  *sp;
919                 *tp = '\0';
920
921                 n = fwrite(buf, 1, strlen(buf), sinkfp);
922             }
923             else if (sinkfp)
924                 n = SockWrite(buf, 1, strlen(buf), sinkfp);
925
926             if (n < 0)
927             {
928                 error(0, errno, "writing message text");
929                 if (ctl->mda)
930                 {
931                     pclose(sinkfp);
932                     signal(SIGCHLD, sigchld);
933                 }
934                 return(PS_IOERR);
935             }
936             else if (outlevel == O_VERBOSE)
937                 fputc('*', stderr);
938         }
939     }
940
941     /*
942      * End-of-message processing starts here
943      */
944
945     if (outlevel == O_VERBOSE)
946         fputc('\n', stderr);
947
948     if (ctl->mda)
949     {
950         int rc;
951
952         /* close the delivery pipe, we'll reopen before next message */
953         rc = pclose(sinkfp);
954         signal(SIGCHLD, sigchld);
955         if (rc)
956         {
957             error(0, 0, "MDA exited abnormally or returned nonzero status");
958             return(PS_IOERR);
959         }
960     }
961     else if (sinkfp)
962     {
963         /* write message terminator */
964         if (SMTP_eom(sinkfp) != SM_OK)
965         {
966             error(0, 0, "SMTP listener refused delivery");
967             return(PS_TRANSIENT);
968         }
969     }
970
971     return(delete_ok ? PS_SUCCESS : PS_TRANSIENT);
972 }
973
974 #ifdef KERBEROS_V4
975 int
976 kerberos_auth (socket, canonical) 
977 /* authenticate to the server host using Kerberos V4 */
978 int socket;             /* socket to server host */
979 const char *canonical;  /* server name */
980 {
981     char * host_primary;
982     KTEXT ticket;
983     MSG_DAT msg_data;
984     CREDENTIALS cred;
985     Key_schedule schedule;
986     int rem;
987   
988     ticket = ((KTEXT) (malloc (sizeof (KTEXT_ST))));
989     rem = (krb_sendauth (0L, socket, ticket, "pop",
990                          canonical,
991                          ((char *) (krb_realmofhost (canonical))),
992                          ((unsigned long) 0),
993                          (&msg_data),
994                          (&cred),
995                          (schedule),
996                          ((struct sockaddr_in *) 0),
997                          ((struct sockaddr_in *) 0),
998                          "KPOPV0.1"));
999     free (ticket);
1000     if (rem != KSUCCESS)
1001     {
1002         error(0, 0, "kerberos error %s", (krb_get_err_text (rem)));
1003         return (PS_ERROR);
1004     }
1005     return (0);
1006 }
1007 #endif /* KERBEROS_V4 */
1008
1009 int do_protocol(ctl, proto)
1010 /* retrieve messages from server using given protocol method table */
1011 struct query *ctl;              /* parsed options with merged-in defaults */
1012 const struct method *proto;     /* protocol method table */
1013 {
1014     int ok, js, pst;
1015     char *msg, *sp, *cp, realname[HOSTLEN];
1016     void (*sigsave)();
1017
1018 #ifndef KERBEROS_V4
1019     if (ctl->server.authenticate == A_KERBEROS)
1020     {
1021         error(0, 0, "Kerberos support not linked.");
1022         return(PS_ERROR);
1023     }
1024 #endif /* KERBEROS_V4 */
1025
1026     /* lacking methods, there are some options that may fail */
1027     if (!proto->is_old)
1028     {
1029         /* check for unsupported options */
1030         if (ctl->flush) {
1031             error(0, 0,
1032                     "Option --flush is not supported with %s",
1033                     proto->name);
1034             return(PS_SYNTAX);
1035         }
1036         else if (ctl->fetchall) {
1037             error(0, 0,
1038                     "Option --all is not supported with %s",
1039                     proto->name);
1040             return(PS_SYNTAX);
1041         }
1042     }
1043     if (!proto->getsizes && ctl->limit)
1044     {
1045         error(0, 0,
1046                 "Option --limit is not supported with %s",
1047                 proto->name);
1048         return(PS_SYNTAX);
1049     }
1050
1051     protocol = proto;
1052     tagnum = 0;
1053     tag[0] = '\0';      /* nuke any tag hanging out from previous query */
1054     ok = 0;
1055     error_init(poll_interval == 0 && !logfile);
1056
1057     /* set up the server-nonresponse timeout */
1058     sigsave = signal(SIGVTALRM, vtalarm_handler);
1059     vtalarm(mytimeout = ctl->server.timeout);
1060
1061     if ((js = setjmp(restart)) == 1)
1062     {
1063         error(0, 0,
1064                 "timeout after %d seconds waiting for %s.",
1065                 ctl->server.timeout, ctl->server.names->id);
1066         ok = PS_ERROR;
1067     }
1068     else if (js == 2)
1069     {
1070         /* error message printed at point of longjmp */
1071         ok = PS_ERROR;
1072     }
1073     else
1074     {
1075         char buf [POPBUFSIZE+1];
1076         int *msgsizes, len, num, count, new, deletions = 0;
1077         FILE *sockfp; 
1078         /* execute pre-initialization command, if any */
1079         if (ctl->preconnect && (ok = system(ctl->preconnect)))
1080         {
1081             sprintf(buf, "pre-connection command failed with status %d", ok);
1082             error(0, 0, buf);
1083             ok = PS_SYNTAX;
1084             goto closeUp;
1085         }
1086
1087         /* open a socket to the mail server */
1088         if (!(sockfp = SockOpen(ctl->server.names->id,
1089                      ctl->server.port ? ctl->server.port : protocol->port)))
1090         {
1091 #ifndef EHOSTUNREACH
1092 #define EHOSTUNREACH (-1)
1093 #endif
1094             if (errno != EHOSTUNREACH)
1095                 error(0, errno, "connecting to host");
1096             ok = PS_SOCKET;
1097             goto closeUp;
1098         }
1099
1100 #ifdef KERBEROS_V4
1101         if (ctl->authenticate == A_KERBEROS)
1102         {
1103             ok = kerberos_auth(fileno(sockfp), ctl->server.canonical_name);
1104             if (ok != 0)
1105                 goto cleanUp;
1106             vtalarm(ctl->server.timeout);
1107         }
1108 #endif /* KERBEROS_V4 */
1109
1110         /* accept greeting message from mail server */
1111         ok = (protocol->parse_response)(sockfp, buf);
1112         if (ok != 0)
1113             goto cleanUp;
1114         vtalarm(ctl->server.timeout);
1115
1116         /*
1117          * Try to parse the host's actual name out of the greeting
1118          * message.  We do this so that the progress messages will
1119          * make sense even if the connection is indirected through
1120          * ssh. *Do* use this for hacking reply headers, but *don't*
1121          * use it for error logging, as the names in the log should
1122          * correlate directly back to rc file entries.
1123          *
1124          * This assumes that the first space-delimited token found
1125          * that contains at least two dots (with the characters on
1126          * each side of the dot alphanumeric to exclude version
1127          * numbers) is the hostname.  The hostname candidate may not
1128          * contain @ -- if it does it's probably a mailserver
1129          * maintainer's name.  If no such token is found, fall back on
1130          * the .fetchmailrc id.
1131          */
1132         pst = 0;
1133         for (cp = buf; *cp; cp++)
1134         {
1135             switch (pst)
1136             {
1137             case 0:             /* skip to end of current token */
1138                 if (*cp == ' ')
1139                     pst = 1;
1140                 break;
1141
1142             case 1:             /* look for blank-delimited token */
1143                 if (*cp != ' ')
1144                 {
1145                     sp = cp;
1146                     pst = 2;
1147                 }
1148                 break;
1149
1150             case 2:             /* look for first dot */
1151                 if (*cp == '@')
1152                     pst = 0;
1153                 else if (*cp == ' ')
1154                     pst = 1;
1155                 else if (*cp == '.' && isalpha(cp[1]) && isalpha(cp[-1]))
1156                     pst = 3;
1157                 break;
1158
1159             case 3:             /* look for second dot */
1160                 if (*cp == '@')
1161                     pst = 0;
1162                 else if (*cp == ' ')
1163                     pst = 1;
1164                 else if (*cp == '.' && isalpha(cp[1]) && isalpha(cp[-1]))
1165                     pst = 4;
1166                 break;
1167
1168             case 4:             /* look for trailing space */
1169                 if (*cp == '@')
1170                     pst = 0;
1171                 else if (*cp == ' ')
1172                 {
1173                     pst = 5;
1174                     goto done;
1175                 }
1176                 break;
1177             }
1178         }
1179     done:
1180         if (pst == 5)
1181         {
1182             char        *tp = realname;
1183
1184             while (sp < cp)
1185                 *tp++ = *sp++;
1186             *tp = '\0';
1187         }
1188         else
1189             strcpy(realname, ctl->server.names->id);
1190
1191         /* try to get authorized to fetch mail */
1192         shroud = ctl->password;
1193         ok = (protocol->getauth)(sockfp, ctl, buf);
1194         shroud = (char *)NULL;
1195         if (ok == PS_ERROR)
1196             ok = PS_AUTHFAIL;
1197         if (ok != 0)
1198         {
1199             error(0, 0, "Authorization failure on %s@%s", 
1200                   ctl->remotename,
1201                   realname);
1202             goto cleanUp;
1203         }
1204         vtalarm(ctl->server.timeout);
1205
1206         /* compute number of messages and number of new messages waiting */
1207         ok = (protocol->getrange)(sockfp, ctl, &count, &new);
1208         if (ok != 0)
1209             goto cleanUp;
1210         vtalarm(ctl->server.timeout);
1211
1212         /* show user how many messages we downloaded */
1213         if (outlevel > O_SILENT)
1214             if (count == 0)
1215                 error(0, 0, "No mail from %s@%s", 
1216                         ctl->remotename,
1217                         realname);
1218             else
1219             {
1220                 if (new != -1 && (count - new) > 0)
1221                     error(0, 0, "%d message%s (%d seen) from %s@%s.",
1222                                 count, count > 1 ? "s" : "", count-new,
1223                                 ctl->remotename,
1224                                 realname);
1225                 else
1226                     error(0, 0, "%d message%s from %s@%s.", count, count > 1 ? "s" : "",
1227                                 ctl->remotename,
1228                                 realname);
1229             }
1230
1231         /* we may need to get sizes in order to check message limits */
1232         msgsizes = (int *)NULL;
1233         if (!ctl->fetchall && proto->getsizes && ctl->limit)
1234         {
1235             msgsizes = (int *)alloca(sizeof(int) * count);
1236
1237             ok = (proto->getsizes)(sockfp, count, msgsizes);
1238             if (ok != 0)
1239                 goto cleanUp;
1240             vtalarm(ctl->server.timeout);
1241         }
1242
1243         if (check_only)
1244         {
1245             if (new == -1 || ctl->fetchall)
1246                 new = count;
1247             ok = ((new > 0) ? PS_SUCCESS : PS_NOMAIL);
1248             goto cleanUp;
1249         }
1250         else if (count > 0)
1251         {    
1252             /*
1253              * What forces this code is that in POP3 and IMAP2BIS you can't
1254              * fetch a message without having it marked `seen'.  In IMAP4,
1255              * on the other hand, you can (peek_capable is set to convey
1256              * this).
1257              *
1258              * The result of being unable to peek is that if there's
1259              * any kind of transient error (DNS lookup failure, or
1260              * sendmail refusing delivery due to process-table limits)
1261              * the message will be marked "seen" on the server without
1262              * having been delivered.  This is not a big problem if
1263              * fetchmail is running in foreground, because the user
1264              * will see a "skipped" message when it next runs and get
1265              * clued in.
1266              *
1267              * But in daemon mode this leads to the message being silently
1268              * ignored forever.  This is not acceptable.
1269              *
1270              * We compensate for this by checking the error count from the 
1271              * previous pass and forcing all messages to be considered new
1272              * if it's nonzero.
1273              */
1274             int force_retrieval = !peek_capable && (ctl->errcount > 0);
1275
1276             ctl->errcount = 0;
1277
1278             /* read, forward, and delete messages */
1279             for (num = 1; num <= count; num++)
1280             {
1281                 int     toolarge = msgsizes && (msgsizes[num-1] > ctl->limit);
1282                 int     fetch_it = ctl->fetchall ||
1283                     (!toolarge && (force_retrieval || !(protocol->is_old && (protocol->is_old)(sockfp,ctl,num))));
1284                 int     suppress_delete = FALSE;
1285
1286                 /* we may want to reject this message if it's old */
1287                 if (!fetch_it)
1288                 {
1289                     if (outlevel > O_SILENT)
1290                     {
1291                         error_build("skipping message %d", num);
1292                         if (toolarge)
1293                             error_build(" (oversized, %d bytes)", msgsizes[num-1]);
1294                     }
1295                 }
1296                 else
1297                 {
1298                     /* request a message */
1299                     ok = (protocol->fetch)(sockfp, ctl, num, &len);
1300                     if (ok != 0)
1301                         goto cleanUp;
1302                     vtalarm(ctl->server.timeout);
1303
1304                     if (outlevel > O_SILENT)
1305                     {
1306                         error_build("reading message %d", num);
1307                         if (len > 0)
1308                             error_build(" (%d bytes)", len);
1309                         if (outlevel == O_VERBOSE)
1310                             error_complete(0, 0, "");
1311                         else
1312                             error_build(" ");
1313                     }
1314
1315                     /* read the message and ship it to the output sink */
1316                     ok = gen_readmsg(sockfp,
1317                                      len, 
1318                                      protocol->delimited,
1319                                      ctl,
1320                                      realname);
1321                     if (ok == PS_TRANSIENT)
1322                         suppress_delete = TRUE;
1323                     else if (ok)
1324                         goto cleanUp;
1325                     vtalarm(ctl->server.timeout);
1326
1327                     /* tell the server we got it OK and resynchronize */
1328                     if (protocol->trail)
1329                     {
1330                         ok = (protocol->trail)(sockfp, ctl, num);
1331                         if (ok != 0)
1332                             goto cleanUp;
1333                         vtalarm(ctl->server.timeout);
1334                     }
1335                 }
1336
1337                 /*
1338                  * At this point in flow of control, either we've bombed
1339                  * on a protocol error or had delivery refused by the SMTP
1340                  * server (unlikely -- I've never seen it) or we've seen
1341                  * `accepted for delivery' and the message is shipped.
1342                  * It's safe to mark the message seen and delete it on the
1343                  * server now.
1344                  */
1345
1346                 /* maybe we delete this message now? */
1347                 if (protocol->delete
1348                     && !suppress_delete
1349                     && (fetch_it ? !ctl->keep : ctl->flush))
1350                 {
1351                     deletions++;
1352                     if (outlevel > O_SILENT) 
1353                         error_complete(0, 0, " flushed");
1354                     ok = (protocol->delete)(sockfp, ctl, num);
1355                     if (ok != 0)
1356                         goto cleanUp;
1357                     vtalarm(ctl->server.timeout);
1358                     delete_str(&ctl->newsaved, num);
1359                 }
1360                 else if (outlevel > O_SILENT) 
1361                     error_complete(0, 0, " not flushed");
1362
1363                 /* perhaps this as many as we're ready to handle */
1364                 if (ctl->fetchlimit && ctl->fetchlimit <= num)
1365                     break;
1366             }
1367
1368             ok = gen_transact(sockfp, protocol->exit_cmd);
1369             if (ok == 0)
1370                 ok = PS_SUCCESS;
1371             vtalarm(0);
1372             fclose(sockfp);
1373             goto closeUp;
1374         }
1375         else {
1376             ok = gen_transact(sockfp, protocol->exit_cmd);
1377             if (ok == 0)
1378                 ok = PS_NOMAIL;
1379             vtalarm(0);
1380             fclose(sockfp);
1381             goto closeUp;
1382         }
1383
1384     cleanUp:
1385         vtalarm(ctl->server.timeout);
1386         if (ok != 0 && ok != PS_SOCKET)
1387             gen_transact(sockfp, protocol->exit_cmd);
1388         vtalarm(0);
1389         fclose(sockfp);
1390     }
1391
1392     switch (ok)
1393     {
1394     case PS_SOCKET:
1395         msg = "socket";
1396         break;
1397     case PS_AUTHFAIL:
1398         msg = "authorization";
1399         break;
1400     case PS_SYNTAX:
1401         msg = "missing or bad RFC822 header";
1402         break;
1403     case PS_IOERR:
1404         msg = "MDA";
1405         break;
1406     case PS_ERROR:
1407         msg = "client/server synchronization";
1408         break;
1409     case PS_PROTOCOL:
1410         msg = "client/server protocol";
1411         break;
1412     case PS_SMTP:
1413         msg = "SMTP transaction";
1414         break;
1415     case PS_UNDEFINED:
1416         error(0, 0, "undefined");
1417         break;
1418     }
1419     if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX || ok==PS_IOERR
1420                 || ok==PS_ERROR || ok==PS_PROTOCOL || ok==PS_SMTP)
1421         error(0, 0, "%s error while fetching from %s", msg, ctl->server.names->id);
1422
1423 closeUp:
1424     signal(SIGVTALRM, sigsave);
1425     return(ok);
1426 }
1427
1428 #if defined(HAVE_STDARG_H)
1429 void gen_send(FILE *sockfp, char *fmt, ... )
1430 /* assemble command in printf(3) style and send to the server */
1431 #else
1432 void gen_send(sockfp, fmt, va_alist)
1433 /* assemble command in printf(3) style and send to the server */
1434 FILE *sockfp;           /* socket to which server is connected */
1435 const char *fmt;        /* printf-style format */
1436 va_dcl
1437 #endif
1438 {
1439     char buf [POPBUFSIZE+1];
1440     va_list ap;
1441
1442     if (protocol->tagged)
1443         (void) sprintf(buf, "%s ", GENSYM);
1444     else
1445         buf[0] = '\0';
1446
1447 #if defined(HAVE_STDARG_H)
1448     va_start(ap, fmt) ;
1449 #else
1450     va_start(ap);
1451 #endif
1452     vsprintf(buf + strlen(buf), fmt, ap);
1453     va_end(ap);
1454
1455     strcat(buf, "\r\n");
1456     SockWrite(buf, 1, strlen(buf), sockfp);
1457
1458     if (outlevel == O_VERBOSE)
1459     {
1460         char *cp;
1461
1462         if (shroud && (cp = strstr(buf, shroud)))
1463             memset(cp, '*', strlen(shroud));
1464         buf[strlen(buf)-1] = '\0';
1465         error(0, 0, "%s> %s", protocol->name, buf);
1466     }
1467 }
1468
1469 int gen_recv(sockfp, buf, size)
1470 /* get one line of input from the server */
1471 FILE *sockfp;   /* socket to which server is connected */
1472 char *buf;      /* buffer to receive input */
1473 int size;       /* length of buffer */
1474 {
1475     if (!SockGets(buf, size, sockfp))
1476         return(PS_SOCKET);
1477     else
1478     {
1479         if (buf[strlen(buf)-1] == '\n')
1480             buf[strlen(buf)-1] = '\0';
1481         if (buf[strlen(buf)-1] == '\r')
1482             buf[strlen(buf)-1] = '\r';
1483         if (outlevel == O_VERBOSE)
1484             error(0, 0, "%s< %s", protocol->name, buf);
1485         return(PS_SUCCESS);
1486     }
1487 }
1488
1489 #if defined(HAVE_STDARG_H)
1490 int gen_transact(FILE *sockfp, char *fmt, ... )
1491 /* assemble command in printf(3) style, send to server, accept a response */
1492 #else
1493 int gen_transact(sockfp, fmt, va_alist)
1494 /* assemble command in printf(3) style, send to server, accept a response */
1495 FILE *sockfp;           /* socket to which server is connected */
1496 const char *fmt;        /* printf-style format */
1497 va_dcl
1498 #endif
1499 {
1500     int ok;
1501     char buf [POPBUFSIZE+1];
1502     va_list ap;
1503
1504     if (protocol->tagged)
1505         (void) sprintf(buf, "%s ", GENSYM);
1506     else
1507         buf[0] = '\0';
1508
1509 #if defined(HAVE_STDARG_H)
1510     va_start(ap, fmt) ;
1511 #else
1512     va_start(ap);
1513 #endif
1514     vsprintf(buf + strlen(buf), fmt, ap);
1515     va_end(ap);
1516
1517     strcat(buf, "\r\n");
1518     SockWrite(buf, 1, strlen(buf), sockfp);
1519
1520     if (outlevel == O_VERBOSE)
1521     {
1522         char *cp;
1523
1524         if (shroud && (cp = strstr(buf, shroud)))
1525             memset(cp, '*', strlen(shroud));
1526         buf[strlen(buf)-1] = '\0';
1527         error(0, 0, "%s> %s", protocol->name, buf);
1528     }
1529
1530     /* we presume this does its own response echoing */
1531     ok = (protocol->parse_response)(sockfp, buf);
1532     vtalarm(mytimeout);
1533
1534     return(ok);
1535 }
1536
1537 /* driver.c ends here */