]> Pileus Git - ~andy/fetchmail/blob - pop3.c
Reverse order of arguments in OK method.
[~andy/fetchmail] / pop3.c
1 /* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond
2  * All rights reserved.
3  * For license terms, see the file COPYING in this directory.
4  */
5
6 /***********************************************************************
7   module:       pop3.c
8   project:      fetchmail
9   programmer:   Carl Harris, ceharris@mal.com
10                 Hacks and bug fixes by esr.
11   description:  POP3 client code.
12
13  ***********************************************************************/
14
15 #include  <config.h>
16 #include  <stdio.h>
17 #include  "socket.h"
18 #include  "fetchmail.h"
19
20 static int last;
21
22 int pop3_ok (socket, argbuf)
23 /* parse command response */
24 int socket;
25 char *argbuf;
26 {
27   int ok;
28   char buf [POPBUFSIZE+1];
29   char *bufp;
30
31   if (SockGets(socket, buf, sizeof(buf)) >= 0) {
32     if (outlevel == O_VERBOSE)
33       fprintf(stderr,"%s\n",buf);
34
35     bufp = buf;
36     if (*bufp == '+' || *bufp == '-')
37       bufp++;
38     else
39       return(PS_PROTOCOL);
40
41     while (isalpha(*bufp))
42       bufp++;
43     *(bufp++) = '\0';
44
45     if (strcmp(buf,"+OK") == 0)
46       ok = 0;
47     else if (strcmp(buf,"-ERR") == 0)
48       ok = PS_ERROR;
49     else
50       ok = PS_PROTOCOL;
51
52     if (argbuf != NULL)
53       strcpy(argbuf,bufp);
54   }
55   else 
56     ok = PS_SOCKET;
57
58   return(ok);
59 }
60
61 int pop3_getauth(socket, queryctl, greeting)
62 /* apply for connection authorization */
63 int socket;
64 struct hostrec *queryctl;
65 char *greeting;
66 {
67     char buf [POPBUFSIZE+1];
68
69     /* build MD5 digest from greeting timestamp + password */
70     if (queryctl->protocol == P_APOP) 
71     {
72         char *start,*end;
73         char *msg;
74
75         /* find start of timestamp */
76         for (start = greeting;  *start != 0 && *start != '<';  start++)
77             continue;
78         if (*start == 0) {
79             fprintf(stderr,"Required APOP timestamp not found in greeting\n");
80             return(PS_AUTHFAIL);
81         }
82
83         /* find end of timestamp */
84         for (end = start;  *end != 0  && *end != '>';  end++)
85             continue;
86         if (*end == 0 || (end - start - 1) == 1) {
87             fprintf(stderr,"Timestamp syntax error in greeting\n");
88             return(PS_AUTHFAIL);
89         }
90
91         /* copy timestamp and password into digestion buffer */
92         msg = (char *) malloc((end-start-1) + strlen(queryctl->password) + 1);
93         *(++end) = 0;
94         strcpy(msg,start);
95         strcat(msg,queryctl->password);
96
97         strcpy(queryctl->digest, MD5Digest(msg));
98         free(msg);
99     }
100
101     switch (queryctl->protocol) {
102     case P_POP3:
103         gen_send(socket,"USER %s", queryctl->remotename);
104         if (pop3_ok(socket, buf) != 0)
105             goto badAuth;
106
107         gen_send(socket, "PASS %s", queryctl->password);
108         if (pop3_ok(socket, buf) != 0)
109             goto badAuth;
110         break;
111
112     case P_RPOP:
113         gen_send(socket,"USER %s", queryctl->remotename);
114         if (pop3_ok(socket, buf) != 0)
115             goto badAuth;
116
117         gen_send(socket, "RPOP %s", queryctl->password);
118         if (pop3_ok(socket, buf) != 0)
119             goto badAuth;
120         break;
121
122     case P_APOP:
123         gen_send(socket,"APOP %s %s", queryctl->remotename, queryctl->digest);
124         if (pop3_ok(socket, buf) != 0) 
125             goto badAuth;
126         break;
127
128     default:
129         fprintf(stderr,"Undefined protocol request in POP3_auth\n");
130     }
131
132     /* we're approved */
133     return(0);
134
135     /*NOTREACHED*/
136
137 badAuth:
138     if (outlevel > O_SILENT && outlevel < O_VERBOSE)
139         fprintf(stderr,"%s\n",buf);
140     return(PS_ERROR);
141 }
142
143 static pop3_getrange(socket, queryctl, countp)
144 /* get range of messages to be fetched */
145 int socket;
146 struct hostrec *queryctl;
147 int *countp;
148 {
149     int ok;
150     char buf [POPBUFSIZE+1];
151
152     /* get the total message count */
153     gen_send(socket, "STAT");
154     ok = pop3_ok(socket, buf);
155     if (ok == 0)
156         sscanf(buf,"%d %*d", countp);
157     else
158         return(ok);
159
160     /*
161      * Newer, RFC-1725-conformant POP servers may not have the LAST command.
162      */
163     last = 0;
164     if (*countp > 0 && !queryctl->fetchall)
165     {
166         char id [IDLEN+1];
167
168         gen_send(socket,"LAST");
169         ok = pop3_ok(socket, buf);
170         if (ok == 0 && sscanf(buf, "%d", &last) == 0)
171             return(PS_ERROR);
172     }
173
174     return(0);
175 }
176
177 static int pop3_is_old(socket, queryctl, num)
178 int socket;
179 struct hostrec *queryctl;
180 int num;
181 {
182     return (num <= last);
183 }
184
185 static int pop3_fetch(socket, number, lenp)
186 /* request nth message */
187 int socket;
188 int number;
189 int *lenp; 
190 {
191     *lenp = 0;
192     return(gen_transact(socket, "RETR %d", number));
193 }
194
195 static pop3_delete(socket, queryctl, number)
196 /* delete a given message */
197 int socket;
198 struct hostrec *queryctl;
199 int number;
200 {
201     int ok;
202
203     /* send the deletion request */
204     if ((ok = gen_transact(socket, "DELE %d", number)) != 0)
205         return(ok);
206 }
207
208 const static struct method pop3 =
209 {
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 */
223 };
224
225 int doPOP3 (queryctl)
226 /* retrieve messages using POP3 */
227 struct hostrec *queryctl;
228 {
229     if (queryctl->remotefolder[0]) {
230         fprintf(stderr,"Option --remote is not supported with POP3\n");
231         return(PS_SYNTAX);
232     }
233
234     return(do_protocol(queryctl, &pop3));
235 }
236
237