2 * For license terms, see the file COPYING in this directory.
5 /***********************************************************************
8 programmer: Eric S. Raymond <esr@thyrsus.com>
9 description: POP3 client code.
11 ***********************************************************************/
17 #include "fetchmail.h"
21 int pop3_ok (socket, argbuf)
22 /* parse command response */
27 char buf [POPBUFSIZE+1];
30 if (SockGets(socket, buf, sizeof(buf)) >= 0) {
31 if (outlevel == O_VERBOSE)
32 fprintf(stderr,"%s\n",buf);
35 if (*bufp == '+' || *bufp == '-')
40 while (isalpha(*bufp))
44 if (strcmp(buf,"+OK") == 0)
46 else if (strcmp(buf,"-ERR") == 0)
60 int pop3_getauth(socket, queryctl, greeting)
61 /* apply for connection authorization */
63 struct hostrec *queryctl;
66 char buf [POPBUFSIZE+1];
68 /* build MD5 digest from greeting timestamp + password */
69 if (queryctl->protocol == P_APOP)
74 /* find start of timestamp */
75 for (start = greeting; *start != 0 && *start != '<'; start++)
78 fprintf(stderr,"Required APOP timestamp not found in greeting\n");
82 /* find end of timestamp */
83 for (end = start; *end != 0 && *end != '>'; end++)
85 if (*end == 0 || (end - start - 1) == 1) {
86 fprintf(stderr,"Timestamp syntax error in greeting\n");
90 /* copy timestamp and password into digestion buffer */
91 msg = (char *)xmalloc((end-start-1) + strlen(queryctl->password) + 1);
94 strcat(msg,queryctl->password);
96 strcpy(queryctl->digest, MD5Digest(msg));
100 switch (queryctl->protocol) {
102 if ((gen_transact(socket,"USER %s", queryctl->remotename)) != 0)
105 if ((gen_transact(socket, "PASS %s", queryctl->password)) != 0)
110 if ((gen_transact(socket, "APOP %s %s",
111 queryctl->remotename, queryctl->digest)) != 0)
116 fprintf(stderr,"Undefined protocol request in POP3_auth\n");
123 static pop3_getrange(socket, queryctl, countp)
124 /* get range of messages to be fetched */
126 struct hostrec *queryctl;
130 char buf [POPBUFSIZE+1];
132 /* get the total message count */
133 gen_send(socket, "STAT");
134 ok = pop3_ok(socket, buf);
136 sscanf(buf,"%d %*d", countp);
141 * Newer, RFC-1725-conformant POP servers may not have the LAST command.
144 if (*countp > 0 && !queryctl->fetchall)
148 gen_send(socket,"LAST");
149 ok = pop3_ok(socket, buf);
152 if (sscanf(buf, "%d", &last) == 0)
159 /* grab the mailbox's UID list */
160 gen_send(socket, "UIDL");
161 if ((ok = pop3_ok(buf, socket)) == 0) {
162 while (SockGets(socket, buf, sizeof(buf)) >= 0) {
163 if (outlevel == O_VERBOSE)
164 fprintf(stderr,"%s\n",buf);
165 if (strcmp(buf, ".\n") == 0) {
168 if (sscanf(buf, "%d %s\n", &num, id) == 2)
169 save_uid(&queryctl->newsaved, num, id);
178 static int pop3_is_old(socket, queryctl, num)
180 struct hostrec *queryctl;
183 if (!queryctl->oldsaved)
184 return (num <= last);
187 char buf [POPBUFSIZE+1];
190 gen_send(socket, "UIDL %d", num);
191 if ((ok = pop3_ok(socket, buf)) != 0)
197 if (sscanf(buf, "%*d %s", id) == 2)
198 return(uid_in_list(&queryctl->oldsaved, id));
205 static int pop3_fetch(socket, number, lenp)
206 /* request nth message */
212 char buf [POPBUFSIZE+1];
214 gen_send(socket, "RETR %d", number);
215 if ((ok = pop3_ok(socket, buf)) != 0)
221 static pop3_delete(socket, queryctl, number)
222 /* delete a given message */
224 struct hostrec *queryctl;
227 return(gen_transact(socket, "DELE %d", number));
230 const static struct method pop3 =
232 "POP3", /* Post Office Protocol v3 */
233 110, /* standard POP3 port */
234 0, /* this is not a tagged protocol */
235 1, /* this uses a message delimiter */
236 pop3_ok, /* parse command response */
237 pop3_getauth, /* get authorization */
238 pop3_getrange, /* query range of messages */
239 pop3_is_old, /* how do we tell a message is old? */
240 pop3_fetch, /* request given message */
241 NULL, /* no message trailer */
242 pop3_delete, /* how to delete a message */
243 NULL, /* no POP3 expunge command */
244 "QUIT", /* the POP3 exit command */
247 int doPOP3 (queryctl)
248 /* retrieve messages using POP3 */
249 struct hostrec *queryctl;
251 if (queryctl->mailbox[0]) {
252 fprintf(stderr,"Option --remote is not supported with POP3\n");
255 return(do_protocol(queryctl, &pop3));