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