]> Pileus Git - ~andy/fetchmail/blob - transact.c
Freeaddrinfo() fix for Uli Zappe's bug.
[~andy/fetchmail] / transact.c
1 /*
2  * transact.c -- transaction primitives for the fetchmail driver loop
3  *
4  * Copyright 2001 by Eric S. Raymond
5  * For license terms, see the file COPYING in this directory.
6  *
7  * 
8  */
9
10 #include  "config.h"
11 #include  <stdio.h>
12 #include  <string.h>
13 #include  <ctype.h>
14 #ifdef HAVE_MEMORY_H
15 #include  <memory.h>
16 #endif /* HAVE_MEMORY_H */
17 #if defined(STDC_HEADERS)
18 #include  <stdlib.h>
19 #endif
20 #if defined(HAVE_UNISTD_H)
21 #include <unistd.h>
22 #endif
23 #if defined(HAVE_STDARG_H)
24 #include  <stdarg.h>
25 #else
26 #include  <varargs.h>
27 #endif
28
29 #ifdef HAVE_NET_SOCKET_H
30 #include <net/socket.h>
31 #endif
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include "md5.h"
35
36 #include "i18n.h"
37 #include "socket.h"
38 #include "fetchmail.h"
39
40 /* global variables: please reinitialize them explicitly for proper
41  * working in daemon mode */
42
43 /* session variables initialized in init_transact() */
44 int suppress_tags = FALSE;      /* emit tags? */
45 char tag[TAGLEN];
46 static int tagnum;
47 #define GENSYM  (sprintf(tag, "A%04d", ++tagnum % TAGMOD), tag)
48 static struct method *protocol;
49 char shroud[PASSWORDLEN*2+3];   /* string to shroud in debug output */
50
51 /* session variables initialized in do_session() */
52 int mytimeout;          /* value of nonreponse timeout */
53
54 /* mail variables initialized in readheaders() */
55 struct msgblk msgblk;
56 static int accept_count, reject_count;
57
58 static void map_name(const char *name, struct query *ctl, struct idlist **xmit_names)
59 /* add given name to xmit_names if it matches declared localnames */
60 /*   name:       name to map */
61 /*   ctl:        list of permissible aliases */
62 /*   xmit_names: list of recipient names parsed out */
63 {
64     const char  *lname;
65     int off = 0;
66     
67     lname = idpair_find(&ctl->localnames, name+off);
68     if (!lname && ctl->wildcard)
69         lname = name+off;
70
71     if (lname != (char *)NULL)
72     {
73         if (outlevel >= O_DEBUG)
74             report(stdout, GT_("mapped %s to local %s\n"), name, lname);
75         save_str(xmit_names, lname, XMIT_ACCEPT);
76         accept_count++;
77     }
78 }
79
80 static void find_server_names(const char *hdr,
81                               struct query *ctl,
82                               struct idlist **xmit_names)
83 /* parse names out of a RFC822 header into an ID list */
84 /*   hdr:               RFC822 header in question */
85 /*   ctl:               list of permissible aliases */
86 /*   xmit_names:        list of recipient names parsed out */
87 {
88     if (hdr == (char *)NULL)
89         return;
90     else
91     {
92         char    *cp;
93
94         for (cp = nxtaddr(hdr); cp != NULL; cp = nxtaddr(NULL))
95         {
96             char        *atsign;
97
98             /* 
99              * Handle empty address from a To: header containing only 
100              * a comment.
101              */
102             if (!*cp)
103                 continue;
104
105             /*
106              * If the name of the user begins with a qmail virtual
107              * domain prefix, ignore the prefix.  Doing this here
108              * means qvirtual will work either with ordinary name
109              * mapping or with a localdomains option.
110              */
111             if (ctl->server.qvirtual)
112             {
113                 int sl = strlen(ctl->server.qvirtual);
114  
115                 if (!strncasecmp((char *)cp, ctl->server.qvirtual, sl))
116                     cp += sl;
117             }
118
119             if ((atsign = strchr((char *)cp, '@'))) {
120                 struct idlist   *idp;
121
122                 /*
123                  * Does a trailing segment of the hostname match something
124                  * on the localdomains list?  If so, save the whole name
125                  * and keep going.
126                  */
127                 for (idp = ctl->server.localdomains; idp; idp = idp->next) {
128                     char        *rhs;
129
130                     rhs = atsign + (strlen(atsign) - strlen(idp->id));
131                     if (rhs > atsign &&
132                         (rhs[-1] == '.' || rhs[-1] == '@') &&
133                         strcasecmp(rhs, idp->id) == 0)
134                     {
135                         if (outlevel >= O_DEBUG)
136                             report(stdout, GT_("passed through %s matching %s\n"), 
137                                   cp, idp->id);
138                         save_str(xmit_names, (const char *)cp, XMIT_ACCEPT);
139                         accept_count++;
140                         goto nomap;
141                     }
142                 }
143
144                 /* if we matched a local domain, idp != NULL */
145                 if (!idp)
146                 {
147                     /*
148                      * Check to see if the right-hand part is an alias
149                      * or MX equivalent of the mailserver.  If it's
150                      * not, skip this name.  If it is, we'll keep
151                      * going and try to find a mapping to a client name.
152                      */
153                     if (!is_host_alias(atsign+1, ctl, &ai0))
154                     {
155                         save_str(xmit_names, cp, XMIT_REJECT);
156                         reject_count++;
157                         continue;
158                     }
159                 }
160                 atsign[0] = '\0';
161                 map_name(cp, ctl, xmit_names);
162             nomap:;
163             }
164         }
165     }
166 }
167
168 /*
169  * Return zero on a syntactically invalid address, nz on a valid one.
170  *
171  * This used to be strchr(a, '.'), but it turns out that lines like this
172  *
173  * Received: from punt-1.mail.demon.net by mailstore for markb@ordern.com
174  *          id 938765929:10:27223:2; Fri, 01 Oct 99 08:18:49 GMT
175  *
176  * are not uncommon.  So now we just check that the following token is
177  * not itself an email address.
178  */
179 #define VALID_ADDRESS(a)        !strchr(a, '@')
180
181 static char *parse_received(struct query *ctl, char *bufp)
182 /* try to extract real address from the Received line */
183 /* If a valid Received: line is found, we return the full address in
184  * a buffer which can be parsed from nxtaddr().  This is to ansure that
185  * the local domain part of the address can be passed along in 
186  * find_server_names() if it contains one.
187  * Note: We should return a dummy header containing the address 
188  * which makes nxtaddr() behave correctly. 
189  */
190 {
191     char *base, *ok = (char *)NULL;
192     static char rbuf[HOSTLEN + USERNAMELEN + 4]; 
193     struct addrinfo *ai0;
194
195 #define RBUF_WRITE(value) if (tp < rbuf+sizeof(rbuf)-1) *tp++=value
196
197     /*
198      * Try to extract the real envelope addressee.  We look here
199      * specifically for the mailserver's Received line.
200      * Note: this will only work for sendmail, or an MTA that
201      * shares sendmail's convention for embedding the envelope
202      * address in the Received line.  Sendmail itself only
203      * does this when the mail has a single recipient.
204      */
205     if (outlevel >= O_DEBUG)
206         report(stdout, GT_("analyzing Received line:\n%s"), bufp);
207
208     /* search for whitepace-surrounded "by" followed by valid address */
209     for (base = bufp;  ; base = ok + 2)
210     {
211         if (!(ok = strstr(base, "by")))
212             break;
213         else if (!isspace((unsigned char)ok[-1]) || !isspace((unsigned char)ok[2]))
214             continue;
215         else
216         {
217             char        *sp, *tp;
218
219             /* extract space-delimited token after "by" */
220             for (sp = ok + 2; isspace((unsigned char)*sp); sp++)
221                 continue;
222             tp = rbuf;
223             for (; *sp && !isspace((unsigned char)*sp); sp++)
224                 RBUF_WRITE(*sp);
225             *tp = '\0';
226
227             /* look for valid address */
228             if (VALID_ADDRESS(rbuf))
229                 break;
230             else
231                 ok = sp - 1;    /* arrange to skip this token */
232         }
233     }
234     if (ok)
235     {
236         /*
237          * If it's a DNS name of the mail server, look for the
238          * recipient name after a following "for".  Otherwise
239          * punt.
240          */
241         if (is_host_alias(rbuf, ctl, &ai0))
242         {
243             if (outlevel >= O_DEBUG)
244                 report(stdout, 
245                       GT_("line accepted, %s is an alias of the mailserver\n"), rbuf);
246         }
247         else
248         {
249             if (outlevel >= O_DEBUG)
250                 report(stdout, 
251                       GT_("line rejected, %s is not an alias of the mailserver\n"), 
252                       rbuf);
253             return(NULL);
254         }
255
256         /* search for whitepace-surrounded "for" followed by xxxx@yyyy */
257         for (base = ok + 4 + strlen(rbuf);  ; base = ok + 2)
258         {
259             if (!(ok = strstr(base, "for")))
260                 break;
261             else if (!isspace((unsigned char)ok[-1]) || !isspace((unsigned char)ok[3]))
262                 continue;
263             else
264             {
265                 char    *sp, *tp;
266
267                 /* extract space-delimited token after "for" */
268                 for (sp = ok + 3; isspace((unsigned char)*sp); sp++)
269                     continue;
270                 tp = rbuf;
271                 for (; !isspace((unsigned char)*sp); sp++)
272                     RBUF_WRITE(*sp);
273                 *tp = '\0';
274
275                 if (strchr(rbuf, '@'))
276                     break;
277                 else
278                     ok = sp - 1;        /* arrange to skip this token */
279             }
280         }
281         if (ok)
282         {
283             flag        want_gt = FALSE;
284             char        *sp, *tp;
285
286             /* char after "for" could be space or a continuation newline */
287             for (sp = ok + 4; isspace((unsigned char)*sp); sp++)
288                 continue;
289             tp = rbuf;
290             RBUF_WRITE(':');    /* Here is the hack.  This is to be friends */
291             RBUF_WRITE(' ');    /* with nxtaddr()... */
292             if (*sp == '<')
293             {
294                 want_gt = TRUE;
295                 sp++;
296             }
297             while (*sp == '@')          /* skip routes */
298                 while (*sp && *sp++ != ':')
299                     continue;
300             while (*sp
301                    && (want_gt ? (*sp != '>') : !isspace((unsigned char)*sp))
302                    && *sp != ';')
303                 if (!isspace((unsigned char)*sp))
304                 {
305                     RBUF_WRITE(*sp);
306                     sp++;
307                 }    
308                 else
309                 {
310                     /* uh oh -- whitespace here can't be right! */
311                     ok = (char *)NULL;
312                     break;
313                 }
314             RBUF_WRITE('\n');
315             *tp = '\0';
316             if (strlen(rbuf) <= 3)      /* apparently nothing has been found */
317                 ok = NULL;
318         } else
319             ok = (char *)NULL;
320     }
321
322     if (!ok)
323     {
324         if (outlevel >= O_DEBUG)
325             report(stdout, GT_("no Received address found\n"));
326         return(NULL);
327     }
328     else
329     {
330         if (outlevel >= O_DEBUG) {
331             char *lf = rbuf + strlen(rbuf)-1;
332             *lf = '\0';
333             if (outlevel >= O_DEBUG)
334                 report(stdout, GT_("found Received address `%s'\n"), rbuf+2);
335             *lf = '\n';
336         }
337         return(rbuf);
338     }
339 }
340
341 /* shared by readheaders and readbody */
342 static int sizeticker;
343
344 #define EMPTYLINE(s)   (((s)[0] == '\r' && (s)[1] == '\n' && (s)[2] == '\0') \
345                        || ((s)[0] == '\n' && (s)[1] == '\0'))
346
347 static int end_of_header (const char *s)
348 /* accept "\r*\n" as EOH in order to be bulletproof against broken survers */
349 {
350     while (s[0] == '\r')
351         s++;
352     return (s[0] == '\n' && s[1] == '\0');
353 }
354
355 int readheaders(int sock,
356                        long fetchlen,
357                        long reallen,
358                        struct query *ctl,
359                        int num,
360                        flag *suppress_readbody)
361 /* read message headers and ship to SMTP or MDA */
362 /*   sock:              to which the server is connected */
363 /*   fetchlen:          length of message according to fetch response */
364 /*   reallen:           length of message according to getsizes */
365 /*   ctl:               query control record */
366 /*   num:               index of message */
367 /*   suppress_readbody: whether call to readbody() should be supressed */
368 {
369     struct addrblk
370     {
371         int             offset;
372         struct addrblk  *next;
373     };
374     struct addrblk      *to_addrchain = NULL;
375     struct addrblk      **to_chainptr = &to_addrchain;
376     struct addrblk      *resent_to_addrchain = NULL;
377     struct addrblk      **resent_to_chainptr = &resent_to_addrchain;
378
379     char                buf[MSGBUFSIZE+1];
380     int                 from_offs, reply_to_offs, resent_from_offs;
381     int                 app_from_offs, sender_offs, resent_sender_offs;
382     int                 env_offs;
383     char                *received_for, *rcv, *cp;
384     static char         *delivered_to = NULL;
385     int                 n, oldlen, ch, remaining, skipcount;
386     size_t              linelen;
387     int                 delivered_to_count;
388     struct idlist       *idp;
389     flag                no_local_matches = FALSE;
390     flag                has_nuls;
391     int                 olderrs, good_addresses, bad_addresses;
392     int                 retain_mail = 0, refuse_mail = 0;
393     flag                already_has_return_path = FALSE;
394
395     sizeticker = 0;
396     has_nuls = FALSE;
397     msgblk.return_path[0] = '\0';
398     olderrs = ctl->errcount;
399
400     /* read message headers */
401     msgblk.reallen = reallen;
402
403     /*
404      * We used to free the header block unconditionally at the end of 
405      * readheaders, but it turns out that if close_sink() hits an error
406      * condition the code for sending bouncemail will actually look
407      * at the freed storage and coredump...
408      */
409     xfree(msgblk.headers);
410     free_str_list(&msgblk.recipients);
411     xfree(delivered_to);
412
413     /* initially, no message digest */
414     memset(ctl->digest, '\0', sizeof(ctl->digest));
415
416     received_for = NULL;
417     from_offs = reply_to_offs = resent_from_offs = app_from_offs = 
418         sender_offs = resent_sender_offs = env_offs = -1;
419     oldlen = 0;
420     msgblk.msglen = 0;
421     skipcount = 0;
422     delivered_to_count = 0;
423     ctl->mimemsg = 0;
424
425     for (remaining = fetchlen; remaining > 0 || protocol->delimited; )
426     {
427         char *line, *rline;
428
429         line = xmalloc(sizeof(buf));
430         linelen = 0;
431         line[0] = '\0';
432         do {
433             do {
434                 char    *sp, *tp;
435
436                 set_timeout(mytimeout);
437                 if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1) {
438                     set_timeout(0);
439                     free(line);
440                     return(PS_SOCKET);
441                 }
442                 set_timeout(0);
443
444                 /*
445                  * Smash out any NULs, they could wreak havoc later on.
446                  * Some network stacks seem to generate these at random,
447                  * especially (according to reports) at the beginning of the
448                  * first read.  NULs are illegal in RFC822 format.
449                  */
450                 for (sp = tp = buf; sp < buf + n; sp++)
451                     if (*sp)
452                         *tp++ = *sp;
453                 *tp = '\0';
454                 n = tp - buf;
455             } while
456                   (n == 0);
457
458             remaining -= n;
459             linelen += n;
460             msgblk.msglen += n;
461
462             /*
463              * Try to gracefully handle the case where the length of a
464              * line exceeds MSGBUFSIZE.
465              */
466             if (n && buf[n-1] != '\n') 
467             {
468                 rline = (char *) realloc(line, linelen + 1);
469                 if (rline == NULL)
470                 {
471                     free (line);
472                     return(PS_IOERR);
473                 }
474                 line = rline;
475                 memcpy(line + linelen - n, buf, n);
476                 line[linelen] = '\0';
477                 ch = ' '; /* So the next iteration starts */
478                 continue;
479             }
480
481             /* lines may not be properly CRLF terminated; fix this for qmail */
482             /* we don't want to overflow the buffer here */
483             if (ctl->forcecr && buf[n-1]=='\n' && (n==1 || buf[n-2]!='\r'))
484             {
485                 char * tcp;
486                 rline = (char *) realloc(line, linelen + 2);
487                 if (rline == NULL)
488                 {
489                     free (line);
490                     return(PS_IOERR);
491                 }
492                 line = rline;
493                 memcpy(line + linelen - n, buf, n - 1);
494                 tcp = line + linelen - 1;
495                 *tcp++ = '\r';
496                 *tcp++ = '\n';
497                 *tcp++ = '\0';
498                 n++;
499                 linelen++;
500             }
501             else
502             {
503                 rline = (char *) realloc(line, linelen + 1);
504                 if (rline == NULL)
505                 {
506                     free (line);
507                     return(PS_IOERR);
508                 }
509                 line = rline;
510                 memcpy(line + linelen - n, buf, n + 1);
511             }
512
513             /* check for end of headers */
514             if (end_of_header(line))
515             {
516                 if (linelen != strlen (line))
517                     has_nuls = TRUE;
518                 free(line);
519                 goto process_headers;
520             }
521
522             /*
523              * Check for end of message immediately.  If one of your folders
524              * has been mangled, the delimiter may occur directly after the
525              * header.
526              */
527             if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
528             {
529                 if (outlevel > O_SILENT)
530                     report(stdout,
531                            GT_("message delimiter found while scanning headers\n"));
532                 if (suppress_readbody)
533                     *suppress_readbody = TRUE;
534                 if (linelen != strlen (line))
535                     has_nuls = TRUE;
536                 free(line);
537                 goto process_headers;
538             }
539
540             /*
541              * At least one brain-dead website (netmind.com) is known to
542              * send out robotmail that's missing the RFC822 delimiter blank
543              * line before the body! Without this check fetchmail segfaults.
544              * With it, we treat such messages as spam and refuse them.
545              *
546              * Frederic Marchal reported in February 2006 that hotmail
547              * or something improperly wrapped a very long TO header
548              * (wrapped without inserting whitespace in the continuation
549              * line) and found that this code thus refused a message
550              * that should have been delivered.
551              *
552              * XXX FIXME: we should probably wrap the message up as
553              * message/rfc822 attachment and forward to postmaster (Rob
554              * MacGregor)
555              */
556             if (!refuse_mail && !isspace((unsigned char)line[0]) && !strchr(line, ':'))
557             {
558                 if (linelen != strlen (line))
559                     has_nuls = TRUE;
560                 if (outlevel > O_SILENT)
561                     report(stdout,
562                            GT_("incorrect header line found while scanning headers\n"));
563                 if (outlevel >= O_VERBOSE)
564                     report (stdout, GT_("line: %s"), line);
565                 refuse_mail = 1;
566             }
567
568             /* check for RFC822 continuations */
569             set_timeout(mytimeout);
570             ch = SockPeek(sock);
571             set_timeout(0);
572         } while
573             (ch == ' ' || ch == '\t');  /* continuation to next line? */
574
575         /* write the message size dots */
576         if ((outlevel > O_SILENT && outlevel < O_VERBOSE) && linelen > 0)
577         {
578             sizeticker += linelen;
579             while (sizeticker >= SIZETICKER)
580             {
581                 if (outlevel > O_SILENT && run.showdots && !run.use_syslog)
582                 {
583                     fputc('.', stdout);
584                     fflush(stdout);
585                 }
586                 sizeticker -= SIZETICKER;
587             }
588         }
589                 /*
590                  * Decode MIME encoded headers. We MUST do this before
591                  * looking at the Content-Type / Content-Transfer-Encoding
592                  * headers (RFC 2046).
593                  */
594                 if ( ctl->mimedecode )
595                 {
596                     char *tcp;
597                     UnMimeHeader(line);
598                     /* the line is now shorter. So we retrace back till we find our terminating
599                      * combination \n\0, we move backwards to make sure that we don't catch som
600                      * \n\0 stored in the decoded part of the message */
601                     for(tcp = line + linelen - 1; tcp > line && (*tcp != 0 || tcp[-1] != '\n'); tcp--);
602                     if(tcp > line) linelen = tcp - line;
603                 }
604
605
606         /* skip processing if we are going to retain or refuse this mail */
607         if (retain_mail || refuse_mail)
608         {
609             free(line);
610             continue;
611         }
612
613         /* we see an ordinary (non-header, non-message-delimiter) line */
614         if (linelen != strlen (line))
615             has_nuls = TRUE;
616
617         /*
618          * The University of Washington IMAP server (the reference
619          * implementation of IMAP4 written by Mark Crispin) relies
620          * on being able to keep base-UID information in a special
621          * message at the head of the mailbox.  This message should
622          * neither be deleted nor forwarded.
623          *
624          * An example for such a message is (keep this in so people
625          * find it when looking where the special code is to handle the
626          * data):
627          *
628          *   From MAILER-DAEMON Wed Nov 23 11:38:42 2005
629          *   Date: 23 Nov 2005 11:38:42 +0100
630          *   From: Mail System Internal Data <MAILER-DAEMON@mail.example.org>
631          *   Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA
632          *   Message-ID: <1132742322@mail.example.org>
633          *   X-IMAP: 1132742306 0000000001
634          *   Status: RO
635          *
636          *   This text is part of the internal format of your mail folder, and is not
637          *   a real message.  It is created automatically by the mail system software.
638          *   If deleted, important folder data will be lost, and it will be re-created
639          *   with the data reset to initial values.
640          *
641          * This message is only visible if a POP3 server that is unaware
642          * of these UWIMAP messages is used besides UWIMAP or PINE.
643          *
644          * We will just check if the first message in the mailbox has an
645          * X-IMAP: header.
646          */
647 #ifdef POP2_ENABLE
648         /*
649          * We disable this check under POP2 because there's no way to
650          * prevent deletion of the message.  So at least we ought to
651          * forward it to the user so he or she will have some clue
652          * that things have gone awry.
653          */
654         if (servport("pop2") != servport(protocol->service))
655 #endif /* POP2_ENABLE */
656             if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
657                 free(line);
658                 retain_mail = 1;
659                 continue;
660             }
661
662         /*
663          * This code prevents fetchmail from becoming an accessory after
664          * the fact to upstream sendmails with the `E' option on.  It also
665          * copes with certain brain-dead POP servers (like NT's) that pass
666          * through Unix from_ lines.
667          *
668          * Either of these bugs can result in a non-RFC822 line at the
669          * beginning of the headers.  If fetchmail just passes it
670          * through, the client listener may think the message has *no*
671          * headers (since the first) line it sees doesn't look
672          * RFC822-conformant) and fake up a set.
673          *
674          * What the user would see in this case is bogus (synthesized)
675          * headers, followed by a blank line, followed by the >From, 
676          * followed by the real headers, followed by a blank line,
677          * followed by text.
678          *
679          * We forestall this lossage by tossing anything that looks
680          * like an escaped or passed-through From_ line in headers.
681          * These aren't RFC822 so our conscience is clear...
682          */
683         if (!strncasecmp(line, ">From ", 6) || !strncasecmp(line, "From ", 5))
684         {
685             free(line);
686             continue;
687         }
688
689         /*
690          * We remove all Delivered-To: headers if dropdelivered is set
691          * - special care must be taken if Delivered-To: is also used
692          * as envelope at the same time.
693          *
694          * This is to avoid false mail loops errors when delivering
695          * local messages to and from a Postfix or qmail mailserver.
696          */
697         if (ctl->dropdelivered && !strncasecmp(line, "Delivered-To:", 13)) 
698         {
699             if (delivered_to ||
700                 ctl->server.envelope == STRING_DISABLED ||
701                 !ctl->server.envelope ||
702                 strcasecmp(ctl->server.envelope, "Delivered-To") ||
703                 delivered_to_count != ctl->server.envskip)
704                 free(line);
705             else 
706                 delivered_to = line;
707             delivered_to_count++;
708             continue;
709         }
710
711         /*
712          * If we see a Status line, it may have been inserted by an MUA
713          * on the mail host, or it may have been inserted by the server
714          * program after the headers in the transaction stream.  This
715          * can actually hose some new-mail notifiers such as xbuffy,
716          * which assumes any Status line came from a *local* MDA and
717          * therefore indicates that the message has been seen.
718          *
719          * Some buggy POP servers (including at least the 3.3(20)
720          * version of the one distributed with IMAP) insert empty
721          * Status lines in the transaction stream; we'll chuck those
722          * unconditionally.  Nonempty ones get chucked if the user
723          * turns on the dropstatus flag.
724          */
725         {
726             char        *cp;
727
728             if (!strncasecmp(line, "Status:", 7))
729                 cp = line + 7;
730             else if (!strncasecmp(line, "X-Mozilla-Status:", 17))
731                 cp = line + 17;
732             else
733                 cp = NULL;
734             if (cp) {
735                 while (*cp && isspace((unsigned char)*cp)) cp++;
736                 if (!*cp || ctl->dropstatus)
737                 {
738                     free(line);
739                     continue;
740                 }
741             }
742         }
743
744         if (ctl->rewrite)
745             line = reply_hack(line, ctl->server.truename, &linelen);
746
747         /*
748          * OK, this is messy.  If we're forwarding by SMTP, it's the
749          * SMTP-receiver's job (according to RFC821, page 22, section
750          * 4.1.1) to generate a Return-Path line on final delivery.
751          * The trouble is, we've already got one because the
752          * mailserver's SMTP thought *it* was responsible for final
753          * delivery.
754          *
755          * Stash away the contents of Return-Path (as modified by reply_hack)
756          * for use in generating MAIL FROM later on, then prevent the header
757          * from being saved with the others.  In effect, we strip it off here.
758          *
759          * If the SMTP server conforms to the standards, and fetchmail gets the
760          * envelope sender from the Return-Path, the new Return-Path should be
761          * exactly the same as the original one.
762          *
763          * We do *not* want to ignore empty Return-Path headers.  These should
764          * be passed through as a way of indicating that a message should
765          * not trigger bounces if delivery fails.  What we *do* need to do is
766          * make sure we never try to rewrite such a blank Return-Path.  We
767          * handle this with a check for <> in the rewrite logic above.
768          *
769          * Also, if an email has multiple Return-Path: headers, we only
770          * read the first occurance, as some spam email has more than one
771          * Return-Path.
772          *
773          */
774         if ((already_has_return_path==FALSE) && !strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line)))
775         {
776             already_has_return_path = TRUE;
777             if (cp[0]=='\0')    /* nxtaddr() strips the brackets... */
778                 cp="<>";
779             strncpy(msgblk.return_path, cp, sizeof(msgblk.return_path));
780             msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0';
781             if (!ctl->mda) {
782                 free(line);
783                 continue;
784             }
785         }
786
787         if (!msgblk.headers)
788         {
789             oldlen = linelen;
790             msgblk.headers = xmalloc(oldlen + 1);
791             (void) memcpy(msgblk.headers, line, linelen);
792             msgblk.headers[oldlen] = '\0';
793             free(line);
794             line = msgblk.headers;
795         }
796         else
797         {
798             char *newhdrs;
799             int newlen;
800
801             newlen = oldlen + linelen;
802             newhdrs = (char *) realloc(msgblk.headers, newlen + 1);
803             if (newhdrs == NULL) {
804                 free(line);
805                 return(PS_IOERR);
806             }
807             msgblk.headers = newhdrs;
808             memcpy(msgblk.headers + oldlen, line, linelen);
809             msgblk.headers[newlen] = '\0';
810             free(line);
811             line = msgblk.headers + oldlen;
812             oldlen = newlen;
813         }
814
815         /* find offsets of various special headers */
816         if (!strncasecmp("From:", line, 5))
817             from_offs = (line - msgblk.headers);
818         else if (!strncasecmp("Reply-To:", line, 9))
819             reply_to_offs = (line - msgblk.headers);
820         else if (!strncasecmp("Resent-From:", line, 12))
821             resent_from_offs = (line - msgblk.headers);
822         else if (!strncasecmp("Apparently-From:", line, 16))
823             app_from_offs = (line - msgblk.headers);
824         /*
825          * Netscape 4.7 puts "Sender: zap" in mail headers.  Perverse...
826          *
827          * But a literal reading of RFC822 sec. 4.4.2 supports the idea
828          * that Sender: *doesn't* have to be a working email address.
829          *
830          * The definition of the Sender header in RFC822 says, in
831          * part, "The Sender mailbox specification includes a word
832          * sequence which must correspond to a specific agent (i.e., a
833          * human user or a computer program) rather than a standard
834          * address."  That implies that the contents of the Sender
835          * field don't need to be a legal email address at all So
836          * ignore any Sender or Resent-Sender lines unless they
837          * contain @.
838          *
839          * (RFC2822 says the contents of Sender must be a valid mailbox
840          * address, which is also what RFC822 4.4.4 implies.)
841          */
842         else if (!strncasecmp("Sender:", line, 7) && (strchr(line, '@') || strchr(line, '!')))
843             sender_offs = (line - msgblk.headers);
844         else if (!strncasecmp("Resent-Sender:", line, 14) && (strchr(line, '@') || strchr(line, '!')))
845             resent_sender_offs = (line - msgblk.headers);
846
847 #ifdef __UNUSED__
848         else if (!strncasecmp("Message-Id:", line, 11))
849         {
850             if (ctl->server.uidl)
851             {
852                 char id[IDLEN+1];
853
854                 line[IDLEN+12] = 0;             /* prevent stack overflow */
855                 sscanf(line+12, "%s", id);
856                 if (!str_find( &ctl->newsaved, num))
857                 {
858                     struct idlist *newl = save_str(&ctl->newsaved,id,UID_SEEN);
859                     newl->val.status.num = num;
860                 }
861             }
862         }
863 #endif /* __UNUSED__ */
864
865         /* if multidrop is on, gather addressee headers */
866         if (MULTIDROP(ctl))
867         {
868             if (!strncasecmp("To:", line, 3)
869                 || !strncasecmp("Cc:", line, 3)
870                 || !strncasecmp("Bcc:", line, 4)
871                 || !strncasecmp("Apparently-To:", line, 14))
872             {
873                 *to_chainptr = (struct addrblk *)xmalloc(sizeof(struct addrblk));
874                 (*to_chainptr)->offset = (line - msgblk.headers);
875                 to_chainptr = &(*to_chainptr)->next; 
876                 *to_chainptr = NULL;
877             }
878
879             else if (!strncasecmp("Resent-To:", line, 10)
880                      || !strncasecmp("Resent-Cc:", line, 10)
881                      || !strncasecmp("Resent-Bcc:", line, 11))
882             {
883                 *resent_to_chainptr = (struct addrblk *)xmalloc(sizeof(struct addrblk));
884                 (*resent_to_chainptr)->offset = (line - msgblk.headers);
885                 resent_to_chainptr = &(*resent_to_chainptr)->next; 
886                 *resent_to_chainptr = NULL;
887             }
888
889             else if (ctl->server.envelope != STRING_DISABLED)
890             {
891                 if (ctl->server.envelope 
892                     && strcasecmp(ctl->server.envelope, "Received"))
893                 {
894                     if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
895                                                        line,
896                                                        strlen(ctl->server.envelope)))
897                     {                           
898                         if (skipcount++ < ctl->server.envskip)
899                             continue;
900                         env_offs = (line - msgblk.headers);
901                     }    
902                 }
903                 else if (!received_for && !strncasecmp("Received:", line, 9))
904                 {
905                     if (skipcount++ < ctl->server.envskip)
906                         continue;
907                     received_for = parse_received(ctl, line);
908                 }
909             }
910         }
911     }
912
913  process_headers:    
914
915     if (retain_mail)
916     {
917         return(PS_RETAINED);
918     }
919     if (refuse_mail)
920         return(PS_REFUSED);
921     /*
922      * This is the duplicate-message killer code.
923      *
924      * When mail delivered to a multidrop mailbox on the server is
925      * addressed to multiple people on the client machine, there will
926      * be one copy left in the box for each recipient.  This is not a
927      * problem if we have the actual recipient address to dispatch on
928      * (e.g. because we've mined it out of sendmail trace headers, or
929      * a qmail Delivered-To line, or a declared sender envelope line).
930      *
931      * But if we're mining addressees out of the To/Cc/Bcc fields, and
932      * if the mail is addressed to N people, each recipient will
933      * get N copies.  This is bad when N > 1.
934      *
935      * Foil this by suppressing all but one copy of a message with a
936      * given set of headers.
937      *
938      * Note: This implementation only catches runs of successive
939      * messages with the same ID, but that should be good
940      * enough. A more general implementation would have to store
941      * ever-growing lists of seen message-IDs; in a long-running
942      * daemon this would turn into a memory leak even if the 
943      * implementation were perfect.
944      * 
945      * Don't mess with this code casually.  It would be way too easy
946      * to break it in a way that blackholed mail.  Better to pass
947      * the occasional duplicate than to do that...
948      *
949      * Matthias Andree:
950      * The real fix however is to insist on Delivered-To: or similar
951      * headers and require that one copy per recipient be dropped.
952      * Everything else breaks sooner or later.
953      */
954     if (MULTIDROP(ctl) && msgblk.headers)
955     {
956         MD5_CTX context;
957
958         MD5Init(&context);
959         MD5Update(&context, msgblk.headers, strlen(msgblk.headers));
960         MD5Final(ctl->digest, &context);
961
962         if (!received_for && env_offs == -1 && !delivered_to)
963         {
964             /*
965              * Hmmm...can MD5 ever yield all zeroes as a hash value?
966              * If so there is a one in 18-quadrillion chance this 
967              * code will incorrectly nuke the first message.
968              */
969             if (!memcmp(ctl->lastdigest, ctl->digest, DIGESTLEN))
970                 return(PS_REFUSED);
971         }
972         memcpy(ctl->lastdigest, ctl->digest, DIGESTLEN);
973     }
974
975     /*
976      * Hack time.  If the first line of the message was blank, with no headers
977      * (this happens occasionally due to bad gatewaying software) cons up
978      * a set of fake headers.  
979      *
980      * If you modify the fake header template below, be sure you don't
981      * make either From or To address @-less, otherwise the reply_hack
982      * logic will do bad things.
983      */
984     if (msgblk.headers == (char *)NULL)
985     {
986         snprintf(buf, sizeof(buf),
987                 "From: FETCHMAIL-DAEMON\r\n"
988                 "To: %s@%s\r\n"
989                 "Subject: Headerless mail from %s's mailbox on %s\r\n",
990                 user, fetchmailhost, ctl->remotename, ctl->server.truename);
991         msgblk.headers = xstrdup(buf);
992     }
993
994     /*
995      * We can now process message headers before reading the text.
996      * In fact we have to, as this will tell us where to forward to.
997      */
998
999     /* Check for MIME headers indicating possible 8-bit data */
1000     ctl->mimemsg = MimeBodyType(msgblk.headers, ctl->mimedecode);
1001
1002 #ifdef SDPS_ENABLE
1003     if (ctl->server.sdps && sdps_envfrom)
1004     {
1005         /* We have the real envelope return-path, stored out of band by
1006          * SDPS - that's more accurate than any header is going to be.
1007          */
1008         strlcpy(msgblk.return_path, sdps_envfrom, sizeof(msgblk.return_path));
1009         free(sdps_envfrom);
1010     } else
1011 #endif /* SDPS_ENABLE */
1012     /*
1013      * If there is a Return-Path address on the message, this was
1014      * almost certainly the MAIL FROM address given the originating
1015      * sendmail.  This is the best thing to use for logging the
1016      * message origin (it sets up the right behavior for bounces and
1017      * mailing lists).  Otherwise, fall down to the next available 
1018      * envelope address (which is the most probable real sender).
1019      * *** The order is important! ***
1020      * This is especially useful when receiving mailing list
1021      * messages in multidrop mode.  if a local address doesn't
1022      * exist, the bounce message won't be returned blindly to the 
1023      * author or to the list itself but rather to the list manager
1024      * (ex: specified by "Sender:") which is much less annoying.  This 
1025      * is true for most mailing list packages.
1026      */
1027     if( !msgblk.return_path[0] ){
1028         char *ap = NULL;
1029         if (resent_sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_sender_offs)));
1030         else if (sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + sender_offs)));
1031         else if (resent_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_from_offs)));
1032         else if (from_offs >= 0 && (ap = nxtaddr(msgblk.headers + from_offs)));
1033         else if (reply_to_offs >= 0 && (ap = nxtaddr(msgblk.headers + reply_to_offs)));
1034         else if (app_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + app_from_offs))) {}
1035         /* multi-line MAIL FROM addresses confuse SMTP terribly */
1036         if (ap && !strchr(ap, '\n')) {
1037             strncpy(msgblk.return_path, ap, sizeof(msgblk.return_path));
1038             msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0';
1039         }
1040     }
1041
1042     /* cons up a list of local recipients */
1043     msgblk.recipients = (struct idlist *)NULL;
1044     accept_count = reject_count = 0;
1045     /* is this a multidrop box? */
1046     if (MULTIDROP(ctl))
1047     {
1048 #ifdef SDPS_ENABLE
1049         if (ctl->server.sdps && sdps_envto)
1050         {
1051             /* We have the real envelope recipient, stored out of band by
1052              * SDPS - that's more accurate than any header is going to be.
1053              */
1054             find_server_names(sdps_envto, ctl, &msgblk.recipients);
1055             free(sdps_envto);
1056         } else
1057 #endif /* SDPS_ENABLE */ 
1058         if (env_offs > -1)          /* We have the actual envelope addressee */
1059             find_server_names(msgblk.headers + env_offs, ctl, &msgblk.recipients);
1060         else if (delivered_to && ctl->server.envelope != STRING_DISABLED &&
1061       ctl->server.envelope && !strcasecmp(ctl->server.envelope, "Delivered-To"))
1062    {
1063             find_server_names(delivered_to, ctl, &msgblk.recipients);
1064             xfree(delivered_to);
1065    }
1066         else if (received_for)
1067             /*
1068              * We have the Received for addressee.  
1069              * It has to be a mailserver address, or we
1070              * wouldn't have got here.
1071              * We use find_server_names() to let local 
1072              * hostnames go through.
1073              */
1074             find_server_names(received_for, ctl, &msgblk.recipients);
1075         else
1076         {
1077             /*
1078              * We haven't extracted the envelope address.
1079              * So check all the "Resent-To" header addresses if 
1080              * they exist.  If and only if they don't, consider
1081              * the "To" addresses.
1082              */
1083             register struct addrblk *nextptr;
1084             if (resent_to_addrchain) {
1085                 /* delete the "To" chain and substitute it 
1086                  * with the "Resent-To" list 
1087                  */
1088                 while (to_addrchain) {
1089                     nextptr = to_addrchain->next;
1090                     free(to_addrchain);
1091                     to_addrchain = nextptr;
1092                 }
1093                 to_addrchain = resent_to_addrchain;
1094                 resent_to_addrchain = NULL;
1095             }
1096             /* now look for remaining adresses */
1097             while (to_addrchain) {
1098                 find_server_names(msgblk.headers+to_addrchain->offset, ctl, &msgblk.recipients);
1099                 nextptr = to_addrchain->next;
1100                 free(to_addrchain);
1101                 to_addrchain = nextptr;
1102             }
1103         }
1104         if (!accept_count)
1105         {
1106             no_local_matches = TRUE;
1107             save_str(&msgblk.recipients, run.postmaster, XMIT_ACCEPT);
1108             if (outlevel >= O_DEBUG)
1109                 report(stdout,
1110                       GT_("no local matches, forwarding to %s\n"),
1111                       run.postmaster);
1112         }
1113     }
1114     else        /* it's a single-drop box, use first localname */
1115         save_str(&msgblk.recipients, ctl->localnames->id, XMIT_ACCEPT);
1116
1117
1118     /*
1119      * Time to either address the message or decide we can't deliver it yet.
1120      */
1121     if (ctl->errcount > olderrs)        /* there were DNS errors above */
1122     {
1123         if (outlevel >= O_DEBUG)
1124             report(stdout,
1125                    GT_("forwarding and deletion suppressed due to DNS errors\n"));
1126         return(PS_TRANSIENT);
1127     }
1128     else
1129     {
1130         /* set up stuffline() so we can deliver the message body through it */ 
1131         if ((n = open_sink(ctl, &msgblk,
1132                            &good_addresses, &bad_addresses)) != PS_SUCCESS)
1133         {
1134             return(n);
1135         }
1136     }
1137
1138     n = 0;
1139     /*
1140      * Some server/sendmail combinations cause problems when our
1141      * synthetic Received line is before the From header.  Cope
1142      * with this...
1143      */
1144     if ((rcv = strstr(msgblk.headers, "Received:")) == (char *)NULL)
1145         rcv = msgblk.headers;
1146     /* handle ">Received:" lines too */
1147     while (rcv > msgblk.headers && rcv[-1] != '\n')
1148         rcv--;
1149     if (rcv > msgblk.headers)
1150     {
1151         char    c = *rcv;
1152
1153         *rcv = '\0';
1154         n = stuffline(ctl, msgblk.headers);
1155         *rcv = c;
1156     }
1157     if (!run.invisible && n != -1)
1158     {
1159         /* utter any per-message Received information we need here */
1160         if (ctl->server.trueaddr) {
1161             char saddr[50];
1162             int e;
1163
1164             e = getnameinfo(ctl->server.trueaddr, ctl->server.trueaddr_len,
1165                     saddr, sizeof(saddr), NULL, 0,
1166                     NI_NUMERICHOST);
1167             if (e)
1168                 snprintf(saddr, sizeof(saddr), "(%-.*s)", (int)(sizeof(saddr) - 3), gai_strerror(e));
1169             snprintf(buf, sizeof(buf),
1170                     "Received: from %s [%s]\r\n", 
1171                     ctl->server.truename, saddr);
1172         } else {
1173             snprintf(buf, sizeof(buf),
1174                   "Received: from %s\r\n", ctl->server.truename);
1175         }
1176         n = stuffline(ctl, buf);
1177         if (n != -1)
1178         {
1179             /*
1180              * We SHOULD (RFC-2821 sec. 4.4/p. 53) make sure to only use
1181              * IANA registered protocol names here.
1182              */
1183             snprintf(buf, sizeof(buf),
1184                     "\tby %s with %s (fetchmail-%s",
1185                     fetchmailhost,
1186                     protocol->name,
1187                     VERSION);
1188             if (ctl->server.tracepolls)
1189             {
1190                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1191                         " polling %s account %s",
1192                         ctl->server.pollname,
1193                         ctl->remotename);
1194                 if (ctl->folder)
1195                     snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1196                             " folder %s",
1197                             ctl->folder);
1198             }
1199             snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), ")\r\n");
1200             n = stuffline(ctl, buf);
1201             if (n != -1)
1202             {
1203                 buf[0] = '\t';
1204                 if (good_addresses == 0)
1205                 {
1206                     snprintf(buf+1, sizeof(buf)-1, "for <%s> (by default); ",
1207                             rcpt_address (ctl, run.postmaster, 0));
1208                 }
1209                 else if (good_addresses == 1)
1210                 {
1211                     for (idp = msgblk.recipients; idp; idp = idp->next)
1212                         if (idp->val.status.mark == XMIT_ACCEPT)
1213                             break;      /* only report first address */
1214                     snprintf(buf+1, sizeof(buf)-1,
1215                             "for <%s>", rcpt_address (ctl, idp->id, 1));
1216                     snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf)-1,
1217                             " (%s); ",
1218                             MULTIDROP(ctl) ? "multi-drop" : "single-drop");
1219                 }
1220                 else
1221                     buf[1] = '\0';
1222
1223                 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s\r\n",
1224                         rfc822timestamp());
1225                 n = stuffline(ctl, buf);
1226             }
1227         }
1228     }
1229
1230     if (n != -1)
1231         n = stuffline(ctl, rcv);        /* ship out rest of msgblk.headers */
1232
1233     if (n == -1)
1234     {
1235         report(stdout, GT_("writing RFC822 msgblk.headers\n"));
1236         release_sink(ctl);
1237         return(PS_IOERR);
1238     }
1239     else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE && !is_a_file(1) && !run.use_syslog)
1240         fputc('#', stdout);
1241
1242     /* write error notifications */
1243     if (no_local_matches || has_nuls || bad_addresses)
1244     {
1245         int     errlen = 0;
1246         char    errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
1247
1248         errmsg = errhd;
1249         strlcpy(errhd, "X-Fetchmail-Warning: ", sizeof(errhd));
1250         if (no_local_matches)
1251         {
1252             if (reject_count != 1)
1253                 strlcat(errhd, GT_("no recipient addresses matched declared local names"), sizeof(errhd));
1254             else
1255             {
1256                 for (idp = msgblk.recipients; idp; idp = idp->next)
1257                     if (idp->val.status.mark == XMIT_REJECT)
1258                         break;
1259                 snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd),
1260                         GT_("recipient address %s didn't match any local name"), idp->id);
1261             }
1262         }
1263
1264         if (has_nuls)
1265         {
1266             if (errhd[sizeof("X-Fetchmail-Warning: ")])
1267                 snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), "; ");
1268             snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd),
1269                         GT_("message has embedded NULs"));
1270         }
1271
1272         if (bad_addresses)
1273         {
1274             if (errhd[sizeof("X-Fetchmail-Warning: ")])
1275                 snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), "; ");
1276             snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd),
1277                         GT_("SMTP listener rejected local recipient addresses: "));
1278             errlen = strlen(errhd);
1279             for (idp = msgblk.recipients; idp; idp = idp->next)
1280                 if (idp->val.status.mark == XMIT_RCPTBAD)
1281                     errlen += strlen(idp->id) + 2;
1282
1283             errmsg = xmalloc(errlen + 3);
1284             strcpy(errmsg, errhd);
1285             for (idp = msgblk.recipients; idp; idp = idp->next)
1286                 if (idp->val.status.mark == XMIT_RCPTBAD)
1287                 {
1288                     strcat(errmsg, idp->id);
1289                     if (idp->next)
1290                         strcat(errmsg, ", ");
1291                 }
1292
1293         }
1294
1295         strcat(errmsg, "\r\n");
1296
1297         /* ship out the error line */
1298         stuffline(ctl, errmsg);
1299
1300         if (errmsg != errhd)
1301             free(errmsg);
1302     }
1303
1304     /* issue the delimiter line */
1305     cp = buf;
1306     *cp++ = '\r';
1307     *cp++ = '\n';
1308     *cp++ = '\0';
1309     n = stuffline(ctl, buf);
1310
1311     if (n == strlen(buf))
1312         return PS_SUCCESS;
1313     else
1314         return PS_SOCKET;
1315 }
1316
1317 int readbody(int sock, struct query *ctl, flag forward, int len)
1318 /* read and dispose of a message body presented on sock */
1319 /*   ctl:               query control record */
1320 /*   sock:              to which the server is connected */
1321 /*   len:               length of message */
1322 /*   forward:           TRUE to forward */
1323 {
1324     int linelen;
1325     char buf[MSGBUFSIZE+4];
1326     char *inbufp = buf;
1327     flag issoftline = FALSE;
1328
1329     /*
1330      * Pass through the text lines in the body.
1331      *
1332      * Yes, this wants to be ||, not &&.  The problem is that in the most
1333      * important delimited protocol, POP3, the length is not reliable.
1334      * As usual, the problem is Microsoft brain damage; see FAQ item S2.
1335      * So, for delimited protocols we need to ignore the length here and
1336      * instead drop out of the loop with a break statement when we see
1337      * the message delimiter.
1338      */
1339     while (protocol->delimited || len > 0)
1340     {
1341         set_timeout(mytimeout);
1342         /* XXX FIXME: for undelimited protocols that ship the size, such
1343          * as IMAP, we might want to use the count of remaining characters
1344          * instead of the buffer size -- not for fetchmail 6.3.X though */
1345         if ((linelen = SockRead(sock, inbufp, sizeof(buf)-4-(inbufp-buf)))==-1)
1346         {
1347             set_timeout(0);
1348             release_sink(ctl);
1349             return(PS_SOCKET);
1350         }
1351         set_timeout(0);
1352
1353         /* write the message size dots */
1354         if (linelen > 0)
1355         {
1356             sizeticker += linelen;
1357             while (sizeticker >= SIZETICKER)
1358             {
1359                 if (outlevel > O_SILENT && run.showdots && !run.use_syslog)
1360                 {
1361                     fputc('.', stdout);
1362                     fflush(stdout);
1363                 }
1364                 sizeticker -= SIZETICKER;
1365             }
1366         }
1367
1368         /* Mike Jones, Manchester University, 2006:
1369          * "To fix IMAP MIME Messages in which fetchmail adds the remainder of
1370          * the IMAP packet including the ')' character (part of the IMAP)
1371          * Protocol causing the addition of an extra MIME boundary locally."
1372          *
1373          * However, we shouldn't do this for delimited protocols:
1374          * many POP3 servers (Microsoft, qmail) goof up message sizes
1375          * so we might end truncating messages prematurely.
1376          */
1377         if (!protocol->delimited && linelen > len) {
1378             inbufp[len] = '\0';
1379         }
1380
1381         len -= linelen;
1382
1383         /* check for end of message */
1384         if (protocol->delimited && *inbufp == '.')
1385         {
1386             if (EMPTYLINE(inbufp+1))
1387                 break;
1388             else
1389                 msgblk.msglen--;        /* subtract the size of the dot escape */
1390         }
1391
1392         msgblk.msglen += linelen;
1393
1394         if (ctl->mimedecode && (ctl->mimemsg & MSG_NEEDS_DECODE)) {
1395             issoftline = UnMimeBodyline(&inbufp, protocol->delimited, issoftline);
1396             if (issoftline && (sizeof(buf)-1-(inbufp-buf) < 200))
1397             {
1398                 /*
1399                  * Soft linebreak, but less than 200 bytes left in
1400                  * input buffer. Rather than doing a buffer overrun,
1401                  * ignore the soft linebreak, NL-terminate data and
1402                  * deliver what we have now.
1403                  * (Who writes lines longer than 2K anyway?)
1404                  */
1405                 *inbufp = '\n'; *(inbufp+1) = '\0';
1406                 issoftline = 0;
1407             }
1408         }
1409
1410         /* ship out the text line */
1411         if (forward && (!issoftline))
1412         {
1413             int n;
1414             inbufp = buf;
1415
1416             /* guard against very long lines */
1417             buf[MSGBUFSIZE+1] = '\r';
1418             buf[MSGBUFSIZE+2] = '\n';
1419             buf[MSGBUFSIZE+3] = '\0';
1420
1421             n = stuffline(ctl, buf);
1422
1423             if (n < 0)
1424             {
1425                 report(stdout, GT_("error writing message text\n"));
1426                 release_sink(ctl);
1427                 return(PS_IOERR);
1428             }
1429             else if (outlevel >= O_VERBOSE && !is_a_file(1) && !run.use_syslog)
1430             {
1431                 fputc('*', stdout);
1432                 fflush(stdout);
1433             }
1434         }
1435     }
1436
1437     return(PS_SUCCESS);
1438 }
1439
1440 void init_transact(const struct method *proto)
1441 /* initialize state for the send and receive functions */
1442 {
1443     suppress_tags = FALSE;
1444     tagnum = 0;
1445     tag[0] = '\0';      /* nuke any tag hanging out from previous query */
1446     protocol = (struct method *)proto;
1447     shroud[0] = '\0';
1448 }
1449
1450 static void enshroud(char *buf)
1451 /* shroud a password in the given buffer */
1452 {
1453     char *cp;
1454
1455     if (shroud[0] && (cp = strstr(buf, shroud)))
1456     {
1457        char    *sp;
1458
1459        sp = cp + strlen(shroud);
1460        *cp++ = '*';
1461        while (*sp)
1462            *cp++ = *sp++;
1463        *cp = '\0';
1464     }
1465 }
1466
1467 #if defined(HAVE_STDARG_H)
1468 void gen_send(int sock, const char *fmt, ... )
1469 #else
1470 void gen_send(sock, fmt, va_alist)
1471 int sock;               /* socket to which server is connected */
1472 const char *fmt;        /* printf-style format */
1473 va_dcl
1474 #endif
1475 /* assemble command in printf(3) style and send to the server */
1476 {
1477     char buf [MSGBUFSIZE+1];
1478     va_list ap;
1479
1480     if (protocol->tagged && !suppress_tags)
1481         snprintf(buf, sizeof(buf) - 2, "%s ", GENSYM);
1482     else
1483         buf[0] = '\0';
1484
1485 #if defined(HAVE_STDARG_H)
1486     va_start(ap, fmt);
1487 #else
1488     va_start(ap);
1489 #endif
1490     vsnprintf(buf + strlen(buf), sizeof(buf)-2-strlen(buf), fmt, ap);
1491     va_end(ap);
1492
1493     snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
1494     SockWrite(sock, buf, strlen(buf));
1495
1496     if (outlevel >= O_MONITOR)
1497     {
1498         enshroud(buf);
1499         buf[strlen(buf)-2] = '\0';
1500         report(stdout, "%s> %s\n", protocol->name, buf);
1501     }
1502 }
1503
1504 /** get one line of input from the server */
1505 int gen_recv(int sock  /** socket to which server is connected */,
1506              char *buf /* buffer to receive input */,
1507              int size  /* length of buffer */)
1508 {
1509     int oldphase = phase;       /* we don't have to be re-entrant */
1510
1511     phase = SERVER_WAIT;
1512     set_timeout(mytimeout);
1513     if (SockRead(sock, buf, size) == -1)
1514     {
1515         set_timeout(0);
1516         phase = oldphase;
1517         if(is_idletimeout())
1518         {
1519           resetidletimeout();
1520           return(PS_IDLETIMEOUT);
1521         }
1522         else
1523           return(PS_SOCKET);
1524     }
1525     else
1526     {
1527         set_timeout(0);
1528         if (buf[strlen(buf)-1] == '\n')
1529             buf[strlen(buf)-1] = '\0';
1530         if (buf[strlen(buf)-1] == '\r')
1531             buf[strlen(buf)-1] = '\0';
1532         if (outlevel >= O_MONITOR)
1533             report(stdout, "%s< %s\n", protocol->name, buf);
1534         phase = oldphase;
1535         return(PS_SUCCESS);
1536     }
1537 }
1538
1539 #if defined(HAVE_STDARG_H)
1540 int gen_transact(int sock, const char *fmt, ... )
1541 #else
1542 int gen_transact(int sock, fmt, va_alist)
1543 int sock;               /* socket to which server is connected */
1544 const char *fmt;        /* printf-style format */
1545 va_dcl
1546 #endif
1547 /* assemble command in printf(3) style, send to server, accept a response */
1548 {
1549     int ok;
1550     char buf [MSGBUFSIZE+1];
1551     va_list ap;
1552     int oldphase = phase;       /* we don't have to be re-entrant */
1553
1554     phase = SERVER_WAIT;
1555
1556     if (protocol->tagged && !suppress_tags)
1557         snprintf(buf, sizeof(buf) - 2, "%s ", GENSYM);
1558     else
1559         buf[0] = '\0';
1560
1561 #if defined(HAVE_STDARG_H)
1562     va_start(ap, fmt) ;
1563 #else
1564     va_start(ap);
1565 #endif
1566     vsnprintf(buf + strlen(buf), sizeof(buf)-2-strlen(buf), fmt, ap);
1567     va_end(ap);
1568
1569     snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
1570     ok = SockWrite(sock, buf, strlen(buf));
1571     if (ok == -1 || (size_t)ok != strlen(buf)) {
1572         /* short write, bail out */
1573         return PS_SOCKET;
1574     }
1575
1576     if (outlevel >= O_MONITOR)
1577     {
1578         enshroud(buf);
1579         buf[strlen(buf)-2] = '\0';
1580         report(stdout, "%s> %s\n", protocol->name, buf);
1581     }
1582
1583     /* we presume this does its own response echoing */
1584     ok = (protocol->parse_response)(sock, buf);
1585
1586     phase = oldphase;
1587     return(ok);
1588 }
1589
1590 /* transact.c ends here */