]> Pileus Git - ~andy/fetchmail/blob - pop3.c
8e356f18a1ebcc24e02f765029756ddd09f9d2a4
[~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 /* these variables are shared between the CAPA probe and the authenticator */
43 #if defined(GSSAPI)
44     flag has_gssapi = FALSE;
45 #endif /* defined(GSSAPI) */
46 #if defined(KERBEROS_V4) || defined(KERBEROS_V5)
47     flag has_kerberos = FALSE;
48 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
49     flag has_cram = FALSE;
50 #ifdef OPIE_ENABLE
51     flag has_otp = FALSE;
52 #endif /* OPIE_ENABLE */
53 #ifdef SSL_ENABLE
54     flag has_ssl = FALSE;
55 #endif /* SSL_ENABLE */
56
57 #if NTLM_ENABLE
58 #include "ntlm.h"
59
60 static tSmbNtlmAuthRequest   request;              
61 static tSmbNtlmAuthChallenge challenge;
62 static tSmbNtlmAuthResponse  response;
63
64 /*
65  * NTLM support by Grant Edwards.
66  *
67  * Handle MS-Exchange NTLM authentication method.  This is the same
68  * as the NTLM auth used by Samba for SMB related services. We just
69  * encode the packets in base64 instead of sending them out via a
70  * network interface.
71  * 
72  * Much source (ntlm.h, smb*.c smb*.h) was borrowed from Samba.
73  */
74
75 static int do_pop3_ntlm(int sock, struct query *ctl)
76 {
77     char msgbuf[2048];
78     int result,len;
79   
80     gen_send(sock, "AUTH MSN");
81
82     if ((result = gen_recv(sock, msgbuf, sizeof msgbuf)))
83         return result;
84   
85     if (msgbuf[0] != '+')
86         return PS_AUTHFAIL;
87   
88     buildSmbNtlmAuthRequest(&request,ctl->remotename,NULL);
89
90     if (outlevel >= O_DEBUG)
91         dumpSmbNtlmAuthRequest(stdout, &request);
92
93     memset(msgbuf,0,sizeof msgbuf);
94     to64frombits (msgbuf, (unsigned char*)&request, SmbLength(&request));
95   
96     if (outlevel >= O_MONITOR)
97         report(stdout, "POP3> %s\n", msgbuf);
98   
99     strcat(msgbuf,"\r\n");
100     SockWrite (sock, msgbuf, strlen (msgbuf));
101
102     if ((gen_recv(sock, msgbuf, sizeof msgbuf)))
103         return result;
104   
105     len = from64tobits ((unsigned char*)&challenge, msgbuf, sizeof(msgbuf));
106     
107     if (outlevel >= O_DEBUG)
108         dumpSmbNtlmAuthChallenge(stdout, &challenge);
109     
110     buildSmbNtlmAuthResponse(&challenge, &response,ctl->remotename,ctl->password);
111   
112     if (outlevel >= O_DEBUG)
113         dumpSmbNtlmAuthResponse(stdout, &response);
114   
115     memset(msgbuf,0,sizeof msgbuf);
116     to64frombits (msgbuf, (unsigned char*)&response, SmbLength(&response));
117
118     if (outlevel >= O_MONITOR)
119         report(stdout, "POP3> %s\n", msgbuf);
120       
121     strcat(msgbuf,"\r\n");
122     SockWrite (sock, msgbuf, strlen (msgbuf));
123   
124     if ((result = gen_recv (sock, msgbuf, sizeof msgbuf)))
125         return result;
126   
127     if (strstr (msgbuf, "OK"))
128         return PS_SUCCESS;
129     else
130         return PS_AUTHFAIL;
131 }
132 #endif /* NTLM */
133
134
135 #define DOTLINE(s)      (s[0] == '.' && (s[1]=='\r'||s[1]=='\n'||s[1]=='\0'))
136
137 static int pop3_ok (int sock, char *argbuf)
138 /* parse command response */
139 {
140     int ok;
141     char buf [POPBUFSIZE+1];
142     char *bufp;
143
144     if ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
145     {   bufp = buf;
146         if (*bufp == '+' || *bufp == '-')
147             bufp++;
148         else
149             return(PS_PROTOCOL);
150
151         while (isalpha(*bufp))
152             bufp++;
153
154         if (*bufp)
155           *(bufp++) = '\0';
156
157         if (strcmp(buf,"+OK") == 0)
158         {
159 #if OPIE_ENABLE
160             strcpy(lastok, bufp);
161 #endif /* OPIE_ENABLE */
162             ok = 0;
163         }
164         else if (strncmp(buf,"-ERR", 4) == 0)
165         {
166             if (stage == STAGE_FETCH)
167                 ok = PS_TRANSIENT;
168             else if (stage > STAGE_GETAUTH)
169                 ok = PS_PROTOCOL;
170             /*
171              * We're checking for "lock busy", "unable to lock", 
172              * "already locked", "wait a few minutes" etc. here. 
173              * This indicates that we have to wait for the server to
174              * unwedge itself before we can poll again.
175              *
176              * PS_LOCKBUSY check empirically verified with two recent
177              * versions of the Berkeley popper; QPOP (version 2.2)  and
178              * QUALCOMM Pop server derived from UCB (version 2.1.4-R3)
179              * These are caught by the case-indifferent "lock" check.
180              * The "wait" catches "mail storage services unavailable,
181              * wait a few minutes and try again" on the InterMail server.
182              *
183              * If these aren't picked up on correctly, fetchmail will 
184              * think there is an authentication failure and wedge the
185              * connection in order to prevent futile polls.
186              *
187              * Gad, what a kluge.
188              */
189             else if (strstr(bufp,"lock")
190                      || strstr(bufp,"Lock")
191                      || strstr(bufp,"LOCK")
192                      || strstr(bufp,"wait")
193                      /* these are blessed by RFC 2449 */
194                      || strstr(bufp,"[IN-USE]")||strstr(bufp,"[LOGIN-DELAY]"))
195                 ok = PS_LOCKBUSY;
196             else if ((strstr(bufp,"Service")
197                      || strstr(bufp,"service"))
198                          && (strstr(bufp,"unavailable")))
199                 ok = PS_SERVBUSY;
200             else
201                 ok = PS_AUTHFAIL;
202             /*
203              * We always want to pass the user lock-busy messages, because
204              * they're red flags.  Other stuff (like AUTH failures on non-
205              * RFC1734 servers) only if we're debugging.
206              */
207             if (*bufp && (ok == PS_LOCKBUSY || outlevel >= O_MONITOR))
208               report(stderr, "%s\n", bufp);
209         }
210         else
211             ok = PS_PROTOCOL;
212
213         if (argbuf != NULL)
214             strcpy(argbuf,bufp);
215     }
216
217     return(ok);
218 }
219
220
221
222 static int capa_probe(sock)
223 /* probe the capabilities of the remote server */
224 {
225     int ok;
226
227 #if defined(GSSAPI)
228     has_gssapi = FALSE;
229 #endif /* defined(GSSAPI) */
230 #if defined(KERBEROS_V4) || defined(KERBEROS_V5)
231     has_kerberos = FALSE;
232 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
233     has_cram = FALSE;
234 #ifdef OPIE_ENABLE
235     has_otp = FALSE;
236 #endif /* OPIE_ENABLE */
237
238     ok = gen_transact(sock, "CAPA");
239     if (ok == PS_SUCCESS)
240     {
241         char buffer[64];
242
243         /* determine what authentication methods we have available */
244         while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0)
245         {
246             if (DOTLINE(buffer))
247                 break;
248 #ifdef SSL_ENABLE
249             if (strstr(buffer, "STLS"))
250                 has_ssl = TRUE;
251 #endif /* SSL_ENABLE */
252 #if defined(GSSAPI)
253             if (strstr(buffer, "GSSAPI"))
254                 has_gssapi = TRUE;
255 #endif /* defined(GSSAPI) */
256 #if defined(KERBEROS_V4)
257             if (strstr(buffer, "KERBEROS_V4"))
258                 has_kerberos = TRUE;
259 #endif /* defined(KERBEROS_V4)  */
260 #ifdef OPIE_ENABLE
261             if (strstr(buffer, "X-OTP"))
262                 has_otp = TRUE;
263 #endif /* OPIE_ENABLE */
264             if (strstr(buffer, "CRAM-MD5"))
265                 has_cram = TRUE;
266         }
267     }
268     return(ok);
269 }
270
271 static int pop3_getauth(int sock, struct query *ctl, char *greeting)
272 /* apply for connection authorization */
273 {
274     int ok;
275     char *start,*end;
276     char *msg;
277 #if OPIE_ENABLE
278     char *challenge;
279 #endif /* OPIE_ENABLE */
280 #ifdef SSL_ENABLE
281     flag did_stls = FALSE;
282 #endif /* SSL_ENABLE */
283
284 #if defined(GSSAPI)
285     has_gssapi = FALSE;
286 #endif /* defined(GSSAPI) */
287 #if defined(KERBEROS_V4) || defined(KERBEROS_V5)
288     has_kerberos = FALSE;
289 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
290     has_cram = FALSE;
291 #ifdef OPIE_ENABLE
292     has_otp = FALSE;
293 #endif /* OPIE_ENABLE */
294 #ifdef SSL_ENABLE
295     has_ssl = FALSE;
296 #endif /* SSL_ENABLE */
297
298     if (ctl->server.authenticate == A_SSH) {
299         return PS_SUCCESS;
300     }
301
302 #ifdef SDPS_ENABLE
303     /*
304      * This needs to catch both demon.co.uk and demon.net.
305      * If we see either, and we're in multidrop mode, try to use
306      * the SDPS *ENV extension.
307      */
308     if (!(ctl->server.sdps) && MULTIDROP(ctl) && strstr(greeting, "demon."))
309         ctl->server.sdps = TRUE;
310 #endif /* SDPS_ENABLE */
311 #ifdef NTLM_ENABLE
312         /* MSN servers require the use of NTLM (MSN) authentication */
313         if (!strcasecmp(ctl->server.pollname, "pop3.email.msn.com") ||
314             ctl->server.authenticate == A_NTLM)
315         {
316             if (!do_pop3_ntlm(sock, ctl))
317             {
318                 return(PS_SUCCESS);
319             }
320             else
321             {
322                 return(PS_AUTHFAIL);
323             }
324         }
325 #endif
326
327     switch (ctl->server.protocol) {
328     case P_POP3:
329 #ifdef RPA_ENABLE
330         /* CompuServe POP3 Servers as of 990730 want AUTH first for RPA */
331         if (strstr(ctl->remotename, "@compuserve.com"))
332         {
333             /* AUTH command should return a list of available mechanisms */
334             if (gen_transact(sock, "AUTH") == 0)
335             {
336                 char buffer[10];
337                 flag has_rpa = FALSE;
338
339                 while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0)
340                 {
341                     if (DOTLINE(buffer))
342                         break;
343                     if (strncasecmp(buffer, "rpa", 3) == 0)
344                         has_rpa = TRUE;
345                 }
346                 if (has_rpa && !POP3_auth_rpa(ctl->remotename, 
347                                               ctl->password, sock))
348                     return(PS_SUCCESS);
349             }
350
351             return(PS_AUTHFAIL);
352         }
353 #endif /* RPA_ENABLE */
354
355         /*
356          * CAPA command may return a list including available
357          * authentication mechanisms.  if it doesn't, no harm done, we
358          * just fall back to a plain login.  Note that this code 
359          * latches the server's authentication type, so that in daemon mode
360          * the CAPA check only needs to be done once at start of run.
361          *
362          * If CAPA fails, then force the authentication method to PASSORD
363          * and repoll immediately.
364          *
365          * These authentication methods are blessed by RFC1734,
366          * describing the POP3 AUTHentication command.
367          */
368         if (ctl->server.authenticate == A_ANY)
369         {
370             if ((ok = capa_probe(sock)) != PS_SUCCESS)
371             /* we are in STAGE_GETAUTH! */
372                 if (ok == PS_AUTHFAIL ||
373                     /* Some servers directly close the socket. However, if we
374                      * have already authenticated before, then a previous CAPA
375                      * must have succeeded. In that case, treat this as a
376                      * genuine socket error and do not change the auth method.
377                      */
378                     (ok == PS_SOCKET && !ctl->wehaveauthed))
379                 {
380                     ctl->server.authenticate = A_PASSWORD;
381                     /* repoll immediately */
382                     ok = PS_REPOLL;
383                     break;
384                 }
385         }
386
387 #ifdef SSL_ENABLE
388         if (has_ssl
389             && !ctl->use_ssl
390             && (!ctl->sslproto || !strcmp(ctl->sslproto,"tls1")))
391         {
392             char *realhost;
393
394            realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
395            ok = gen_transact(sock, "STLS");
396
397            /* We use "tls1" instead of ctl->sslproto, as we want STLS,
398             * not other SSL protocols
399             */
400            if (ok == PS_SUCCESS &&
401                SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
402            {
403                if (!ctl->sslproto && !ctl->wehaveauthed)
404                {
405                    ctl->sslproto = xstrdup("");
406                    /* repoll immediately */
407                    return(PS_REPOLL);
408                }
409                report(stderr,
410                        GT_("SSL connection failed.\n"));
411                 return(PS_AUTHFAIL);
412             }
413            did_stls = TRUE;
414
415            /*
416             * RFC 2595 says this:
417             *
418             * "Once TLS has been started, the client MUST discard cached
419             * information about server capabilities and SHOULD re-issue the
420             * CAPABILITY command.  This is necessary to protect against
421             * man-in-the-middle attacks which alter the capabilities list prior
422             * to STARTTLS.  The server MAY advertise different capabilities
423             * after STARTTLS."
424             */
425            capa_probe(sock);
426         }
427 #endif /* SSL_ENABLE */
428
429         /*
430          * OK, we have an authentication type now.
431          */
432 #if defined(KERBEROS_V4)
433         /* 
434          * Servers doing KPOP have to go through a dummy login sequence
435          * rather than doing SASL.
436          */
437         if (has_kerberos &&
438 #if INET6_ENABLE
439             ctl->server.service && (strcmp(ctl->server.service, KPOP_PORT)!=0)
440 #else /* INET6_ENABLE */
441             ctl->server.port != KPOP_PORT
442 #endif /* INET6_ENABLE */
443             && (ctl->server.authenticate == A_KERBEROS_V4
444              || ctl->server.authenticate == A_KERBEROS_V5
445              || ctl->server.authenticate == A_ANY))
446         {
447             ok = do_rfc1731(sock, "AUTH", ctl->server.truename);
448             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
449                 break;
450         }
451 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
452
453 #if defined(GSSAPI)
454         if (has_gssapi &&
455             (ctl->server.authenticate == A_GSSAPI ||
456              ctl->server.authenticate == A_ANY))
457         {
458             ok = do_gssauth(sock,"AUTH",ctl->server.truename,ctl->remotename);
459             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
460                 break;
461         }
462 #endif /* defined(GSSAPI) */
463
464 #ifdef OPIE_ENABLE
465         if (has_otp &&
466             (ctl->server.authenticate == A_OTP ||
467              ctl->server.authenticate == A_ANY))
468         {
469             ok = do_otp(sock, "AUTH", ctl);
470             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
471                 break;
472         }
473 #endif /* OPIE_ENABLE */
474
475         if (ctl->server.authenticate == A_CRAM_MD5 || 
476             (has_cram && ctl->server.authenticate == A_ANY))
477         {
478             ok = do_cram_md5(sock, "AUTH", ctl, NULL);
479             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
480                 break;
481         }
482
483         /* ordinary validation, no one-time password or RPA */ 
484         gen_transact(sock, "USER %s", ctl->remotename);
485
486 #if OPIE_ENABLE
487         /* see RFC1938: A One-Time Password System */
488         if (challenge = strstr(lastok, "otp-")) {
489           char response[OPIE_RESPONSE_MAX+1];
490           int i;
491
492           i = opiegenerator(challenge, !strcmp(ctl->password, "opie") ? "" : ctl->password, response);
493           if ((i == -2) && !run.poll_interval) {
494             char secret[OPIE_SECRET_MAX+1];
495             fprintf(stderr, GT_("Secret pass phrase: "));
496             if (opiereadpass(secret, sizeof(secret), 0))
497               i = opiegenerator(challenge,  secret, response);
498             memset(secret, 0, sizeof(secret));
499           };
500
501           if (i) {
502             ok = PS_ERROR;
503             break;
504           };
505
506           ok = gen_transact(sock, "PASS %s", response);
507           break;
508         }
509 #endif /* OPIE_ENABLE */
510
511         strcpy(shroud, ctl->password);
512         ok = gen_transact(sock, "PASS %s", ctl->password);
513         shroud[0] = '\0';
514 #ifdef SSL_ENABLE
515         /* this is for servers which claim to support TLS, but actually
516          * don't! */
517         if (did_stls && ok == PS_SOCKET && !ctl->sslproto && !ctl->wehaveauthed)
518         {
519             ctl->sslproto = xstrdup("");
520             /* repoll immediately */
521             ok = PS_REPOLL;
522         }
523 #endif
524         break;
525
526     case P_APOP:
527         /* build MD5 digest from greeting timestamp + password */
528         /* find start of timestamp */
529         for (start = greeting;  *start != 0 && *start != '<';  start++)
530             continue;
531         if (*start == 0) {
532             report(stderr,
533                    GT_("Required APOP timestamp not found in greeting\n"));
534             return(PS_AUTHFAIL);
535         }
536
537         /* find end of timestamp */
538         for (end = start;  *end != 0  && *end != '>';  end++)
539             continue;
540         if (*end == 0 || end == start + 1) {
541             report(stderr, 
542                    GT_("Timestamp syntax error in greeting\n"));
543             return(PS_AUTHFAIL);
544         }
545         else
546             *++end = '\0';
547
548         /* copy timestamp and password into digestion buffer */
549         xalloca(msg, char *, (end-start+1) + strlen(ctl->password) + 1);
550         strcpy(msg,start);
551         strcat(msg,ctl->password);
552
553         strcpy(ctl->digest, MD5Digest((unsigned char *)msg));
554
555         ok = gen_transact(sock, "APOP %s %s", ctl->remotename, ctl->digest);
556         break;
557
558     case P_RPOP:
559         if ((ok = gen_transact(sock,"USER %s", ctl->remotename)) == 0)
560             ok = gen_transact(sock, "RPOP %s", ctl->password);
561         break;
562
563     default:
564         report(stderr, GT_("Undefined protocol request in POP3_auth\n"));
565         ok = PS_ERROR;
566     }
567
568     if (ok != 0)
569     {
570         /* maybe we detected a lock-busy condition? */
571         if (ok == PS_LOCKBUSY)
572             report(stderr, GT_("lock busy!  Is another session active?\n")); 
573
574         return(ok);
575     }
576
577     /*
578      * Empirical experience shows some server/OS combinations
579      * may need a brief pause even after any lockfiles on the
580      * server are released, to give the server time to finish
581      * copying back very large mailfolders from the temp-file...
582      * this is only ever an issue with extremely large mailboxes.
583      */
584     sleep(3); /* to be _really_ safe, probably need sleep(5)! */
585
586     /* we're peek-capable if use of TOP is enabled */
587     peek_capable = !(ctl->fetchall || ctl->keep);
588
589     /* we're approved */
590     return(PS_SUCCESS);
591 }
592
593 static int pop3_gettopid( int sock, int num , char *id)
594 {
595     int ok;
596     int got_it;
597     char buf [POPBUFSIZE+1];
598     sprintf( buf, "TOP %d 1", num );
599     if ((ok = gen_transact(sock, buf )) != 0)
600        return ok; 
601     got_it = 0;
602     while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0) 
603     {
604         if (DOTLINE(buf))
605             break;
606         if ( ! got_it && ! strncasecmp("Message-Id:", buf, 11 )) {
607             got_it = 1;
608             /* prevent stack overflows */
609             buf[IDLEN+12] = 0;
610             sscanf( buf+12, "%s", id);
611         }
612     }
613     return 0;
614 }
615
616 static int pop3_getuidl( int sock, int num , char *id)
617 {
618     int ok;
619     char buf [POPBUFSIZE+1];
620     gen_send(sock, "UIDL %d", num);
621     if ((ok = pop3_ok(sock, buf)) != 0)
622         return(ok);
623     if (sscanf(buf, "%d %s", &num, id) != 2)
624         return(PS_PROTOCOL);
625     return(PS_SUCCESS);
626 }
627
628 static int pop3_fastuidl( int sock,  struct query *ctl, unsigned int count, int *newp)
629 {
630     int ok;
631     unsigned int first_nr, last_nr, try_nr;
632     char id [IDLEN+1];
633
634     first_nr = 0;
635     last_nr = count + 1;
636     while (first_nr < last_nr - 1)
637     {
638         struct idlist   *new;
639
640         try_nr = (first_nr + last_nr) / 2;
641         if( (ok = pop3_getuidl( sock, try_nr, id )) != 0 )
642             return ok;
643         if ((new = str_in_list(&ctl->oldsaved, id, FALSE)))
644         {
645             flag mark = new->val.status.mark;
646             if (mark == UID_DELETED || mark == UID_EXPUNGED)
647             {
648                 if (outlevel >= O_VERBOSE)
649                     report(stderr, GT_("id=%s (num=%d) was deleted, but is still present!\n"), id, try_nr);
650                 /* just mark it as seen now! */
651                 new->val.status.mark = mark = UID_SEEN;
652             }
653
654             /* narrow the search region! */
655             if (mark == UID_UNSEEN)
656             {
657                 if (outlevel >= O_DEBUG)
658                     report(stdout, GT_("%u is unseen\n"), try_nr);
659                 last_nr = try_nr;
660             }
661             else
662                 first_nr = try_nr;
663
664             /* save the number */
665             new->val.status.num = try_nr;
666         }
667         else
668         {
669             if (outlevel >= O_DEBUG)
670                 report(stdout, GT_("%u is unseen\n"), try_nr);
671             last_nr = try_nr;
672
673             /* save it */
674             new = save_str(&ctl->oldsaved, id, UID_UNSEEN);
675             new->val.status.num = try_nr;
676         }
677     }
678     if (outlevel >= O_DEBUG && last_nr <= count)
679         report(stdout, GT_("%u is first unseen\n"), last_nr);
680
681     /* update last! */
682     *newp = count - first_nr;
683     last = first_nr;
684     return 0;
685 }
686
687 static int pop3_slowuidl( int sock,  struct query *ctl, int *countp, int *newp)
688 {
689     /* This approach tries to get the message headers from the
690      * remote hosts and compares the message-id to the already known
691      * ones:
692      *  + if the first message containes a new id, all messages on
693      *    the server will be new
694      *  + if the first is known, try to estimate the last known message
695      *    on the server and check. If this works you know the total number
696      *    of messages to get.
697      *  + Otherwise run a binary search to determine the last known message
698      */
699     int ok, nolinear = 0;
700     int first_nr, list_len, try_id, try_nr, add_id;
701     int num;
702     char id [IDLEN+1];
703     
704     if( (ok = pop3_gettopid( sock, 1, id )) != 0 )
705         return ok;
706     
707     if( ( first_nr = str_nr_in_list(&ctl->oldsaved, id) ) == -1 ) {
708         /* the first message is unknown -> all messages are new */
709         *newp = *countp;        
710         return 0;
711     }
712
713     /* check where we expect the latest known message */
714     list_len = count_list( &ctl->oldsaved );
715     try_id = list_len  - first_nr; /* -1 + 1 */
716     if( try_id > 1 ) {
717         if( try_id <= *countp ) {
718             if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
719                 return ok;
720     
721             try_nr = str_nr_last_in_list(&ctl->oldsaved, id);
722         } else {
723             try_id = *countp+1;
724             try_nr = -1;
725         }
726         if( try_nr != list_len -1 ) {
727             /* some messages inbetween have been deleted... */
728             if( try_nr == -1 ) {
729                 nolinear = 1;
730
731                 for( add_id = 1<<30; add_id > try_id-1; add_id >>= 1 )
732                     ;
733                 for( ; add_id; add_id >>= 1 ) {
734                     if( try_nr == -1 ) {
735                         if( try_id - add_id <= 1 ) {
736                             continue;
737                         }
738                         try_id -= add_id;
739                     } else 
740                         try_id += add_id;
741                     
742                     if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
743                         return ok;
744                     try_nr = str_nr_in_list(&ctl->oldsaved, id);
745                 }
746                 if( try_nr == -1 ) {
747                     try_id--;
748                 }
749             } else {
750                 report(stderr, 
751                        GT_("Messages inserted into list on server. Cannot handle this.\n"));
752                 return -1;
753             }
754         } 
755     }
756     /* the first try_id messages are known -> copy them to the newsaved list */
757     for( num = first_nr; num < list_len; num++ )
758     {
759         struct idlist   *new = save_str(&ctl->newsaved, 
760                                 str_from_nr_list(&ctl->oldsaved, num),
761                                 UID_UNSEEN);
762         new->val.status.num = num - first_nr + 1;
763     }
764
765     if( nolinear ) {
766         free_str_list(&ctl->oldsaved);
767         ctl->oldsaved = 0;
768         last = try_id;
769     }
770
771     *newp = *countp - try_id;
772     return 0;
773 }
774
775 static int pop3_getrange(int sock, 
776                          struct query *ctl,
777                          const char *folder,
778                          int *countp, int *newp, int *bytes)
779 /* get range of messages to be fetched */
780 {
781     int ok;
782     char buf [POPBUFSIZE+1];
783
784     /* Ensure that the new list is properly empty */
785     ctl->newsaved = (struct idlist *)NULL;
786
787 #ifdef MBOX
788     /* Alain Knaff suggests this, but it's not RFC standard */
789     if (folder)
790         if ((ok = gen_transact(sock, "MBOX %s", folder)))
791             return ok;
792 #endif /* MBOX */
793
794     /* get the total message count */
795     gen_send(sock, "STAT");
796     ok = pop3_ok(sock, buf);
797     if (ok == 0)
798         sscanf(buf,"%d %d", countp, bytes);
799     else
800         return(ok);
801
802     /*
803      * Newer, RFC-1725-conformant POP servers may not have the LAST command.
804      * We work as hard as possible to hide this ugliness, but it makes 
805      * counting new messages intrinsically quadratic in the worst case.
806      */
807     last = 0;
808     *newp = -1;
809     if (*countp > 0 && !ctl->fetchall)
810     {
811         int fastuidl;
812         char id [IDLEN+1];
813
814         /* should we do fast uidl this time? */
815         fastuidl = ctl->fastuidl;
816         if (*countp > 7 &&              /* linear search is better if there are few mails! */
817             !ctl->flush &&              /* with flush, it is safer to disable fastuidl */
818             NUM_NONZERO (fastuidl))
819         {
820             if (fastuidl == 1)
821                 dofastuidl = 1;
822             else
823                 dofastuidl = ctl->fastuidlcount != 0;
824         }
825         else
826             dofastuidl = 0;
827
828         if (!ctl->server.uidl) {
829             gen_send(sock, "LAST");
830             ok = pop3_ok(sock, buf);
831         } else
832             ok = 1;
833         if (ok == 0)
834         {
835             if (sscanf(buf, "%d", &last) == 0)
836             {
837                 report(stderr, GT_("protocol error\n"));
838                 return(PS_ERROR);
839             }
840             *newp = (*countp - last);
841         }
842         else
843         {
844             if (dofastuidl)
845                 return(pop3_fastuidl( sock, ctl, *countp, newp));
846             /* grab the mailbox's UID list */
847             if ((ok = gen_transact(sock, "UIDL")) != 0)
848             {
849                 /* don't worry, yet! do it the slow way */
850                 if((ok = pop3_slowuidl( sock, ctl, countp, newp))!=0)
851                 {
852                     report(stderr, GT_("protocol error while fetching UIDLs\n"));
853                     return(PS_ERROR);
854                 }
855             }
856             else
857             {
858                 int     num;
859
860                 *newp = 0;
861                 while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
862                 {
863                     if (DOTLINE(buf))
864                         break;
865                     else if (sscanf(buf, "%d %s", &num, id) == 2)
866                     {
867                         struct idlist   *old, *new;
868
869                         new = save_str(&ctl->newsaved, id, UID_UNSEEN);
870                         new->val.status.num = num;
871
872                         if ((old = str_in_list(&ctl->oldsaved, id, FALSE)))
873                         {
874                             flag mark = old->val.status.mark;
875                             if (mark == UID_DELETED || mark == UID_EXPUNGED)
876                             {
877                                 if (outlevel >= O_VERBOSE)
878                                     report(stderr, GT_("id=%s (num=%d) was deleted, but is still present!\n"), id, num);
879                                 /* just mark it as seen now! */
880                                 old->val.status.mark = mark = UID_SEEN;
881                             }
882                             new->val.status.mark = mark;
883                             if (mark == UID_UNSEEN)
884                             {
885                                 (*newp)++;
886                                 if (outlevel >= O_DEBUG)
887                                     report(stdout, GT_("%u is unseen\n"), num);
888                             }
889                         }
890                         else
891                         {
892                             (*newp)++;
893                             if (outlevel >= O_DEBUG)
894                                 report(stdout, GT_("%u is unseen\n"), num);
895                             /* add it to oldsaved also! In case, we do not
896                              * swap the lists (say, due to socket error),
897                              * the same mail will not be downloaded again.
898                              */
899                             old = save_str(&ctl->oldsaved, id, UID_UNSEEN);
900                             old->val.status.num = num;
901                         }
902                     }
903                 }
904             }
905         }
906     }
907
908     return(PS_SUCCESS);
909 }
910
911 static int pop3_getpartialsizes(int sock, int first, int last, int *sizes)
912 /* capture the size of message #first */
913 {
914     int ok, i;
915     char buf [POPBUFSIZE+1];
916     unsigned int num, size;
917
918     for (i = first; i <= last; i++) {
919         gen_send(sock, "LIST %d", i);
920         if ((ok = pop3_ok(sock, buf)) != 0)
921             return(ok);
922         if (sscanf(buf, "%u %u", &num, &size) == 2) {
923             if (num == i)
924                 sizes[i - first] = size;
925             else
926                 /* warn about possible attempt to induce buffer overrun
927                  *
928                  * we expect server reply message number and requested
929                  * message number to match */
930                 report(stderr, "Warning: ignoring bogus data for message sizes returned by server.\n");
931         }
932     }
933     return(ok);
934 }
935
936 static int pop3_getsizes(int sock, int count, int *sizes)
937 /* capture the sizes of all messages */
938 {
939     int ok;
940
941     if ((ok = gen_transact(sock, "LIST")) != 0)
942         return(ok);
943     else
944     {
945         char buf [POPBUFSIZE+1];
946
947         while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
948         {
949             unsigned int num, size;
950
951             if (DOTLINE(buf))
952                 break;
953             else if (sscanf(buf, "%u %u", &num, &size) == 2) {
954                 if (num > 0 && num <= count)
955                     sizes[num - 1] = size;
956                 else
957                     /* warn about possible attempt to induce buffer overrun */
958                     report(stderr, "Warning: ignoring bogus data for message sizes returned by server.\n");
959             }
960         }
961
962         return(ok);
963     }
964 }
965
966 static int pop3_is_old(int sock, struct query *ctl, int num)
967 /* is the given message old? */
968 {
969     struct idlist *new;
970     if (!ctl->oldsaved)
971         return (num <= last);
972     else if (dofastuidl)
973     {
974         char id [IDLEN+1];
975
976         if (num <= last)
977             return(TRUE);
978
979         /* in fast uidl, we manipulate the old list only! */
980
981         if ((new = id_find(&ctl->oldsaved, num)))
982         {
983             /* we already have the id! */
984             return(new->val.status.mark != UID_UNSEEN);
985         }
986
987         /* get the uidl first! */
988         if (pop3_getuidl(sock, num, id) != PS_SUCCESS)
989             return(TRUE);
990
991         if ((new = str_in_list(&ctl->oldsaved, id, FALSE))) {
992             /* we already have the id! */
993             new->val.status.num = num;
994             return(new->val.status.mark != UID_UNSEEN);
995         }
996
997         /* save it */
998         new = save_str(&ctl->oldsaved, id, UID_UNSEEN);
999         new->val.status.num = num;
1000         return(FALSE);
1001     }
1002     else
1003         return ((new = id_find(&ctl->newsaved, num)) != NULL &&
1004             new->val.status.mark != UID_UNSEEN);
1005 }
1006
1007 #ifdef UNUSED
1008 /*
1009  * We could use this to fetch headers only as we do for IMAP.  The trouble 
1010  * is that there's no way to fetch the body only.  So the following RETR 
1011  * would have to re-fetch the header.  Enough messages have longer headers
1012  * than bodies to make this a net loss.
1013  */
1014 static int pop_fetch_headers(int sock, struct query *ctl,int number,int *lenp)
1015 /* request headers of nth message */
1016 {
1017     int ok;
1018     char buf[POPBUFSIZE+1];
1019
1020     gen_send(sock, "TOP %d 0", number);
1021     if ((ok = pop3_ok(sock, buf)) != 0)
1022         return(ok);
1023
1024     *lenp = -1;         /* we got sizes from the LIST response */
1025
1026     return(PS_SUCCESS);
1027 }
1028 #endif /* UNUSED */
1029
1030 static int pop3_fetch(int sock, struct query *ctl, int number, int *lenp)
1031 /* request nth message */
1032 {
1033     int ok;
1034     char buf[POPBUFSIZE+1];
1035
1036 #ifdef SDPS_ENABLE
1037     /*
1038      * See http://www.demon.net/services/mail/sdps-tech.html
1039      * for a description of what we're parsing here.
1040      */
1041     if (ctl->server.sdps)
1042     {
1043         int     linecount = 0;
1044
1045         sdps_envfrom = (char *)NULL;
1046         sdps_envto = (char *)NULL;
1047         gen_send(sock, "*ENV %d", number);
1048         do {
1049             if (gen_recv(sock, buf, sizeof(buf)))
1050             {
1051                 break;
1052             }
1053             linecount++;
1054             switch (linecount) {
1055             case 4:
1056                 /* No need to wrap envelope from address */
1057                 sdps_envfrom = xmalloc(strlen(buf)+1);
1058                 strcpy(sdps_envfrom,buf);
1059                 break;
1060             case 5:
1061                 /* Wrap address with To: <> so nxtaddr() likes it */
1062                 sdps_envto = xmalloc(strlen(buf)+7);
1063                 sprintf(sdps_envto,"To: <%s>",buf);
1064                 break;
1065             }
1066         } while
1067             (!(buf[0] == '.' && (buf[1] == '\r' || buf[1] == '\n' || buf[1] == '\0')));
1068     }
1069 #endif /* SDPS_ENABLE */
1070
1071     /*
1072      * Though the POP RFCs don't document this fact, on almost every
1073      * POP3 server I know of messages are marked "seen" only at the
1074      * time the OK response to a RETR is issued.
1075      *
1076      * This means we can use TOP to fetch the message without setting its
1077      * seen flag.  This is good!  It means that if the protocol exchange
1078      * craps out during the message, it will still be marked `unseen' on
1079      * the server.  (Exception: in early 1999 SpryNet's POP3 servers were
1080      * reported to mark messages seen on a TOP fetch.)
1081      *
1082      * However...*don't* do this if we're using keep to suppress deletion!
1083      * In that case, marking the seen flag is the only way to prevent the
1084      * message from being re-fetched on subsequent runs.
1085      *
1086      * Also use RETR if fetchall is on.  This gives us a workaround
1087      * for servers like usa.net's that bungle TOP.  It's pretty
1088      * harmless because fetchall guarantees that any message dropped
1089      * by an interrupted RETR will be picked up on the next poll of the
1090      * site.
1091      *
1092      * We take advantage here of the fact that, according to all the
1093      * POP RFCs, "if the number of lines requested by the POP3 client
1094      * is greater than than the number of lines in the body, then the
1095      * POP3 server sends the entire message.").
1096      *
1097      * The line count passed (99999999) is the maximum value CompuServe will
1098      * accept; it's much lower than the natural value 2147483646 (the maximum
1099      * twos-complement signed 32-bit integer minus 1) */
1100     if (ctl->keep || ctl->fetchall)
1101         gen_send(sock, "RETR %d", number);
1102     else
1103         gen_send(sock, "TOP %d 99999999", number);
1104     if ((ok = pop3_ok(sock, buf)) != 0)
1105         return(ok);
1106
1107     *lenp = -1;         /* we got sizes from the LIST response */
1108
1109     return(PS_SUCCESS);
1110 }
1111
1112 static void mark_uid_seen(struct query *ctl, int number)
1113 /* Tell the UID code we've seen this. */
1114 {
1115     struct idlist       *sdp;
1116
1117     if ((sdp = id_find(&ctl->newsaved, number)))
1118         sdp->val.status.mark = UID_SEEN;
1119     /* mark it as seen in oldsaved also! In case, we do not swap the lists
1120      * (say, due to socket error), the same mail will not be downloaded
1121      * again.
1122      */
1123     if ((sdp = id_find(&ctl->oldsaved, number)))
1124         sdp->val.status.mark = UID_SEEN;
1125 }
1126
1127 static int pop3_delete(int sock, struct query *ctl, int number)
1128 /* delete a given message */
1129 {
1130     int ok;
1131     mark_uid_seen(ctl, number);
1132     /* actually, mark for deletion -- doesn't happen until QUIT time */
1133     ok = gen_transact(sock, "DELE %d", number);
1134     if (ok != PS_SUCCESS)
1135         return(ok);
1136     delete_str(dofastuidl ? &ctl->oldsaved : &ctl->newsaved, number);
1137     return(PS_SUCCESS);
1138 }
1139
1140 static int pop3_mark_seen(int sock, struct query *ctl, int number)
1141 /* mark a given message as seen */
1142 {
1143     mark_uid_seen(ctl, number);
1144     return(PS_SUCCESS);
1145 }
1146
1147 static int pop3_logout(int sock, struct query *ctl)
1148 /* send logout command */
1149 {
1150     int ok;
1151
1152 #ifdef __UNUSED__
1153     /*
1154      * We used to do this in case the server marks messages deleted when seen.
1155      * (Yes, this has been reported, in the MercuryP/NLM server.
1156      * It's even legal under RFC 1939 (section 8) as a site policy.)
1157      * It interacted badly with UIDL, though.  Thomas Zajic wrote:
1158      * "Running 'fetchmail -F -v' and checking the logs, I found out
1159      * that fetchmail did in fact flush my mailbox properly, but sent
1160      * a RSET just before sending QUIT to log off.  This caused the
1161      * POP3 server to undo/forget about the previous DELEs, resetting
1162      * my mailbox to its original (ie.  unflushed) state. The
1163      * ~/.fetchids file did get flushed though, so the next time
1164      * fetchmail was run it saw all the old messages as new ones ..."
1165      */
1166      if (ctl->keep)
1167         gen_transact(sock, "RSET");
1168 #endif /* __UNUSED__ */
1169
1170     ok = gen_transact(sock, "QUIT");
1171     if (!ok)
1172         expunge_uids(ctl);
1173
1174     return(ok);
1175 }
1176
1177 const static struct method pop3 =
1178 {
1179     "POP3",             /* Post Office Protocol v3 */
1180 #if INET6_ENABLE
1181     "pop3",             /* standard POP3 port */
1182     "pop3s",            /* ssl POP3 port */
1183 #else /* INET6_ENABLE */
1184     110,                /* standard POP3 port */
1185     995,                /* ssl POP3 port */
1186 #endif /* INET6_ENABLE */
1187     FALSE,              /* this is not a tagged protocol */
1188     TRUE,               /* this uses a message delimiter */
1189     pop3_ok,            /* parse command response */
1190     pop3_getauth,       /* get authorization */
1191     pop3_getrange,      /* query range of messages */
1192     pop3_getsizes,      /* we can get a list of sizes */
1193     pop3_getpartialsizes,       /* we can get the size of 1 mail */
1194     pop3_is_old,        /* how do we tell a message is old? */
1195     pop3_fetch,         /* request given message */
1196     NULL,               /* no way to fetch body alone */
1197     NULL,               /* no message trailer */
1198     pop3_delete,        /* how to delete a message */
1199     pop3_mark_seen,     /* how to mark a message as seen */
1200     pop3_logout,        /* log out, we're done */
1201     FALSE,              /* no, we can't re-poll */
1202 };
1203
1204 int doPOP3 (struct query *ctl)
1205 /* retrieve messages using POP3 */
1206 {
1207 #ifndef MBOX
1208     if (ctl->mailboxes->id) {
1209         fprintf(stderr,GT_("Option --remote is not supported with POP3\n"));
1210         return(PS_SYNTAX);
1211     }
1212 #endif /* MBOX */
1213     peek_capable = !ctl->fetchall;
1214     return(do_protocol(ctl, &pop3));
1215 }
1216 #endif /* POP3_ENABLE */
1217
1218 /* pop3.c ends here */