1 /* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond
3 * For license terms, see the file COPYING in this directory.
6 /***********************************************************************
9 programmer: Carl Harris, ceharris@mal.com
10 Hacks and bug fixes by esr.
11 description: POP3 client code.
13 ***********************************************************************/
18 #include "fetchmail.h"
22 int pop3_ok (socket, argbuf)
23 /* parse command response */
28 char buf [POPBUFSIZE+1];
31 if (SockGets(socket, buf, sizeof(buf)) >= 0) {
32 if (outlevel == O_VERBOSE)
33 fprintf(stderr,"%s\n",buf);
36 if (*bufp == '+' || *bufp == '-')
41 while (isalpha(*bufp))
45 if (strcmp(buf,"+OK") == 0)
47 else if (strcmp(buf,"-ERR") == 0)
61 int pop3_getauth(socket, queryctl, greeting)
62 /* apply for connection authorization */
64 struct hostrec *queryctl;
67 char buf [POPBUFSIZE+1];
69 /* build MD5 digest from greeting timestamp + password */
70 if (queryctl->protocol == P_APOP)
75 /* find start of timestamp */
76 for (start = greeting; *start != 0 && *start != '<'; start++)
79 fprintf(stderr,"Required APOP timestamp not found in greeting\n");
83 /* find end of timestamp */
84 for (end = start; *end != 0 && *end != '>'; end++)
86 if (*end == 0 || (end - start - 1) == 1) {
87 fprintf(stderr,"Timestamp syntax error in greeting\n");
91 /* copy timestamp and password into digestion buffer */
92 msg = (char *) malloc((end-start-1) + strlen(queryctl->password) + 1);
95 strcat(msg,queryctl->password);
97 strcpy(queryctl->digest, MD5Digest(msg));
101 switch (queryctl->protocol) {
103 gen_send(socket,"USER %s", queryctl->remotename);
104 if (pop3_ok(socket, buf) != 0)
107 gen_send(socket, "PASS %s", queryctl->password);
108 if (pop3_ok(socket, buf) != 0)
113 gen_send(socket,"USER %s", queryctl->remotename);
114 if (pop3_ok(socket, buf) != 0)
117 gen_send(socket, "RPOP %s", queryctl->password);
118 if (pop3_ok(socket, buf) != 0)
123 gen_send(socket,"APOP %s %s", queryctl->remotename, queryctl->digest);
124 if (pop3_ok(socket, buf) != 0)
129 fprintf(stderr,"Undefined protocol request in POP3_auth\n");
138 if (outlevel > O_SILENT && outlevel < O_VERBOSE)
139 fprintf(stderr,"%s\n",buf);
143 static pop3_getrange(socket, queryctl, countp)
144 /* get range of messages to be fetched */
146 struct hostrec *queryctl;
150 char buf [POPBUFSIZE+1];
152 /* get the total message count */
153 gen_send(socket, "STAT");
154 ok = pop3_ok(socket, buf);
156 sscanf(buf,"%d %*d", countp);
161 * Newer, RFC-1725-conformant POP servers may not have the LAST command.
164 if (*countp > 0 && !queryctl->fetchall)
168 gen_send(socket,"LAST");
169 ok = pop3_ok(socket, buf);
170 if (ok == 0 && sscanf(buf, "%d", &last) == 0)
177 static int pop3_is_old(socket, queryctl, num)
179 struct hostrec *queryctl;
182 return (num <= last);
185 static int pop3_fetch(socket, number, lenp)
186 /* request nth message */
192 return(gen_transact(socket, "RETR %d", number));
195 static pop3_delete(socket, queryctl, number)
196 /* delete a given message */
198 struct hostrec *queryctl;
203 /* send the deletion request */
204 if ((ok = gen_transact(socket, "DELE %d", number)) != 0)
208 const static struct method pop3 =
210 "POP3", /* Post Office Protocol v3 */
211 110, /* standard POP3 port */
212 0, /* this is not a tagged protocol */
213 1, /* this uses a message delimiter */
214 pop3_ok, /* parse command response */
215 pop3_getauth, /* get authorization */
216 pop3_getrange, /* query range of messages */
217 pop3_is_old, /* how do we tell a message is old? */
218 pop3_fetch, /* request given message */
219 NULL, /* no message trailer */
220 pop3_delete, /* how to delete a message */
221 NULL, /* no POP3 expunge command */
222 "QUIT", /* the POP3 exit command */
225 int doPOP3 (queryctl)
226 /* retrieve messages using POP3 */
227 struct hostrec *queryctl;
229 if (queryctl->remotefolder[0]) {
230 fprintf(stderr,"Option --remote is not supported with POP3\n");
234 return(do_protocol(queryctl, &pop3));