2 * pop3.c -- POP3 protocol methods
4 * For license terms, see the file COPYING in this directory.
11 #if defined(HAVE_UNISTD_H)
14 #if defined(STDC_HEADERS)
19 #include "fetchmail.h"
21 #define PROTOCOL_ERROR {fputs("fetchmail: protocol error\n", stderr); return(PS_ERROR);}
25 int pop3_ok (FILE *sockfp, char *argbuf)
26 /* parse command response */
29 char buf [POPBUFSIZE+1];
32 if (SockGets(buf, sizeof(buf), sockfp) >= 0) {
33 if (outlevel == O_VERBOSE)
34 fprintf(stderr,"%s\n",buf);
37 if (*bufp == '+' || *bufp == '-')
42 while (isalpha(*bufp))
46 if (strcmp(buf,"+OK") == 0)
48 else if (strcmp(buf,"-ERR") == 0)
62 int pop3_getauth(FILE *sockfp, struct query *ctl, char *greeting)
63 /* apply for connection authorization */
65 /* build MD5 digest from greeting timestamp + password */
66 if (ctl->protocol == P_APOP)
71 /* find start of timestamp */
72 for (start = greeting; *start != 0 && *start != '<'; start++)
75 fprintf(stderr,"Required APOP timestamp not found in greeting\n");
79 /* find end of timestamp */
80 for (end = start; *end != 0 && *end != '>'; end++)
82 if (*end == 0 || (end - start - 1) == 1) {
83 fprintf(stderr,"Timestamp syntax error in greeting\n");
87 /* copy timestamp and password into digestion buffer */
88 msg = (char *)xmalloc((end-start-1) + strlen(ctl->password) + 1);
91 strcat(msg,ctl->password);
93 strcpy(ctl->digest, MD5Digest(msg));
97 switch (ctl->protocol) {
99 if ((gen_transact(sockfp,"USER %s", ctl->remotename)) != 0)
102 if ((gen_transact(sockfp, "PASS %s", ctl->password)) != 0)
107 if ((gen_transact(sockfp, "APOP %s %s",
108 ctl->remotename, ctl->digest)) != 0)
113 fprintf(stderr,"Undefined protocol request in POP3_auth\n");
120 static int pop3_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp)
121 /* get range of messages to be fetched */
124 char buf [POPBUFSIZE+1];
126 /* Ensure that the new list is properly empty */
127 ctl->newsaved = (struct idlist *)NULL;
129 /* get the total message count */
130 gen_send(sockfp, "STAT");
131 ok = pop3_ok(sockfp, buf);
133 sscanf(buf,"%d %*d", countp);
138 * Newer, RFC-1725-conformant POP servers may not have the LAST command.
139 * We work as hard as possible to hide this ugliness, but it makes
140 * counting new messages intrinsically quadratic in the worst case.
144 if (*countp > 0 && !ctl->fetchall)
148 gen_send(sockfp,"LAST");
149 ok = pop3_ok(sockfp, buf);
152 if (sscanf(buf, "%d", &last) == 0)
154 *newp = (*countp - last);
158 /* grab the mailbox's UID list */
159 if ((ok = gen_transact(sockfp, "UIDL")) != 0)
166 while (SockGets(buf, sizeof(buf), sockfp) >= 0)
168 if (outlevel == O_VERBOSE)
169 fprintf(stderr,"%s\n",buf);
172 else if (sscanf(buf, "%d %s", &num, id) == 2)
174 save_uid(&ctl->newsaved, num, id);
175 if (!uid_in_list(&ctl->oldsaved, id))
186 static int pop3_getsizes(FILE *sockfp, int count, int *sizes)
187 /* capture the sizes of all messages */
191 if ((ok = gen_transact(sockfp, "LIST")) != 0)
195 char buf [POPBUFSIZE+1];
197 while (SockGets(buf, sizeof(buf), sockfp) >= 0)
201 if (outlevel == O_VERBOSE)
202 fprintf(stderr,"%s\n",buf);
205 else if (sscanf(buf, "%d %d", &num, &size) == 2)
206 sizes[num - 1] = size;
215 static int pop3_is_old(FILE *sockfp, struct query *ctl, int num)
216 /* is the given message old? */
219 return (num <= last);
221 return (uid_in_list(&ctl->oldsaved,
222 uid_find (&ctl->newsaved, num)));
225 static int pop3_fetch(FILE *sockfp, int number, int *lenp)
226 /* request nth message */
229 char buf [POPBUFSIZE+1], *cp;
231 gen_send(sockfp, "RETR %d", number);
232 if ((ok = pop3_ok(sockfp, buf)) != 0)
234 /* look for "nnn octets" -- there may or may not be preceding cruft */
235 if ((cp = strstr(buf, " octets")) == (char *)NULL)
239 while (--cp > buf && isdigit(*cp))
246 static int pop3_delete(FILE *sockfp, struct query *ctl, int number)
247 /* delete a given message */
249 return(gen_transact(sockfp, "DELE %d", number));
252 const static struct method pop3 =
254 "POP3", /* Post Office Protocol v3 */
255 110, /* standard POP3 port */
256 0, /* this is not a tagged protocol */
257 1, /* this uses a message delimiter */
258 pop3_ok, /* parse command response */
259 pop3_getauth, /* get authorization */
260 pop3_getrange, /* query range of messages */
261 pop3_getsizes, /* we can get a list of sizes */
262 pop3_is_old, /* how do we tell a message is old? */
263 pop3_fetch, /* request given message */
264 NULL, /* no message trailer */
265 pop3_delete, /* how to delete a message */
266 NULL, /* no POP3 expunge command */
267 "QUIT", /* the POP3 exit command */
270 int doPOP3 (struct query *ctl)
271 /* retrieve messages using POP3 */
273 if (ctl->mailbox[0]) {
274 fprintf(stderr,"Option --remote is not supported with POP3\n");
277 return(do_protocol(ctl, &pop3));
280 /* pop3.c ends here */