]> Pileus Git - ~andy/fetchmail/blob - pop3.c
Do not disable TOP in 'keep, but not uidl' mode.
[~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 #ifndef strstr          /* glibc-2.1 declares this as a macro */
29 extern char *strstr(const char *, const char *);        /* 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 #ifdef 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 #ifdef 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((unsigned char)*bufp))
152             bufp++;
153
154         if (*bufp)
155           *(bufp++) = '\0';
156
157         if (strcmp(buf,"+OK") == 0)
158         {
159 #ifdef 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(int 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 #ifdef 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->use_ssl != FLAG_FALSE) ||
369             (ctl->server.authenticate == A_ANY) ||
370             (ctl->server.authenticate == A_GSSAPI) ||
371             (ctl->server.authenticate == A_KERBEROS_V4) ||
372             (ctl->server.authenticate == A_OTP) ||
373             (ctl->server.authenticate == A_CRAM_MD5))
374         {
375             if ((ok = capa_probe(sock)) != PS_SUCCESS)
376             /* we are in STAGE_GETAUTH! */
377                 if (ok == PS_AUTHFAIL ||
378                     /* Some servers directly close the socket. However, if we
379                      * have already authenticated before, then a previous CAPA
380                      * must have succeeded. In that case, treat this as a
381                      * genuine socket error and do not change the auth method.
382                      */
383                     (ok == PS_SOCKET && !ctl->wehaveauthed))
384                 {
385                     ctl->server.authenticate = A_PASSWORD;
386                     /* repoll immediately */
387                     ok = PS_REPOLL;
388                     break;
389                 }
390         }
391
392 #ifdef SSL_ENABLE
393         if (has_ssl
394             && !ctl->use_ssl
395             && (!ctl->sslproto || !strcmp(ctl->sslproto,"tls1")))
396         {
397             char *realhost;
398
399            realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
400            ok = gen_transact(sock, "STLS");
401
402            /* We use "tls1" instead of ctl->sslproto, as we want STLS,
403             * not other SSL protocols
404             */
405            if (ok == PS_SUCCESS &&
406                SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
407            {
408                if (!ctl->sslproto && !ctl->wehaveauthed)
409                {
410                    ctl->sslproto = xstrdup("");
411                    /* repoll immediately */
412                    return(PS_REPOLL);
413                }
414                report(stderr,
415                        GT_("SSL connection failed.\n"));
416                 return(PS_AUTHFAIL);
417             }
418            did_stls = TRUE;
419
420            /*
421             * RFC 2595 says this:
422             *
423             * "Once TLS has been started, the client MUST discard cached
424             * information about server capabilities and SHOULD re-issue the
425             * CAPABILITY command.  This is necessary to protect against
426             * man-in-the-middle attacks which alter the capabilities list prior
427             * to STARTTLS.  The server MAY advertise different capabilities
428             * after STARTTLS."
429             */
430            capa_probe(sock);
431         }
432 #endif /* SSL_ENABLE */
433
434         /*
435          * OK, we have an authentication type now.
436          */
437 #if defined(KERBEROS_V4)
438         /* 
439          * Servers doing KPOP have to go through a dummy login sequence
440          * rather than doing SASL.
441          */
442         if (has_kerberos &&
443 #ifdef INET6_ENABLE
444             ctl->server.service && (strcmp(ctl->server.service, KPOP_PORT)!=0)
445 #else /* INET6_ENABLE */
446             ctl->server.port != KPOP_PORT
447 #endif /* INET6_ENABLE */
448             && (ctl->server.authenticate == A_KERBEROS_V4
449              || ctl->server.authenticate == A_KERBEROS_V5
450              || ctl->server.authenticate == A_ANY))
451         {
452             ok = do_rfc1731(sock, "AUTH", ctl->server.truename);
453             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
454                 break;
455         }
456 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
457
458 #if defined(GSSAPI)
459         if (has_gssapi &&
460             (ctl->server.authenticate == A_GSSAPI ||
461              ctl->server.authenticate == A_ANY))
462         {
463             ok = do_gssauth(sock,"AUTH","pop",ctl->server.truename,ctl->remotename);
464             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
465                 break;
466         }
467 #endif /* defined(GSSAPI) */
468
469 #ifdef OPIE_ENABLE
470         if (has_otp &&
471             (ctl->server.authenticate == A_OTP ||
472              ctl->server.authenticate == A_ANY))
473         {
474             ok = do_otp(sock, "AUTH", ctl);
475             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
476                 break;
477         }
478 #endif /* OPIE_ENABLE */
479
480         if (ctl->server.authenticate == A_CRAM_MD5 || 
481             (has_cram && ctl->server.authenticate == A_ANY))
482         {
483             ok = do_cram_md5(sock, "AUTH", ctl, NULL);
484             if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
485                 break;
486         }
487
488         /* ordinary validation, no one-time password or RPA */ 
489         gen_transact(sock, "USER %s", ctl->remotename);
490
491 #ifdef OPIE_ENABLE
492         /* see RFC1938: A One-Time Password System */
493         if ((challenge = strstr(lastok, "otp-"))) {
494           char response[OPIE_RESPONSE_MAX+1];
495           int i;
496
497           i = opiegenerator(challenge, !strcmp(ctl->password, "opie") ? "" : ctl->password, response);
498           if ((i == -2) && !run.poll_interval) {
499             char secret[OPIE_SECRET_MAX+1];
500             fprintf(stderr, GT_("Secret pass phrase: "));
501             if (opiereadpass(secret, sizeof(secret), 0))
502               i = opiegenerator(challenge,  secret, response);
503             memset(secret, 0, sizeof(secret));
504           };
505
506           if (i) {
507             ok = PS_ERROR;
508             break;
509           };
510
511           ok = gen_transact(sock, "PASS %s", response);
512           break;
513         }
514 #endif /* OPIE_ENABLE */
515
516         strcpy(shroud, ctl->password);
517         ok = gen_transact(sock, "PASS %s", ctl->password);
518         shroud[0] = '\0';
519 #ifdef SSL_ENABLE
520         /* this is for servers which claim to support TLS, but actually
521          * don't! */
522         if (did_stls && ok == PS_SOCKET && !ctl->sslproto && !ctl->wehaveauthed)
523         {
524             ctl->sslproto = xstrdup("");
525             /* repoll immediately */
526             ok = PS_REPOLL;
527         }
528 #endif
529         break;
530
531     case P_APOP:
532         /* build MD5 digest from greeting timestamp + password */
533         /* find start of timestamp */
534         for (start = greeting;  *start != 0 && *start != '<';  start++)
535             continue;
536         if (*start == 0) {
537             report(stderr,
538                    GT_("Required APOP timestamp not found in greeting\n"));
539             return(PS_AUTHFAIL);
540         }
541
542         /* find end of timestamp */
543         for (end = start;  *end != 0  && *end != '>';  end++)
544             continue;
545         if (*end == 0 || end == start + 1) {
546             report(stderr, 
547                    GT_("Timestamp syntax error in greeting\n"));
548             return(PS_AUTHFAIL);
549         }
550         else
551             *++end = '\0';
552
553         /* copy timestamp and password into digestion buffer */
554         xalloca(msg, char *, (end-start+1) + strlen(ctl->password) + 1);
555         strcpy(msg,start);
556         strcat(msg,ctl->password);
557
558         strcpy(ctl->digest, MD5Digest((unsigned char *)msg));
559
560         ok = gen_transact(sock, "APOP %s %s", ctl->remotename, ctl->digest);
561         break;
562
563     case P_RPOP:
564         if ((ok = gen_transact(sock,"USER %s", ctl->remotename)) == 0)
565             ok = gen_transact(sock, "RPOP %s", ctl->password);
566         break;
567
568     default:
569         report(stderr, GT_("Undefined protocol request in POP3_auth\n"));
570         ok = PS_ERROR;
571     }
572
573     if (ok != 0)
574     {
575         /* maybe we detected a lock-busy condition? */
576         if (ok == PS_LOCKBUSY)
577             report(stderr, GT_("lock busy!  Is another session active?\n")); 
578
579         return(ok);
580     }
581
582     /*
583      * Empirical experience shows some server/OS combinations
584      * may need a brief pause even after any lockfiles on the
585      * server are released, to give the server time to finish
586      * copying back very large mailfolders from the temp-file...
587      * this is only ever an issue with extremely large mailboxes.
588      */
589     sleep(3); /* to be _really_ safe, probably need sleep(5)! */
590
591     /* we're peek-capable if use of TOP is enabled */
592     peek_capable = !(ctl->fetchall || (ctl->keep && !ctl->server.uidl));
593
594     /* we're approved */
595     return(PS_SUCCESS);
596 }
597
598 static int pop3_gettopid( int sock, int num , char *id)
599 {
600     int ok;
601     int got_it;
602     char buf [POPBUFSIZE+1];
603     sprintf( buf, "TOP %d 1", num );
604     if ((ok = gen_transact(sock, buf )) != 0)
605        return ok; 
606     got_it = 0;
607     while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0) 
608     {
609         if (DOTLINE(buf))
610             break;
611         if ( ! got_it && ! strncasecmp("Message-Id:", buf, 11 )) {
612             got_it = 1;
613             /* prevent stack overflows */
614             buf[IDLEN+12] = 0;
615             sscanf( buf+12, "%s", id);
616         }
617     }
618     return 0;
619 }
620
621 static int pop3_getuidl( int sock, int num , char *id)
622 {
623     int ok;
624     char buf [POPBUFSIZE+1];
625     gen_send(sock, "UIDL %d", num);
626     if ((ok = pop3_ok(sock, buf)) != 0)
627         return(ok);
628     if (sscanf(buf, "%d %s", &num, id) != 2)
629         return(PS_PROTOCOL);
630     return(PS_SUCCESS);
631 }
632
633 static int pop3_fastuidl( int sock,  struct query *ctl, unsigned int count, int *newp)
634 {
635     int ok;
636     unsigned int first_nr, last_nr, try_nr;
637     char id [IDLEN+1];
638
639     first_nr = 0;
640     last_nr = count + 1;
641     while (first_nr < last_nr - 1)
642     {
643         struct idlist   *new;
644
645         try_nr = (first_nr + last_nr) / 2;
646         if( (ok = pop3_getuidl( sock, try_nr, id )) != 0 )
647             return ok;
648         if ((new = str_in_list(&ctl->oldsaved, id, FALSE)))
649         {
650             flag mark = new->val.status.mark;
651             if (mark == UID_DELETED || mark == UID_EXPUNGED)
652             {
653                 if (outlevel >= O_VERBOSE)
654                     report(stderr, GT_("id=%s (num=%d) was deleted, but is still present!\n"), id, try_nr);
655                 /* just mark it as seen now! */
656                 new->val.status.mark = mark = UID_SEEN;
657             }
658
659             /* narrow the search region! */
660             if (mark == UID_UNSEEN)
661             {
662                 if (outlevel >= O_DEBUG)
663                     report(stdout, GT_("%u is unseen\n"), try_nr);
664                 last_nr = try_nr;
665             }
666             else
667                 first_nr = try_nr;
668
669             /* save the number */
670             new->val.status.num = try_nr;
671         }
672         else
673         {
674             if (outlevel >= O_DEBUG)
675                 report(stdout, GT_("%u is unseen\n"), try_nr);
676             last_nr = try_nr;
677
678             /* save it */
679             new = save_str(&ctl->oldsaved, id, UID_UNSEEN);
680             new->val.status.num = try_nr;
681         }
682     }
683     if (outlevel >= O_DEBUG && last_nr <= count)
684         report(stdout, GT_("%u is first unseen\n"), last_nr);
685
686     /* update last! */
687     *newp = count - first_nr;
688     last = first_nr;
689     return 0;
690 }
691
692 static int pop3_slowuidl( int sock,  struct query *ctl, int *countp, int *newp)
693 {
694     /* This approach tries to get the message headers from the
695      * remote hosts and compares the message-id to the already known
696      * ones:
697      *  + if the first message containes a new id, all messages on
698      *    the server will be new
699      *  + if the first is known, try to estimate the last known message
700      *    on the server and check. If this works you know the total number
701      *    of messages to get.
702      *  + Otherwise run a binary search to determine the last known message
703      */
704     int ok, nolinear = 0;
705     int first_nr, list_len, try_id, try_nr, add_id;
706     int num;
707     char id [IDLEN+1];
708     
709     if( (ok = pop3_gettopid( sock, 1, id )) != 0 )
710         return ok;
711     
712     if( ( first_nr = str_nr_in_list(&ctl->oldsaved, id) ) == -1 ) {
713         /* the first message is unknown -> all messages are new */
714         *newp = *countp;        
715         return 0;
716     }
717
718     /* check where we expect the latest known message */
719     list_len = count_list( &ctl->oldsaved );
720     try_id = list_len  - first_nr; /* -1 + 1 */
721     if( try_id > 1 ) {
722         if( try_id <= *countp ) {
723             if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
724                 return ok;
725     
726             try_nr = str_nr_last_in_list(&ctl->oldsaved, id);
727         } else {
728             try_id = *countp+1;
729             try_nr = -1;
730         }
731         if( try_nr != list_len -1 ) {
732             /* some messages inbetween have been deleted... */
733             if( try_nr == -1 ) {
734                 nolinear = 1;
735
736                 for( add_id = 1<<30; add_id > try_id-1; add_id >>= 1 )
737                     ;
738                 for( ; add_id; add_id >>= 1 ) {
739                     if( try_nr == -1 ) {
740                         if( try_id - add_id <= 1 ) {
741                             continue;
742                         }
743                         try_id -= add_id;
744                     } else 
745                         try_id += add_id;
746                     
747                     if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
748                         return ok;
749                     try_nr = str_nr_in_list(&ctl->oldsaved, id);
750                 }
751                 if( try_nr == -1 ) {
752                     try_id--;
753                 }
754             } else {
755                 report(stderr, 
756                        GT_("Messages inserted into list on server. Cannot handle this.\n"));
757                 return -1;
758             }
759         } 
760     }
761     /* the first try_id messages are known -> copy them to the newsaved list */
762     for( num = first_nr; num < list_len; num++ )
763     {
764         struct idlist   *new = save_str(&ctl->newsaved, 
765                                 str_from_nr_list(&ctl->oldsaved, num),
766                                 UID_UNSEEN);
767         new->val.status.num = num - first_nr + 1;
768     }
769
770     if( nolinear ) {
771         free_str_list(&ctl->oldsaved);
772         ctl->oldsaved = 0;
773         last = try_id;
774     }
775
776     *newp = *countp - try_id;
777     return 0;
778 }
779
780 static int pop3_getrange(int sock, 
781                          struct query *ctl,
782                          const char *folder,
783                          int *countp, int *newp, int *bytes)
784 /* get range of messages to be fetched */
785 {
786     int ok;
787     char buf [POPBUFSIZE+1];
788
789     /* Ensure that the new list is properly empty */
790     ctl->newsaved = (struct idlist *)NULL;
791
792 #ifdef MBOX
793     /* Alain Knaff suggests this, but it's not RFC standard */
794     if (folder)
795         if ((ok = gen_transact(sock, "MBOX %s", folder)))
796             return ok;
797 #endif /* MBOX */
798
799     /* get the total message count */
800     gen_send(sock, "STAT");
801     ok = pop3_ok(sock, buf);
802     if (ok == 0)
803         sscanf(buf,"%d %d", countp, bytes);
804     else
805         return(ok);
806
807     /*
808      * Newer, RFC-1725-conformant POP servers may not have the LAST command.
809      * We work as hard as possible to hide this ugliness, but it makes 
810      * counting new messages intrinsically quadratic in the worst case.
811      */
812     last = 0;
813     *newp = -1;
814     if (*countp > 0 && !ctl->fetchall)
815     {
816         int fastuidl;
817         char id [IDLEN+1];
818
819         /* should we do fast uidl this time? */
820         fastuidl = ctl->fastuidl;
821         if (*countp > 7 &&              /* linear search is better if there are few mails! */
822             !ctl->flush &&              /* with flush, it is safer to disable fastuidl */
823             NUM_NONZERO (fastuidl))
824         {
825             if (fastuidl == 1)
826                 dofastuidl = 1;
827             else
828                 dofastuidl = ctl->fastuidlcount != 0;
829         }
830         else
831             dofastuidl = 0;
832
833         if (!ctl->server.uidl) {
834             gen_send(sock, "LAST");
835             ok = pop3_ok(sock, buf);
836         } else
837             ok = 1;
838         if (ok == 0)
839         {
840             if (sscanf(buf, "%d", &last) == 0)
841             {
842                 report(stderr, GT_("protocol error\n"));
843                 return(PS_ERROR);
844             }
845             *newp = (*countp - last);
846         }
847         else
848         {
849             if (dofastuidl)
850                 return(pop3_fastuidl( sock, ctl, *countp, newp));
851             /* grab the mailbox's UID list */
852             if ((ok = gen_transact(sock, "UIDL")) != 0)
853             {
854                 /* don't worry, yet! do it the slow way */
855                 if((ok = pop3_slowuidl( sock, ctl, countp, newp))!=0)
856                 {
857                     report(stderr, GT_("protocol error while fetching UIDLs\n"));
858                     return(PS_ERROR);
859                 }
860             }
861             else
862             {
863                 int     num;
864
865                 *newp = 0;
866                 while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
867                 {
868                     if (DOTLINE(buf))
869                         break;
870                     else if (sscanf(buf, "%d %s", &num, id) == 2)
871                     {
872                         struct idlist   *old, *new;
873
874                         new = save_str(&ctl->newsaved, id, UID_UNSEEN);
875                         new->val.status.num = num;
876
877                         if ((old = str_in_list(&ctl->oldsaved, id, FALSE)))
878                         {
879                             flag mark = old->val.status.mark;
880                             if (mark == UID_DELETED || mark == UID_EXPUNGED)
881                             {
882                                 if (outlevel >= O_VERBOSE)
883                                     report(stderr, GT_("id=%s (num=%d) was deleted, but is still present!\n"), id, num);
884                                 /* just mark it as seen now! */
885                                 old->val.status.mark = mark = UID_SEEN;
886                             }
887                             new->val.status.mark = mark;
888                             if (mark == UID_UNSEEN)
889                             {
890                                 (*newp)++;
891                                 if (outlevel >= O_DEBUG)
892                                     report(stdout, GT_("%u is unseen\n"), num);
893                             }
894                         }
895                         else
896                         {
897                             (*newp)++;
898                             if (outlevel >= O_DEBUG)
899                                 report(stdout, GT_("%u is unseen\n"), num);
900                             /* add it to oldsaved also! In case, we do not
901                              * swap the lists (say, due to socket error),
902                              * the same mail will not be downloaded again.
903                              */
904                             old = save_str(&ctl->oldsaved, id, UID_UNSEEN);
905                             old->val.status.num = num;
906                         }
907                     }
908                 }
909             }
910         }
911     }
912
913     return(PS_SUCCESS);
914 }
915
916 static int pop3_getpartialsizes(int sock, int first, int last, int *sizes)
917 /* capture the size of message #first */
918 {
919     int ok = 0, i;
920     char buf [POPBUFSIZE+1];
921     unsigned int num, size;
922
923     for (i = first; i <= last; i++) {
924         gen_send(sock, "LIST %d", i);
925         if ((ok = pop3_ok(sock, buf)) != 0)
926             return(ok);
927         if (sscanf(buf, "%u %u", &num, &size) == 2) {
928             if (num == i)
929                 sizes[i - first] = size;
930             else
931                 /* warn about possible attempt to induce buffer overrun
932                  *
933                  * we expect server reply message number and requested
934                  * message number to match */
935                 report(stderr, "Warning: ignoring bogus data for message sizes returned by server.\n");
936         }
937     }
938     return(ok);
939 }
940
941 static int pop3_getsizes(int sock, int count, int *sizes)
942 /* capture the sizes of all messages */
943 {
944     int ok;
945
946     if ((ok = gen_transact(sock, "LIST")) != 0)
947         return(ok);
948     else
949     {
950         char buf [POPBUFSIZE+1];
951
952         while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
953         {
954             unsigned int num, size;
955
956             if (DOTLINE(buf))
957                 break;
958             else if (sscanf(buf, "%u %u", &num, &size) == 2) {
959                 if (num > 0 && num <= count)
960                     sizes[num - 1] = size;
961                 else
962                     /* warn about possible attempt to induce buffer overrun */
963                     report(stderr, "Warning: ignoring bogus data for message sizes returned by server.\n");
964             }
965         }
966
967         return(ok);
968     }
969 }
970
971 static int pop3_is_old(int sock, struct query *ctl, int num)
972 /* is the given message old? */
973 {
974     struct idlist *new;
975     if (!ctl->oldsaved)
976         return (num <= last);
977     else if (dofastuidl)
978     {
979         char id [IDLEN+1];
980
981         if (num <= last)
982             return(TRUE);
983
984         /* in fast uidl, we manipulate the old list only! */
985
986         if ((new = id_find(&ctl->oldsaved, num)))
987         {
988             /* we already have the id! */
989             return(new->val.status.mark != UID_UNSEEN);
990         }
991
992         /* get the uidl first! */
993         if (pop3_getuidl(sock, num, id) != PS_SUCCESS)
994             return(TRUE);
995
996         if ((new = str_in_list(&ctl->oldsaved, id, FALSE))) {
997             /* we already have the id! */
998             new->val.status.num = num;
999             return(new->val.status.mark != UID_UNSEEN);
1000         }
1001
1002         /* save it */
1003         new = save_str(&ctl->oldsaved, id, UID_UNSEEN);
1004         new->val.status.num = num;
1005         return(FALSE);
1006     }
1007     else
1008         return ((new = id_find(&ctl->newsaved, num)) != NULL &&
1009             new->val.status.mark != UID_UNSEEN);
1010 }
1011
1012 #ifdef UNUSED
1013 /*
1014  * We could use this to fetch headers only as we do for IMAP.  The trouble 
1015  * is that there's no way to fetch the body only.  So the following RETR 
1016  * would have to re-fetch the header.  Enough messages have longer headers
1017  * than bodies to make this a net loss.
1018  */
1019 static int pop_fetch_headers(int sock, struct query *ctl,int number,int *lenp)
1020 /* request headers of nth message */
1021 {
1022     int ok;
1023     char buf[POPBUFSIZE+1];
1024
1025     gen_send(sock, "TOP %d 0", number);
1026     if ((ok = pop3_ok(sock, buf)) != 0)
1027         return(ok);
1028
1029     *lenp = -1;         /* we got sizes from the LIST response */
1030
1031     return(PS_SUCCESS);
1032 }
1033 #endif /* UNUSED */
1034
1035 static int pop3_fetch(int sock, struct query *ctl, int number, int *lenp)
1036 /* request nth message */
1037 {
1038     int ok;
1039     char buf[POPBUFSIZE+1];
1040
1041 #ifdef SDPS_ENABLE
1042     /*
1043      * See http://www.demon.net/services/mail/sdps-tech.html
1044      * for a description of what we're parsing here.
1045      */
1046     if (ctl->server.sdps)
1047     {
1048         int     linecount = 0;
1049
1050         sdps_envfrom = (char *)NULL;
1051         sdps_envto = (char *)NULL;
1052         gen_send(sock, "*ENV %d", number);
1053         do {
1054             if (gen_recv(sock, buf, sizeof(buf)))
1055             {
1056                 break;
1057             }
1058             linecount++;
1059             switch (linecount) {
1060             case 4:
1061                 /* No need to wrap envelope from address */
1062                 sdps_envfrom = xmalloc(strlen(buf)+1);
1063                 strcpy(sdps_envfrom,buf);
1064                 break;
1065             case 5:
1066                 /* Wrap address with To: <> so nxtaddr() likes it */
1067                 sdps_envto = xmalloc(strlen(buf)+7);
1068                 sprintf(sdps_envto,"To: <%s>",buf);
1069                 break;
1070             }
1071         } while
1072             (!(buf[0] == '.' && (buf[1] == '\r' || buf[1] == '\n' || buf[1] == '\0')));
1073     }
1074 #endif /* SDPS_ENABLE */
1075
1076     /*
1077      * Though the POP RFCs don't document this fact, on almost every
1078      * POP3 server I know of messages are marked "seen" only at the
1079      * time the OK response to a RETR is issued.
1080      *
1081      * This means we can use TOP to fetch the message without setting its
1082      * seen flag.  This is good!  It means that if the protocol exchange
1083      * craps out during the message, it will still be marked `unseen' on
1084      * the server.  (Exception: in early 1999 SpryNet's POP3 servers were
1085      * reported to mark messages seen on a TOP fetch.)
1086      *
1087      * However...*don't* do this if we're using keep to suppress deletion!
1088      * In that case, marking the seen flag is the only way to prevent the
1089      * message from being re-fetched on subsequent runs.
1090      *
1091      * Also use RETR if fetchall is on.  This gives us a workaround
1092      * for servers like usa.net's that bungle TOP.  It's pretty
1093      * harmless because fetchall guarantees that any message dropped
1094      * by an interrupted RETR will be picked up on the next poll of the
1095      * site.
1096      *
1097      * We take advantage here of the fact that, according to all the
1098      * POP RFCs, "if the number of lines requested by the POP3 client
1099      * is greater than than the number of lines in the body, then the
1100      * POP3 server sends the entire message.").
1101      *
1102      * The line count passed (99999999) is the maximum value CompuServe will
1103      * accept; it's much lower than the natural value 2147483646 (the maximum
1104      * twos-complement signed 32-bit integer minus 1) */
1105     if (!peek_capable)
1106         gen_send(sock, "RETR %d", number);
1107     else
1108         gen_send(sock, "TOP %d 99999999", number);
1109     if ((ok = pop3_ok(sock, buf)) != 0)
1110         return(ok);
1111
1112     *lenp = -1;         /* we got sizes from the LIST response */
1113
1114     return(PS_SUCCESS);
1115 }
1116
1117 static void mark_uid_seen(struct query *ctl, int number)
1118 /* Tell the UID code we've seen this. */
1119 {
1120     struct idlist       *sdp;
1121
1122     if ((sdp = id_find(&ctl->newsaved, number)))
1123         sdp->val.status.mark = UID_SEEN;
1124     /* mark it as seen in oldsaved also! In case, we do not swap the lists
1125      * (say, due to socket error), the same mail will not be downloaded
1126      * again.
1127      */
1128     if ((sdp = id_find(&ctl->oldsaved, number)))
1129         sdp->val.status.mark = UID_SEEN;
1130 }
1131
1132 static int pop3_delete(int sock, struct query *ctl, int number)
1133 /* delete a given message */
1134 {
1135     int ok;
1136     mark_uid_seen(ctl, number);
1137     /* actually, mark for deletion -- doesn't happen until QUIT time */
1138     ok = gen_transact(sock, "DELE %d", number);
1139     if (ok != PS_SUCCESS)
1140         return(ok);
1141     delete_str(dofastuidl ? &ctl->oldsaved : &ctl->newsaved, number);
1142     return(PS_SUCCESS);
1143 }
1144
1145 static int pop3_mark_seen(int sock, struct query *ctl, int number)
1146 /* mark a given message as seen */
1147 {
1148     mark_uid_seen(ctl, number);
1149     return(PS_SUCCESS);
1150 }
1151
1152 static int pop3_logout(int sock, struct query *ctl)
1153 /* send logout command */
1154 {
1155     int ok;
1156
1157 #ifdef __UNUSED__
1158     /*
1159      * We used to do this in case the server marks messages deleted when seen.
1160      * (Yes, this has been reported, in the MercuryP/NLM server.
1161      * It's even legal under RFC 1939 (section 8) as a site policy.)
1162      * It interacted badly with UIDL, though.  Thomas Zajic wrote:
1163      * "Running 'fetchmail -F -v' and checking the logs, I found out
1164      * that fetchmail did in fact flush my mailbox properly, but sent
1165      * a RSET just before sending QUIT to log off.  This caused the
1166      * POP3 server to undo/forget about the previous DELEs, resetting
1167      * my mailbox to its original (ie.  unflushed) state. The
1168      * ~/.fetchids file did get flushed though, so the next time
1169      * fetchmail was run it saw all the old messages as new ones ..."
1170      */
1171      if (ctl->keep)
1172         gen_transact(sock, "RSET");
1173 #endif /* __UNUSED__ */
1174
1175     ok = gen_transact(sock, "QUIT");
1176     if (!ok)
1177         expunge_uids(ctl);
1178
1179     return(ok);
1180 }
1181
1182 static const struct method pop3 =
1183 {
1184     "POP3",             /* Post Office Protocol v3 */
1185 #ifdef INET6_ENABLE
1186     "pop3",             /* standard POP3 port */
1187     "pop3s",            /* ssl POP3 port */
1188 #else /* INET6_ENABLE */
1189     110,                /* standard POP3 port */
1190     995,                /* ssl POP3 port */
1191 #endif /* INET6_ENABLE */
1192     FALSE,              /* this is not a tagged protocol */
1193     TRUE,               /* this uses a message delimiter */
1194     pop3_ok,            /* parse command response */
1195     pop3_getauth,       /* get authorization */
1196     pop3_getrange,      /* query range of messages */
1197     pop3_getsizes,      /* we can get a list of sizes */
1198     pop3_getpartialsizes,       /* we can get the size of 1 mail */
1199     pop3_is_old,        /* how do we tell a message is old? */
1200     pop3_fetch,         /* request given message */
1201     NULL,               /* no way to fetch body alone */
1202     NULL,               /* no message trailer */
1203     pop3_delete,        /* how to delete a message */
1204     pop3_mark_seen,     /* how to mark a message as seen */
1205     pop3_logout,        /* log out, we're done */
1206     FALSE,              /* no, we can't re-poll */
1207 };
1208
1209 int doPOP3 (struct query *ctl)
1210 /* retrieve messages using POP3 */
1211 {
1212 #ifndef MBOX
1213     if (ctl->mailboxes->id) {
1214         fprintf(stderr,GT_("Option --remote is not supported with POP3\n"));
1215         return(PS_SYNTAX);
1216     }
1217 #endif /* MBOX */
1218     peek_capable = !ctl->fetchall;
1219     return(do_protocol(ctl, &pop3));
1220 }
1221 #endif /* POP3_ENABLE */
1222
1223 /* pop3.c ends here */