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