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