masqmail-0.2

view src/pop3_in.c @ 162:52c82d755215

replaced the MD5 implementation with the one of Solar Designer Until now, the sample code of RFC 1321 was used. It had an ugly license. Now we use the implementation of Solar Designer, which is in the Public Domain. http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
author meillo@marmaro.de
date Sun, 18 Jul 2010 22:01:04 +0200
parents 2685e59f6f43
children
line source
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 */
18 /* see RFC 1725 */
20 #include <sys/wait.h>
21 #include <sys/stat.h>
23 #include "masqmail.h"
24 #include "pop3_in.h"
25 #include "readsock.h"
27 #ifdef USE_LIB_CRYPTO
28 #include <openssl/md5.h>
29 #else
30 #include "md5/md5.h"
31 #endif
33 #ifdef ENABLE_POP3
35 /* experimental feature */
36 #define DO_WRITE_UIDL_EARLY 1
38 static gchar*
39 MD5String(char *string)
40 {
41 MD5_CTX context;
42 unsigned char digest[16];
43 char str_digest[33];
44 int i;
46 #ifdef USE_LIB_CRYPTO
47 MD5(string, strlen(string), digest);
48 #else
49 MD5_Init(&context);
50 MD5_Update(&context, string, strlen(string));
51 MD5_Final(digest, &context);
52 #endif
53 for (i = 0; i < 16; i++)
54 sprintf(str_digest + 2 * i, "%02x", digest[i]);
56 return g_strdup(str_digest);
57 }
59 static pop3_base*
60 create_pop3base(gint sock, guint flags)
61 {
62 gint dup_sock;
64 pop3_base *popb = (pop3_base *) g_malloc(sizeof(pop3_base));
65 if (popb) {
66 memset(popb, 0, sizeof(pop3_base));
68 popb->error = pop3_ok;
70 popb->buffer = (gchar *) g_malloc(POP3_BUF_LEN);
72 dup_sock = dup(sock);
73 popb->out = fdopen(sock, "w");
74 popb->in = fdopen(dup_sock, "r");
76 popb->flags = flags;
77 }
78 return popb;
79 }
81 static void
82 pop3_printf(FILE * out, gchar * fmt, ...)
83 {
84 va_list args;
85 va_start(args, fmt);
87 DEBUG(4) {
88 gchar buf[256];
89 va_list args_copy;
91 va_copy(args_copy, args);
92 vsnprintf(buf, 255, fmt, args_copy);
93 va_end(args_copy);
95 debugf(">>>%s", buf);
96 }
98 vfprintf(out, fmt, args);
99 fflush(out);
101 va_end(args);
102 }
104 static gboolean
105 find_uid(pop3_base * popb, gchar * str)
106 {
107 GList *node, *node_next;
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 }
124 static gboolean
125 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", conf.spool_dir, user, popb->remote_host);
130 gchar *tmpname = g_strdup_printf("%s.tmp", filename);
131 FILE *fptr = fopen(tmpname, "wt");
133 if (fptr) {
134 foreach(popb->drop_list, node) {
135 msg_info *info = (msg_info *) (node->data);
136 if (info->is_fetched || info->is_in_uidl)
137 fprintf(fptr, "%s\n", info->uid);
138 }
139 fclose(fptr);
140 ok = (rename(tmpname, filename) != -1);
141 }
143 g_free(tmpname);
144 g_free(filename);
145 return ok;
146 }
148 static gboolean
149 read_uidl_fname(pop3_base * popb, gchar * filename)
150 {
151 gboolean ok = FALSE;
152 FILE *fptr = fopen(filename, "rt");
153 gchar buf[256];
155 if (fptr) {
156 popb->list_uid_old = NULL;
157 while (fgets(buf, 255, fptr)) {
158 if (buf[strlen(buf) - 1] == '\n') {
159 g_strchomp(buf);
160 popb->list_uid_old = g_list_append(popb->list_uid_old, g_strdup(buf));
161 } else {
162 logwrite(LOG_ALERT, "broken uid: %s\n", buf);
163 break;
164 }
165 }
166 fclose(fptr);
167 ok = TRUE;
168 } else
169 logwrite(LOG_ALERT, "opening of %s failed: %s", filename, strerror(errno));
170 return ok;
171 }
173 static gboolean
174 read_uidl(pop3_base * popb, gchar * user)
175 {
176 gboolean ok = FALSE;
177 struct stat statbuf;
178 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host);
180 if (stat(filename, &statbuf) == 0) {
181 ok = read_uidl_fname(popb, filename);
182 if (ok) {
183 GList *drop_node;
184 foreach(popb->drop_list, drop_node) {
185 msg_info *info = (msg_info *) (drop_node->data);
186 if (find_uid(popb, info->uid)) {
187 DEBUG(5) debugf("msg with uid '%s' already known\n", info->uid);
188 info->is_in_uidl = TRUE;
189 popb->uidl_known_cnt++;
190 } else
191 DEBUG(5) debugf("msg with uid '%s' not known\n", info->uid);
192 }
193 }
194 } else {
195 logwrite(LOG_DEBUG, "no uidl file '%s' found\n", filename);
196 ok = TRUE;
197 }
199 g_free(filename);
200 return ok; /* return code is irrelevant, do not check... */
201 }
203 static gboolean
204 read_response(pop3_base * popb, int timeout)
205 {
206 gint len;
208 len = read_sockline(popb->in, popb->buffer, POP3_BUF_LEN, timeout, READSOCKL_CHUG);
210 if (len == -3) {
211 popb->error = pop3_timeout;
212 return FALSE;
213 } else if (len == -2) {
214 popb->error = pop3_syntax;
215 return FALSE;
216 } else if (len == -1) {
217 popb->error = pop3_eof;
218 return FALSE;
219 }
221 return TRUE;
222 }
224 static gboolean
225 check_response(pop3_base * popb)
226 {
227 char c = popb->buffer[0];
229 if (c == '+') {
230 popb->error = pop3_ok;
231 return TRUE;
232 } else if (c == '-')
233 popb->error = pop3_fail;
234 else
235 popb->error = pop3_syntax;
236 return FALSE;
237 }
239 static gboolean
240 strtoi(gchar * p, gchar ** pend, gint * val)
241 {
242 gchar buf[12];
243 gint i = 0;
245 while (*p && isspace(*p))
246 p++;
247 if (*p) {
248 while ((i < 11) && isdigit(*p))
249 buf[i++] = *(p++);
250 buf[i] = 0;
251 *val = atoi(buf);
252 *pend = p;
253 return TRUE;
254 }
255 return FALSE;
256 }
258 static gboolean
259 check_response_int_int(pop3_base * popb, gint * arg0, gint * arg1)
260 {
261 if (check_response(popb)) {
262 gchar *p = &(popb->buffer[3]);
263 gchar *pe;
265 if (strtoi(p, &pe, arg0)) {
266 DEBUG(5) debugf("arg0 = %d\n", *arg0);
267 p = pe;
268 if (strtoi(p, &pe, arg1))
269 DEBUG(5) debugf("arg1 = %d\n", *arg1);
270 return TRUE;
271 /* FIXME: Paolo's code has the return stmt
272 inside the if block right above it. What
273 is correct? */
274 }
275 popb->error = pop3_syntax;
276 }
277 return FALSE;
278 }
280 static gboolean
281 get_drop_listing(pop3_base * popb)
282 {
283 gchar buf[64];
285 DEBUG(5) debugf("get_drop_listing() entered\n");
287 while (1) {
288 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
289 if (len > 0) {
290 if (buf[0] == '.')
291 return TRUE;
292 else {
293 gint number, msg_size;
294 gchar *p = buf, *pe;
295 if (strtoi(p, &pe, &number)) {
296 p = pe;
297 if (strtoi(p, &pe, &msg_size)) {
298 msg_info *info = g_malloc(sizeof(msg_info));
299 info->number = number;
300 info->size = msg_size;
302 DEBUG(5) debugf ("get_drop_listing(), number = %d, msg_size = %d\n", number, msg_size);
304 info->uid = NULL;
305 info->is_fetched = FALSE;
306 info->is_in_uidl = FALSE;
307 popb->drop_list = g_list_append(popb->drop_list, info);
308 } else {
309 popb->error = pop3_syntax;
310 break;
311 }
312 } else {
313 popb->error = pop3_syntax;
314 break;
315 }
316 }
317 } else {
318 popb->error = (len == -1) ? pop3_eof : pop3_timeout;
319 return FALSE;
320 }
321 }
322 return FALSE;
323 }
325 static gboolean
326 get_uid_listing(pop3_base * popb)
327 {
328 gchar buf[64];
330 while (1) {
331 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
332 if (len > 0) {
333 if (buf[0] == '.')
334 return TRUE;
335 else {
336 gint number;
337 gchar *p = buf, *pe;
338 if (strtoi(p, &pe, &number)) {
339 msg_info *info = NULL;
340 GList *drop_node;
342 p = pe;
343 while (*p && isspace(*p))
344 p++;
346 foreach(popb->drop_list, drop_node) {
347 msg_info *curr_info = (msg_info *) (drop_node->data);
348 if (curr_info->number == number) {
349 info = curr_info;
350 break;
351 }
352 }
353 if (info) {
354 info->uid = g_strdup(p);
355 g_strchomp(info->uid);
356 }
358 } else {
359 popb->error = pop3_syntax;
360 break;
361 }
362 }
363 }
364 }
365 return FALSE;
366 }
368 static gboolean
369 check_init_response(pop3_base * popb)
370 {
371 if (check_response(popb)) {
372 gchar buf[256];
373 gchar *p = popb->buffer;
374 gint i = 0;
375 if (*p) {
376 while (*p && (*p != '<'))
377 p++;
378 while (*p && (*p != '>') && (i < 254))
379 buf[i++] = *(p++);
380 buf[i++] = '>';
381 buf[i] = '\0';
383 popb->timestamp = g_strdup(buf);
385 return TRUE;
386 }
387 }
388 return FALSE;
389 }
391 void
392 pop3_in_close(pop3_base * popb)
393 {
394 GList *node;
396 fclose(popb->in);
397 fclose(popb->out);
399 close(popb->sock);
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);
407 foreach(popb->drop_list, node) {
408 msg_info *info = (msg_info *) (node->data);
409 if (info->uid)
410 g_free(info->uid);
411 g_free(info);
412 }
413 g_list_free(popb->drop_list);
415 if (popb->buffer)
416 g_free(popb->buffer);
417 if (popb->timestamp)
418 g_free(popb->timestamp);
419 }
421 pop3_base*
422 pop3_in_open(gchar * host, gint port, GList * resolve_list, guint flags)
423 {
424 pop3_base *popb;
425 gint sock;
426 mxip_addr *addr;
428 DEBUG(5) debugf("pop3_in_open entered, host = %s\n", host);
430 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
431 /* create structure to hold status data: */
432 popb = create_pop3base(sock, flags);
433 popb->remote_host = addr->name;
435 DEBUG(5) {
436 struct sockaddr_in name;
437 int len;
438 getsockname(sock, (struct sockaddr *) (&name), &len);
439 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
440 }
441 return popb;
442 }
443 return NULL;
444 }
446 pop3_base*
447 pop3_in_open_child(gchar * cmd, guint flags)
448 {
449 pop3_base *popb;
450 gint sock;
452 DEBUG(5) debugf("pop3_in_open_child entered, cmd = %s\n", cmd);
453 sock = child(cmd);
454 if (sock > 0) {
455 popb = create_pop3base(sock, flags);
456 popb->remote_host = NULL;
457 return popb;
458 }
459 logwrite(LOG_ALERT, "child failed (sock = %d): %s\n", sock, strerror(errno));
461 return NULL;
462 }
464 gboolean
465 pop3_in_init(pop3_base * popb)
466 {
467 gboolean ok;
469 if ((ok = read_response(popb, POP3_INITIAL_TIMEOUT))) {
470 ok = check_init_response(popb);
471 }
472 if (!ok)
473 /* pop3_in_log_failure(popb, NULL); */
474 logwrite(LOG_ALERT, "pop3 failed\n");
475 return ok;
476 }
478 gboolean
479 pop3_in_login(pop3_base * popb, gchar * user, gchar * pass)
480 {
481 if (popb->flags & POP3_FLAG_APOP) {
483 gchar *string = g_strdup_printf("%s%s", popb->timestamp, pass);
484 gchar *digest = MD5String(string);
485 pop3_printf(popb->out, "APOP %s %s\r\n", user, digest);
486 g_free(string);
487 g_free(digest);
488 if (read_response(popb, POP3_CMD_TIMEOUT)) {
489 if (check_response(popb))
490 return TRUE;
491 else
492 popb->error = pop3_login_failure;
493 }
495 } else {
497 pop3_printf(popb->out, "USER %s\r\n", user);
498 if (read_response(popb, POP3_CMD_TIMEOUT)) {
499 if (check_response(popb)) {
500 pop3_printf(popb->out, "PASS %s\r\n", pass);
501 if (read_response(popb, POP3_CMD_TIMEOUT)) {
502 if (check_response(popb))
503 return TRUE;
504 else
505 popb->error = pop3_login_failure;
506 }
507 } else {
508 popb->error = pop3_login_failure;
509 }
510 }
511 }
512 return FALSE;
513 }
515 gboolean
516 pop3_in_stat(pop3_base * popb)
517 {
518 pop3_printf(popb->out, "STAT\r\n");
519 if (read_response(popb, POP3_CMD_TIMEOUT)) {
520 gint msg_cnt, mbox_size;
521 if (check_response_int_int(popb, &msg_cnt, &mbox_size)) {
522 popb->msg_cnt = msg_cnt;
523 popb->mbox_size = mbox_size;
525 return TRUE;
526 }
527 }
528 return FALSE;
529 }
531 gboolean
532 pop3_in_list(pop3_base * popb)
533 {
534 pop3_printf(popb->out, "LIST\r\n");
535 if (read_response(popb, POP3_CMD_TIMEOUT)) {
536 if (get_drop_listing(popb)) {
537 return TRUE;
538 }
539 }
540 return FALSE;
541 }
543 gboolean
544 pop3_in_dele(pop3_base * popb, gint number)
545 {
546 pop3_printf(popb->out, "DELE %d\r\n", number);
547 if (read_response(popb, POP3_CMD_TIMEOUT)) {
548 return TRUE;
549 }
550 return FALSE;
551 }
553 message*
554 pop3_in_retr(pop3_base * popb, gint number, address * rcpt)
555 {
556 accept_error err;
558 pop3_printf(popb->out, "RETR %d\r\n", number);
559 if (read_response(popb, POP3_CMD_TIMEOUT)) {
560 message *msg = create_message();
561 msg->received_host = popb->remote_host;
562 msg->received_prot = (popb->flags & POP3_FLAG_APOP) ? PROT_APOP : PROT_POP3;
563 msg->transfer_id = (popb->next_id)++;
564 msg->rcpt_list = g_list_append(NULL, copy_address(rcpt));
566 if ((err = accept_message(popb->in, msg, ACC_MAIL_FROM_HEAD
567 | (conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0)))
568 == AERR_OK)
569 return msg;
571 destroy_message(msg);
572 }
573 return NULL;
574 }
576 gboolean
577 pop3_in_uidl(pop3_base * popb)
578 {
579 pop3_printf(popb->out, "UIDL\r\n");
580 if (read_response(popb, POP3_CMD_TIMEOUT)) {
581 if (get_uid_listing(popb)) {
582 return TRUE;
583 }
584 }
585 return FALSE;
586 }
588 gboolean
589 pop3_in_quit(pop3_base * popb)
590 {
591 pop3_printf(popb->out, "QUIT\r\n");
592 DEBUG(4) debugf("QUIT\n");
593 signal(SIGALRM, SIG_DFL);
594 return TRUE;
595 }
597 /* Send a DELE command for each message in (the old) uid listing.
598 This is to prevent mail from to be kept on server, if a previous
599 transaction was interupted. */
600 gboolean
601 pop3_in_uidl_dele(pop3_base * popb)
602 {
603 GList *drop_node;
605 foreach(popb->drop_list, drop_node) {
606 msg_info *info = (msg_info *) (drop_node->data);
607 /* if(find_uid(popb, info->uid)){ */
608 if (info->is_in_uidl) {
609 if (!pop3_in_dele(popb, info->number))
610 return FALSE;
611 /* TODO: it probably makes sense to also delete this uid from the listing */
612 }
613 }
614 return TRUE;
615 }
617 gboolean
618 pop3_get(pop3_base * popb, gchar * user, gchar * pass, address * rcpt, address * return_path,
619 gint max_count, gint max_size, gboolean max_size_delete)
620 {
621 gboolean ok = FALSE;
622 gint num_children = 0;
624 DEBUG(5) debugf("rcpt = %s@%s\n", rcpt->local_part, rcpt->domain);
626 signal(SIGCHLD, SIG_DFL);
628 if (pop3_in_init(popb)) {
629 if (pop3_in_login(popb, user, pass)) {
630 if (pop3_in_stat(popb)) {
631 if (popb->msg_cnt > 0) {
633 logwrite(LOG_NOTICE | LOG_VERBOSE, "%d message(s) for user %s at %s\n",
634 popb->msg_cnt, user, popb->remote_host);
636 if (pop3_in_list(popb)) {
637 gboolean do_get = !(popb->flags & POP3_FLAG_UIDL);
638 if (!do_get)
639 do_get = pop3_in_uidl(popb);
640 if (do_get) {
641 gint count = 0;
642 GList *drop_node;
644 if (popb->flags & POP3_FLAG_UIDL) {
645 read_uidl(popb, user);
646 logwrite(LOG_VERBOSE | LOG_NOTICE, "%d message(s) already in uidl.\n", popb->uidl_known_cnt);
647 }
648 if ((popb->flags & POP3_FLAG_UIDL) && (popb->flags & POP3_FLAG_UIDL_DELE))
649 pop3_in_uidl_dele(popb);
651 foreach(popb->drop_list, drop_node) {
653 msg_info *info = (msg_info *) (drop_node->data);
654 gboolean do_get_this = !(popb->flags & POP3_FLAG_UIDL);
655 /* if(!do_get_this) do_get_this = !find_uid(popb, info->uid); */
656 if (!do_get_this)
657 do_get_this = !(info->is_in_uidl);
658 if (do_get_this) {
660 if ((info->size < max_size) || (max_size == 0)) {
661 message *msg;
663 logwrite(LOG_VERBOSE | LOG_NOTICE, "receiving message %d\n", info->number);
664 msg = pop3_in_retr(popb, info->number, rcpt);
666 if (msg) {
667 if (return_path)
668 msg->return_path = copy_address(return_path);
669 if (spool_write(msg, TRUE)) {
670 pid_t pid;
671 logwrite(LOG_NOTICE, "%s <= %s host=%s with %s\n", msg->uid,
672 addr_string(msg->return_path), popb->remote_host,
673 (popb->flags & POP3_FLAG_APOP) ? prot_names [PROT_APOP] : prot_names [PROT_POP3]);
674 info->is_fetched = TRUE;
675 count++;
676 #if DO_WRITE_UIDL_EARLY
677 if (popb->flags & POP3_FLAG_UIDL)
678 write_uidl(popb, user);
679 #endif
680 if (!conf.do_queue) {
682 /* wait for child processes. If there are too many, we wait blocking, before we fork another one */
683 while (num_children > 0) {
684 int status, options = WNOHANG;
685 pid_t pid;
687 if (num_children >= POP3_MAX_CHILDREN) {
688 logwrite(LOG_NOTICE, "too many children - waiting\n");
689 options = 0;
690 }
691 if ((pid = waitpid(0, &status, options)) > 0) {
692 num_children--;
693 if (WEXITSTATUS(status) != EXIT_SUCCESS)
694 logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS (status));
695 if (WIFSIGNALED(status))
696 logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG (status));
697 } else if (pid < 0) {
698 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
699 }
700 }
702 if ((pid = fork()) == 0) {
703 deliver(msg);
704 _exit(EXIT_SUCCESS);
705 } else if (pid < 0) {
706 logwrite(LOG_ALERT | LOG_VERBOSE, "could not fork for delivery, id = %s: %s\n", msg->uid, strerror(errno));
707 } else
708 num_children++;
709 } else {
710 DEBUG(1) debugf("queuing forced by configuration or option.\n");
711 }
712 if (popb->flags & POP3_FLAG_DELETE)
713 pop3_in_dele(popb, info->number);
715 destroy_message(msg);
716 } /* if(spool_write(msg, TRUE)) */
717 } else {
718 logwrite(LOG_ALERT, "retrieving of message %d failed: %d\n", info->number, popb->error);
719 }
720 } else {
721 /* info->size > max_size */
722 logwrite(LOG_NOTICE | LOG_VERBOSE, "size of message #%d (%d) > max_size (%d)\n", info->number, info->size, max_size);
723 if (max_size_delete)
724 if (popb->flags & POP3_FLAG_DELETE)
725 pop3_in_dele(popb, info->number);
726 }
727 } /* if(do_get_this) ... */
728 else {
729 if (popb->flags & POP3_FLAG_UIDL) {
730 info->is_fetched = TRUE; /* obsolete? */
731 logwrite(LOG_VERBOSE, "message %d already known\n", info->number);
732 DEBUG(1) debugf("message %d (uid = %s) not fetched\n", info->number, info->uid);
733 #if 0
734 #if DO_WRITE_UIDL_EARLY
735 write_uidl(popb, user); /* obsolete? */
736 #endif
737 #endif
738 }
739 }
740 if ((max_count != 0) && (count >= max_count))
741 break;
742 } /* foreach() */
743 #if DO_WRITE_UIDL_EARLY
744 #else
745 if (popb->flags & POP3_FLAG_UIDL)
746 write_uidl(popb, user);
747 #endif
748 } /* if(pop3_in_uidl(popb) ... */
749 } /* if(pop3_in_list(popb)) */
750 } /* if(popb->msg_cnt > 0) */
751 else {
752 logwrite(LOG_NOTICE | LOG_VERBOSE, "no messages for user %s at %s\n", user, popb->remote_host);
753 }
754 ok = TRUE;
755 }
756 pop3_in_quit(popb);
757 } else {
758 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, popb->remote_host);
759 }
760 }
761 if (!ok) {
762 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 failed, error = %d\n", popb->error);
763 }
765 while (num_children > 0) {
766 int status;
767 pid_t pid;
768 if ((pid = wait(&status)) > 0) {
769 num_children--;
770 if (WEXITSTATUS(status) != EXIT_SUCCESS)
771 logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS(status));
772 if (WIFSIGNALED(status))
773 logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG(status));
774 } else {
775 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
776 }
777 }
779 return ok;
780 }
782 /* function just to log into a pop server,
783 for pop_before_smtp (or is it smtp_after_pop?)
784 */
786 gboolean
787 pop3_login(gchar * host, gint port, GList * resolve_list, gchar * user, gchar * pass, guint flags)
788 {
789 gboolean ok = FALSE;
790 pop3_base *popb;
792 signal(SIGCHLD, SIG_IGN);
794 if ((popb = pop3_in_open(host, port, resolve_list, flags))) {
795 if (pop3_in_init(popb)) {
796 if (pop3_in_login(popb, user, pass))
797 ok = TRUE;
798 else
799 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, host);
800 }
801 pop3_in_close(popb);
802 }
803 return ok;
804 }
806 #endif