meillo@0: /* pop3_in.c, Copyright (C) 2000 by Oliver Kurth, meillo@0: * meillo@0: * This program is free software; you can redistribute it and/or modify meillo@0: * it under the terms of the GNU General Public License as published by meillo@0: * the Free Software Foundation; either version 2 of the License, or meillo@0: * (at your option) any later version. meillo@10: * meillo@0: * This program is distributed in the hope that it will be useful, meillo@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of meillo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the meillo@0: * GNU General Public License for more details. meillo@0: * meillo@0: * You should have received a copy of the GNU General Public License meillo@0: * along with this program; if not, write to the Free Software meillo@0: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. meillo@0: */ meillo@0: meillo@0: /* see RFC 1725 */ meillo@0: meillo@0: #include "masqmail.h" meillo@0: #include "pop3_in.h" meillo@0: #include "readsock.h" meillo@0: meillo@0: #include meillo@0: #include meillo@0: meillo@0: #ifdef USE_LIB_CRYPTO meillo@0: #include meillo@0: #else meillo@0: #include "md5/global.h" meillo@0: #include "md5/md5.h" meillo@0: #endif meillo@0: meillo@0: #ifdef ENABLE_POP3 meillo@0: meillo@0: /* experimental feature */ meillo@0: #define DO_WRITE_UIDL_EARLY 1 meillo@0: meillo@10: static gchar* meillo@10: MD5String(char *string) meillo@0: { meillo@10: MD5_CTX context; meillo@10: unsigned char digest[16]; meillo@10: char str_digest[33]; meillo@10: int i; meillo@0: meillo@0: #ifdef USE_LIB_CRYPTO meillo@10: MD5(string, strlen(string), digest); meillo@0: #else meillo@10: MD5Init(&context); meillo@10: MD5Update(&context, string, strlen(string)); meillo@10: MD5Final(digest, &context); meillo@0: #endif meillo@10: for (i = 0; i < 16; i++) meillo@10: sprintf(str_digest + 2 * i, "%02x", digest[i]); meillo@0: meillo@10: return g_strdup(str_digest); meillo@0: } meillo@0: meillo@10: static pop3_base* meillo@10: create_pop3base(gint sock, guint flags) meillo@0: { meillo@10: gint dup_sock; meillo@0: meillo@10: pop3_base *popb = (pop3_base *) g_malloc(sizeof(pop3_base)); meillo@10: if (popb) { meillo@10: memset(popb, 0, sizeof(pop3_base)); meillo@0: meillo@10: popb->error = pop3_ok; meillo@0: meillo@10: popb->buffer = (gchar *) g_malloc(POP3_BUF_LEN); meillo@0: meillo@10: dup_sock = dup(sock); meillo@10: popb->out = fdopen(sock, "w"); meillo@10: popb->in = fdopen(dup_sock, "r"); meillo@10: meillo@10: popb->flags = flags; meillo@10: } meillo@10: return popb; meillo@0: } meillo@0: meillo@10: static void meillo@10: pop3_printf(FILE * out, gchar * fmt, ...) meillo@0: { meillo@10: va_list args; meillo@10: va_start(args, fmt); meillo@0: meillo@10: DEBUG(4) { meillo@10: gchar buf[256]; meillo@10: va_list args_copy; meillo@0: meillo@10: va_copy(args_copy, args); meillo@10: vsnprintf(buf, 255, fmt, args_copy); meillo@10: va_end(args_copy); meillo@0: meillo@10: debugf(">>>%s", buf); meillo@10: } meillo@0: meillo@10: vfprintf(out, fmt, args); meillo@10: fflush(out); meillo@0: meillo@10: va_end(args); meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: find_uid(pop3_base * popb, gchar * str) meillo@0: { meillo@10: GList *node, *node_next; meillo@0: meillo@10: for (node = popb->list_uid_old; node; node = node_next) { meillo@10: gchar *uid = (gchar *) (node->data); meillo@10: node_next = node->next; meillo@10: if (strcmp(uid, str) == 0) { meillo@0: #if 1 meillo@10: popb->list_uid_old = g_list_remove_link(popb->list_uid_old, node); meillo@10: g_list_free_1(node); meillo@10: g_free(uid); meillo@0: #endif meillo@10: return TRUE; meillo@10: } meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: write_uidl(pop3_base * popb, gchar * user) meillo@0: { meillo@10: gboolean ok = FALSE; meillo@10: GList *node; meillo@10: gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host); meillo@10: gchar *tmpname = g_strdup_printf("%s.tmp", filename); meillo@10: FILE *fptr = fopen(tmpname, "wt"); meillo@0: meillo@10: if (fptr) { meillo@10: foreach(popb->drop_list, node) { meillo@10: msg_info *info = (msg_info *) (node->data); meillo@10: if (info->is_fetched || info->is_in_uidl) meillo@10: fprintf(fptr, "%s\n", info->uid); meillo@10: } meillo@10: fclose(fptr); meillo@10: ok = (rename(tmpname, filename) != -1); meillo@10: } meillo@10: meillo@10: g_free(tmpname); meillo@10: g_free(filename); meillo@10: return ok; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: read_uidl_fname(pop3_base * popb, gchar * filename) meillo@0: { meillo@10: gboolean ok = FALSE; meillo@10: FILE *fptr = fopen(filename, "rt"); meillo@10: gchar buf[256]; meillo@0: meillo@10: if (fptr) { meillo@10: popb->list_uid_old = NULL; meillo@10: while (fgets(buf, 255, fptr)) { meillo@10: if (buf[strlen(buf) - 1] == '\n') { meillo@10: g_strchomp(buf); meillo@10: popb->list_uid_old = g_list_append(popb->list_uid_old, g_strdup(buf)); meillo@10: } else { meillo@10: logwrite(LOG_ALERT, "broken uid: %s\n", buf); meillo@10: break; meillo@10: } meillo@10: } meillo@10: fclose(fptr); meillo@10: ok = TRUE; meillo@10: } else meillo@10: logwrite(LOG_ALERT, "opening of %s failed: %s", filename, strerror(errno)); meillo@10: return ok; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: read_uidl(pop3_base * popb, gchar * user) meillo@0: { meillo@10: gboolean ok = FALSE; meillo@10: struct stat statbuf; meillo@10: gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host); meillo@0: meillo@10: if (stat(filename, &statbuf) == 0) { meillo@10: ok = read_uidl_fname(popb, filename); meillo@10: if (ok) { meillo@10: GList *drop_node; meillo@10: foreach(popb->drop_list, drop_node) { meillo@10: msg_info *info = (msg_info *) (drop_node->data); meillo@10: if (find_uid(popb, info->uid)) { meillo@10: DEBUG(5) debugf("msg with uid '%s' already known\n", info->uid); meillo@10: info->is_in_uidl = TRUE; meillo@10: popb->uidl_known_cnt++; meillo@10: } else meillo@10: DEBUG(5) debugf("msg with uid '%s' not known\n", info->uid); meillo@10: } meillo@10: } meillo@10: } else { meillo@10: logwrite(LOG_DEBUG, "no uidl file '%s' found\n", filename); meillo@10: ok = TRUE; meillo@10: } meillo@0: meillo@10: g_free(filename); meillo@10: return ok; /* return code is irrelevant, do not check... */ meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: read_response(pop3_base * popb, int timeout) meillo@0: { meillo@10: gint len; meillo@0: meillo@10: len = read_sockline(popb->in, popb->buffer, POP3_BUF_LEN, timeout, READSOCKL_CHUG); meillo@0: meillo@10: if (len == -3) { meillo@10: popb->error = pop3_timeout; meillo@10: return FALSE; meillo@10: } else if (len == -2) { meillo@10: popb->error = pop3_syntax; meillo@10: return FALSE; meillo@10: } else if (len == -1) { meillo@10: popb->error = pop3_eof; meillo@10: return FALSE; meillo@10: } meillo@10: meillo@10: return TRUE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: check_response(pop3_base * popb) meillo@0: { meillo@10: char c = popb->buffer[0]; meillo@0: meillo@10: if (c == '+') { meillo@10: popb->error = pop3_ok; meillo@10: return TRUE; meillo@10: } else if (c == '-') meillo@10: popb->error = pop3_fail; meillo@10: else meillo@10: popb->error = pop3_syntax; meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: strtoi(gchar * p, gchar ** pend, gint * val) meillo@0: { meillo@10: gchar buf[12]; meillo@10: gint i = 0; meillo@0: meillo@10: while (*p && isspace(*p)) meillo@10: p++; meillo@10: if (*p) { meillo@10: while ((i < 11) && isdigit(*p)) meillo@10: buf[i++] = *(p++); meillo@10: buf[i] = 0; meillo@10: *val = atoi(buf); meillo@10: *pend = p; meillo@10: return TRUE; meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: check_response_int_int(pop3_base * popb, gint * arg0, gint * arg1) meillo@0: { meillo@10: if (check_response(popb)) { meillo@10: gchar *p = &(popb->buffer[3]); meillo@10: gchar *pe; meillo@0: meillo@10: if (strtoi(p, &pe, arg0)) { meillo@10: DEBUG(5) debugf("arg0 = %d\n", *arg0); meillo@10: p = pe; meillo@10: if (strtoi(p, &pe, arg1)) meillo@10: DEBUG(5) debugf("arg1 = %d\n", *arg1); meillo@10: return TRUE; meillo@10: } meillo@10: popb->error = pop3_syntax; meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: get_drop_listing(pop3_base * popb) meillo@0: { meillo@10: gchar buf[64]; meillo@0: meillo@10: DEBUG(5) debugf("get_drop_listing() entered\n"); meillo@0: meillo@10: while (1) { meillo@10: gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG); meillo@10: if (len > 0) { meillo@10: if (buf[0] == '.') meillo@10: return TRUE; meillo@10: else { meillo@10: gint number, msg_size; meillo@10: gchar *p = buf, *pe; meillo@10: if (strtoi(p, &pe, &number)) { meillo@10: p = pe; meillo@10: if (strtoi(p, &pe, &msg_size)) { meillo@10: msg_info *info = g_malloc(sizeof(msg_info)); meillo@10: info->number = number; meillo@10: info->size = msg_size; meillo@0: meillo@10: DEBUG(5) debugf ("get_drop_listing(), number = %d, msg_size = %d\n", number, msg_size); meillo@0: meillo@10: info->uid = NULL; meillo@10: info->is_fetched = FALSE; meillo@10: info->is_in_uidl = FALSE; meillo@10: popb->drop_list = g_list_append(popb->drop_list, info); meillo@10: } else { meillo@10: popb->error = pop3_syntax; meillo@10: break; meillo@10: } meillo@10: } else { meillo@10: popb->error = pop3_syntax; meillo@10: break; meillo@10: } meillo@10: } meillo@10: } else { meillo@10: popb->error = (len == -1) ? pop3_eof : pop3_timeout; meillo@10: return FALSE; meillo@10: } meillo@0: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: get_uid_listing(pop3_base * popb) meillo@0: { meillo@10: gchar buf[64]; meillo@0: meillo@10: while (1) { meillo@10: gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG); meillo@10: if (len > 0) { meillo@10: if (buf[0] == '.') meillo@10: return TRUE; meillo@10: else { meillo@10: gint number; meillo@10: gchar *p = buf, *pe; meillo@10: if (strtoi(p, &pe, &number)) { meillo@10: msg_info *info = NULL; meillo@10: GList *drop_node; meillo@0: meillo@10: p = pe; meillo@10: while (*p && isspace(*p)) meillo@10: p++; meillo@0: meillo@10: foreach(popb->drop_list, drop_node) { meillo@10: msg_info *curr_info = (msg_info *) (drop_node->data); meillo@10: if (curr_info->number == number) { meillo@10: info = curr_info; meillo@10: break; meillo@10: } meillo@10: } meillo@10: if (info) { meillo@10: info->uid = g_strdup(p); meillo@10: g_strchomp(info->uid); meillo@10: } meillo@0: meillo@10: } else { meillo@10: popb->error = pop3_syntax; meillo@10: break; meillo@10: } meillo@10: } meillo@10: } meillo@0: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: static gboolean meillo@10: check_init_response(pop3_base * popb) meillo@0: { meillo@10: if (check_response(popb)) { meillo@10: gchar buf[256]; meillo@10: gchar *p = popb->buffer; meillo@10: gint i = 0; meillo@10: if (*p) { meillo@10: while (*p && (*p != '<')) meillo@10: p++; meillo@10: while (*p && (*p != '>') && (i < 254)) meillo@10: buf[i++] = *(p++); meillo@10: buf[i++] = '>'; meillo@10: buf[i] = 0; meillo@0: meillo@10: popb->timestamp = g_strdup(buf); meillo@0: meillo@10: return TRUE; meillo@10: } meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: void meillo@10: pop3_in_close(pop3_base * popb) meillo@0: { meillo@10: GList *node; meillo@0: meillo@10: fclose(popb->in); meillo@10: fclose(popb->out); meillo@0: meillo@10: close(popb->sock); meillo@0: meillo@10: foreach(popb->list_uid_old, node) { meillo@10: gchar *uid = (gchar *) (node->data); meillo@10: g_free(uid); meillo@10: } meillo@10: g_list_free(popb->list_uid_old); meillo@0: meillo@10: foreach(popb->drop_list, node) { meillo@10: msg_info *info = (msg_info *) (node->data); meillo@10: if (info->uid) meillo@10: g_free(info->uid); meillo@10: g_free(info); meillo@10: } meillo@10: g_list_free(popb->drop_list); meillo@0: meillo@10: if (popb->buffer) meillo@10: g_free(popb->buffer); meillo@10: if (popb->timestamp) meillo@10: g_free(popb->timestamp); meillo@0: } meillo@0: meillo@10: pop3_base* meillo@10: pop3_in_open(gchar * host, gint port, GList * resolve_list, guint flags) meillo@0: { meillo@10: pop3_base *popb; meillo@10: gint sock; meillo@10: mxip_addr *addr; meillo@0: meillo@10: DEBUG(5) debugf("pop3_in_open entered, host = %s\n", host); meillo@0: meillo@10: if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) { meillo@10: /* create structure to hold status data: */ meillo@10: popb = create_pop3base(sock, flags); meillo@10: popb->remote_host = addr->name; meillo@0: meillo@10: DEBUG(5) { meillo@10: struct sockaddr_in name; meillo@10: int len; meillo@10: getsockname(sock, (struct sockaddr *) (&name), &len); meillo@10: debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr)); meillo@10: } meillo@10: return popb; meillo@10: } meillo@10: return NULL; meillo@0: } meillo@0: meillo@10: pop3_base* meillo@10: pop3_in_open_child(gchar * cmd, guint flags) meillo@0: { meillo@10: pop3_base *popb; meillo@10: gint sock; meillo@0: meillo@10: DEBUG(5) debugf("pop3_in_open_child entered, cmd = %s\n", cmd); meillo@0: meillo@10: sock = child(cmd); meillo@0: meillo@10: if (sock > 0) { meillo@0: meillo@10: popb = create_pop3base(sock, flags); meillo@10: popb->remote_host = NULL; meillo@0: meillo@10: return popb; meillo@10: } meillo@10: logwrite(LOG_ALERT, "child failed (sock = %d): %s\n", sock, strerror(errno)); meillo@0: meillo@10: return NULL; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_init(pop3_base * popb) meillo@0: { meillo@10: gboolean ok; meillo@0: meillo@10: if ((ok = read_response(popb, POP3_INITIAL_TIMEOUT))) { meillo@10: ok = check_init_response(popb); meillo@10: } meillo@10: if (!ok) meillo@10: /* pop3_in_log_failure(popb, NULL); */ meillo@10: logwrite(LOG_ALERT, "pop3 failed\n"); meillo@10: return ok; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_login(pop3_base * popb, gchar * user, gchar * pass) meillo@0: { meillo@10: if (popb->flags & POP3_FLAG_APOP) { meillo@0: meillo@10: gchar *string = g_strdup_printf("%s%s", popb->timestamp, pass); meillo@10: gchar *digest = MD5String(string); meillo@10: pop3_printf(popb->out, "APOP %s %s\r\n", user, digest); meillo@10: g_free(string); meillo@10: g_free(digest); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: if (check_response(popb)) meillo@10: return TRUE; meillo@10: else meillo@10: popb->error = pop3_login_failure; meillo@10: } meillo@0: meillo@10: } else { meillo@0: meillo@10: pop3_printf(popb->out, "USER %s\r\n", user); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: if (check_response(popb)) { meillo@10: pop3_printf(popb->out, "PASS %s\r\n", pass); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: if (check_response(popb)) meillo@10: return TRUE; meillo@10: else meillo@10: popb->error = pop3_login_failure; meillo@10: } meillo@10: } else { meillo@10: popb->error = pop3_login_failure; meillo@10: } meillo@10: } meillo@0: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_stat(pop3_base * popb) meillo@0: { meillo@10: pop3_printf(popb->out, "STAT\r\n"); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: gint msg_cnt, mbox_size; meillo@10: if (check_response_int_int(popb, &msg_cnt, &mbox_size)) { meillo@10: popb->msg_cnt = msg_cnt; meillo@10: popb->mbox_size = mbox_size; meillo@0: meillo@10: return TRUE; meillo@10: } meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_list(pop3_base * popb) meillo@0: { meillo@10: pop3_printf(popb->out, "LIST\r\n"); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: if (get_drop_listing(popb)) { meillo@10: return TRUE; meillo@10: } meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_dele(pop3_base * popb, gint number) meillo@0: { meillo@10: pop3_printf(popb->out, "DELE %d\r\n", number); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: return TRUE; meillo@10: } meillo@10: return FALSE; meillo@0: } meillo@0: meillo@10: message* meillo@10: pop3_in_retr(pop3_base * popb, gint number, address * rcpt) meillo@0: { meillo@10: accept_error err; meillo@0: meillo@10: pop3_printf(popb->out, "RETR %d\r\n", number); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: message *msg = create_message(); meillo@10: msg->received_host = popb->remote_host; meillo@10: msg->received_prot = (popb->flags & POP3_FLAG_APOP) ? PROT_APOP : PROT_POP3; meillo@10: msg->transfer_id = (popb->next_id)++; meillo@10: msg->rcpt_list = g_list_append(NULL, copy_address(rcpt)); meillo@0: meillo@10: if ((err = accept_message(popb->in, msg, ACC_MAIL_FROM_HEAD meillo@10: | (conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0))) meillo@10: == AERR_OK) meillo@10: return msg; meillo@0: meillo@10: destroy_message(msg); meillo@10: } meillo@10: return NULL; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_uidl(pop3_base * popb) meillo@0: { meillo@10: pop3_printf(popb->out, "UIDL\r\n"); meillo@10: if (read_response(popb, POP3_CMD_TIMEOUT)) { meillo@10: if (get_uid_listing(popb)) { meillo@10: return TRUE; meillo@10: } meillo@10: } meillo@10: return FALSE; meillo@10: } meillo@0: meillo@10: gboolean meillo@10: pop3_in_quit(pop3_base * popb) meillo@10: { meillo@10: pop3_printf(popb->out, "QUIT\r\n"); meillo@0: meillo@10: DEBUG(4) debugf("QUIT\n"); meillo@10: meillo@10: signal(SIGALRM, SIG_DFL); meillo@10: meillo@10: return TRUE; meillo@0: } meillo@0: meillo@0: /* Send a DELE command for each message in (the old) uid listing. meillo@0: This is to prevent mail from to be kept on server, if a previous meillo@0: transaction was interupted. */ meillo@10: gboolean meillo@10: pop3_in_uidl_dele(pop3_base * popb) meillo@0: { meillo@10: GList *drop_node; meillo@0: meillo@10: foreach(popb->drop_list, drop_node) { meillo@10: msg_info *info = (msg_info *) (drop_node->data); meillo@10: /* if(find_uid(popb, info->uid)){ */ meillo@10: if (info->is_in_uidl) { meillo@10: if (!pop3_in_dele(popb, info->number)) meillo@10: return FALSE; meillo@10: /* TODO: it probably makes sense to also delete this uid from the listing */ meillo@10: } meillo@10: } meillo@10: return TRUE; meillo@0: } meillo@0: meillo@10: gboolean meillo@10: pop3_get(pop3_base * popb, gchar * user, gchar * pass, address * rcpt, address * return_path, gint max_count, gint max_size, gboolean max_size_delete) meillo@0: { meillo@10: gboolean ok = FALSE; meillo@10: gint num_children = 0; meillo@0: meillo@10: DEBUG(5) debugf("rcpt = %s@%s\n", rcpt->local_part, rcpt->domain); meillo@0: meillo@10: signal(SIGCHLD, SIG_DFL); meillo@0: meillo@10: if (pop3_in_init(popb)) { meillo@10: if (pop3_in_login(popb, user, pass)) { meillo@10: if (pop3_in_stat(popb)) { meillo@10: if (popb->msg_cnt > 0) { meillo@0: meillo@10: logwrite(LOG_NOTICE | LOG_VERBOSE, "%d message(s) for user %s at %s\n", popb->msg_cnt, user, popb->remote_host); meillo@0: meillo@10: if (pop3_in_list(popb)) { meillo@10: gboolean do_get = !(popb->flags & POP3_FLAG_UIDL); meillo@10: if (!do_get) meillo@10: do_get = pop3_in_uidl(popb); meillo@10: if (do_get) { meillo@10: gint count = 0; meillo@10: GList *drop_node; meillo@0: meillo@10: if (popb->flags & POP3_FLAG_UIDL) { meillo@10: read_uidl(popb, user); meillo@10: logwrite(LOG_VERBOSE | LOG_NOTICE, "%d message(s) already in uidl.\n", popb->uidl_known_cnt); meillo@10: } meillo@10: if ((popb->flags & POP3_FLAG_UIDL) && (popb->flags & POP3_FLAG_UIDL_DELE)) meillo@10: pop3_in_uidl_dele(popb); meillo@0: meillo@10: foreach(popb->drop_list, drop_node) { meillo@0: meillo@10: msg_info *info = (msg_info *) (drop_node->data); meillo@10: gboolean do_get_this = !(popb->flags & POP3_FLAG_UIDL); meillo@10: /* if(!do_get_this) do_get_this = !find_uid(popb, info->uid); */ meillo@10: if (!do_get_this) meillo@10: do_get_this = !(info->is_in_uidl); meillo@10: if (do_get_this) { meillo@0: meillo@10: if ((info->size < max_size) || (max_size == 0)) { meillo@10: message *msg; meillo@0: meillo@10: logwrite(LOG_VERBOSE | LOG_NOTICE, "receiving message %d\n", info->number); meillo@10: msg = pop3_in_retr(popb, info->number, rcpt); meillo@10: meillo@10: if (msg) { meillo@10: if (return_path) meillo@10: msg->return_path = copy_address(return_path); meillo@10: if (spool_write(msg, TRUE)) { meillo@10: pid_t pid; meillo@10: logwrite(LOG_NOTICE, "%s <= %s host=%s with %s\n", msg->uid, meillo@10: addr_string(msg->return_path), popb->remote_host, meillo@10: (popb->flags & POP3_FLAG_APOP) ? prot_names [PROT_APOP] : prot_names [PROT_POP3]); meillo@10: info->is_fetched = TRUE; meillo@10: count++; meillo@0: #if DO_WRITE_UIDL_EARLY meillo@10: if (popb->flags & POP3_FLAG_UIDL) meillo@10: write_uidl(popb, user); meillo@0: #endif meillo@10: if (!conf.do_queue) { meillo@0: meillo@10: /* wait for child processes. If there are too many, we wait blocking, before we fork another one */ meillo@10: while (num_children > 0) { meillo@10: int status, options = WNOHANG; meillo@10: pid_t pid; meillo@0: meillo@10: if (num_children >= POP3_MAX_CHILDREN) { meillo@10: logwrite(LOG_NOTICE, "too many children - waiting\n"); meillo@10: options = 0; meillo@10: } meillo@10: if ((pid = waitpid(0, &status, options)) > 0) { meillo@10: num_children--; meillo@10: if (WEXITSTATUS(status) != EXIT_SUCCESS) meillo@10: logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS (status)); meillo@10: if (WIFSIGNALED(status)) meillo@10: logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG (status)); meillo@10: } else if (pid < 0) { meillo@10: logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno)); meillo@10: } meillo@10: } meillo@0: meillo@10: if ((pid = fork()) == 0) { meillo@10: deliver(msg); meillo@10: _exit(EXIT_SUCCESS); meillo@10: } else if (pid < 0) { meillo@10: logwrite(LOG_ALERT | LOG_VERBOSE, "could not fork for delivery, id = %s: %s\n", msg->uid, strerror(errno)); meillo@10: } else meillo@10: num_children++; meillo@10: } else { meillo@10: DEBUG(1) debugf("queuing forced by configuration or option.\n"); meillo@10: } meillo@10: if (popb->flags & POP3_FLAG_DELETE) meillo@10: pop3_in_dele(popb, info->number); meillo@0: meillo@10: destroy_message(msg); meillo@10: } /* if(spool_write(msg, TRUE)) */ meillo@10: } else { meillo@10: logwrite(LOG_ALERT, "retrieving of message %d failed: %d\n", info->number, popb->error); meillo@10: } meillo@10: } /* if((info->size > max_size) ... */ meillo@10: else { meillo@10: logwrite(LOG_NOTICE | LOG_VERBOSE, "size of message #%d (%d) > max_size (%d)\n", info->number, info->size, max_size); meillo@10: if (max_size_delete) meillo@10: if (popb->flags & POP3_FLAG_DELETE) meillo@10: pop3_in_dele(popb, info->number); meillo@10: } meillo@10: } /* if(do_get_this) ... */ meillo@10: else { meillo@10: if (popb->flags & POP3_FLAG_UIDL) { meillo@10: info->is_fetched = TRUE; /* obsolete? */ meillo@10: logwrite(LOG_VERBOSE, "message %d already known\n", info->number); meillo@10: DEBUG(1) debugf("message %d (uid = %s) not fetched\n", info->number, info->uid); meillo@0: #if 0 meillo@0: #if DO_WRITE_UIDL_EARLY meillo@10: write_uidl(popb, user); /* obsolete? */ meillo@0: #endif meillo@0: #endif meillo@10: } meillo@10: } meillo@10: if ((max_count != 0) && (count >= max_count)) meillo@10: break; meillo@10: } /* foreach() */ meillo@0: #if DO_WRITE_UIDL_EARLY meillo@0: #else meillo@10: if (popb->flags & POP3_FLAG_UIDL) meillo@10: write_uidl(popb, user); meillo@0: #endif meillo@10: } /* if(pop3_in_uidl(popb) ... */ meillo@10: } /* if(pop3_in_list(popb)) */ meillo@10: } /* if(popb->msg_cnt > 0) */ meillo@10: else { meillo@10: logwrite(LOG_NOTICE | LOG_VERBOSE, "no messages for user %s at %s\n", user, popb->remote_host); meillo@10: } meillo@10: ok = TRUE; meillo@10: } meillo@10: pop3_in_quit(popb); meillo@10: } else { meillo@10: logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, popb->remote_host); meillo@10: } meillo@0: } meillo@10: if (!ok) { meillo@10: logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 failed, error = %d\n", popb->error); meillo@10: } meillo@0: meillo@10: while (num_children > 0) { meillo@10: int status; meillo@10: pid_t pid; meillo@10: if ((pid = wait(&status)) > 0) { meillo@10: num_children--; meillo@10: if (WEXITSTATUS(status) != EXIT_SUCCESS) meillo@10: logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS(status)); meillo@10: if (WIFSIGNALED(status)) meillo@10: logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG(status)); meillo@10: } else { meillo@10: logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno)); meillo@10: } meillo@10: } meillo@0: meillo@10: return ok; meillo@0: } meillo@0: meillo@0: /* function just to log into a pop server, meillo@0: for pop_before_smtp (or is it smtp_after_pop?) meillo@0: */ meillo@0: meillo@10: gboolean meillo@10: pop3_login(gchar * host, gint port, GList * resolve_list, gchar * user, gchar * pass, guint flags) meillo@0: { meillo@10: gboolean ok = FALSE; meillo@10: pop3_base *popb; meillo@0: meillo@10: signal(SIGCHLD, SIG_IGN); meillo@0: meillo@10: if ((popb = pop3_in_open(host, port, resolve_list, flags))) { meillo@10: if (pop3_in_init(popb)) { meillo@10: if (pop3_in_login(popb, user, pass)) meillo@10: ok = TRUE; meillo@10: else meillo@10: logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, host); meillo@10: } meillo@10: pop3_in_close(popb); meillo@10: } meillo@10: return ok; meillo@0: } meillo@0: meillo@0: #endif