]> Pileus Git - ~andy/fetchmail/blob - pop3.c
Header cleanup.
[~andy/fetchmail] / pop3.c
1 /*
2  * pop3.c -- POP3 protocol methods
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include  <config.h>
8
9 #include  <stdio.h>
10 #include  <string.h>
11 #if defined(HAVE_UNISTD_H)
12 #include <unistd.h>
13 #endif
14 #if defined(STDC_HEADERS)
15 #include  <stdlib.h>
16 #endif
17  
18 #include  "socket.h"
19 #include  "fetchmail.h"
20
21 #define PROTOCOL_ERROR  {fputs("fetchmail: protocol error\n", stderr); return(PS_ERROR);}
22
23 static int last;
24
25 int pop3_ok (sockfp, argbuf)
26 /* parse command response */
27 FILE *sockfp;
28 char *argbuf;
29 {
30   int ok;
31   char buf [POPBUFSIZE+1];
32   char *bufp;
33
34   if (SockGets(buf, sizeof(buf), sockfp) >= 0) {
35     if (outlevel == O_VERBOSE)
36       fprintf(stderr,"%s\n",buf);
37
38     bufp = buf;
39     if (*bufp == '+' || *bufp == '-')
40       bufp++;
41     else
42       return(PS_PROTOCOL);
43
44     while (isalpha(*bufp))
45       bufp++;
46     *(bufp++) = '\0';
47
48     if (strcmp(buf,"+OK") == 0)
49       ok = 0;
50     else if (strcmp(buf,"-ERR") == 0)
51       ok = PS_ERROR;
52     else
53       ok = PS_PROTOCOL;
54
55     if (argbuf != NULL)
56       strcpy(argbuf,bufp);
57   }
58   else 
59     ok = PS_SOCKET;
60
61   return(ok);
62 }
63
64 int pop3_getauth(sockfp, ctl, greeting)
65 /* apply for connection authorization */
66 FILE *sockfp;
67 struct query *ctl;
68 char *greeting;
69 {
70     /* build MD5 digest from greeting timestamp + password */
71     if (ctl->protocol == P_APOP) 
72     {
73         char *start,*end;
74         char *msg;
75
76         /* find start of timestamp */
77         for (start = greeting;  *start != 0 && *start != '<';  start++)
78             continue;
79         if (*start == 0) {
80             fprintf(stderr,"Required APOP timestamp not found in greeting\n");
81             return(PS_AUTHFAIL);
82         }
83
84         /* find end of timestamp */
85         for (end = start;  *end != 0  && *end != '>';  end++)
86             continue;
87         if (*end == 0 || (end - start - 1) == 1) {
88             fprintf(stderr,"Timestamp syntax error in greeting\n");
89             return(PS_AUTHFAIL);
90         }
91
92         /* copy timestamp and password into digestion buffer */
93         msg = (char *)xmalloc((end-start-1) + strlen(ctl->password) + 1);
94         *(++end) = 0;
95         strcpy(msg,start);
96         strcat(msg,ctl->password);
97
98         strcpy(ctl->digest, MD5Digest(msg));
99         free(msg);
100     }
101
102     switch (ctl->protocol) {
103     case P_POP3:
104         if ((gen_transact(sockfp,"USER %s", ctl->remotename)) != 0)
105             PROTOCOL_ERROR
106
107         if ((gen_transact(sockfp, "PASS %s", ctl->password)) != 0)
108             PROTOCOL_ERROR
109         break;
110
111     case P_APOP:
112         if ((gen_transact(sockfp, "APOP %s %s",
113                           ctl->remotename, ctl->digest)) != 0)
114             PROTOCOL_ERROR
115         break;
116
117     default:
118         fprintf(stderr,"Undefined protocol request in POP3_auth\n");
119     }
120
121     /* we're approved */
122     return(0);
123 }
124
125 static int pop3_getrange(sockfp, ctl, countp, newp)
126 /* get range of messages to be fetched */
127 FILE *sockfp;
128 struct query *ctl;
129 int *countp, *newp;
130 {
131     int ok;
132     char buf [POPBUFSIZE+1];
133
134     /* Ensure that the new list is properly empty */
135     ctl->newsaved = (struct idlist *)NULL;
136
137     /* get the total message count */
138     gen_send(sockfp, "STAT");
139     ok = pop3_ok(sockfp, buf);
140     if (ok == 0)
141         sscanf(buf,"%d %*d", countp);
142     else
143         return(ok);
144
145     /*
146      * Newer, RFC-1725-conformant POP servers may not have the LAST command.
147      * We work as hard as possible to hide this ugliness, but it makes 
148      * counting new messages intrinsically quadratic in the worst case.
149      */
150     last = 0;
151     *newp = -1;
152     if (*countp > 0 && !ctl->fetchall)
153     {
154         char id [IDLEN+1];
155
156         gen_send(sockfp,"LAST");
157         ok = pop3_ok(sockfp, buf);
158         if (ok == 0)
159         {
160             if (sscanf(buf, "%d", &last) == 0)
161                 PROTOCOL_ERROR
162             *newp = (*countp - last);
163         }
164         else
165         {
166             /* grab the mailbox's UID list */
167             if ((ok = gen_transact(sockfp, "UIDL")) != 0)
168                 PROTOCOL_ERROR
169             else
170             {
171                 int     num;
172
173                 *newp = 0;
174                 while (SockGets(buf, sizeof(buf), sockfp) >= 0)
175                 {
176                     if (outlevel == O_VERBOSE)
177                         fprintf(stderr,"%s\n",buf);
178                     if (buf[0] == '.')
179                         break;
180                     else if (sscanf(buf, "%d %s", &num, id) == 2)
181                     {
182                         save_uid(&ctl->newsaved, num, id);
183                         if (!uid_in_list(&ctl->oldsaved, id))
184                             (*newp)++;
185                     }
186                 }
187             }
188         }
189     }
190
191     return(0);
192 }
193
194 static int pop3_getsizes(sockfp, count, sizes)
195 /* capture the sizes of all messages */
196 FILE    *sockfp;
197 int     count;
198 int     *sizes;
199 {
200     int ok;
201
202     if ((ok = gen_transact(sockfp, "LIST")) != 0)
203         return(ok);
204     else
205     {
206         char buf [POPBUFSIZE+1];
207
208         while (SockGets(buf, sizeof(buf), sockfp) >= 0)
209         {
210             int num, size;
211
212             if (outlevel == O_VERBOSE)
213                 fprintf(stderr,"%s\n",buf);
214             if (buf[0] == '.')
215                 break;
216             else if (sscanf(buf, "%d %d", &num, &size) == 2)
217                 sizes[num - 1] = size;
218             else
219                 sizes[num - 1] = -1;
220         }
221
222         return(0);
223     }
224 }
225
226 static int pop3_is_old(sockfp, ctl, num)
227 /* is the given message old? */
228 FILE *sockfp;
229 struct query *ctl;
230 int num;
231 {
232     if (!ctl->oldsaved)
233         return (num <= last);
234     else
235         return (uid_in_list(&ctl->oldsaved,
236                             uid_find (&ctl->newsaved, num)));
237 }
238
239 static int pop3_fetch(sockfp, number, lenp)
240 /* request nth message */
241 FILE *sockfp;
242 int number;
243 int *lenp; 
244 {
245     int ok;
246     char buf [POPBUFSIZE+1], *cp;
247
248     gen_send(sockfp, "RETR %d", number);
249     if ((ok = pop3_ok(sockfp, buf)) != 0)
250         return(ok);
251     /* look for "nnn octets" -- there may or may not be preceding cruft */
252     if ((cp = strstr(buf, " octets")) == (char *)NULL)
253         *lenp = 0;
254     else
255     {
256         while (isdigit(*--cp))
257             continue;
258         *lenp = atoi(++cp);
259     }
260     return(0);
261 }
262
263 static int pop3_delete(sockfp, ctl, number)
264 /* delete a given message */
265 FILE *sockfp;
266 struct query *ctl;
267 int number;
268 {
269     return(gen_transact(sockfp, "DELE %d", number));
270 }
271
272 const static struct method pop3 =
273 {
274     "POP3",             /* Post Office Protocol v3 */
275     110,                /* standard POP3 port */
276     0,                  /* this is not a tagged protocol */
277     1,                  /* this uses a message delimiter */
278     pop3_ok,            /* parse command response */
279     pop3_getauth,       /* get authorization */
280     pop3_getrange,      /* query range of messages */
281     pop3_getsizes,      /* we can get a list of sizes */
282     pop3_is_old,        /* how do we tell a message is old? */
283     pop3_fetch,         /* request given message */
284     NULL,               /* no message trailer */
285     pop3_delete,        /* how to delete a message */
286     NULL,               /* no POP3 expunge command */
287     "QUIT",             /* the POP3 exit command */
288 };
289
290 int doPOP3 (ctl)
291 /* retrieve messages using POP3 */
292 struct query *ctl;
293 {
294     if (ctl->mailbox[0]) {
295         fprintf(stderr,"Option --remote is not supported with POP3\n");
296         return(PS_SYNTAX);
297     }
298     return(do_protocol(ctl, &pop3));
299 }
300
301 /* pop3.c ends here */