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)
19 #include "fetchmail.h"
21 #define PROTOCOL_ERROR {error(0, 0, "protocol error"); return(PS_ERROR);}
25 int pop3_ok (FILE *sockfp, char *argbuf)
26 /* parse command response */
29 char buf [POPBUFSIZE+1];
32 if (fgets(buf, sizeof(buf), sockfp)) {
33 if (buf[strlen(buf)-1] == '\n')
34 buf[strlen(buf)-1] = '\0';
35 if (buf[strlen(buf)-1] == '\r')
36 buf[strlen(buf)-1] = '\r';
37 if (outlevel == O_VERBOSE)
38 error(0, 0, "POP3< %s", buf);
41 if (*bufp == '+' || *bufp == '-')
46 while (isalpha(*bufp))
50 if (strcmp(buf,"+OK") == 0)
52 else if (strcmp(buf,"-ERR") == 0)
66 int pop3_getauth(FILE *sockfp, struct query *ctl, char *greeting)
67 /* apply for connection authorization */
69 /* build MD5 digest from greeting timestamp + password */
70 if (ctl->protocol == P_APOP)
75 /* find start of timestamp */
76 for (start = greeting; *start != 0 && *start != '<'; start++)
79 error(0, 0, "Required APOP timestamp not found in greeting");
83 /* find end of timestamp */
84 for (end = start; *end != 0 && *end != '>'; end++)
86 if (*end == 0 || end == start + 1) {
87 error(0, 0, "Timestamp syntax error in greeting");
93 /* copy timestamp and password into digestion buffer */
94 msg = (char *)xmalloc((end-start+1) + strlen(ctl->password) + 1);
96 strcat(msg,ctl->password);
98 strcpy(ctl->digest, MD5Digest(msg));
102 switch (ctl->protocol) {
104 if ((gen_transact(sockfp,"USER %s", ctl->remotename)) != 0)
107 if ((gen_transact(sockfp, "PASS %s", ctl->password)) != 0)
112 if ((gen_transact(sockfp, "APOP %s %s",
113 ctl->remotename, ctl->digest)) != 0)
118 error(0, 0, "Undefined protocol request in POP3_auth");
125 static int pop3_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp)
126 /* get range of messages to be fetched */
129 char buf [POPBUFSIZE+1];
131 /* Ensure that the new list is properly empty */
132 ctl->newsaved = (struct idlist *)NULL;
134 /* get the total message count */
135 gen_send(sockfp, "STAT");
136 ok = pop3_ok(sockfp, buf);
138 sscanf(buf,"%d %*d", countp);
143 * Newer, RFC-1725-conformant POP servers may not have the LAST command.
144 * We work as hard as possible to hide this ugliness, but it makes
145 * counting new messages intrinsically quadratic in the worst case.
149 if (*countp > 0 && !ctl->fetchall)
153 gen_send(sockfp,"LAST");
154 ok = pop3_ok(sockfp, buf);
157 if (sscanf(buf, "%d", &last) == 0)
159 *newp = (*countp - last);
163 /* grab the mailbox's UID list */
164 if ((ok = gen_transact(sockfp, "UIDL")) != 0)
171 while (fgets(buf, sizeof(buf), sockfp))
173 if (buf[strlen(buf)-1] == '\n')
174 buf[strlen(buf)-1] = '\0';
175 if (buf[strlen(buf)-1] == '\r')
176 buf[strlen(buf)-1] = '\r';
177 if (outlevel == O_VERBOSE)
178 error(0, 0, "POP3< %s", buf);
181 else if (sscanf(buf, "%d %s", &num, id) == 2)
183 save_str(&ctl->newsaved, num, id);
185 /* note: ID comparison is caseblind */
186 if (!str_in_list(&ctl->oldsaved, id))
197 static int pop3_getsizes(FILE *sockfp, int count, int *sizes)
198 /* capture the sizes of all messages */
202 if ((ok = gen_transact(sockfp, "LIST")) != 0)
206 char buf [POPBUFSIZE+1];
208 while (fgets(buf, sizeof(buf), sockfp))
212 if (buf[strlen(buf)-1] == '\n')
213 buf[strlen(buf)-1] = '\0';
214 if (buf[strlen(buf)-1] == '\r')
215 buf[strlen(buf)-1] = '\r';
216 if (outlevel == O_VERBOSE)
217 error(0, 0, "POP3< %s", buf);
220 else if (sscanf(buf, "%d %d", &num, &size) == 2)
221 sizes[num - 1] = size;
230 static int pop3_is_old(FILE *sockfp, struct query *ctl, int num)
231 /* is the given message old? */
234 return (num <= last);
236 /* note: ID comparison is caseblind */
237 return (str_in_list(&ctl->oldsaved,
238 str_find (&ctl->newsaved, num)));
241 static int pop3_fetch(FILE *sockfp, int number, int *lenp)
242 /* request nth message */
245 char buf [POPBUFSIZE+1], *cp;
247 gen_send(sockfp, "RETR %d", number);
248 if ((ok = pop3_ok(sockfp, buf)) != 0)
250 /* look for "nnn octets" -- there may or may not be preceding cruft */
251 if ((cp = strstr(buf, " octets")) == (char *)NULL)
255 while (--cp > buf && isdigit(*cp))
262 static int pop3_delete(FILE *sockfp, struct query *ctl, int number)
263 /* delete a given message */
265 return(gen_transact(sockfp, "DELE %d", number));
268 const static struct method pop3 =
270 "POP3", /* Post Office Protocol v3 */
271 110, /* standard POP3 port */
272 0, /* this is not a tagged protocol */
273 1, /* this uses a message delimiter */
274 pop3_ok, /* parse command response */
275 pop3_getauth, /* get authorization */
276 pop3_getrange, /* query range of messages */
277 pop3_getsizes, /* we can get a list of sizes */
278 pop3_is_old, /* how do we tell a message is old? */
279 pop3_fetch, /* request given message */
280 NULL, /* no message trailer */
281 pop3_delete, /* how to delete a message */
282 NULL, /* no POP3 expunge command */
283 "QUIT", /* the POP3 exit command */
286 int doPOP3 (struct query *ctl)
287 /* retrieve messages using POP3 */
289 if (ctl->mailbox[0]) {
290 fprintf(stderr,"Option --remote is not supported with POP3\n");
293 peek_capable = FALSE;
294 return(do_protocol(ctl, &pop3));
297 /* pop3.c ends here */