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