masqmail-0.2
diff src/pop3_in.c @ 0:08114f7dcc23
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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/pop3_in.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,820 @@ 1.4 +/* pop3_in.c, Copyright (C) 2000 by Oliver Kurth, 1.5 + * 1.6 + * This program is free software; you can redistribute it and/or modify 1.7 + * it under the terms of the GNU General Public License as published by 1.8 + * the Free Software Foundation; either version 2 of the License, or 1.9 + * (at your option) any later version. 1.10 + * 1.11 + * This program is distributed in the hope that it will be useful, 1.12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.14 + * GNU General Public License for more details. 1.15 + * 1.16 + * You should have received a copy of the GNU General Public License 1.17 + * along with this program; if not, write to the Free Software 1.18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1.19 + */ 1.20 + 1.21 +/* see RFC 1725 */ 1.22 + 1.23 +#include "masqmail.h" 1.24 +#include "pop3_in.h" 1.25 +#include "readsock.h" 1.26 + 1.27 +#include <sys/wait.h> 1.28 +#include <sys/stat.h> 1.29 + 1.30 +#ifdef USE_LIB_CRYPTO 1.31 +#include <openssl/md5.h> 1.32 +#else 1.33 +#include "md5/global.h" 1.34 +#include "md5/md5.h" 1.35 +#endif 1.36 + 1.37 +#ifdef ENABLE_POP3 1.38 + 1.39 +/* experimental feature */ 1.40 +#define DO_WRITE_UIDL_EARLY 1 1.41 + 1.42 +static 1.43 +gchar *MD5String (char *string) 1.44 +{ 1.45 + MD5_CTX context; 1.46 + unsigned char digest[16]; 1.47 + char str_digest[33]; 1.48 + int i; 1.49 + 1.50 +#ifdef USE_LIB_CRYPTO 1.51 + MD5(string, strlen(string), digest); 1.52 +#else 1.53 + MD5Init(&context); 1.54 + MD5Update(&context, string, strlen(string)); 1.55 + MD5Final(digest, &context); 1.56 +#endif 1.57 + for (i = 0; i < 16; i++) 1.58 + sprintf(str_digest+2*i, "%02x", digest[i]); 1.59 + 1.60 + return g_strdup(str_digest); 1.61 +} 1.62 + 1.63 +static 1.64 +pop3_base *create_pop3base(gint sock, guint flags) 1.65 +{ 1.66 + gint dup_sock; 1.67 + 1.68 + pop3_base *popb = (pop3_base *)g_malloc(sizeof(pop3_base)); 1.69 + if(popb){ 1.70 + memset(popb, 0, sizeof(pop3_base)); 1.71 + 1.72 + popb->error = pop3_ok; 1.73 + 1.74 + popb->buffer = (gchar *)g_malloc(POP3_BUF_LEN); 1.75 + 1.76 + dup_sock = dup(sock); 1.77 + popb->out = fdopen(sock, "w"); 1.78 + popb->in = fdopen(dup_sock, "r"); 1.79 + 1.80 + popb->flags = flags; 1.81 + } 1.82 + return popb; 1.83 +} 1.84 + 1.85 +static 1.86 +void pop3_printf(FILE *out, gchar *fmt, ...) 1.87 +{ 1.88 + va_list args; 1.89 + va_start(args, fmt); 1.90 + 1.91 + DEBUG(4){ 1.92 + gchar buf[256]; 1.93 + va_list args_copy; 1.94 + 1.95 + va_copy(args_copy, args); 1.96 + vsnprintf(buf, 255, fmt, args_copy); 1.97 + va_end(args_copy); 1.98 + 1.99 + debugf(">>>%s", buf); 1.100 + } 1.101 + 1.102 + vfprintf(out, fmt, args); fflush(out); 1.103 + 1.104 + va_end(args); 1.105 +} 1.106 + 1.107 +static 1.108 +gboolean find_uid(pop3_base *popb, gchar *str) 1.109 +{ 1.110 + GList *node, *node_next; 1.111 + 1.112 + for(node = popb->list_uid_old; node; node=node_next){ 1.113 + gchar *uid = (gchar *)(node->data); 1.114 + node_next = node->next; 1.115 + if(strcmp(uid, str) == 0){ 1.116 +#if 1 1.117 + popb->list_uid_old = g_list_remove_link(popb->list_uid_old, node); 1.118 + g_list_free_1(node); 1.119 + g_free(uid); 1.120 +#endif 1.121 + return TRUE; 1.122 + } 1.123 + } 1.124 + return FALSE; 1.125 +} 1.126 + 1.127 +static 1.128 +gboolean write_uidl(pop3_base *popb, gchar *user) 1.129 +{ 1.130 + gboolean ok = FALSE; 1.131 + GList *node; 1.132 + gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", 1.133 + conf.spool_dir, 1.134 + user, popb->remote_host); 1.135 + gchar *tmpname = g_strdup_printf("%s.tmp", filename); 1.136 + FILE *fptr = fopen(tmpname, "wt"); 1.137 + 1.138 + if(fptr){ 1.139 + foreach(popb->drop_list, node){ 1.140 + msg_info *info = (msg_info *)(node->data); 1.141 + if(info->is_fetched || info->is_in_uidl) 1.142 + fprintf(fptr, "%s\n", info->uid); 1.143 + } 1.144 + fclose(fptr); 1.145 + ok = (rename(tmpname, filename) != -1); 1.146 + } 1.147 + 1.148 + g_free(tmpname); 1.149 + g_free(filename); 1.150 + return ok; 1.151 +} 1.152 + 1.153 +static 1.154 +gboolean read_uidl_fname(pop3_base *popb, gchar *filename) 1.155 +{ 1.156 + gboolean ok = FALSE; 1.157 + FILE *fptr = fopen(filename, "rt"); 1.158 + gchar buf[256]; 1.159 + 1.160 + if(fptr){ 1.161 + popb->list_uid_old = NULL; 1.162 + while(fgets(buf, 255, fptr)){ 1.163 + if(buf[strlen(buf)-1] == '\n'){ 1.164 + g_strchomp(buf); 1.165 + popb->list_uid_old = 1.166 + g_list_append(popb->list_uid_old, g_strdup(buf)); 1.167 + }else{ 1.168 + logwrite(LOG_ALERT, "broken uid: %s\n", buf); 1.169 + break; 1.170 + } 1.171 + } 1.172 + fclose(fptr); 1.173 + ok = TRUE; 1.174 + }else 1.175 + logwrite(LOG_ALERT, "opening of %s failed: %s", filename, strerror(errno)); 1.176 + return ok; 1.177 +} 1.178 + 1.179 +static 1.180 +gboolean read_uidl(pop3_base *popb, gchar *user) 1.181 +{ 1.182 + gboolean ok = FALSE; 1.183 + struct stat statbuf; 1.184 + gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", 1.185 + conf.spool_dir, 1.186 + user, popb->remote_host); 1.187 + 1.188 + if(stat(filename, &statbuf) == 0){ 1.189 + ok = read_uidl_fname(popb, filename); 1.190 + if(ok){ 1.191 + GList *drop_node; 1.192 + foreach(popb->drop_list, drop_node){ 1.193 + msg_info *info = (msg_info *)(drop_node->data); 1.194 + if(find_uid(popb, info->uid)){ 1.195 + DEBUG(5) debugf("msg with uid '%s' already known\n", info->uid); 1.196 + info->is_in_uidl = TRUE; 1.197 + popb->uidl_known_cnt++; 1.198 + }else 1.199 + DEBUG(5) debugf("msg with uid '%s' not known\n", info->uid); 1.200 + } 1.201 + } 1.202 + }else{ 1.203 + logwrite(LOG_DEBUG, "no uidl file '%s' found\n", filename); 1.204 + ok = TRUE; 1.205 + } 1.206 + 1.207 + g_free(filename); 1.208 + return ok; /* return code is irrelevant, do not check... */ 1.209 +} 1.210 + 1.211 +static 1.212 +gboolean read_response(pop3_base *popb, int timeout) 1.213 +{ 1.214 + gint len; 1.215 + 1.216 + len = read_sockline(popb->in, popb->buffer, POP3_BUF_LEN, timeout, READSOCKL_CHUG); 1.217 + 1.218 + if(len == -3){ 1.219 + popb->error = pop3_timeout; 1.220 + return FALSE; 1.221 + } 1.222 + else if(len == -2){ 1.223 + popb->error = pop3_syntax; 1.224 + return FALSE; 1.225 + } 1.226 + else if(len == -1){ 1.227 + popb->error = pop3_eof; 1.228 + return FALSE; 1.229 + } 1.230 + 1.231 + return TRUE; 1.232 +} 1.233 + 1.234 +static 1.235 +gboolean check_response(pop3_base *popb) 1.236 +{ 1.237 + char c = popb->buffer[0]; 1.238 + 1.239 + if(c == '+'){ 1.240 + popb->error = pop3_ok; 1.241 + return TRUE; 1.242 + }else if(c == '-') 1.243 + popb->error = pop3_fail; 1.244 + else 1.245 + popb->error = pop3_syntax; 1.246 + return FALSE; 1.247 +} 1.248 + 1.249 +static 1.250 +gboolean strtoi(gchar *p, gchar **pend, gint *val) 1.251 +{ 1.252 + gchar buf[12]; 1.253 + gint i = 0; 1.254 + 1.255 + while(*p && isspace(*p)) p++; 1.256 + if(*p){ 1.257 + while((i < 11) && isdigit(*p)) 1.258 + buf[i++] = *(p++); 1.259 + buf[i] = 0; 1.260 + *val = atoi(buf); 1.261 + *pend = p; 1.262 + return TRUE; 1.263 + } 1.264 + return FALSE; 1.265 +} 1.266 + 1.267 +static 1.268 +gboolean check_response_int_int(pop3_base *popb, gint *arg0, gint *arg1) 1.269 +{ 1.270 + if(check_response(popb)){ 1.271 + gchar *p = &(popb->buffer[3]); 1.272 + gchar *pe; 1.273 + 1.274 + if(strtoi(p, &pe, arg0)){ 1.275 + DEBUG(5) debugf("arg0 = %d\n", *arg0); 1.276 + p = pe; 1.277 + if(strtoi(p, &pe, arg1)) 1.278 + DEBUG(5) debugf("arg1 = %d\n", *arg1); 1.279 + return TRUE; 1.280 + } 1.281 + popb->error = pop3_syntax; 1.282 + } 1.283 + return FALSE; 1.284 +} 1.285 + 1.286 +static 1.287 +gboolean get_drop_listing(pop3_base *popb) 1.288 +{ 1.289 + gchar buf[64]; 1.290 + 1.291 + DEBUG(5) debugf("get_drop_listing() entered\n"); 1.292 + 1.293 + while(1){ 1.294 + gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG); 1.295 + if(len > 0){ 1.296 + if(buf[0] == '.') 1.297 + return TRUE; 1.298 + else{ 1.299 + gint number, msg_size; 1.300 + gchar *p = buf, *pe; 1.301 + if(strtoi(p, &pe, &number)){ 1.302 + p = pe; 1.303 + if(strtoi(p, &pe, &msg_size)){ 1.304 + msg_info *info = g_malloc(sizeof(msg_info)); 1.305 + info->number = number; 1.306 + info->size = msg_size; 1.307 + 1.308 + DEBUG(5) debugf("get_drop_listing(), number = %d, msg_size = %d\n", number, msg_size); 1.309 + 1.310 + info->uid = NULL; 1.311 + info->is_fetched = FALSE; 1.312 + info->is_in_uidl = FALSE; 1.313 + popb->drop_list = g_list_append(popb->drop_list, info); 1.314 + }else{ 1.315 + popb->error = pop3_syntax; 1.316 + break; 1.317 + } 1.318 + }else{ 1.319 + popb->error = pop3_syntax; 1.320 + break; 1.321 + } 1.322 + } 1.323 + }else{ 1.324 + popb->error = (len == -1) ? pop3_eof : pop3_timeout; 1.325 + return FALSE; 1.326 + } 1.327 + } 1.328 + return FALSE; 1.329 +} 1.330 + 1.331 +static 1.332 +gboolean get_uid_listing(pop3_base *popb) 1.333 +{ 1.334 + gchar buf[64]; 1.335 + 1.336 + while(1){ 1.337 + gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG); 1.338 + if(len > 0){ 1.339 + if(buf[0] == '.') 1.340 + return TRUE; 1.341 + else{ 1.342 + gint number; 1.343 + gchar *p = buf, *pe; 1.344 + if(strtoi(p, &pe, &number)){ 1.345 + msg_info *info = NULL; 1.346 + GList *drop_node; 1.347 + 1.348 + p = pe; 1.349 + while(*p && isspace(*p)) p++; 1.350 + 1.351 + foreach(popb->drop_list, drop_node){ 1.352 + msg_info *curr_info = (msg_info *)(drop_node->data); 1.353 + if(curr_info->number == number){ 1.354 + info = curr_info; 1.355 + break; 1.356 + } 1.357 + } 1.358 + if(info){ 1.359 + info->uid = g_strdup(p); 1.360 + g_strchomp(info->uid); 1.361 + } 1.362 + 1.363 + }else{ 1.364 + popb->error = pop3_syntax; 1.365 + break; 1.366 + } 1.367 + } 1.368 + } 1.369 + } 1.370 + return FALSE; 1.371 +} 1.372 + 1.373 +static 1.374 +gboolean check_init_response(pop3_base *popb) 1.375 +{ 1.376 + if(check_response(popb)){ 1.377 + gchar buf[256]; 1.378 + gchar *p = popb->buffer; 1.379 + gint i = 0; 1.380 + if(*p){ 1.381 + while(*p && (*p != '<')) p++; 1.382 + while(*p && (*p != '>') && (i < 254)) 1.383 + buf[i++] = *(p++); 1.384 + buf[i++] = '>'; 1.385 + buf[i] = 0; 1.386 + 1.387 + popb->timestamp = g_strdup(buf); 1.388 + 1.389 + return TRUE; 1.390 + } 1.391 + } 1.392 + return FALSE; 1.393 +} 1.394 + 1.395 +void pop3_in_close(pop3_base *popb) 1.396 +{ 1.397 + GList *node; 1.398 + 1.399 + fclose(popb->in); 1.400 + fclose(popb->out); 1.401 + 1.402 + close(popb->sock); 1.403 + 1.404 + foreach(popb->list_uid_old, node){ 1.405 + gchar *uid = (gchar *)(node->data); 1.406 + g_free(uid); 1.407 + } 1.408 + g_list_free(popb->list_uid_old); 1.409 + 1.410 + foreach(popb->drop_list, node){ 1.411 + msg_info *info = (msg_info *)(node->data); 1.412 + if(info->uid) g_free(info->uid); 1.413 + g_free(info); 1.414 + } 1.415 + g_list_free(popb->drop_list); 1.416 + 1.417 + if(popb->buffer) g_free(popb->buffer); 1.418 + if(popb->timestamp) g_free(popb->timestamp); 1.419 +} 1.420 + 1.421 +pop3_base *pop3_in_open(gchar *host, gint port, GList *resolve_list, guint flags) 1.422 +{ 1.423 + pop3_base *popb; 1.424 + gint sock; 1.425 + mxip_addr *addr; 1.426 + 1.427 + DEBUG(5) debugf("pop3_in_open entered, host = %s\n", host); 1.428 + 1.429 + if((addr = connect_resolvelist(&sock, host, port, resolve_list))){ 1.430 + /* create structure to hold status data: */ 1.431 + popb = create_pop3base(sock, flags); 1.432 + popb->remote_host = addr->name; 1.433 + 1.434 + DEBUG(5){ 1.435 + struct sockaddr_in name; 1.436 + int len; 1.437 + getsockname(sock, (struct sockaddr *)(&name), &len); 1.438 + debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr)); 1.439 + } 1.440 + return popb; 1.441 + } 1.442 + return NULL; 1.443 +} 1.444 + 1.445 +pop3_base *pop3_in_open_child(gchar *cmd, guint flags) 1.446 +{ 1.447 + pop3_base *popb; 1.448 + gint sock; 1.449 + 1.450 + DEBUG(5) debugf("pop3_in_open_child entered, cmd = %s\n", cmd); 1.451 + 1.452 + sock = child(cmd); 1.453 + 1.454 + if(sock > 0){ 1.455 + 1.456 + popb = create_pop3base(sock, flags); 1.457 + popb->remote_host = NULL; 1.458 + 1.459 + return popb; 1.460 + } 1.461 + logwrite(LOG_ALERT, "child failed (sock = %d): %s\n", sock, strerror(errno)); 1.462 + 1.463 + return NULL; 1.464 +} 1.465 + 1.466 +gboolean pop3_in_init(pop3_base *popb) 1.467 +{ 1.468 + gboolean ok; 1.469 + 1.470 + if((ok = read_response(popb, POP3_INITIAL_TIMEOUT))){ 1.471 + ok = check_init_response(popb); 1.472 + } 1.473 + if(!ok) 1.474 + /* pop3_in_log_failure(popb, NULL);*/ 1.475 + logwrite(LOG_ALERT, "pop3 failed\n"); 1.476 + return ok; 1.477 +} 1.478 + 1.479 +gboolean pop3_in_login(pop3_base *popb, gchar *user, gchar *pass) 1.480 +{ 1.481 + if(popb->flags & POP3_FLAG_APOP){ 1.482 + 1.483 + gchar *string = g_strdup_printf("%s%s", popb->timestamp, pass); 1.484 + gchar *digest = MD5String(string); 1.485 + pop3_printf(popb->out, "APOP %s %s\r\n", user, digest); 1.486 + g_free(string); 1.487 + g_free(digest); 1.488 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.489 + if(check_response(popb)) 1.490 + return TRUE; 1.491 + else 1.492 + popb->error = pop3_login_failure; 1.493 + } 1.494 + 1.495 + }else{ 1.496 + 1.497 + pop3_printf(popb->out, "USER %s\r\n", user); 1.498 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.499 + if(check_response(popb)){ 1.500 + pop3_printf(popb->out, "PASS %s\r\n", pass); 1.501 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.502 + if(check_response(popb)) 1.503 + return TRUE; 1.504 + else 1.505 + popb->error = pop3_login_failure; 1.506 + } 1.507 + }else{ 1.508 + popb->error = pop3_login_failure; 1.509 + } 1.510 + } 1.511 + } 1.512 + return FALSE; 1.513 +} 1.514 + 1.515 +gboolean pop3_in_stat(pop3_base *popb) 1.516 +{ 1.517 + pop3_printf(popb->out, "STAT\r\n"); 1.518 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.519 + gint msg_cnt, mbox_size; 1.520 + if(check_response_int_int(popb, &msg_cnt, &mbox_size)){ 1.521 + popb->msg_cnt = msg_cnt; 1.522 + popb->mbox_size = mbox_size; 1.523 + 1.524 + return TRUE; 1.525 + } 1.526 + } 1.527 + return FALSE; 1.528 +} 1.529 + 1.530 +gboolean pop3_in_list(pop3_base *popb) 1.531 +{ 1.532 + pop3_printf(popb->out, "LIST\r\n"); 1.533 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.534 + if(get_drop_listing(popb)){ 1.535 + return TRUE; 1.536 + } 1.537 + } 1.538 + return FALSE; 1.539 +} 1.540 + 1.541 +gboolean pop3_in_dele(pop3_base *popb, gint number) 1.542 +{ 1.543 + pop3_printf(popb->out, "DELE %d\r\n", number); 1.544 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.545 + return TRUE; 1.546 + } 1.547 + return FALSE; 1.548 +} 1.549 + 1.550 +message *pop3_in_retr(pop3_base *popb, gint number, address *rcpt) 1.551 +{ 1.552 + accept_error err; 1.553 + 1.554 + pop3_printf(popb->out, "RETR %d\r\n", number); 1.555 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.556 + message *msg = create_message(); 1.557 + msg->received_host = popb->remote_host; 1.558 + msg->received_prot = (popb->flags & POP3_FLAG_APOP) ? PROT_APOP : PROT_POP3; 1.559 + msg->transfer_id = (popb->next_id)++; 1.560 + msg->rcpt_list = g_list_append(NULL, copy_address(rcpt)); 1.561 + 1.562 + if((err = accept_message(popb->in, msg, 1.563 + ACC_MAIL_FROM_HEAD|(conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0))) 1.564 + == AERR_OK) 1.565 + return msg; 1.566 + 1.567 + destroy_message(msg); 1.568 + } 1.569 + return NULL; 1.570 +} 1.571 + 1.572 +gboolean pop3_in_uidl(pop3_base *popb) 1.573 +{ 1.574 + pop3_printf(popb->out, "UIDL\r\n"); 1.575 + if(read_response(popb, POP3_CMD_TIMEOUT)){ 1.576 + if(get_uid_listing(popb)){ 1.577 + return TRUE; 1.578 + } 1.579 + } 1.580 + return FALSE; 1.581 +} 1.582 + 1.583 +gboolean pop3_in_quit(pop3_base *popb) 1.584 +{ 1.585 + pop3_printf(popb->out, "QUIT\r\n"); 1.586 + 1.587 + DEBUG(4) debugf("QUIT\n"); 1.588 + 1.589 + signal(SIGALRM, SIG_DFL); 1.590 + 1.591 + return TRUE; 1.592 +} 1.593 + 1.594 +/* Send a DELE command for each message in (the old) uid listing. 1.595 + This is to prevent mail from to be kept on server, if a previous 1.596 + transaction was interupted. */ 1.597 +gboolean pop3_in_uidl_dele(pop3_base *popb) 1.598 +{ 1.599 + GList *drop_node; 1.600 + 1.601 + foreach(popb->drop_list, drop_node){ 1.602 + msg_info *info = (msg_info *)(drop_node->data); 1.603 + /* if(find_uid(popb, info->uid)){*/ 1.604 + if(info->is_in_uidl){ 1.605 + if(!pop3_in_dele(popb, info->number)) 1.606 + return FALSE; 1.607 + /* TODO: it probably makes sense to also 1.608 + delete this uid from the listing */ 1.609 + } 1.610 + } 1.611 + return TRUE; 1.612 +} 1.613 + 1.614 +gboolean pop3_get(pop3_base *popb, 1.615 + gchar *user, gchar *pass, address *rcpt, address *return_path, 1.616 + gint max_count, gint max_size, gboolean max_size_delete) 1.617 +{ 1.618 + gboolean ok = FALSE; 1.619 + gint num_children = 0; 1.620 + 1.621 + DEBUG(5) debugf("rcpt = %s@%s\n", rcpt->local_part, rcpt->domain); 1.622 + 1.623 + signal(SIGCHLD, SIG_DFL); 1.624 + 1.625 + if(pop3_in_init(popb)){ 1.626 + if(pop3_in_login(popb, user, pass)){ 1.627 + if(pop3_in_stat(popb)){ 1.628 + if(popb->msg_cnt > 0){ 1.629 + 1.630 + logwrite(LOG_NOTICE|LOG_VERBOSE, "%d message(s) for user %s at %s\n", 1.631 + popb->msg_cnt, user, popb->remote_host); 1.632 + 1.633 + if(pop3_in_list(popb)){ 1.634 + gboolean do_get = !(popb->flags & POP3_FLAG_UIDL); 1.635 + if(!do_get) do_get = pop3_in_uidl(popb); 1.636 + if(do_get){ 1.637 + gint count = 0; 1.638 + GList *drop_node; 1.639 + 1.640 + if(popb->flags & POP3_FLAG_UIDL){ 1.641 + read_uidl(popb, user); 1.642 + logwrite(LOG_VERBOSE|LOG_NOTICE, "%d message(s) already in uidl.\n", 1.643 + popb->uidl_known_cnt); 1.644 + } 1.645 + if((popb->flags & POP3_FLAG_UIDL) && (popb->flags & POP3_FLAG_UIDL_DELE)) 1.646 + pop3_in_uidl_dele(popb); 1.647 + 1.648 + foreach(popb->drop_list, drop_node){ 1.649 + 1.650 + msg_info *info = (msg_info *)(drop_node->data); 1.651 + gboolean do_get_this = !(popb->flags & POP3_FLAG_UIDL); 1.652 + /* if(!do_get_this) do_get_this = !find_uid(popb, info->uid);*/ 1.653 + if(!do_get_this) do_get_this = !(info->is_in_uidl); 1.654 + if(do_get_this){ 1.655 + 1.656 + if((info->size < max_size) || (max_size == 0)){ 1.657 + message *msg; 1.658 + 1.659 + logwrite(LOG_VERBOSE|LOG_NOTICE, "receiving message %d\n", info->number); 1.660 + msg = pop3_in_retr(popb, info->number, rcpt); 1.661 + 1.662 + if(msg){ 1.663 + if(return_path) 1.664 + msg->return_path = copy_address(return_path); 1.665 + if(spool_write(msg, TRUE)){ 1.666 + pid_t pid; 1.667 + logwrite(LOG_NOTICE, "%s <= %s host=%s with %s\n", 1.668 + msg->uid, 1.669 + addr_string(msg->return_path), 1.670 + popb->remote_host, 1.671 + (popb->flags & POP3_FLAG_APOP) ? 1.672 + prot_names[PROT_APOP] : prot_names[PROT_POP3] 1.673 + ); 1.674 + info->is_fetched = TRUE; 1.675 + count++; 1.676 +#if DO_WRITE_UIDL_EARLY 1.677 + if(popb->flags & POP3_FLAG_UIDL) write_uidl(popb, user); 1.678 +#endif 1.679 + if(!conf.do_queue){ 1.680 + 1.681 + /* wait for child processes. If there are too many, 1.682 + we wait blocking, before we fork another one */ 1.683 + while(num_children > 0){ 1.684 + int status, options = WNOHANG; 1.685 + pid_t pid; 1.686 + 1.687 + if(num_children >= POP3_MAX_CHILDREN){ 1.688 + logwrite(LOG_NOTICE, "too many children - waiting\n"); 1.689 + options = 0; 1.690 + } 1.691 + if((pid = waitpid(0, &status, options)) > 0){ 1.692 + num_children--; 1.693 + if(WEXITSTATUS(status) != EXIT_SUCCESS) 1.694 + logwrite(LOG_WARNING, 1.695 + "delivery process with pid %d returned %d\n", 1.696 + pid, WEXITSTATUS(status)); 1.697 + if(WIFSIGNALED(status)) 1.698 + logwrite(LOG_WARNING, 1.699 + "delivery process with pid %d got signal: %d\n", 1.700 + pid, WTERMSIG(status)); 1.701 + }else if(pid < 0){ 1.702 + logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno)); 1.703 + } 1.704 + } 1.705 + 1.706 + if((pid = fork()) == 0){ 1.707 + deliver(msg); 1.708 + _exit(EXIT_SUCCESS); 1.709 + }else if(pid < 0){ 1.710 + logwrite(LOG_ALERT|LOG_VERBOSE, 1.711 + "could not fork for delivery, id = %s: %s\n", 1.712 + msg->uid, strerror(errno)); 1.713 + }else 1.714 + num_children++; 1.715 + }else{ 1.716 + DEBUG(1) debugf("queuing forced by configuration or option.\n"); 1.717 + } 1.718 + if(popb->flags & POP3_FLAG_DELETE) 1.719 + pop3_in_dele(popb, info->number); 1.720 + 1.721 + destroy_message(msg); 1.722 + }/* if(spool_write(msg, TRUE)) */ 1.723 + }else{ 1.724 + logwrite(LOG_ALERT, 1.725 + "retrieving of message %d failed: %d\n", 1.726 + info->number, popb->error); 1.727 + } 1.728 + }/* if((info->size > max_size) ... */ 1.729 + else{ 1.730 + logwrite(LOG_NOTICE|LOG_VERBOSE, "size of message #%d (%d) > max_size (%d)\n", 1.731 + info->number, info->size, max_size); 1.732 + if(max_size_delete) 1.733 + if(popb->flags & POP3_FLAG_DELETE) 1.734 + pop3_in_dele(popb, info->number); 1.735 + } 1.736 + }/* if(do_get_this) ... */ 1.737 + else{ 1.738 + if(popb->flags & POP3_FLAG_UIDL){ 1.739 + info->is_fetched = TRUE; /* obsolete? */ 1.740 + logwrite(LOG_VERBOSE, "message %d already known\n", 1.741 + info->number); 1.742 + DEBUG(1) debugf("message %d (uid = %s) not fetched\n", 1.743 + info->number, info->uid); 1.744 +#if 0 1.745 +#if DO_WRITE_UIDL_EARLY 1.746 + write_uidl(popb, user); /* obsolete? */ 1.747 +#endif 1.748 +#endif 1.749 + } 1.750 + } 1.751 + if((max_count != 0) && (count >= max_count)) 1.752 + break; 1.753 + }/* foreach() */ 1.754 +#if DO_WRITE_UIDL_EARLY 1.755 +#else 1.756 + if(popb->flags & POP3_FLAG_UIDL) write_uidl(popb, user); 1.757 +#endif 1.758 + }/* if(pop3_in_uidl(popb) ... */ 1.759 + }/* if(pop3_in_list(popb)) */ 1.760 + }/* if(popb->msg_cnt > 0) */ 1.761 + else{ 1.762 + logwrite(LOG_NOTICE|LOG_VERBOSE, 1.763 + "no messages for user %s at %s\n", user, popb->remote_host); 1.764 + } 1.765 + ok = TRUE; 1.766 + } 1.767 + pop3_in_quit(popb); 1.768 + }else{ 1.769 + logwrite(LOG_ALERT|LOG_VERBOSE, 1.770 + "pop3 login failed for user %s, host = %s\n", user, popb->remote_host); 1.771 + } 1.772 + } 1.773 + if(!ok){ 1.774 + logwrite(LOG_ALERT|LOG_VERBOSE, "pop3 failed, error = %d\n", popb->error); 1.775 + } 1.776 + 1.777 + while(num_children > 0){ 1.778 + int status; 1.779 + pid_t pid; 1.780 + if((pid = wait(&status)) > 0){ 1.781 + num_children--; 1.782 + if(WEXITSTATUS(status) != EXIT_SUCCESS) 1.783 + logwrite(LOG_WARNING, 1.784 + "delivery process with pid %d returned %d\n", 1.785 + pid, WEXITSTATUS(status)); 1.786 + if(WIFSIGNALED(status)) 1.787 + logwrite(LOG_WARNING, 1.788 + "delivery process with pid %d got signal: %d\n", 1.789 + pid, WTERMSIG(status)); 1.790 + }else{ 1.791 + logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno)); 1.792 + } 1.793 + } 1.794 + 1.795 + return ok; 1.796 +} 1.797 + 1.798 +/* function just to log into a pop server, 1.799 + for pop_before_smtp (or is it smtp_after_pop?) 1.800 +*/ 1.801 + 1.802 +gboolean pop3_login(gchar *host, gint port, GList *resolve_list, 1.803 + gchar *user, gchar *pass, guint flags) 1.804 +{ 1.805 + gboolean ok = FALSE; 1.806 + pop3_base *popb; 1.807 + 1.808 + signal(SIGCHLD, SIG_IGN); 1.809 + 1.810 + if((popb = pop3_in_open(host, port, resolve_list, flags))){ 1.811 + if(pop3_in_init(popb)){ 1.812 + if(pop3_in_login(popb, user, pass)) 1.813 + ok = TRUE; 1.814 + else 1.815 + logwrite(LOG_ALERT|LOG_VERBOSE, 1.816 + "pop3 login failed for user %s, host = %s\n", user, host); 1.817 + } 1.818 + pop3_in_close(popb); 1.819 + } 1.820 + return ok; 1.821 +} 1.822 + 1.823 +#endif