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