2 * pop3.c -- POP3 protocol methods
4 * For license terms, see the file COPYING in this directory.
12 #if defined(HAVE_UNISTD_H)
15 #if defined(STDC_HEADERS)
20 #include "fetchmail.h"
22 #define PROTOCOL_ERROR {fputs("fetchmail: protocol error\n", stderr); return(PS_ERROR);}
26 int pop3_ok (FILE *sockfp, char *argbuf)
27 /* parse command response */
30 char buf [POPBUFSIZE+1];
33 if (SockGets(buf, sizeof(buf), sockfp) >= 0) {
34 if (outlevel == O_VERBOSE)
35 fprintf(stderr,"%s\n",buf);
38 if (*bufp == '+' || *bufp == '-')
43 while (isalpha(*bufp))
47 if (strcmp(buf,"+OK") == 0)
49 else if (strcmp(buf,"-ERR") == 0)
63 int pop3_getauth(FILE *sockfp, struct query *ctl, char *greeting)
64 /* apply for connection authorization */
66 /* build MD5 digest from greeting timestamp + password */
67 if (ctl->protocol == P_APOP)
72 /* find start of timestamp */
73 for (start = greeting; *start != 0 && *start != '<'; start++)
76 fprintf(stderr,"Required APOP timestamp not found in greeting\n");
80 /* find end of timestamp */
81 for (end = start; *end != 0 && *end != '>'; end++)
83 if (*end == 0 || (end - start - 1) == 1) {
84 fprintf(stderr,"Timestamp syntax error in greeting\n");
88 /* copy timestamp and password into digestion buffer */
89 msg = (char *)xmalloc((end-start-1) + strlen(ctl->password) + 1);
92 strcat(msg,ctl->password);
94 strcpy(ctl->digest, MD5Digest(msg));
98 switch (ctl->protocol) {
100 if ((gen_transact(sockfp,"USER %s", ctl->remotename)) != 0)
103 if ((gen_transact(sockfp, "PASS %s", ctl->password)) != 0)
108 if ((gen_transact(sockfp, "APOP %s %s",
109 ctl->remotename, ctl->digest)) != 0)
114 fprintf(stderr,"Undefined protocol request in POP3_auth\n");
121 static int pop3_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp)
122 /* get range of messages to be fetched */
125 char buf [POPBUFSIZE+1];
127 /* Ensure that the new list is properly empty */
128 ctl->newsaved = (struct idlist *)NULL;
130 /* get the total message count */
131 gen_send(sockfp, "STAT");
132 ok = pop3_ok(sockfp, buf);
134 sscanf(buf,"%d %*d", countp);
139 * Newer, RFC-1725-conformant POP servers may not have the LAST command.
140 * We work as hard as possible to hide this ugliness, but it makes
141 * counting new messages intrinsically quadratic in the worst case.
145 if (*countp > 0 && !ctl->fetchall)
149 gen_send(sockfp,"LAST");
150 ok = pop3_ok(sockfp, buf);
153 if (sscanf(buf, "%d", &last) == 0)
155 *newp = (*countp - last);
159 /* grab the mailbox's UID list */
160 if ((ok = gen_transact(sockfp, "UIDL")) != 0)
167 while (SockGets(buf, sizeof(buf), sockfp) >= 0)
169 if (outlevel == O_VERBOSE)
170 fprintf(stderr,"%s\n",buf);
173 else if (sscanf(buf, "%d %s", &num, id) == 2)
175 save_uid(&ctl->newsaved, num, id);
176 if (!uid_in_list(&ctl->oldsaved, id))
187 static int pop3_getsizes(FILE *sockfp, int count, int *sizes)
188 /* capture the sizes of all messages */
192 if ((ok = gen_transact(sockfp, "LIST")) != 0)
196 char buf [POPBUFSIZE+1];
198 while (SockGets(buf, sizeof(buf), sockfp) >= 0)
202 if (outlevel == O_VERBOSE)
203 fprintf(stderr,"%s\n",buf);
206 else if (sscanf(buf, "%d %d", &num, &size) == 2)
207 sizes[num - 1] = size;
216 static int pop3_is_old(FILE *sockfp, struct query *ctl, int num)
217 /* is the given message old? */
220 return (num <= last);
222 return (uid_in_list(&ctl->oldsaved,
223 uid_find (&ctl->newsaved, num)));
226 static int pop3_fetch(FILE *sockfp, int number, int *lenp)
227 /* request nth message */
230 char buf [POPBUFSIZE+1], *cp;
232 gen_send(sockfp, "RETR %d", number);
233 if ((ok = pop3_ok(sockfp, buf)) != 0)
235 /* look for "nnn octets" -- there may or may not be preceding cruft */
236 if ((cp = strstr(buf, " octets")) == (char *)NULL)
240 while (--cp > buf && isdigit(*cp))
247 static int pop3_delete(FILE *sockfp, struct query *ctl, int number)
248 /* delete a given message */
250 return(gen_transact(sockfp, "DELE %d", number));
253 const static struct method pop3 =
255 "POP3", /* Post Office Protocol v3 */
256 110, /* standard POP3 port */
257 0, /* this is not a tagged protocol */
258 1, /* this uses a message delimiter */
259 pop3_ok, /* parse command response */
260 pop3_getauth, /* get authorization */
261 pop3_getrange, /* query range of messages */
262 pop3_getsizes, /* we can get a list of sizes */
263 pop3_is_old, /* how do we tell a message is old? */
264 pop3_fetch, /* request given message */
265 NULL, /* no message trailer */
266 pop3_delete, /* how to delete a message */
267 NULL, /* no POP3 expunge command */
268 "QUIT", /* the POP3 exit command */
271 int doPOP3 (struct query *ctl)
272 /* retrieve messages using POP3 */
274 if (ctl->mailbox[0]) {
275 fprintf(stderr,"Option --remote is not supported with POP3\n");
278 return(do_protocol(ctl, &pop3));
281 /* pop3.c ends here */