rev |
line source |
meillo@0
|
1 /* pop3_in.c, Copyright (C) 2000 by Oliver Kurth,
|
meillo@0
|
2 *
|
meillo@0
|
3 * This program is free software; you can redistribute it and/or modify
|
meillo@0
|
4 * it under the terms of the GNU General Public License as published by
|
meillo@0
|
5 * the Free Software Foundation; either version 2 of the License, or
|
meillo@0
|
6 * (at your option) any later version.
|
meillo@0
|
7 *
|
meillo@0
|
8 * This program is distributed in the hope that it will be useful,
|
meillo@0
|
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
meillo@0
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
meillo@0
|
11 * GNU General Public License for more details.
|
meillo@0
|
12 *
|
meillo@0
|
13 * You should have received a copy of the GNU General Public License
|
meillo@0
|
14 * along with this program; if not, write to the Free Software
|
meillo@0
|
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
meillo@0
|
16 */
|
meillo@0
|
17
|
meillo@0
|
18 /* see RFC 1725 */
|
meillo@0
|
19
|
meillo@0
|
20 #include "masqmail.h"
|
meillo@0
|
21 #include "pop3_in.h"
|
meillo@0
|
22 #include "readsock.h"
|
meillo@0
|
23
|
meillo@0
|
24 #include <sys/wait.h>
|
meillo@0
|
25 #include <sys/stat.h>
|
meillo@0
|
26
|
meillo@0
|
27 #ifdef USE_LIB_CRYPTO
|
meillo@0
|
28 #include <openssl/md5.h>
|
meillo@0
|
29 #else
|
meillo@0
|
30 #include "md5/global.h"
|
meillo@0
|
31 #include "md5/md5.h"
|
meillo@0
|
32 #endif
|
meillo@0
|
33
|
meillo@0
|
34 #ifdef ENABLE_POP3
|
meillo@0
|
35
|
meillo@0
|
36 /* experimental feature */
|
meillo@0
|
37 #define DO_WRITE_UIDL_EARLY 1
|
meillo@0
|
38
|
meillo@0
|
39 static
|
meillo@0
|
40 gchar *MD5String (char *string)
|
meillo@0
|
41 {
|
meillo@0
|
42 MD5_CTX context;
|
meillo@0
|
43 unsigned char digest[16];
|
meillo@0
|
44 char str_digest[33];
|
meillo@0
|
45 int i;
|
meillo@0
|
46
|
meillo@0
|
47 #ifdef USE_LIB_CRYPTO
|
meillo@0
|
48 MD5(string, strlen(string), digest);
|
meillo@0
|
49 #else
|
meillo@0
|
50 MD5Init(&context);
|
meillo@0
|
51 MD5Update(&context, string, strlen(string));
|
meillo@0
|
52 MD5Final(digest, &context);
|
meillo@0
|
53 #endif
|
meillo@0
|
54 for (i = 0; i < 16; i++)
|
meillo@0
|
55 sprintf(str_digest+2*i, "%02x", digest[i]);
|
meillo@0
|
56
|
meillo@0
|
57 return g_strdup(str_digest);
|
meillo@0
|
58 }
|
meillo@0
|
59
|
meillo@0
|
60 static
|
meillo@0
|
61 pop3_base *create_pop3base(gint sock, guint flags)
|
meillo@0
|
62 {
|
meillo@0
|
63 gint dup_sock;
|
meillo@0
|
64
|
meillo@0
|
65 pop3_base *popb = (pop3_base *)g_malloc(sizeof(pop3_base));
|
meillo@0
|
66 if(popb){
|
meillo@0
|
67 memset(popb, 0, sizeof(pop3_base));
|
meillo@0
|
68
|
meillo@0
|
69 popb->error = pop3_ok;
|
meillo@0
|
70
|
meillo@0
|
71 popb->buffer = (gchar *)g_malloc(POP3_BUF_LEN);
|
meillo@0
|
72
|
meillo@0
|
73 dup_sock = dup(sock);
|
meillo@0
|
74 popb->out = fdopen(sock, "w");
|
meillo@0
|
75 popb->in = fdopen(dup_sock, "r");
|
meillo@0
|
76
|
meillo@0
|
77 popb->flags = flags;
|
meillo@0
|
78 }
|
meillo@0
|
79 return popb;
|
meillo@0
|
80 }
|
meillo@0
|
81
|
meillo@0
|
82 static
|
meillo@0
|
83 void pop3_printf(FILE *out, gchar *fmt, ...)
|
meillo@0
|
84 {
|
meillo@0
|
85 va_list args;
|
meillo@0
|
86 va_start(args, fmt);
|
meillo@0
|
87
|
meillo@0
|
88 DEBUG(4){
|
meillo@0
|
89 gchar buf[256];
|
meillo@0
|
90 va_list args_copy;
|
meillo@0
|
91
|
meillo@0
|
92 va_copy(args_copy, args);
|
meillo@0
|
93 vsnprintf(buf, 255, fmt, args_copy);
|
meillo@0
|
94 va_end(args_copy);
|
meillo@0
|
95
|
meillo@0
|
96 debugf(">>>%s", buf);
|
meillo@0
|
97 }
|
meillo@0
|
98
|
meillo@0
|
99 vfprintf(out, fmt, args); fflush(out);
|
meillo@0
|
100
|
meillo@0
|
101 va_end(args);
|
meillo@0
|
102 }
|
meillo@0
|
103
|
meillo@0
|
104 static
|
meillo@0
|
105 gboolean find_uid(pop3_base *popb, gchar *str)
|
meillo@0
|
106 {
|
meillo@0
|
107 GList *node, *node_next;
|
meillo@0
|
108
|
meillo@0
|
109 for(node = popb->list_uid_old; node; node=node_next){
|
meillo@0
|
110 gchar *uid = (gchar *)(node->data);
|
meillo@0
|
111 node_next = node->next;
|
meillo@0
|
112 if(strcmp(uid, str) == 0){
|
meillo@0
|
113 #if 1
|
meillo@0
|
114 popb->list_uid_old = g_list_remove_link(popb->list_uid_old, node);
|
meillo@0
|
115 g_list_free_1(node);
|
meillo@0
|
116 g_free(uid);
|
meillo@0
|
117 #endif
|
meillo@0
|
118 return TRUE;
|
meillo@0
|
119 }
|
meillo@0
|
120 }
|
meillo@0
|
121 return FALSE;
|
meillo@0
|
122 }
|
meillo@0
|
123
|
meillo@0
|
124 static
|
meillo@0
|
125 gboolean write_uidl(pop3_base *popb, gchar *user)
|
meillo@0
|
126 {
|
meillo@0
|
127 gboolean ok = FALSE;
|
meillo@0
|
128 GList *node;
|
meillo@0
|
129 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s",
|
meillo@0
|
130 conf.spool_dir,
|
meillo@0
|
131 user, popb->remote_host);
|
meillo@0
|
132 gchar *tmpname = g_strdup_printf("%s.tmp", filename);
|
meillo@0
|
133 FILE *fptr = fopen(tmpname, "wt");
|
meillo@0
|
134
|
meillo@0
|
135 if(fptr){
|
meillo@0
|
136 foreach(popb->drop_list, node){
|
meillo@0
|
137 msg_info *info = (msg_info *)(node->data);
|
meillo@0
|
138 if(info->is_fetched || info->is_in_uidl)
|
meillo@0
|
139 fprintf(fptr, "%s\n", info->uid);
|
meillo@0
|
140 }
|
meillo@0
|
141 fclose(fptr);
|
meillo@0
|
142 ok = (rename(tmpname, filename) != -1);
|
meillo@0
|
143 }
|
meillo@0
|
144
|
meillo@0
|
145 g_free(tmpname);
|
meillo@0
|
146 g_free(filename);
|
meillo@0
|
147 return ok;
|
meillo@0
|
148 }
|
meillo@0
|
149
|
meillo@0
|
150 static
|
meillo@0
|
151 gboolean read_uidl_fname(pop3_base *popb, gchar *filename)
|
meillo@0
|
152 {
|
meillo@0
|
153 gboolean ok = FALSE;
|
meillo@0
|
154 FILE *fptr = fopen(filename, "rt");
|
meillo@0
|
155 gchar buf[256];
|
meillo@0
|
156
|
meillo@0
|
157 if(fptr){
|
meillo@0
|
158 popb->list_uid_old = NULL;
|
meillo@0
|
159 while(fgets(buf, 255, fptr)){
|
meillo@0
|
160 if(buf[strlen(buf)-1] == '\n'){
|
meillo@0
|
161 g_strchomp(buf);
|
meillo@0
|
162 popb->list_uid_old =
|
meillo@0
|
163 g_list_append(popb->list_uid_old, g_strdup(buf));
|
meillo@0
|
164 }else{
|
meillo@0
|
165 logwrite(LOG_ALERT, "broken uid: %s\n", buf);
|
meillo@0
|
166 break;
|
meillo@0
|
167 }
|
meillo@0
|
168 }
|
meillo@0
|
169 fclose(fptr);
|
meillo@0
|
170 ok = TRUE;
|
meillo@0
|
171 }else
|
meillo@0
|
172 logwrite(LOG_ALERT, "opening of %s failed: %s", filename, strerror(errno));
|
meillo@0
|
173 return ok;
|
meillo@0
|
174 }
|
meillo@0
|
175
|
meillo@0
|
176 static
|
meillo@0
|
177 gboolean read_uidl(pop3_base *popb, gchar *user)
|
meillo@0
|
178 {
|
meillo@0
|
179 gboolean ok = FALSE;
|
meillo@0
|
180 struct stat statbuf;
|
meillo@0
|
181 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s",
|
meillo@0
|
182 conf.spool_dir,
|
meillo@0
|
183 user, popb->remote_host);
|
meillo@0
|
184
|
meillo@0
|
185 if(stat(filename, &statbuf) == 0){
|
meillo@0
|
186 ok = read_uidl_fname(popb, filename);
|
meillo@0
|
187 if(ok){
|
meillo@0
|
188 GList *drop_node;
|
meillo@0
|
189 foreach(popb->drop_list, drop_node){
|
meillo@0
|
190 msg_info *info = (msg_info *)(drop_node->data);
|
meillo@0
|
191 if(find_uid(popb, info->uid)){
|
meillo@0
|
192 DEBUG(5) debugf("msg with uid '%s' already known\n", info->uid);
|
meillo@0
|
193 info->is_in_uidl = TRUE;
|
meillo@0
|
194 popb->uidl_known_cnt++;
|
meillo@0
|
195 }else
|
meillo@0
|
196 DEBUG(5) debugf("msg with uid '%s' not known\n", info->uid);
|
meillo@0
|
197 }
|
meillo@0
|
198 }
|
meillo@0
|
199 }else{
|
meillo@0
|
200 logwrite(LOG_DEBUG, "no uidl file '%s' found\n", filename);
|
meillo@0
|
201 ok = TRUE;
|
meillo@0
|
202 }
|
meillo@0
|
203
|
meillo@0
|
204 g_free(filename);
|
meillo@0
|
205 return ok; /* return code is irrelevant, do not check... */
|
meillo@0
|
206 }
|
meillo@0
|
207
|
meillo@0
|
208 static
|
meillo@0
|
209 gboolean read_response(pop3_base *popb, int timeout)
|
meillo@0
|
210 {
|
meillo@0
|
211 gint len;
|
meillo@0
|
212
|
meillo@0
|
213 len = read_sockline(popb->in, popb->buffer, POP3_BUF_LEN, timeout, READSOCKL_CHUG);
|
meillo@0
|
214
|
meillo@0
|
215 if(len == -3){
|
meillo@0
|
216 popb->error = pop3_timeout;
|
meillo@0
|
217 return FALSE;
|
meillo@0
|
218 }
|
meillo@0
|
219 else if(len == -2){
|
meillo@0
|
220 popb->error = pop3_syntax;
|
meillo@0
|
221 return FALSE;
|
meillo@0
|
222 }
|
meillo@0
|
223 else if(len == -1){
|
meillo@0
|
224 popb->error = pop3_eof;
|
meillo@0
|
225 return FALSE;
|
meillo@0
|
226 }
|
meillo@0
|
227
|
meillo@0
|
228 return TRUE;
|
meillo@0
|
229 }
|
meillo@0
|
230
|
meillo@0
|
231 static
|
meillo@0
|
232 gboolean check_response(pop3_base *popb)
|
meillo@0
|
233 {
|
meillo@0
|
234 char c = popb->buffer[0];
|
meillo@0
|
235
|
meillo@0
|
236 if(c == '+'){
|
meillo@0
|
237 popb->error = pop3_ok;
|
meillo@0
|
238 return TRUE;
|
meillo@0
|
239 }else if(c == '-')
|
meillo@0
|
240 popb->error = pop3_fail;
|
meillo@0
|
241 else
|
meillo@0
|
242 popb->error = pop3_syntax;
|
meillo@0
|
243 return FALSE;
|
meillo@0
|
244 }
|
meillo@0
|
245
|
meillo@0
|
246 static
|
meillo@0
|
247 gboolean strtoi(gchar *p, gchar **pend, gint *val)
|
meillo@0
|
248 {
|
meillo@0
|
249 gchar buf[12];
|
meillo@0
|
250 gint i = 0;
|
meillo@0
|
251
|
meillo@0
|
252 while(*p && isspace(*p)) p++;
|
meillo@0
|
253 if(*p){
|
meillo@0
|
254 while((i < 11) && isdigit(*p))
|
meillo@0
|
255 buf[i++] = *(p++);
|
meillo@0
|
256 buf[i] = 0;
|
meillo@0
|
257 *val = atoi(buf);
|
meillo@0
|
258 *pend = p;
|
meillo@0
|
259 return TRUE;
|
meillo@0
|
260 }
|
meillo@0
|
261 return FALSE;
|
meillo@0
|
262 }
|
meillo@0
|
263
|
meillo@0
|
264 static
|
meillo@0
|
265 gboolean check_response_int_int(pop3_base *popb, gint *arg0, gint *arg1)
|
meillo@0
|
266 {
|
meillo@0
|
267 if(check_response(popb)){
|
meillo@0
|
268 gchar *p = &(popb->buffer[3]);
|
meillo@0
|
269 gchar *pe;
|
meillo@0
|
270
|
meillo@0
|
271 if(strtoi(p, &pe, arg0)){
|
meillo@0
|
272 DEBUG(5) debugf("arg0 = %d\n", *arg0);
|
meillo@0
|
273 p = pe;
|
meillo@0
|
274 if(strtoi(p, &pe, arg1))
|
meillo@0
|
275 DEBUG(5) debugf("arg1 = %d\n", *arg1);
|
meillo@0
|
276 return TRUE;
|
meillo@0
|
277 }
|
meillo@0
|
278 popb->error = pop3_syntax;
|
meillo@0
|
279 }
|
meillo@0
|
280 return FALSE;
|
meillo@0
|
281 }
|
meillo@0
|
282
|
meillo@0
|
283 static
|
meillo@0
|
284 gboolean get_drop_listing(pop3_base *popb)
|
meillo@0
|
285 {
|
meillo@0
|
286 gchar buf[64];
|
meillo@0
|
287
|
meillo@0
|
288 DEBUG(5) debugf("get_drop_listing() entered\n");
|
meillo@0
|
289
|
meillo@0
|
290 while(1){
|
meillo@0
|
291 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
|
meillo@0
|
292 if(len > 0){
|
meillo@0
|
293 if(buf[0] == '.')
|
meillo@0
|
294 return TRUE;
|
meillo@0
|
295 else{
|
meillo@0
|
296 gint number, msg_size;
|
meillo@0
|
297 gchar *p = buf, *pe;
|
meillo@0
|
298 if(strtoi(p, &pe, &number)){
|
meillo@0
|
299 p = pe;
|
meillo@0
|
300 if(strtoi(p, &pe, &msg_size)){
|
meillo@0
|
301 msg_info *info = g_malloc(sizeof(msg_info));
|
meillo@0
|
302 info->number = number;
|
meillo@0
|
303 info->size = msg_size;
|
meillo@0
|
304
|
meillo@0
|
305 DEBUG(5) debugf("get_drop_listing(), number = %d, msg_size = %d\n", number, msg_size);
|
meillo@0
|
306
|
meillo@0
|
307 info->uid = NULL;
|
meillo@0
|
308 info->is_fetched = FALSE;
|
meillo@0
|
309 info->is_in_uidl = FALSE;
|
meillo@0
|
310 popb->drop_list = g_list_append(popb->drop_list, info);
|
meillo@0
|
311 }else{
|
meillo@0
|
312 popb->error = pop3_syntax;
|
meillo@0
|
313 break;
|
meillo@0
|
314 }
|
meillo@0
|
315 }else{
|
meillo@0
|
316 popb->error = pop3_syntax;
|
meillo@0
|
317 break;
|
meillo@0
|
318 }
|
meillo@0
|
319 }
|
meillo@0
|
320 }else{
|
meillo@0
|
321 popb->error = (len == -1) ? pop3_eof : pop3_timeout;
|
meillo@0
|
322 return FALSE;
|
meillo@0
|
323 }
|
meillo@0
|
324 }
|
meillo@0
|
325 return FALSE;
|
meillo@0
|
326 }
|
meillo@0
|
327
|
meillo@0
|
328 static
|
meillo@0
|
329 gboolean get_uid_listing(pop3_base *popb)
|
meillo@0
|
330 {
|
meillo@0
|
331 gchar buf[64];
|
meillo@0
|
332
|
meillo@0
|
333 while(1){
|
meillo@0
|
334 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
|
meillo@0
|
335 if(len > 0){
|
meillo@0
|
336 if(buf[0] == '.')
|
meillo@0
|
337 return TRUE;
|
meillo@0
|
338 else{
|
meillo@0
|
339 gint number;
|
meillo@0
|
340 gchar *p = buf, *pe;
|
meillo@0
|
341 if(strtoi(p, &pe, &number)){
|
meillo@0
|
342 msg_info *info = NULL;
|
meillo@0
|
343 GList *drop_node;
|
meillo@0
|
344
|
meillo@0
|
345 p = pe;
|
meillo@0
|
346 while(*p && isspace(*p)) p++;
|
meillo@0
|
347
|
meillo@0
|
348 foreach(popb->drop_list, drop_node){
|
meillo@0
|
349 msg_info *curr_info = (msg_info *)(drop_node->data);
|
meillo@0
|
350 if(curr_info->number == number){
|
meillo@0
|
351 info = curr_info;
|
meillo@0
|
352 break;
|
meillo@0
|
353 }
|
meillo@0
|
354 }
|
meillo@0
|
355 if(info){
|
meillo@0
|
356 info->uid = g_strdup(p);
|
meillo@0
|
357 g_strchomp(info->uid);
|
meillo@0
|
358 }
|
meillo@0
|
359
|
meillo@0
|
360 }else{
|
meillo@0
|
361 popb->error = pop3_syntax;
|
meillo@0
|
362 break;
|
meillo@0
|
363 }
|
meillo@0
|
364 }
|
meillo@0
|
365 }
|
meillo@0
|
366 }
|
meillo@0
|
367 return FALSE;
|
meillo@0
|
368 }
|
meillo@0
|
369
|
meillo@0
|
370 static
|
meillo@0
|
371 gboolean check_init_response(pop3_base *popb)
|
meillo@0
|
372 {
|
meillo@0
|
373 if(check_response(popb)){
|
meillo@0
|
374 gchar buf[256];
|
meillo@0
|
375 gchar *p = popb->buffer;
|
meillo@0
|
376 gint i = 0;
|
meillo@0
|
377 if(*p){
|
meillo@0
|
378 while(*p && (*p != '<')) p++;
|
meillo@0
|
379 while(*p && (*p != '>') && (i < 254))
|
meillo@0
|
380 buf[i++] = *(p++);
|
meillo@0
|
381 buf[i++] = '>';
|
meillo@0
|
382 buf[i] = 0;
|
meillo@0
|
383
|
meillo@0
|
384 popb->timestamp = g_strdup(buf);
|
meillo@0
|
385
|
meillo@0
|
386 return TRUE;
|
meillo@0
|
387 }
|
meillo@0
|
388 }
|
meillo@0
|
389 return FALSE;
|
meillo@0
|
390 }
|
meillo@0
|
391
|
meillo@0
|
392 void pop3_in_close(pop3_base *popb)
|
meillo@0
|
393 {
|
meillo@0
|
394 GList *node;
|
meillo@0
|
395
|
meillo@0
|
396 fclose(popb->in);
|
meillo@0
|
397 fclose(popb->out);
|
meillo@0
|
398
|
meillo@0
|
399 close(popb->sock);
|
meillo@0
|
400
|
meillo@0
|
401 foreach(popb->list_uid_old, node){
|
meillo@0
|
402 gchar *uid = (gchar *)(node->data);
|
meillo@0
|
403 g_free(uid);
|
meillo@0
|
404 }
|
meillo@0
|
405 g_list_free(popb->list_uid_old);
|
meillo@0
|
406
|
meillo@0
|
407 foreach(popb->drop_list, node){
|
meillo@0
|
408 msg_info *info = (msg_info *)(node->data);
|
meillo@0
|
409 if(info->uid) g_free(info->uid);
|
meillo@0
|
410 g_free(info);
|
meillo@0
|
411 }
|
meillo@0
|
412 g_list_free(popb->drop_list);
|
meillo@0
|
413
|
meillo@0
|
414 if(popb->buffer) g_free(popb->buffer);
|
meillo@0
|
415 if(popb->timestamp) g_free(popb->timestamp);
|
meillo@0
|
416 }
|
meillo@0
|
417
|
meillo@0
|
418 pop3_base *pop3_in_open(gchar *host, gint port, GList *resolve_list, guint flags)
|
meillo@0
|
419 {
|
meillo@0
|
420 pop3_base *popb;
|
meillo@0
|
421 gint sock;
|
meillo@0
|
422 mxip_addr *addr;
|
meillo@0
|
423
|
meillo@0
|
424 DEBUG(5) debugf("pop3_in_open entered, host = %s\n", host);
|
meillo@0
|
425
|
meillo@0
|
426 if((addr = connect_resolvelist(&sock, host, port, resolve_list))){
|
meillo@0
|
427 /* create structure to hold status data: */
|
meillo@0
|
428 popb = create_pop3base(sock, flags);
|
meillo@0
|
429 popb->remote_host = addr->name;
|
meillo@0
|
430
|
meillo@0
|
431 DEBUG(5){
|
meillo@0
|
432 struct sockaddr_in name;
|
meillo@0
|
433 int len;
|
meillo@0
|
434 getsockname(sock, (struct sockaddr *)(&name), &len);
|
meillo@0
|
435 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
|
meillo@0
|
436 }
|
meillo@0
|
437 return popb;
|
meillo@0
|
438 }
|
meillo@0
|
439 return NULL;
|
meillo@0
|
440 }
|
meillo@0
|
441
|
meillo@0
|
442 pop3_base *pop3_in_open_child(gchar *cmd, guint flags)
|
meillo@0
|
443 {
|
meillo@0
|
444 pop3_base *popb;
|
meillo@0
|
445 gint sock;
|
meillo@0
|
446
|
meillo@0
|
447 DEBUG(5) debugf("pop3_in_open_child entered, cmd = %s\n", cmd);
|
meillo@0
|
448
|
meillo@0
|
449 sock = child(cmd);
|
meillo@0
|
450
|
meillo@0
|
451 if(sock > 0){
|
meillo@0
|
452
|
meillo@0
|
453 popb = create_pop3base(sock, flags);
|
meillo@0
|
454 popb->remote_host = NULL;
|
meillo@0
|
455
|
meillo@0
|
456 return popb;
|
meillo@0
|
457 }
|
meillo@0
|
458 logwrite(LOG_ALERT, "child failed (sock = %d): %s\n", sock, strerror(errno));
|
meillo@0
|
459
|
meillo@0
|
460 return NULL;
|
meillo@0
|
461 }
|
meillo@0
|
462
|
meillo@0
|
463 gboolean pop3_in_init(pop3_base *popb)
|
meillo@0
|
464 {
|
meillo@0
|
465 gboolean ok;
|
meillo@0
|
466
|
meillo@0
|
467 if((ok = read_response(popb, POP3_INITIAL_TIMEOUT))){
|
meillo@0
|
468 ok = check_init_response(popb);
|
meillo@0
|
469 }
|
meillo@0
|
470 if(!ok)
|
meillo@0
|
471 /* pop3_in_log_failure(popb, NULL);*/
|
meillo@0
|
472 logwrite(LOG_ALERT, "pop3 failed\n");
|
meillo@0
|
473 return ok;
|
meillo@0
|
474 }
|
meillo@0
|
475
|
meillo@0
|
476 gboolean pop3_in_login(pop3_base *popb, gchar *user, gchar *pass)
|
meillo@0
|
477 {
|
meillo@0
|
478 if(popb->flags & POP3_FLAG_APOP){
|
meillo@0
|
479
|
meillo@0
|
480 gchar *string = g_strdup_printf("%s%s", popb->timestamp, pass);
|
meillo@0
|
481 gchar *digest = MD5String(string);
|
meillo@0
|
482 pop3_printf(popb->out, "APOP %s %s\r\n", user, digest);
|
meillo@0
|
483 g_free(string);
|
meillo@0
|
484 g_free(digest);
|
meillo@0
|
485 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
486 if(check_response(popb))
|
meillo@0
|
487 return TRUE;
|
meillo@0
|
488 else
|
meillo@0
|
489 popb->error = pop3_login_failure;
|
meillo@0
|
490 }
|
meillo@0
|
491
|
meillo@0
|
492 }else{
|
meillo@0
|
493
|
meillo@0
|
494 pop3_printf(popb->out, "USER %s\r\n", user);
|
meillo@0
|
495 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
496 if(check_response(popb)){
|
meillo@0
|
497 pop3_printf(popb->out, "PASS %s\r\n", pass);
|
meillo@0
|
498 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
499 if(check_response(popb))
|
meillo@0
|
500 return TRUE;
|
meillo@0
|
501 else
|
meillo@0
|
502 popb->error = pop3_login_failure;
|
meillo@0
|
503 }
|
meillo@0
|
504 }else{
|
meillo@0
|
505 popb->error = pop3_login_failure;
|
meillo@0
|
506 }
|
meillo@0
|
507 }
|
meillo@0
|
508 }
|
meillo@0
|
509 return FALSE;
|
meillo@0
|
510 }
|
meillo@0
|
511
|
meillo@0
|
512 gboolean pop3_in_stat(pop3_base *popb)
|
meillo@0
|
513 {
|
meillo@0
|
514 pop3_printf(popb->out, "STAT\r\n");
|
meillo@0
|
515 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
516 gint msg_cnt, mbox_size;
|
meillo@0
|
517 if(check_response_int_int(popb, &msg_cnt, &mbox_size)){
|
meillo@0
|
518 popb->msg_cnt = msg_cnt;
|
meillo@0
|
519 popb->mbox_size = mbox_size;
|
meillo@0
|
520
|
meillo@0
|
521 return TRUE;
|
meillo@0
|
522 }
|
meillo@0
|
523 }
|
meillo@0
|
524 return FALSE;
|
meillo@0
|
525 }
|
meillo@0
|
526
|
meillo@0
|
527 gboolean pop3_in_list(pop3_base *popb)
|
meillo@0
|
528 {
|
meillo@0
|
529 pop3_printf(popb->out, "LIST\r\n");
|
meillo@0
|
530 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
531 if(get_drop_listing(popb)){
|
meillo@0
|
532 return TRUE;
|
meillo@0
|
533 }
|
meillo@0
|
534 }
|
meillo@0
|
535 return FALSE;
|
meillo@0
|
536 }
|
meillo@0
|
537
|
meillo@0
|
538 gboolean pop3_in_dele(pop3_base *popb, gint number)
|
meillo@0
|
539 {
|
meillo@0
|
540 pop3_printf(popb->out, "DELE %d\r\n", number);
|
meillo@0
|
541 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
542 return TRUE;
|
meillo@0
|
543 }
|
meillo@0
|
544 return FALSE;
|
meillo@0
|
545 }
|
meillo@0
|
546
|
meillo@0
|
547 message *pop3_in_retr(pop3_base *popb, gint number, address *rcpt)
|
meillo@0
|
548 {
|
meillo@0
|
549 accept_error err;
|
meillo@0
|
550
|
meillo@0
|
551 pop3_printf(popb->out, "RETR %d\r\n", number);
|
meillo@0
|
552 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
553 message *msg = create_message();
|
meillo@0
|
554 msg->received_host = popb->remote_host;
|
meillo@0
|
555 msg->received_prot = (popb->flags & POP3_FLAG_APOP) ? PROT_APOP : PROT_POP3;
|
meillo@0
|
556 msg->transfer_id = (popb->next_id)++;
|
meillo@0
|
557 msg->rcpt_list = g_list_append(NULL, copy_address(rcpt));
|
meillo@0
|
558
|
meillo@0
|
559 if((err = accept_message(popb->in, msg,
|
meillo@0
|
560 ACC_MAIL_FROM_HEAD|(conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0)))
|
meillo@0
|
561 == AERR_OK)
|
meillo@0
|
562 return msg;
|
meillo@0
|
563
|
meillo@0
|
564 destroy_message(msg);
|
meillo@0
|
565 }
|
meillo@0
|
566 return NULL;
|
meillo@0
|
567 }
|
meillo@0
|
568
|
meillo@0
|
569 gboolean pop3_in_uidl(pop3_base *popb)
|
meillo@0
|
570 {
|
meillo@0
|
571 pop3_printf(popb->out, "UIDL\r\n");
|
meillo@0
|
572 if(read_response(popb, POP3_CMD_TIMEOUT)){
|
meillo@0
|
573 if(get_uid_listing(popb)){
|
meillo@0
|
574 return TRUE;
|
meillo@0
|
575 }
|
meillo@0
|
576 }
|
meillo@0
|
577 return FALSE;
|
meillo@0
|
578 }
|
meillo@0
|
579
|
meillo@0
|
580 gboolean pop3_in_quit(pop3_base *popb)
|
meillo@0
|
581 {
|
meillo@0
|
582 pop3_printf(popb->out, "QUIT\r\n");
|
meillo@0
|
583
|
meillo@0
|
584 DEBUG(4) debugf("QUIT\n");
|
meillo@0
|
585
|
meillo@0
|
586 signal(SIGALRM, SIG_DFL);
|
meillo@0
|
587
|
meillo@0
|
588 return TRUE;
|
meillo@0
|
589 }
|
meillo@0
|
590
|
meillo@0
|
591 /* Send a DELE command for each message in (the old) uid listing.
|
meillo@0
|
592 This is to prevent mail from to be kept on server, if a previous
|
meillo@0
|
593 transaction was interupted. */
|
meillo@0
|
594 gboolean pop3_in_uidl_dele(pop3_base *popb)
|
meillo@0
|
595 {
|
meillo@0
|
596 GList *drop_node;
|
meillo@0
|
597
|
meillo@0
|
598 foreach(popb->drop_list, drop_node){
|
meillo@0
|
599 msg_info *info = (msg_info *)(drop_node->data);
|
meillo@0
|
600 /* if(find_uid(popb, info->uid)){*/
|
meillo@0
|
601 if(info->is_in_uidl){
|
meillo@0
|
602 if(!pop3_in_dele(popb, info->number))
|
meillo@0
|
603 return FALSE;
|
meillo@0
|
604 /* TODO: it probably makes sense to also
|
meillo@0
|
605 delete this uid from the listing */
|
meillo@0
|
606 }
|
meillo@0
|
607 }
|
meillo@0
|
608 return TRUE;
|
meillo@0
|
609 }
|
meillo@0
|
610
|
meillo@0
|
611 gboolean pop3_get(pop3_base *popb,
|
meillo@0
|
612 gchar *user, gchar *pass, address *rcpt, address *return_path,
|
meillo@0
|
613 gint max_count, gint max_size, gboolean max_size_delete)
|
meillo@0
|
614 {
|
meillo@0
|
615 gboolean ok = FALSE;
|
meillo@0
|
616 gint num_children = 0;
|
meillo@0
|
617
|
meillo@0
|
618 DEBUG(5) debugf("rcpt = %s@%s\n", rcpt->local_part, rcpt->domain);
|
meillo@0
|
619
|
meillo@0
|
620 signal(SIGCHLD, SIG_DFL);
|
meillo@0
|
621
|
meillo@0
|
622 if(pop3_in_init(popb)){
|
meillo@0
|
623 if(pop3_in_login(popb, user, pass)){
|
meillo@0
|
624 if(pop3_in_stat(popb)){
|
meillo@0
|
625 if(popb->msg_cnt > 0){
|
meillo@0
|
626
|
meillo@0
|
627 logwrite(LOG_NOTICE|LOG_VERBOSE, "%d message(s) for user %s at %s\n",
|
meillo@0
|
628 popb->msg_cnt, user, popb->remote_host);
|
meillo@0
|
629
|
meillo@0
|
630 if(pop3_in_list(popb)){
|
meillo@0
|
631 gboolean do_get = !(popb->flags & POP3_FLAG_UIDL);
|
meillo@0
|
632 if(!do_get) do_get = pop3_in_uidl(popb);
|
meillo@0
|
633 if(do_get){
|
meillo@0
|
634 gint count = 0;
|
meillo@0
|
635 GList *drop_node;
|
meillo@0
|
636
|
meillo@0
|
637 if(popb->flags & POP3_FLAG_UIDL){
|
meillo@0
|
638 read_uidl(popb, user);
|
meillo@0
|
639 logwrite(LOG_VERBOSE|LOG_NOTICE, "%d message(s) already in uidl.\n",
|
meillo@0
|
640 popb->uidl_known_cnt);
|
meillo@0
|
641 }
|
meillo@0
|
642 if((popb->flags & POP3_FLAG_UIDL) && (popb->flags & POP3_FLAG_UIDL_DELE))
|
meillo@0
|
643 pop3_in_uidl_dele(popb);
|
meillo@0
|
644
|
meillo@0
|
645 foreach(popb->drop_list, drop_node){
|
meillo@0
|
646
|
meillo@0
|
647 msg_info *info = (msg_info *)(drop_node->data);
|
meillo@0
|
648 gboolean do_get_this = !(popb->flags & POP3_FLAG_UIDL);
|
meillo@0
|
649 /* if(!do_get_this) do_get_this = !find_uid(popb, info->uid);*/
|
meillo@0
|
650 if(!do_get_this) do_get_this = !(info->is_in_uidl);
|
meillo@0
|
651 if(do_get_this){
|
meillo@0
|
652
|
meillo@0
|
653 if((info->size < max_size) || (max_size == 0)){
|
meillo@0
|
654 message *msg;
|
meillo@0
|
655
|
meillo@0
|
656 logwrite(LOG_VERBOSE|LOG_NOTICE, "receiving message %d\n", info->number);
|
meillo@0
|
657 msg = pop3_in_retr(popb, info->number, rcpt);
|
meillo@0
|
658
|
meillo@0
|
659 if(msg){
|
meillo@0
|
660 if(return_path)
|
meillo@0
|
661 msg->return_path = copy_address(return_path);
|
meillo@0
|
662 if(spool_write(msg, TRUE)){
|
meillo@0
|
663 pid_t pid;
|
meillo@0
|
664 logwrite(LOG_NOTICE, "%s <= %s host=%s with %s\n",
|
meillo@0
|
665 msg->uid,
|
meillo@0
|
666 addr_string(msg->return_path),
|
meillo@0
|
667 popb->remote_host,
|
meillo@0
|
668 (popb->flags & POP3_FLAG_APOP) ?
|
meillo@0
|
669 prot_names[PROT_APOP] : prot_names[PROT_POP3]
|
meillo@0
|
670 );
|
meillo@0
|
671 info->is_fetched = TRUE;
|
meillo@0
|
672 count++;
|
meillo@0
|
673 #if DO_WRITE_UIDL_EARLY
|
meillo@0
|
674 if(popb->flags & POP3_FLAG_UIDL) write_uidl(popb, user);
|
meillo@0
|
675 #endif
|
meillo@0
|
676 if(!conf.do_queue){
|
meillo@0
|
677
|
meillo@0
|
678 /* wait for child processes. If there are too many,
|
meillo@0
|
679 we wait blocking, before we fork another one */
|
meillo@0
|
680 while(num_children > 0){
|
meillo@0
|
681 int status, options = WNOHANG;
|
meillo@0
|
682 pid_t pid;
|
meillo@0
|
683
|
meillo@0
|
684 if(num_children >= POP3_MAX_CHILDREN){
|
meillo@0
|
685 logwrite(LOG_NOTICE, "too many children - waiting\n");
|
meillo@0
|
686 options = 0;
|
meillo@0
|
687 }
|
meillo@0
|
688 if((pid = waitpid(0, &status, options)) > 0){
|
meillo@0
|
689 num_children--;
|
meillo@0
|
690 if(WEXITSTATUS(status) != EXIT_SUCCESS)
|
meillo@0
|
691 logwrite(LOG_WARNING,
|
meillo@0
|
692 "delivery process with pid %d returned %d\n",
|
meillo@0
|
693 pid, WEXITSTATUS(status));
|
meillo@0
|
694 if(WIFSIGNALED(status))
|
meillo@0
|
695 logwrite(LOG_WARNING,
|
meillo@0
|
696 "delivery process with pid %d got signal: %d\n",
|
meillo@0
|
697 pid, WTERMSIG(status));
|
meillo@0
|
698 }else if(pid < 0){
|
meillo@0
|
699 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
|
meillo@0
|
700 }
|
meillo@0
|
701 }
|
meillo@0
|
702
|
meillo@0
|
703 if((pid = fork()) == 0){
|
meillo@0
|
704 deliver(msg);
|
meillo@0
|
705 _exit(EXIT_SUCCESS);
|
meillo@0
|
706 }else if(pid < 0){
|
meillo@0
|
707 logwrite(LOG_ALERT|LOG_VERBOSE,
|
meillo@0
|
708 "could not fork for delivery, id = %s: %s\n",
|
meillo@0
|
709 msg->uid, strerror(errno));
|
meillo@0
|
710 }else
|
meillo@0
|
711 num_children++;
|
meillo@0
|
712 }else{
|
meillo@0
|
713 DEBUG(1) debugf("queuing forced by configuration or option.\n");
|
meillo@0
|
714 }
|
meillo@0
|
715 if(popb->flags & POP3_FLAG_DELETE)
|
meillo@0
|
716 pop3_in_dele(popb, info->number);
|
meillo@0
|
717
|
meillo@0
|
718 destroy_message(msg);
|
meillo@0
|
719 }/* if(spool_write(msg, TRUE)) */
|
meillo@0
|
720 }else{
|
meillo@0
|
721 logwrite(LOG_ALERT,
|
meillo@0
|
722 "retrieving of message %d failed: %d\n",
|
meillo@0
|
723 info->number, popb->error);
|
meillo@0
|
724 }
|
meillo@0
|
725 }/* if((info->size > max_size) ... */
|
meillo@0
|
726 else{
|
meillo@0
|
727 logwrite(LOG_NOTICE|LOG_VERBOSE, "size of message #%d (%d) > max_size (%d)\n",
|
meillo@0
|
728 info->number, info->size, max_size);
|
meillo@0
|
729 if(max_size_delete)
|
meillo@0
|
730 if(popb->flags & POP3_FLAG_DELETE)
|
meillo@0
|
731 pop3_in_dele(popb, info->number);
|
meillo@0
|
732 }
|
meillo@0
|
733 }/* if(do_get_this) ... */
|
meillo@0
|
734 else{
|
meillo@0
|
735 if(popb->flags & POP3_FLAG_UIDL){
|
meillo@0
|
736 info->is_fetched = TRUE; /* obsolete? */
|
meillo@0
|
737 logwrite(LOG_VERBOSE, "message %d already known\n",
|
meillo@0
|
738 info->number);
|
meillo@0
|
739 DEBUG(1) debugf("message %d (uid = %s) not fetched\n",
|
meillo@0
|
740 info->number, info->uid);
|
meillo@0
|
741 #if 0
|
meillo@0
|
742 #if DO_WRITE_UIDL_EARLY
|
meillo@0
|
743 write_uidl(popb, user); /* obsolete? */
|
meillo@0
|
744 #endif
|
meillo@0
|
745 #endif
|
meillo@0
|
746 }
|
meillo@0
|
747 }
|
meillo@0
|
748 if((max_count != 0) && (count >= max_count))
|
meillo@0
|
749 break;
|
meillo@0
|
750 }/* foreach() */
|
meillo@0
|
751 #if DO_WRITE_UIDL_EARLY
|
meillo@0
|
752 #else
|
meillo@0
|
753 if(popb->flags & POP3_FLAG_UIDL) write_uidl(popb, user);
|
meillo@0
|
754 #endif
|
meillo@0
|
755 }/* if(pop3_in_uidl(popb) ... */
|
meillo@0
|
756 }/* if(pop3_in_list(popb)) */
|
meillo@0
|
757 }/* if(popb->msg_cnt > 0) */
|
meillo@0
|
758 else{
|
meillo@0
|
759 logwrite(LOG_NOTICE|LOG_VERBOSE,
|
meillo@0
|
760 "no messages for user %s at %s\n", user, popb->remote_host);
|
meillo@0
|
761 }
|
meillo@0
|
762 ok = TRUE;
|
meillo@0
|
763 }
|
meillo@0
|
764 pop3_in_quit(popb);
|
meillo@0
|
765 }else{
|
meillo@0
|
766 logwrite(LOG_ALERT|LOG_VERBOSE,
|
meillo@0
|
767 "pop3 login failed for user %s, host = %s\n", user, popb->remote_host);
|
meillo@0
|
768 }
|
meillo@0
|
769 }
|
meillo@0
|
770 if(!ok){
|
meillo@0
|
771 logwrite(LOG_ALERT|LOG_VERBOSE, "pop3 failed, error = %d\n", popb->error);
|
meillo@0
|
772 }
|
meillo@0
|
773
|
meillo@0
|
774 while(num_children > 0){
|
meillo@0
|
775 int status;
|
meillo@0
|
776 pid_t pid;
|
meillo@0
|
777 if((pid = wait(&status)) > 0){
|
meillo@0
|
778 num_children--;
|
meillo@0
|
779 if(WEXITSTATUS(status) != EXIT_SUCCESS)
|
meillo@0
|
780 logwrite(LOG_WARNING,
|
meillo@0
|
781 "delivery process with pid %d returned %d\n",
|
meillo@0
|
782 pid, WEXITSTATUS(status));
|
meillo@0
|
783 if(WIFSIGNALED(status))
|
meillo@0
|
784 logwrite(LOG_WARNING,
|
meillo@0
|
785 "delivery process with pid %d got signal: %d\n",
|
meillo@0
|
786 pid, WTERMSIG(status));
|
meillo@0
|
787 }else{
|
meillo@0
|
788 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
|
meillo@0
|
789 }
|
meillo@0
|
790 }
|
meillo@0
|
791
|
meillo@0
|
792 return ok;
|
meillo@0
|
793 }
|
meillo@0
|
794
|
meillo@0
|
795 /* function just to log into a pop server,
|
meillo@0
|
796 for pop_before_smtp (or is it smtp_after_pop?)
|
meillo@0
|
797 */
|
meillo@0
|
798
|
meillo@0
|
799 gboolean pop3_login(gchar *host, gint port, GList *resolve_list,
|
meillo@0
|
800 gchar *user, gchar *pass, guint flags)
|
meillo@0
|
801 {
|
meillo@0
|
802 gboolean ok = FALSE;
|
meillo@0
|
803 pop3_base *popb;
|
meillo@0
|
804
|
meillo@0
|
805 signal(SIGCHLD, SIG_IGN);
|
meillo@0
|
806
|
meillo@0
|
807 if((popb = pop3_in_open(host, port, resolve_list, flags))){
|
meillo@0
|
808 if(pop3_in_init(popb)){
|
meillo@0
|
809 if(pop3_in_login(popb, user, pass))
|
meillo@0
|
810 ok = TRUE;
|
meillo@0
|
811 else
|
meillo@0
|
812 logwrite(LOG_ALERT|LOG_VERBOSE,
|
meillo@0
|
813 "pop3 login failed for user %s, host = %s\n", user, host);
|
meillo@0
|
814 }
|
meillo@0
|
815 pop3_in_close(popb);
|
meillo@0
|
816 }
|
meillo@0
|
817 return ok;
|
meillo@0
|
818 }
|
meillo@0
|
819
|
meillo@0
|
820 #endif
|