]> Pileus Git - ~andy/fetchmail/blob - pop3.c
Removed all pretentions to RPOP support.
[~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_APOP:
113         gen_send(socket,"APOP %s %s", queryctl->remotename, queryctl->digest);
114         if (pop3_ok(socket, buf) != 0) 
115             goto badAuth;
116         break;
117
118     default:
119         fprintf(stderr,"Undefined protocol request in POP3_auth\n");
120     }
121
122     /* we're approved */
123     return(0);
124
125     /*NOTREACHED*/
126
127 badAuth:
128     if (outlevel > O_SILENT && outlevel < O_VERBOSE)
129         fprintf(stderr,"%s\n",buf);
130     return(PS_ERROR);
131 }
132
133 static pop3_getrange(socket, queryctl, countp)
134 /* get range of messages to be fetched */
135 int socket;
136 struct hostrec *queryctl;
137 int *countp;
138 {
139     int ok;
140     char buf [POPBUFSIZE+1];
141
142     /* get the total message count */
143     gen_send(socket, "STAT");
144     ok = pop3_ok(socket, buf);
145     if (ok == 0)
146         sscanf(buf,"%d %*d", countp);
147     else
148         return(ok);
149
150     /*
151      * Newer, RFC-1725-conformant POP servers may not have the LAST command.
152      */
153     last = 0;
154     if (*countp > 0 && !queryctl->fetchall)
155     {
156         char id [IDLEN+1];
157
158         gen_send(socket,"LAST");
159         ok = pop3_ok(socket, buf);
160         if (ok == 0 && sscanf(buf, "%d", &last) == 0)
161             return(PS_ERROR);
162     }
163
164     return(0);
165 }
166
167 static int pop3_is_old(socket, queryctl, num)
168 int socket;
169 struct hostrec *queryctl;
170 int num;
171 {
172     return (num <= last);
173 }
174
175 static int pop3_fetch(socket, number, lenp)
176 /* request nth message */
177 int socket;
178 int number;
179 int *lenp; 
180 {
181     *lenp = 0;
182     return(gen_transact(socket, "RETR %d", number));
183 }
184
185 static pop3_delete(socket, queryctl, number)
186 /* delete a given message */
187 int socket;
188 struct hostrec *queryctl;
189 int number;
190 {
191     return(gen_transact(socket, "DELE %d", number));
192 }
193
194 const static struct method pop3 =
195 {
196     "POP3",             /* Post Office Protocol v3 */
197     110,                /* standard POP3 port */
198     0,                  /* this is not a tagged protocol */
199     1,                  /* this uses a message delimiter */
200     pop3_ok,            /* parse command response */
201     pop3_getauth,       /* get authorization */
202     pop3_getrange,      /* query range of messages */
203     pop3_is_old,        /* how do we tell a message is old? */
204     pop3_fetch,         /* request given message */
205     NULL,               /* no message trailer */
206     pop3_delete,        /* how to delete a message */
207     NULL,               /* no POP3 expunge command */
208     "QUIT",             /* the POP3 exit command */
209 };
210
211 int doPOP3 (queryctl)
212 /* retrieve messages using POP3 */
213 struct hostrec *queryctl;
214 {
215     if (queryctl->mailbox[0]) {
216         fprintf(stderr,"Option --remote is not supported with POP3\n");
217         return(PS_SYNTAX);
218     }
219
220     return(do_protocol(queryctl, &pop3));
221 }
222
223