masqmail-0.2

view src/pop3_in.c @ 75:257a9e6d1a8e

fixed correct processing of mails with data lines longer 4096 chars Mail messages with lines longer than 4096 chars were already read correctly, i.e. the spool files were correct. This commit fixes the reading of spool files with long lines. The old behavior was that the message body was truncated right before the first line longer 4096 chars. The number comes from MAX_DATALINE.
author meillo@marmaro.de
date Wed, 16 Jun 2010 19:06:34 +0200
parents 26e34ae9a3e3
children c93023f58cc7
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/global.h"
31 #include "md5/md5.h"
32 #endif
34 #ifdef ENABLE_POP3
36 /* experimental feature */
37 #define DO_WRITE_UIDL_EARLY 1
39 static gchar*
40 MD5String(char *string)
41 {
42 MD5_CTX context;
43 unsigned char digest[16];
44 char str_digest[33];
45 int i;
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]);
57 return g_strdup(str_digest);
58 }
60 static pop3_base*
61 create_pop3base(gint sock, guint flags)
62 {
63 gint dup_sock;
65 pop3_base *popb = (pop3_base *) g_malloc(sizeof(pop3_base));
66 if (popb) {
67 memset(popb, 0, sizeof(pop3_base));
69 popb->error = pop3_ok;
71 popb->buffer = (gchar *) g_malloc(POP3_BUF_LEN);
73 dup_sock = dup(sock);
74 popb->out = fdopen(sock, "w");
75 popb->in = fdopen(dup_sock, "r");
77 popb->flags = flags;
78 }
79 return popb;
80 }
82 static void
83 pop3_printf(FILE * out, gchar * fmt, ...)
84 {
85 va_list args;
86 va_start(args, fmt);
88 DEBUG(4) {
89 gchar buf[256];
90 va_list args_copy;
92 va_copy(args_copy, args);
93 vsnprintf(buf, 255, fmt, args_copy);
94 va_end(args_copy);
96 debugf(">>>%s", buf);
97 }
99 vfprintf(out, fmt, args);
100 fflush(out);
102 va_end(args);
103 }
105 static gboolean
106 find_uid(pop3_base * popb, gchar * str)
107 {
108 GList *node, *node_next;
110 for (node = popb->list_uid_old; node; node = node_next) {
111 gchar *uid = (gchar *) (node->data);
112 node_next = node->next;
113 if (strcmp(uid, str) == 0) {
114 #if 1
115 popb->list_uid_old = g_list_remove_link(popb->list_uid_old, node);
116 g_list_free_1(node);
117 g_free(uid);
118 #endif
119 return TRUE;
120 }
121 }
122 return FALSE;
123 }
125 static gboolean
126 write_uidl(pop3_base * popb, gchar * user)
127 {
128 gboolean ok = FALSE;
129 GList *node;
130 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host);
131 gchar *tmpname = g_strdup_printf("%s.tmp", filename);
132 FILE *fptr = fopen(tmpname, "wt");
134 if (fptr) {
135 foreach(popb->drop_list, node) {
136 msg_info *info = (msg_info *) (node->data);
137 if (info->is_fetched || info->is_in_uidl)
138 fprintf(fptr, "%s\n", info->uid);
139 }
140 fclose(fptr);
141 ok = (rename(tmpname, filename) != -1);
142 }
144 g_free(tmpname);
145 g_free(filename);
146 return ok;
147 }
149 static gboolean
150 read_uidl_fname(pop3_base * popb, gchar * filename)
151 {
152 gboolean ok = FALSE;
153 FILE *fptr = fopen(filename, "rt");
154 gchar buf[256];
156 if (fptr) {
157 popb->list_uid_old = NULL;
158 while (fgets(buf, 255, fptr)) {
159 if (buf[strlen(buf) - 1] == '\n') {
160 g_strchomp(buf);
161 popb->list_uid_old = g_list_append(popb->list_uid_old, g_strdup(buf));
162 } else {
163 logwrite(LOG_ALERT, "broken uid: %s\n", buf);
164 break;
165 }
166 }
167 fclose(fptr);
168 ok = TRUE;
169 } else
170 logwrite(LOG_ALERT, "opening of %s failed: %s", filename, strerror(errno));
171 return ok;
172 }
174 static gboolean
175 read_uidl(pop3_base * popb, gchar * user)
176 {
177 gboolean ok = FALSE;
178 struct stat statbuf;
179 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host);
181 if (stat(filename, &statbuf) == 0) {
182 ok = read_uidl_fname(popb, filename);
183 if (ok) {
184 GList *drop_node;
185 foreach(popb->drop_list, drop_node) {
186 msg_info *info = (msg_info *) (drop_node->data);
187 if (find_uid(popb, info->uid)) {
188 DEBUG(5) debugf("msg with uid '%s' already known\n", info->uid);
189 info->is_in_uidl = TRUE;
190 popb->uidl_known_cnt++;
191 } else
192 DEBUG(5) debugf("msg with uid '%s' not known\n", info->uid);
193 }
194 }
195 } else {
196 logwrite(LOG_DEBUG, "no uidl file '%s' found\n", filename);
197 ok = TRUE;
198 }
200 g_free(filename);
201 return ok; /* return code is irrelevant, do not check... */
202 }
204 static gboolean
205 read_response(pop3_base * popb, int timeout)
206 {
207 gint len;
209 len = read_sockline(popb->in, popb->buffer, POP3_BUF_LEN, timeout, READSOCKL_CHUG);
211 if (len == -3) {
212 popb->error = pop3_timeout;
213 return FALSE;
214 } else if (len == -2) {
215 popb->error = pop3_syntax;
216 return FALSE;
217 } else if (len == -1) {
218 popb->error = pop3_eof;
219 return FALSE;
220 }
222 return TRUE;
223 }
225 static gboolean
226 check_response(pop3_base * popb)
227 {
228 char c = popb->buffer[0];
230 if (c == '+') {
231 popb->error = pop3_ok;
232 return TRUE;
233 } else if (c == '-')
234 popb->error = pop3_fail;
235 else
236 popb->error = pop3_syntax;
237 return FALSE;
238 }
240 static gboolean
241 strtoi(gchar * p, gchar ** pend, gint * val)
242 {
243 gchar buf[12];
244 gint i = 0;
246 while (*p && isspace(*p))
247 p++;
248 if (*p) {
249 while ((i < 11) && isdigit(*p))
250 buf[i++] = *(p++);
251 buf[i] = 0;
252 *val = atoi(buf);
253 *pend = p;
254 return TRUE;
255 }
256 return FALSE;
257 }
259 static gboolean
260 check_response_int_int(pop3_base * popb, gint * arg0, gint * arg1)
261 {
262 if (check_response(popb)) {
263 gchar *p = &(popb->buffer[3]);
264 gchar *pe;
266 if (strtoi(p, &pe, arg0)) {
267 DEBUG(5) debugf("arg0 = %d\n", *arg0);
268 p = pe;
269 if (strtoi(p, &pe, arg1))
270 DEBUG(5) debugf("arg1 = %d\n", *arg1);
271 return TRUE;
272 }
273 popb->error = pop3_syntax;
274 }
275 return FALSE;
276 }
278 static gboolean
279 get_drop_listing(pop3_base * popb)
280 {
281 gchar buf[64];
283 DEBUG(5) debugf("get_drop_listing() entered\n");
285 while (1) {
286 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
287 if (len > 0) {
288 if (buf[0] == '.')
289 return TRUE;
290 else {
291 gint number, msg_size;
292 gchar *p = buf, *pe;
293 if (strtoi(p, &pe, &number)) {
294 p = pe;
295 if (strtoi(p, &pe, &msg_size)) {
296 msg_info *info = g_malloc(sizeof(msg_info));
297 info->number = number;
298 info->size = msg_size;
300 DEBUG(5) debugf ("get_drop_listing(), number = %d, msg_size = %d\n", number, msg_size);
302 info->uid = NULL;
303 info->is_fetched = FALSE;
304 info->is_in_uidl = FALSE;
305 popb->drop_list = g_list_append(popb->drop_list, info);
306 } else {
307 popb->error = pop3_syntax;
308 break;
309 }
310 } else {
311 popb->error = pop3_syntax;
312 break;
313 }
314 }
315 } else {
316 popb->error = (len == -1) ? pop3_eof : pop3_timeout;
317 return FALSE;
318 }
319 }
320 return FALSE;
321 }
323 static gboolean
324 get_uid_listing(pop3_base * popb)
325 {
326 gchar buf[64];
328 while (1) {
329 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
330 if (len > 0) {
331 if (buf[0] == '.')
332 return TRUE;
333 else {
334 gint number;
335 gchar *p = buf, *pe;
336 if (strtoi(p, &pe, &number)) {
337 msg_info *info = NULL;
338 GList *drop_node;
340 p = pe;
341 while (*p && isspace(*p))
342 p++;
344 foreach(popb->drop_list, drop_node) {
345 msg_info *curr_info = (msg_info *) (drop_node->data);
346 if (curr_info->number == number) {
347 info = curr_info;
348 break;
349 }
350 }
351 if (info) {
352 info->uid = g_strdup(p);
353 g_strchomp(info->uid);
354 }
356 } else {
357 popb->error = pop3_syntax;
358 break;
359 }
360 }
361 }
362 }
363 return FALSE;
364 }
366 static gboolean
367 check_init_response(pop3_base * popb)
368 {
369 if (check_response(popb)) {
370 gchar buf[256];
371 gchar *p = popb->buffer;
372 gint i = 0;
373 if (*p) {
374 while (*p && (*p != '<'))
375 p++;
376 while (*p && (*p != '>') && (i < 254))
377 buf[i++] = *(p++);
378 buf[i++] = '>';
379 buf[i] = '\0';
381 popb->timestamp = g_strdup(buf);
383 return TRUE;
384 }
385 }
386 return FALSE;
387 }
389 void
390 pop3_in_close(pop3_base * popb)
391 {
392 GList *node;
394 fclose(popb->in);
395 fclose(popb->out);
397 close(popb->sock);
399 foreach(popb->list_uid_old, node) {
400 gchar *uid = (gchar *) (node->data);
401 g_free(uid);
402 }
403 g_list_free(popb->list_uid_old);
405 foreach(popb->drop_list, node) {
406 msg_info *info = (msg_info *) (node->data);
407 if (info->uid)
408 g_free(info->uid);
409 g_free(info);
410 }
411 g_list_free(popb->drop_list);
413 if (popb->buffer)
414 g_free(popb->buffer);
415 if (popb->timestamp)
416 g_free(popb->timestamp);
417 }
419 pop3_base*
420 pop3_in_open(gchar * host, gint port, GList * resolve_list, guint flags)
421 {
422 pop3_base *popb;
423 gint sock;
424 mxip_addr *addr;
426 DEBUG(5) debugf("pop3_in_open entered, host = %s\n", host);
428 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
429 /* create structure to hold status data: */
430 popb = create_pop3base(sock, flags);
431 popb->remote_host = addr->name;
433 DEBUG(5) {
434 struct sockaddr_in name;
435 int len;
436 getsockname(sock, (struct sockaddr *) (&name), &len);
437 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
438 }
439 return popb;
440 }
441 return NULL;
442 }
444 pop3_base*
445 pop3_in_open_child(gchar * cmd, guint flags)
446 {
447 pop3_base *popb;
448 gint sock;
450 DEBUG(5) debugf("pop3_in_open_child entered, cmd = %s\n", cmd);
451 sock = child(cmd);
452 if (sock > 0) {
453 popb = create_pop3base(sock, flags);
454 popb->remote_host = NULL;
455 return popb;
456 }
457 logwrite(LOG_ALERT, "child failed (sock = %d): %s\n", sock, strerror(errno));
459 return NULL;
460 }
462 gboolean
463 pop3_in_init(pop3_base * popb)
464 {
465 gboolean ok;
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 }
476 gboolean
477 pop3_in_login(pop3_base * popb, gchar * user, gchar * pass)
478 {
479 if (popb->flags & POP3_FLAG_APOP) {
481 gchar *string = g_strdup_printf("%s%s", popb->timestamp, pass);
482 gchar *digest = MD5String(string);
483 pop3_printf(popb->out, "APOP %s %s\r\n", user, digest);
484 g_free(string);
485 g_free(digest);
486 if (read_response(popb, POP3_CMD_TIMEOUT)) {
487 if (check_response(popb))
488 return TRUE;
489 else
490 popb->error = pop3_login_failure;
491 }
493 } else {
495 pop3_printf(popb->out, "USER %s\r\n", user);
496 if (read_response(popb, POP3_CMD_TIMEOUT)) {
497 if (check_response(popb)) {
498 pop3_printf(popb->out, "PASS %s\r\n", pass);
499 if (read_response(popb, POP3_CMD_TIMEOUT)) {
500 if (check_response(popb))
501 return TRUE;
502 else
503 popb->error = pop3_login_failure;
504 }
505 } else {
506 popb->error = pop3_login_failure;
507 }
508 }
509 }
510 return FALSE;
511 }
513 gboolean
514 pop3_in_stat(pop3_base * popb)
515 {
516 pop3_printf(popb->out, "STAT\r\n");
517 if (read_response(popb, POP3_CMD_TIMEOUT)) {
518 gint msg_cnt, mbox_size;
519 if (check_response_int_int(popb, &msg_cnt, &mbox_size)) {
520 popb->msg_cnt = msg_cnt;
521 popb->mbox_size = mbox_size;
523 return TRUE;
524 }
525 }
526 return FALSE;
527 }
529 gboolean
530 pop3_in_list(pop3_base * popb)
531 {
532 pop3_printf(popb->out, "LIST\r\n");
533 if (read_response(popb, POP3_CMD_TIMEOUT)) {
534 if (get_drop_listing(popb)) {
535 return TRUE;
536 }
537 }
538 return FALSE;
539 }
541 gboolean
542 pop3_in_dele(pop3_base * popb, gint number)
543 {
544 pop3_printf(popb->out, "DELE %d\r\n", number);
545 if (read_response(popb, POP3_CMD_TIMEOUT)) {
546 return TRUE;
547 }
548 return FALSE;
549 }
551 message*
552 pop3_in_retr(pop3_base * popb, gint number, address * rcpt)
553 {
554 accept_error err;
556 pop3_printf(popb->out, "RETR %d\r\n", number);
557 if (read_response(popb, POP3_CMD_TIMEOUT)) {
558 message *msg = create_message();
559 msg->received_host = popb->remote_host;
560 msg->received_prot = (popb->flags & POP3_FLAG_APOP) ? PROT_APOP : PROT_POP3;
561 msg->transfer_id = (popb->next_id)++;
562 msg->rcpt_list = g_list_append(NULL, copy_address(rcpt));
564 if ((err = accept_message(popb->in, msg, ACC_MAIL_FROM_HEAD
565 | (conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0)))
566 == AERR_OK)
567 return msg;
569 destroy_message(msg);
570 }
571 return NULL;
572 }
574 gboolean
575 pop3_in_uidl(pop3_base * popb)
576 {
577 pop3_printf(popb->out, "UIDL\r\n");
578 if (read_response(popb, POP3_CMD_TIMEOUT)) {
579 if (get_uid_listing(popb)) {
580 return TRUE;
581 }
582 }
583 return FALSE;
584 }
586 gboolean
587 pop3_in_quit(pop3_base * popb)
588 {
589 pop3_printf(popb->out, "QUIT\r\n");
590 DEBUG(4) debugf("QUIT\n");
591 signal(SIGALRM, SIG_DFL);
592 return TRUE;
593 }
595 /* Send a DELE command for each message in (the old) uid listing.
596 This is to prevent mail from to be kept on server, if a previous
597 transaction was interupted. */
598 gboolean
599 pop3_in_uidl_dele(pop3_base * popb)
600 {
601 GList *drop_node;
603 foreach(popb->drop_list, drop_node) {
604 msg_info *info = (msg_info *) (drop_node->data);
605 /* if(find_uid(popb, info->uid)){ */
606 if (info->is_in_uidl) {
607 if (!pop3_in_dele(popb, info->number))
608 return FALSE;
609 /* TODO: it probably makes sense to also delete this uid from the listing */
610 }
611 }
612 return TRUE;
613 }
615 gboolean
616 pop3_get(pop3_base * popb, gchar * user, gchar * pass, address * rcpt, address * return_path,
617 gint max_count, gint max_size, gboolean max_size_delete)
618 {
619 gboolean ok = FALSE;
620 gint num_children = 0;
622 DEBUG(5) debugf("rcpt = %s@%s\n", rcpt->local_part, rcpt->domain);
624 signal(SIGCHLD, SIG_DFL);
626 if (pop3_in_init(popb)) {
627 if (pop3_in_login(popb, user, pass)) {
628 if (pop3_in_stat(popb)) {
629 if (popb->msg_cnt > 0) {
631 logwrite(LOG_NOTICE | LOG_VERBOSE, "%d message(s) for user %s at %s\n",
632 popb->msg_cnt, user, popb->remote_host);
634 if (pop3_in_list(popb)) {
635 gboolean do_get = !(popb->flags & POP3_FLAG_UIDL);
636 if (!do_get)
637 do_get = pop3_in_uidl(popb);
638 if (do_get) {
639 gint count = 0;
640 GList *drop_node;
642 if (popb->flags & POP3_FLAG_UIDL) {
643 read_uidl(popb, user);
644 logwrite(LOG_VERBOSE | LOG_NOTICE, "%d message(s) already in uidl.\n", popb->uidl_known_cnt);
645 }
646 if ((popb->flags & POP3_FLAG_UIDL) && (popb->flags & POP3_FLAG_UIDL_DELE))
647 pop3_in_uidl_dele(popb);
649 foreach(popb->drop_list, drop_node) {
651 msg_info *info = (msg_info *) (drop_node->data);
652 gboolean do_get_this = !(popb->flags & POP3_FLAG_UIDL);
653 /* if(!do_get_this) do_get_this = !find_uid(popb, info->uid); */
654 if (!do_get_this)
655 do_get_this = !(info->is_in_uidl);
656 if (do_get_this) {
658 if ((info->size < max_size) || (max_size == 0)) {
659 message *msg;
661 logwrite(LOG_VERBOSE | LOG_NOTICE, "receiving message %d\n", info->number);
662 msg = pop3_in_retr(popb, info->number, rcpt);
664 if (msg) {
665 if (return_path)
666 msg->return_path = copy_address(return_path);
667 if (spool_write(msg, TRUE)) {
668 pid_t pid;
669 logwrite(LOG_NOTICE, "%s <= %s host=%s with %s\n", msg->uid,
670 addr_string(msg->return_path), popb->remote_host,
671 (popb->flags & POP3_FLAG_APOP) ? prot_names [PROT_APOP] : prot_names [PROT_POP3]);
672 info->is_fetched = TRUE;
673 count++;
674 #if DO_WRITE_UIDL_EARLY
675 if (popb->flags & POP3_FLAG_UIDL)
676 write_uidl(popb, user);
677 #endif
678 if (!conf.do_queue) {
680 /* wait for child processes. If there are too many, we wait blocking, before we fork another one */
681 while (num_children > 0) {
682 int status, options = WNOHANG;
683 pid_t pid;
685 if (num_children >= POP3_MAX_CHILDREN) {
686 logwrite(LOG_NOTICE, "too many children - waiting\n");
687 options = 0;
688 }
689 if ((pid = waitpid(0, &status, options)) > 0) {
690 num_children--;
691 if (WEXITSTATUS(status) != EXIT_SUCCESS)
692 logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS (status));
693 if (WIFSIGNALED(status))
694 logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG (status));
695 } else if (pid < 0) {
696 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
697 }
698 }
700 if ((pid = fork()) == 0) {
701 deliver(msg);
702 _exit(EXIT_SUCCESS);
703 } else if (pid < 0) {
704 logwrite(LOG_ALERT | LOG_VERBOSE, "could not fork for delivery, id = %s: %s\n", msg->uid, strerror(errno));
705 } else
706 num_children++;
707 } else {
708 DEBUG(1) debugf("queuing forced by configuration or option.\n");
709 }
710 if (popb->flags & POP3_FLAG_DELETE)
711 pop3_in_dele(popb, info->number);
713 destroy_message(msg);
714 } /* if(spool_write(msg, TRUE)) */
715 } else {
716 logwrite(LOG_ALERT, "retrieving of message %d failed: %d\n", info->number, popb->error);
717 }
718 } /* if((info->size > max_size) ... */
719 else {
720 logwrite(LOG_NOTICE | LOG_VERBOSE, "size of message #%d (%d) > max_size (%d)\n", info->number, info->size, max_size);
721 if (max_size_delete)
722 if (popb->flags & POP3_FLAG_DELETE)
723 pop3_in_dele(popb, info->number);
724 }
725 } /* if(do_get_this) ... */
726 else {
727 if (popb->flags & POP3_FLAG_UIDL) {
728 info->is_fetched = TRUE; /* obsolete? */
729 logwrite(LOG_VERBOSE, "message %d already known\n", info->number);
730 DEBUG(1) debugf("message %d (uid = %s) not fetched\n", info->number, info->uid);
731 #if 0
732 #if DO_WRITE_UIDL_EARLY
733 write_uidl(popb, user); /* obsolete? */
734 #endif
735 #endif
736 }
737 }
738 if ((max_count != 0) && (count >= max_count))
739 break;
740 } /* foreach() */
741 #if DO_WRITE_UIDL_EARLY
742 #else
743 if (popb->flags & POP3_FLAG_UIDL)
744 write_uidl(popb, user);
745 #endif
746 } /* if(pop3_in_uidl(popb) ... */
747 } /* if(pop3_in_list(popb)) */
748 } /* if(popb->msg_cnt > 0) */
749 else {
750 logwrite(LOG_NOTICE | LOG_VERBOSE, "no messages for user %s at %s\n", user, popb->remote_host);
751 }
752 ok = TRUE;
753 }
754 pop3_in_quit(popb);
755 } else {
756 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, popb->remote_host);
757 }
758 }
759 if (!ok) {
760 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 failed, error = %d\n", popb->error);
761 }
763 while (num_children > 0) {
764 int status;
765 pid_t pid;
766 if ((pid = wait(&status)) > 0) {
767 num_children--;
768 if (WEXITSTATUS(status) != EXIT_SUCCESS)
769 logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS(status));
770 if (WIFSIGNALED(status))
771 logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG(status));
772 } else {
773 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
774 }
775 }
777 return ok;
778 }
780 /* function just to log into a pop server,
781 for pop_before_smtp (or is it smtp_after_pop?)
782 */
784 gboolean
785 pop3_login(gchar * host, gint port, GList * resolve_list, gchar * user, gchar * pass, guint flags)
786 {
787 gboolean ok = FALSE;
788 pop3_base *popb;
790 signal(SIGCHLD, SIG_IGN);
792 if ((popb = pop3_in_open(host, port, resolve_list, flags))) {
793 if (pop3_in_init(popb)) {
794 if (pop3_in_login(popb, user, pass))
795 ok = TRUE;
796 else
797 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, host);
798 }
799 pop3_in_close(popb);
800 }
801 return ok;
802 }
804 #endif