]> Pileus Git - ~andy/fetchmail/blob - pop3.c
STLS fix.
[~andy/fetchmail] / pop3.c
1 /*
2  * pop3.c -- POP3 protocol methods
3  *
4  * Copyright 1998 by Eric S. Raymond.
5  * For license terms, see the file COPYING in this directory.
6  */
7
8 #include  "config.h"
9 #ifdef POP3_ENABLE
10 #include  <stdio.h>
11 #include  <string.h>
12 #include  <ctype.h>
13 #if defined(HAVE_UNISTD_H)
14 #include <unistd.h>
15 #endif
16 #if defined(STDC_HEADERS)
17 #include  <stdlib.h>
18 #endif
19  
20 #include  "fetchmail.h"
21 #include  "socket.h"
22 #include  "i18n.h"
23
24 #if OPIE_ENABLE
25 #include <opie.h>
26 #endif /* OPIE_ENABLE */
27
28 #ifndef strstr          /* glibc-2.1 declares this as a macro */
29 extern char *strstr();  /* needed on sysV68 R3V7.1. */
30 #endif /* strstr */
31
32 static int last;
33 #ifdef SDPS_ENABLE
34 char *sdps_envfrom;
35 char *sdps_envto;
36 #endif /* SDPS_ENABLE */
37
38 #if OPIE_ENABLE
39 static char lastok[POPBUFSIZE+1];
40 #endif /* OPIE_ENABLE */
41
42 #define DOTLINE(s)      (s[0] == '.' && (s[1]=='\r'||s[1]=='\n'||s[1]=='\0'))
43
44 static int pop3_ok (int sock, char *argbuf)
45 /* parse command response */
46 {
47     int ok;
48     char buf [POPBUFSIZE+1];
49     char *bufp;
50
51     if ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
52     {   bufp = buf;
53         if (*bufp == '+' || *bufp == '-')
54             bufp++;
55         else
56             return(PS_PROTOCOL);
57
58         while (isalpha(*bufp))
59             bufp++;
60
61         if (*bufp)
62           *(bufp++) = '\0';
63
64         if (strcmp(buf,"+OK") == 0)
65         {
66 #if OPIE_ENABLE
67             strcpy(lastok, bufp);
68 #endif /* OPIE_ENABLE */
69             ok = 0;
70         }
71         else if (strncmp(buf,"-ERR", 4) == 0)
72         {
73             if (stage > STAGE_GETAUTH) 
74                 ok = PS_PROTOCOL;
75             /*
76              * We're checking for "lock busy", "unable to lock", 
77              * "already locked", "wait a few minutes" etc. here. 
78              * This indicates that we have to wait for the server to
79              * unwedge itself before we can poll again.
80              *
81              * PS_LOCKBUSY check empirically verified with two recent
82              * versions of the Berkeley popper; QPOP (version 2.2)  and
83              * QUALCOMM Pop server derived from UCB (version 2.1.4-R3)
84              * These are caught by the case-indifferent "lock" check.
85              * The "wait" catches "mail storage services unavailable,
86              * wait a few minutes and try again" on the InterMail server.
87              *
88              * If these aren't picked up on correctly, fetchmail will 
89              * think there is an authentication failure and wedge the
90              * connection in order to prevent futile polls.
91              *
92              * Gad, what a kluge.
93              */
94             else if (strstr(bufp,"lock")
95                      || strstr(bufp,"Lock")
96                      || strstr(bufp,"LOCK")
97                      || strstr(bufp,"wait")
98                      /* these are blessed by RFC 2449 */
99                      || strstr(bufp,"[IN-USE]")||strstr(bufp,"[LOGIN-DELAY]"))
100                 ok = PS_LOCKBUSY;
101             else if ((strstr(bufp,"Service")
102                      || strstr(bufp,"service"))
103                          && (strstr(bufp,"unavailable")))
104                 ok = PS_SERVBUSY;
105             else
106                 ok = PS_AUTHFAIL;
107             /*
108              * We always want to pass the user lock-busy messages, because
109              * they're red flags.  Other stuff (like AUTH failures on non-
110              * RFC1734 servers) only if we're debugging.
111              */
112             if (*bufp && (ok == PS_LOCKBUSY || outlevel >= O_MONITOR))
113               report(stderr, "%s\n", bufp);
114         }
115         else
116             ok = PS_PROTOCOL;
117
118         if (argbuf != NULL)
119             strcpy(argbuf,bufp);
120     }
121
122     return(ok);
123 }
124
125 static int pop3_getauth(int sock, struct query *ctl, char *greeting)
126 /* apply for connection authorization */
127 {
128     int ok;
129     char *start,*end;
130     char *msg;
131 #if OPIE_ENABLE
132     char *challenge;
133 #endif /* OPIE_ENABLE */
134 #if defined(GSSAPI)
135     flag has_gssapi = FALSE;
136 #endif /* defined(GSSAPI) */
137 #if defined(KERBEROS_V4) || defined(KERBEROS_V5)
138     flag has_kerberos = FALSE;
139 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
140     flag has_cram = FALSE;
141 #ifdef OPIE_ENABLE
142     flag has_otp = FALSE;
143 #endif /* OPIE_ENABLE */
144 #ifdef SSL_ENABLE
145     flag has_ssl = FALSE;
146 #endif /* SSL_ENABLE */
147
148 #ifdef SDPS_ENABLE
149     /*
150      * This needs to catch both demon.co.uk and demon.net.
151      * If we see either, and we're in multidrop mode, try to use
152      * the SDPS *ENV extension.
153      */
154     if (!(ctl->server.sdps) && MULTIDROP(ctl) && strstr(greeting, "demon."))
155         ctl->server.sdps = TRUE;
156 #endif /* SDPS_ENABLE */
157
158     switch (ctl->server.protocol) {
159     case P_POP3:
160 #ifdef RPA_ENABLE
161         /* CompuServe POP3 Servers as of 990730 want AUTH first for RPA */
162         if (strstr(ctl->remotename, "@compuserve.com"))
163         {
164             /* AUTH command should return a list of available mechanisms */
165             if (gen_transact(sock, "AUTH") == 0)
166             {
167                 char buffer[10];
168                 flag has_rpa = FALSE;
169
170                 while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0)
171                 {
172                     if (DOTLINE(buffer))
173                         break;
174                     if (strncasecmp(buffer, "rpa", 3) == 0)
175                         has_rpa = TRUE;
176                 }
177                 if (has_rpa && !POP3_auth_rpa(ctl->remotename, 
178                                               ctl->password, sock))
179                     return(PS_SUCCESS);
180             }
181
182             return(PS_AUTHFAIL);
183         }
184 #endif /* RPA_ENABLE */
185
186         /*
187          * CAPA command may return a list including available
188          * authentication mechanisms.  if it doesn't, no harm done, we
189          * just fall back to a plain login.  Note that this code 
190          * latches the server's authentication type, so that in daemon mode
191          * the CAPA check only needs to be done once at start of run.
192          *
193          * APOP was introduced in RFC 1450, and CAPA not until
194          * RFC2449. So the < check is an easy way to prevent CAPA from
195          * being sent to the more primitive POP3 servers dating from
196          * RFC 1081 and RFC 1225, which seem more likely to choke on
197          * it.  This certainly catches IMAP-2000's POP3 gateway.
198          * 
199          * These authentication methods are blessed by RFC1734,
200          * describing the POP3 AUTHentication command.
201          */
202         if (ctl->server.authenticate == A_ANY 
203             && strchr(greeting, '<') 
204             && gen_transact(sock, "CAPA") == 0)
205         {
206             char buffer[64];
207
208             /* determine what authentication methods we have available */
209             while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0)
210             {
211                 if (DOTLINE(buffer))
212                     break;
213 #ifdef SSL_ENABLE
214                if (strstr(buffer, "STLS"))
215                    has_ssl = TRUE;
216 #endif /* SSL_ENABLE */
217 #if defined(GSSAPI)
218                 if (strstr(buffer, "GSSAPI"))
219                     has_gssapi = TRUE;
220 #endif /* defined(GSSAPI) */
221 #if defined(KERBEROS_V4)
222                 if (strstr(buffer, "KERBEROS_V4"))
223                     has_kerberos = TRUE;
224 #endif /* defined(KERBEROS_V4)  */
225 #ifdef OPIE_ENABLE
226                 if (strstr(buffer, "X-OTP"))
227                     has_otp = TRUE;
228 #endif /* OPIE_ENABLE */
229                 if (strstr(buffer, "CRAM-MD5"))
230                     has_cram = TRUE;
231             }
232         }
233
234 #ifdef SSL_ENABLE
235        if (has_ssl && !ctl->use_ssl &&
236 #if INET6_ENABLE
237            ctl->server.service && (strcmp(ctl->server.service, "pop3s"))
238 #else /* INET6_ENABLE */
239            ctl->server.port != 995
240 #endif /* INET6_ENABLE */
241            )
242        {
243            char *realhost;
244
245            realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;           gen_transact(sock, "STLS");
246            if (SSLOpen(sock,ctl->sslcert,ctl->sslkey,ctl->sslproto,ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
247            {
248                report(stderr,
249                       GT_("SSL connection failed.\n"));
250                return(PS_AUTHFAIL);
251            }
252        }
253 #endif /* SSL_ENABLE */
254
255         /*
256          * OK, we have an authentication type now.
257          */
258 #if defined(KERBEROS_V4)
259         /* 
260          * Servers doing KPOP have to go through a dummy login sequence
261          * rather than doing SASL.
262          */
263         if (has_kerberos &&
264 #if INET6_ENABLE
265             ctl->server.service && (strcmp(ctl->server.service, KPOP_PORT)!=0)
266 #else /* INET6_ENABLE */
267             ctl->server.port != KPOP_PORT
268 #endif /* INET6_ENABLE */
269             && (ctl->server.authenticate == A_KERBEROS_V4
270              || ctl->server.authenticate == A_KERBEROS_V5
271              || ctl->server.authenticate == A_ANY))
272         {
273             ok = do_rfc1731(sock, "AUTH", ctl->server.truename);
274             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
275                 break;
276         }
277 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
278
279 #if defined(GSSAPI)
280         if (has_gssapi &&
281             (ctl->server.authenticate == A_GSSAPI ||
282              ctl->server.authenticate == A_ANY))
283         {
284             ok = do_gssauth(sock,"AUTH",ctl->server.truename,ctl->remotename);
285             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
286                 break;
287         }
288 #endif /* defined(GSSAPI) */
289
290 #ifdef OPIE_ENABLE
291         if (has_otp &&
292             (ctl->server.authenticate == A_OTP ||
293              ctl->server.authenticate == A_ANY))
294         {
295             ok = do_otp(sock, "AUTH", ctl);
296             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
297                 break;
298         }
299 #endif /* OPIE_ENABLE */
300
301         if (has_cram &&
302             (ctl->server.authenticate == A_CRAM_MD5 ||
303              ctl->server.authenticate == A_ANY))
304         {
305             ok = do_cram_md5(sock, "AUTH", ctl, NULL);
306             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
307                 break;
308         }
309
310         /* ordinary validation, no one-time password or RPA */ 
311         gen_transact(sock, "USER %s", ctl->remotename);
312         strcpy(shroud, ctl->password);
313         ok = gen_transact(sock, "PASS %s", ctl->password);
314         shroud[0] = '\0';
315         break;
316
317     case P_APOP:
318         /* build MD5 digest from greeting timestamp + password */
319         /* find start of timestamp */
320         for (start = greeting;  *start != 0 && *start != '<';  start++)
321             continue;
322         if (*start == 0) {
323             report(stderr,
324                    GT_("Required APOP timestamp not found in greeting\n"));
325             return(PS_AUTHFAIL);
326         }
327
328         /* find end of timestamp */
329         for (end = start;  *end != 0  && *end != '>';  end++)
330             continue;
331         if (*end == 0 || end == start + 1) {
332             report(stderr, 
333                    GT_("Timestamp syntax error in greeting\n"));
334             return(PS_AUTHFAIL);
335         }
336         else
337             *++end = '\0';
338
339         /* copy timestamp and password into digestion buffer */
340         xalloca(msg, char *, (end-start+1) + strlen(ctl->password) + 1);
341         strcpy(msg,start);
342         strcat(msg,ctl->password);
343
344         strcpy(ctl->digest, MD5Digest((unsigned char *)msg));
345
346         ok = gen_transact(sock, "APOP %s %s", ctl->remotename, ctl->digest);
347         break;
348
349     case P_RPOP:
350         if ((ok = gen_transact(sock,"USER %s", ctl->remotename)) == 0)
351             ok = gen_transact(sock, "RPOP %s", ctl->password);
352         break;
353
354     default:
355         report(stderr, GT_("Undefined protocol request in POP3_auth\n"));
356         ok = PS_ERROR;
357     }
358
359     if (ok != 0)
360     {
361         /* maybe we detected a lock-busy condition? */
362         if (ok == PS_LOCKBUSY)
363             report(stderr, GT_("lock busy!  Is another session active?\n")); 
364
365         return(ok);
366     }
367
368     /*
369      * Empirical experience shows some server/OS combinations
370      * may need a brief pause even after any lockfiles on the
371      * server are released, to give the server time to finish
372      * copying back very large mailfolders from the temp-file...
373      * this is only ever an issue with extremely large mailboxes.
374      */
375     sleep(3); /* to be _really_ safe, probably need sleep(5)! */
376
377     /* we're peek-capable if use of TOP is enabled */
378     peek_capable = !(ctl->fetchall || ctl->keep);
379
380     /* we're approved */
381     return(PS_SUCCESS);
382 }
383
384 static int pop3_gettopid( int sock, int num , char *id)
385 {
386     int ok;
387     int got_it;
388     char buf [POPBUFSIZE+1];
389     sprintf( buf, "TOP %d 1", num );
390     if ((ok = gen_transact(sock, buf )) != 0)
391        return ok; 
392     got_it = 0;
393     while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0) 
394     {
395         if (DOTLINE(buf))
396             break;
397         if ( ! got_it && ! strncasecmp("Message-Id:", buf, 11 )) {
398             got_it = 1;
399             /* prevent stack overflows */
400             buf[IDLEN+12] = 0;
401             sscanf( buf+12, "%s", id);
402         }
403     }
404     return 0;
405 }
406
407 static int pop3_slowuidl( int sock,  struct query *ctl, int *countp, int *newp)
408 {
409     /* This approach tries to get the message headers from the
410      * remote hosts and compares the message-id to the already known
411      * ones:
412      *  + if the first message containes a new id, all messages on
413      *    the server will be new
414      *  + if the first is known, try to estimate the last known message
415      *    on the server and check. If this works you know the total number
416      *    of messages to get.
417      *  + Otherwise run a binary search to determine the last known message
418      */
419     int ok, nolinear = 0;
420     int first_nr, list_len, try_id, try_nr, add_id;
421     int num;
422     char id [IDLEN+1];
423     
424     if( (ok = pop3_gettopid( sock, 1, id )) != 0 )
425         return ok;
426     
427     if( ( first_nr = str_nr_in_list(&ctl->oldsaved, id) ) == -1 ) {
428         /* the first message is unknown -> all messages are new */
429         *newp = *countp;        
430         return 0;
431     }
432
433     /* check where we expect the latest known message */
434     list_len = count_list( &ctl->oldsaved );
435     try_id = list_len  - first_nr; /* -1 + 1 */
436     if( try_id > 1 ) {
437         if( try_id <= *countp ) {
438             if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
439                 return ok;
440     
441             try_nr = str_nr_last_in_list(&ctl->oldsaved, id);
442         } else {
443             try_id = *countp+1;
444             try_nr = -1;
445         }
446         if( try_nr != list_len -1 ) {
447             /* some messages inbetween have been deleted... */
448             if( try_nr == -1 ) {
449                 nolinear = 1;
450
451                 for( add_id = 1<<30; add_id > try_id-1; add_id >>= 1 )
452                     ;
453                 for( ; add_id; add_id >>= 1 ) {
454                     if( try_nr == -1 ) {
455                         if( try_id - add_id <= 1 ) {
456                             continue;
457                         }
458                         try_id -= add_id;
459                     } else 
460                         try_id += add_id;
461                     
462                     if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
463                         return ok;
464                     try_nr = str_nr_in_list(&ctl->oldsaved, id);
465                 }
466                 if( try_nr == -1 ) {
467                     try_id--;
468                 }
469             } else {
470                 report(stderr, 
471                        GT_("Messages inserted into list on server. Cannot handle this.\n"));
472                 return -1;
473             }
474         } 
475     }
476     /* the first try_id messages are known -> copy them to the newsaved list */
477     for( num = first_nr; num < list_len; num++ )
478     {
479         struct idlist   *new = save_str(&ctl->newsaved, 
480                                 str_from_nr_list(&ctl->oldsaved, num),
481                                 UID_UNSEEN);
482         new->val.status.num = num - first_nr + 1;
483     }
484
485     if( nolinear ) {
486         free_str_list(&ctl->oldsaved);
487         ctl->oldsaved = 0;
488         last = try_id;
489     }
490
491     *newp = *countp - try_id;
492     return 0;
493 }
494
495 static int pop3_getrange(int sock, 
496                          struct query *ctl,
497                          const char *folder,
498                          int *countp, int *newp, int *bytes)
499 /* get range of messages to be fetched */
500 {
501     int ok;
502     char buf [POPBUFSIZE+1];
503
504     /* Ensure that the new list is properly empty */
505     ctl->newsaved = (struct idlist *)NULL;
506
507 #ifdef MBOX
508     /* Alain Knaff suggests this, but it's not RFC standard */
509     if (folder)
510         if ((ok = gen_transact(sock, "MBOX %s", folder)))
511             return ok;
512 #endif /* MBOX */
513
514     /* get the total message count */
515     gen_send(sock, "STAT");
516     ok = pop3_ok(sock, buf);
517     if (ok == 0)
518         sscanf(buf,"%d %d", countp, bytes);
519     else
520         return(ok);
521
522     /*
523      * Newer, RFC-1725-conformant POP servers may not have the LAST command.
524      * We work as hard as possible to hide this ugliness, but it makes 
525      * counting new messages intrinsically quadratic in the worst case.
526      */
527     last = 0;
528     *newp = -1;
529     if (*countp > 0 && !ctl->fetchall)
530     {
531         char id [IDLEN+1];
532
533         if (!ctl->server.uidl) {
534             gen_send(sock, "LAST");
535             ok = pop3_ok(sock, buf);
536         } else
537             ok = 1;
538         if (ok == 0)
539         {
540             if (sscanf(buf, "%d", &last) == 0)
541             {
542                 report(stderr, GT_("protocol error\n"));
543                 return(PS_ERROR);
544             }
545             *newp = (*countp - last);
546         }
547         else
548         {
549             /* grab the mailbox's UID list */
550             if ((ok = gen_transact(sock, "UIDL")) != 0)
551             {
552                 /* don't worry, yet! do it the slow way */
553                 if((ok = pop3_slowuidl( sock, ctl, countp, newp))!=0)
554                 {
555                     report(stderr, GT_("protocol error while fetching UIDLs\n"));
556                     return(PS_ERROR);
557                 }
558             }
559             else
560             {
561                 int     num;
562
563                 *newp = 0;
564                 while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
565                 {
566                     if (DOTLINE(buf))
567                         break;
568                     else if (sscanf(buf, "%d %s", &num, id) == 2)
569                     {
570                         struct idlist   *new;
571
572                         new = save_str(&ctl->newsaved, id, UID_UNSEEN);
573                         new->val.status.num = num;
574
575                         if (str_in_list(&ctl->oldsaved, id, FALSE)) {
576                             new->val.status.mark = UID_SEEN;
577                             str_set_mark(&ctl->oldsaved, id, UID_SEEN);
578                         }
579                         else
580                             (*newp)++;
581                     }
582                 }
583             }
584         }
585     }
586
587     return(PS_SUCCESS);
588 }
589
590 static int pop3_getsizes(int sock, int count, int *sizes)
591 /* capture the sizes of all messages */
592 {
593     int ok;
594
595     if ((ok = gen_transact(sock, "LIST")) != 0)
596         return(ok);
597     else
598     {
599         char buf [POPBUFSIZE+1];
600
601         while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
602         {
603             unsigned int num, size;
604
605             if (DOTLINE(buf))
606                 break;
607             else if (sscanf(buf, "%u %u", &num, &size) == 2) {
608                 if (num > 0 && num <= count)
609                     sizes[num - 1] = size;
610                 else
611                     /* warn about possible attempt to induce buffer overrun */
612                     report(stderr, "Warning: ignoring bogus data for message sizes returned by server.\n");
613             }
614         }
615
616         return(ok);
617     }
618 }
619
620 static int pop3_is_old(int sock, struct query *ctl, int num)
621 /* is the given message old? */
622 {
623     if (!ctl->oldsaved)
624         return (num <= last);
625     else
626         return (str_in_list(&ctl->oldsaved,
627                             str_find(&ctl->newsaved, num), FALSE));
628 }
629
630 #ifdef UNUSED
631 /*
632  * We could use this to fetch headers only as we do for IMAP.  The trouble 
633  * is that there's no way to fetch the body only.  So the following RETR 
634  * would have to re-fetch the header.  Enough messages have longer headers
635  * than bodies to make this a net loss.
636  */
637 static int pop_fetch_headers(int sock, struct query *ctl,int number,int *lenp)
638 /* request headers of nth message */
639 {
640     int ok;
641     char buf[POPBUFSIZE+1];
642
643     gen_send(sock, "TOP %d 0", number);
644     if ((ok = pop3_ok(sock, buf)) != 0)
645         return(ok);
646
647     *lenp = -1;         /* we got sizes from the LIST response */
648
649     return(PS_SUCCESS);
650 }
651 #endif /* UNUSED */
652
653 static int pop3_fetch(int sock, struct query *ctl, int number, int *lenp)
654 /* request nth message */
655 {
656     int ok;
657     char buf[POPBUFSIZE+1];
658
659 #ifdef SDPS_ENABLE
660     /*
661      * See http://www.demon.net/services/mail/sdps-tech.html
662      * for a description of what we're parsing here.
663      */
664     if (ctl->server.sdps)
665     {
666         int     linecount = 0;
667
668         sdps_envfrom = (char *)NULL;
669         sdps_envto = (char *)NULL;
670         gen_send(sock, "*ENV %d", number);
671         do {
672             if (gen_recv(sock, buf, sizeof(buf)))
673             {
674                 break;
675             }
676             linecount++;
677             switch (linecount) {
678             case 4:
679                 /* No need to wrap envelope from address */
680                 sdps_envfrom = xmalloc(strlen(buf)+1);
681                 strcpy(sdps_envfrom,buf);
682                 break;
683             case 5:
684                 /* Wrap address with To: <> so nxtaddr() likes it */
685                 sdps_envto = xmalloc(strlen(buf)+7);
686                 sprintf(sdps_envto,"To: <%s>",buf);
687                 break;
688             }
689         } while
690             (!(buf[0] == '.' && (buf[1] == '\r' || buf[1] == '\n' || buf[1] == '\0')));
691     }
692 #endif /* SDPS_ENABLE */
693
694     /*
695      * Though the POP RFCs don't document this fact, on almost every
696      * POP3 server I know of messages are marked "seen" only at the
697      * time the OK response to a RETR is issued.
698      *
699      * This means we can use TOP to fetch the message without setting its
700      * seen flag.  This is good!  It means that if the protocol exchange
701      * craps out during the message, it will still be marked `unseen' on
702      * the server.  (Exception: in early 1999 SpryNet's POP3 servers were
703      * reported to mark messages seen on a TOP fetch.)
704      *
705      * However...*don't* do this if we're using keep to suppress deletion!
706      * In that case, marking the seen flag is the only way to prevent the
707      * message from being re-fetched on subsequent runs.
708      *
709      * Also use RETR if fetchall is on.  This gives us a workaround
710      * for servers like usa.net's that bungle TOP.  It's pretty
711      * harmless because fetchall guarantees that any message dropped
712      * by an interrupted RETR will be picked up on the next poll of the
713      * site.
714      *
715      * We take advantage here of the fact that, according to all the
716      * POP RFCs, "if the number of lines requested by the POP3 client
717      * is greater than than the number of lines in the body, then the
718      * POP3 server sends the entire message.").
719      *
720      * The line count passed (99999999) is the maximum value CompuServe will
721      * accept; it's much lower than the natural value 2147483646 (the maximum
722      * twos-complement signed 32-bit integer minus 1) */
723     if (ctl->keep || ctl->fetchall)
724         gen_send(sock, "RETR %d", number);
725     else
726         gen_send(sock, "TOP %d 99999999", number);
727     if ((ok = pop3_ok(sock, buf)) != 0)
728         return(ok);
729
730     *lenp = -1;         /* we got sizes from the LIST response */
731
732     return(PS_SUCCESS);
733 }
734
735 static int pop3_delete(int sock, struct query *ctl, int number)
736 /* delete a given message */
737 {
738     /* actually, mark for deletion -- doesn't happen until QUIT time */
739     return(gen_transact(sock, "DELE %d", number));
740 }
741
742 static int pop3_logout(int sock, struct query *ctl)
743 /* send logout command */
744 {
745     int ok;
746
747 #ifdef __UNUSED__
748     /*
749      * We used to do this in case the server marks messages deleted when seen.
750      * (Yes, this has been reported, in the MercuryP/NLM server.
751      * It's even legal under RFC 1939 (section 8) as a site policy.)
752      * It interacted badly with UIDL, though.  Thomas Zajic wrote:
753      * "Running 'fetchmail -F -v' and checking the logs, I found out
754      * that fetchmail did in fact flush my mailbox properly, but sent
755      * a RSET just before sending QUIT to log off.  This caused the
756      * POP3 server to undo/forget about the previous DELEs, resetting
757      * my mailbox to its original (ie.  unflushed) state. The
758      * ~/.fetchids file did get flushed though, so the next time
759      * fetchmail was run it saw all the old messages as new ones ..."
760      */
761      if (ctl->keep)
762         gen_transact(sock, "RSET");
763 #endif /* __UNUSED__ */
764
765     ok = gen_transact(sock, "QUIT");
766     if (!ok)
767         expunge_uids(ctl);
768
769     if (ctl->lastid)
770     {
771         free(ctl->lastid);
772         ctl->lastid = NULL;
773     }
774
775     return(ok);
776 }
777
778 const static struct method pop3 =
779 {
780     "POP3",             /* Post Office Protocol v3 */
781 #if INET6_ENABLE
782     "pop3",             /* standard POP3 port */
783     "pop3s",            /* ssl POP3 port */
784 #else /* INET6_ENABLE */
785     110,                /* standard POP3 port */
786     995,                /* ssl POP3 port */
787 #endif /* INET6_ENABLE */
788     FALSE,              /* this is not a tagged protocol */
789     TRUE,               /* this uses a message delimiter */
790     pop3_ok,            /* parse command response */
791     pop3_getauth,       /* get authorization */
792     pop3_getrange,      /* query range of messages */
793     pop3_getsizes,      /* we can get a list of sizes */
794     pop3_is_old,        /* how do we tell a message is old? */
795     pop3_fetch,         /* request given message */
796     NULL,               /* no way to fetch body alone */
797     NULL,               /* no message trailer */
798     pop3_delete,        /* how to delete a message */
799     pop3_logout,        /* log out, we're done */
800     FALSE,              /* no, we can't re-poll */
801 };
802
803 int doPOP3 (struct query *ctl)
804 /* retrieve messages using POP3 */
805 {
806 #ifndef MBOX
807     if (ctl->mailboxes->id) {
808         fprintf(stderr,GT_("Option --remote is not supported with POP3\n"));
809         return(PS_SYNTAX);
810     }
811 #endif /* MBOX */
812     peek_capable = !ctl->fetchall;
813     return(do_protocol(ctl, &pop3));
814 }
815 #endif /* POP3_ENABLE */
816
817 /* pop3.c ends here */