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