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