masqmail
diff src/get.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/get.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,410 @@ 1.4 +/* MasqMail 1.5 + Copyright (C) 2000-2002 Oliver Kurth 1.6 + 1.7 + This program is free software; you can redistribute it and/or modify 1.8 + it under the terms of the GNU General Public License as published by 1.9 + the Free Software Foundation; either version 2 of the License, or 1.10 + (at your option) any later version. 1.11 + 1.12 + This program is distributed in the hope that it will be useful, 1.13 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.15 + GNU General Public License for more details. 1.16 + 1.17 + You should have received a copy of the GNU General Public License 1.18 + along with this program; if not, write to the Free Software 1.19 + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1.20 +*/ 1.21 + 1.22 +#include <sys/wait.h> 1.23 +#include <sys/file.h> 1.24 +#include <sys/types.h> 1.25 + 1.26 +#include "masqmail.h" 1.27 +#include "pop3_in.h" 1.28 + 1.29 +#ifdef ENABLE_POP3 1.30 + 1.31 +static int volatile sighup_seen = 0; 1.32 + 1.33 +static 1.34 +void sighup_handler(int sig) 1.35 +{ 1.36 + sighup_seen = 1; 1.37 + signal(SIGHUP, sighup_handler); 1.38 +} 1.39 + 1.40 +static 1.41 +void sigchld_handler(int sig) 1.42 +{ 1.43 + pid_t pid; 1.44 + int status; 1.45 + 1.46 + pid = waitpid(0, &status, 0); 1.47 + if(pid > 0){ 1.48 + if(WEXITSTATUS(status) != EXIT_SUCCESS) 1.49 + logwrite(LOG_WARNING, "process %d exited with %d\n", 1.50 + pid, WEXITSTATUS(status)); 1.51 + if(WIFSIGNALED(status)) 1.52 + logwrite(LOG_WARNING, 1.53 + "process with pid %d got signal: %d\n", 1.54 + pid, WTERMSIG(status)); 1.55 + } 1.56 + signal(SIGCHLD, sigchld_handler); 1.57 +} 1.58 + 1.59 +static 1.60 +int get_lock(get_conf *gc) 1.61 +{ 1.62 +#ifdef USE_DOTLOCK 1.63 + gboolean ok = FALSE; 1.64 + gchar *hitch_name; 1.65 + gchar *lock_name; 1.66 + 1.67 + /* the name of the lock is constructed from the user 1.68 + and the server name, to prevent more than one connection at the same time 1.69 + to the same server and the same user. This way concurrent connections 1.70 + are possible to different servers or different users */ 1.71 + hitch_name = g_strdup_printf("%s/masqmail-get-%s@%s-%d.lock", 1.72 + conf.lock_dir, gc->login_user, 1.73 + gc->server_name, getpid()); 1.74 + lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", 1.75 + conf.lock_dir, gc->login_user, gc->server_name); 1.76 + 1.77 + ok = dot_lock(lock_name, hitch_name); 1.78 + if(!ok) logwrite(LOG_WARNING, 1.79 + "getting mail for %s@%s is locked\n", 1.80 + gc->login_user, gc->server_name); 1.81 + 1.82 + g_free(lock_name); 1.83 + g_free(hitch_name); 1.84 + 1.85 + return ok; 1.86 +#else 1.87 + gchar *lock_name; 1.88 + int fd; 1.89 + 1.90 + lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", 1.91 + conf.lock_dir, gc->login_user, gc->server_name); 1.92 + 1.93 + if((fd = open(lock_name, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) >= 0){ 1.94 + if(flock(fd, LOCK_EX|LOCK_NB) != 0){ 1.95 + close(fd); 1.96 + logwrite(LOG_WARNING, 1.97 + "getting mail for %s@%s is locked\n", 1.98 + gc->login_user, gc->server_name); 1.99 + fd = -1; 1.100 + } 1.101 + }else 1.102 + logwrite(LOG_WARNING, 1.103 + "could not open lock %s: %s\n", lock_name, strerror(errno)); 1.104 + 1.105 + g_free(lock_name); 1.106 + 1.107 + return fd; 1.108 +#endif 1.109 +} 1.110 + 1.111 +#ifdef USE_DOTLOCK 1.112 +static 1.113 +gboolean get_unlock(get_conf *gc) 1.114 +{ 1.115 + gchar *lock_name lock_name = 1.116 + g_strdup_printf("%s/masqmail-get-%s@%s.lock", 1.117 + conf.lock_dir, gc->login_user, gc->server_name); 1.118 + 1.119 + dot_unlock(lock_name); 1.120 + 1.121 + g_free(lock_name); 1.122 + 1.123 + return TRUE; 1.124 +} 1.125 +#else 1.126 +static void get_unlock(get_conf *gc, int fd) 1.127 +{ 1.128 + gchar *lock_name = 1.129 + g_strdup_printf("%s/masqmail-get-%s@%s.lock", 1.130 + conf.lock_dir, gc->login_user, gc->server_name); 1.131 + 1.132 + flock(fd, LOCK_UN); 1.133 + close(fd); 1.134 + 1.135 + unlink(lock_name); 1.136 + g_free(lock_name); 1.137 +} 1.138 +#endif 1.139 + 1.140 +gboolean get_from_file(gchar *fname) 1.141 +{ 1.142 + guint flags = 0; 1.143 + get_conf *gc = read_get_conf(fname); 1.144 + gboolean ok = TRUE; 1.145 + int lock; 1.146 + 1.147 + if(gc){ 1.148 + if(!gc->do_keep) flags |= POP3_FLAG_DELETE; 1.149 + if(gc->do_uidl) flags |= POP3_FLAG_UIDL; 1.150 + if(gc->do_uidl_dele) flags |= POP3_FLAG_UIDL_DELE; 1.151 + 1.152 + if(!(gc->server_name)){ 1.153 + logwrite(LOG_ALERT, "no server name given in %s\n", fname); return FALSE; 1.154 + } 1.155 + if(!(gc->address)){ 1.156 + logwrite(LOG_ALERT, "no address given in %s\n", fname); return FALSE; 1.157 + } 1.158 + if(!(gc->login_user)){ 1.159 + logwrite(LOG_ALERT, "no user name given in %s\n", fname); return FALSE; 1.160 + } 1.161 + if(!(gc->login_pass)){ 1.162 + logwrite(LOG_ALERT, "no password given in %s\n", fname); return FALSE; 1.163 + } 1.164 + 1.165 + DEBUG(3) debugf("flags = %d\n", flags); 1.166 + 1.167 + if((strcmp(gc->protocol, "pop3") == 0) || (strcmp(gc->protocol, "apop") == 0)){ 1.168 + pop3_base *popb = NULL; 1.169 + 1.170 + if(strcmp(gc->protocol, "apop") == 0){ 1.171 + flags |= POP3_FLAG_APOP; 1.172 + DEBUG(3) debugf("attempting to get mail for user %s at host %s" 1.173 + " for %s@%s with apop\n", 1.174 + gc->login_user, gc->server_name, 1.175 + gc->address->local_part, gc->address->domain); 1.176 + }else{ 1.177 + DEBUG(3) debugf("attempting to get mail for user %s at host %s" 1.178 + " for %s@%s with pop3\n", 1.179 + gc->login_user, gc->server_name, 1.180 + gc->address->local_part, gc->address->domain); 1.181 + } 1.182 +#ifdef USE_DOTLOCK 1.183 + if((lock = get_lock(gc))){ 1.184 +#else 1.185 + if((lock = get_lock(gc)) >= 0){ 1.186 +#endif 1.187 + if(gc->wrapper){ 1.188 + popb = pop3_in_open_child(gc->wrapper, flags); 1.189 + /* quick hack */ 1.190 + popb->remote_host = gc->server_name; 1.191 + }else{ 1.192 + popb = pop3_in_open(gc->server_name, gc->server_port, 1.193 + gc->resolve_list, flags); 1.194 + } 1.195 + if(popb){ 1.196 + ok = pop3_get(popb, gc->login_user, gc->login_pass, 1.197 + gc->address, gc->return_path, 1.198 + gc->max_count, gc->max_size, gc->max_size_delete); 1.199 + pop3_in_close(popb); 1.200 + }else{ 1.201 + ok = FALSE; 1.202 + logwrite(LOG_ALERT, "failed to connect to host %s\n", gc->server_name); 1.203 + } 1.204 +#ifdef USE_DOTLOCK 1.205 + get_unlock(gc); 1.206 +#else 1.207 + get_unlock(gc, lock); 1.208 +#endif 1.209 + } 1.210 + }else{ 1.211 + logwrite(LOG_ALERT, "get protocol %s unknown\n", gc->protocol); 1.212 + ok = FALSE; 1.213 + } 1.214 + 1.215 + destroy_get_conf(gc); 1.216 + } 1.217 + return ok; 1.218 +} 1.219 + 1.220 +gboolean get_from_name(gchar *name) 1.221 +{ 1.222 + gchar *fname = (gchar *)table_find(conf.get_names, name); 1.223 + if(fname) 1.224 + return get_from_file(fname); 1.225 + return FALSE; 1.226 +} 1.227 + 1.228 +gboolean get_all() 1.229 +{ 1.230 + GList *get_table = conf.get_names; 1.231 + GList *get_node; 1.232 + void (*old_signal)(int); 1.233 + 1.234 + old_signal = signal(SIGCHLD, SIG_DFL); 1.235 + 1.236 + foreach(get_table, get_node){ 1.237 + table_pair *pair = (table_pair *)(get_node->data); 1.238 + gchar *fname = (gchar *)pair->value; 1.239 + pid_t pid; 1.240 + 1.241 + pid = fork(); 1.242 + if(pid == 0){ 1.243 + signal(SIGCHLD, old_signal); 1.244 + exit(get_from_file(fname) ? EXIT_SUCCESS : EXIT_FAILURE); 1.245 + }else if(pid > 0){ 1.246 + int status; 1.247 + waitpid(pid, &status, 0); 1.248 + if(WEXITSTATUS(status) != EXIT_SUCCESS) 1.249 + logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status)); 1.250 + if(WIFSIGNALED(status)) 1.251 + logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status)); 1.252 + }else 1.253 + logwrite(LOG_WARNING, "forking child failed: %s\n", strerror(errno)); 1.254 + } 1.255 + 1.256 + signal(SIGCHLD, old_signal); 1.257 + 1.258 + return TRUE; 1.259 +} 1.260 + 1.261 +void get_online() 1.262 +{ 1.263 + GList *gf_list = NULL; 1.264 + gchar *connect_name = detect_online(); 1.265 + 1.266 + if(connect_name != NULL){ 1.267 + void (*old_signal)(int); 1.268 + 1.269 + old_signal = signal(SIGCHLD, SIG_DFL); 1.270 + 1.271 + logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name); 1.272 + /* we are online! */ 1.273 + gf_list = (GList *)table_find(conf.online_gets, connect_name); 1.274 + if(gf_list != NULL){ 1.275 + GList *node; 1.276 + foreach(gf_list, node){ 1.277 + gchar *fname = (gchar *)(node->data); 1.278 + pid_t pid; 1.279 + 1.280 + if(fname[0] != '/') 1.281 + fname = (gchar *)table_find(conf.get_names, fname); 1.282 + 1.283 + if(fname != NULL){ 1.284 + pid = fork(); 1.285 + if(pid == 0){ 1.286 + signal(SIGCHLD, old_signal); 1.287 + exit(get_from_file(fname) ? EXIT_SUCCESS : EXIT_FAILURE); 1.288 + }else if(pid > 0){ 1.289 + int status; 1.290 + waitpid(pid, &status, 0); 1.291 + if(WEXITSTATUS(status) != EXIT_SUCCESS) 1.292 + logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status)); 1.293 + if(WIFSIGNALED(status)) 1.294 + logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status)); 1.295 + }else 1.296 + logwrite(LOG_WARNING, "forking child failed: %s\n", strerror(errno)); 1.297 + } 1.298 + } 1.299 + } 1.300 + signal(SIGCHLD, old_signal); 1.301 + } 1.302 +} 1.303 + 1.304 +void get_daemon(gint gival, char *argv[]) 1.305 +{ 1.306 + struct timeval tm; 1.307 + time_t time_before, time_now; 1.308 + int sel_ret; 1.309 + 1.310 + /* setup handler for HUP signal: */ 1.311 + signal(SIGHUP, sighup_handler); 1.312 + 1.313 + /* we can give up root privileges */ 1.314 + if(!conf.run_as_user){ 1.315 + if(setegid(conf.mail_gid) != 0){ 1.316 + logwrite(LOG_ALERT, "could not change gid to %d: %s\n", 1.317 + conf.mail_gid, strerror(errno)); 1.318 + exit(EXIT_FAILURE); 1.319 + } 1.320 + if(seteuid(conf.mail_uid) != 0){ 1.321 + logwrite(LOG_ALERT, "could not change uid to %d: %s\n", 1.322 + conf.mail_uid, strerror(errno)); 1.323 + exit(EXIT_FAILURE); 1.324 + } 1.325 + } 1.326 + 1.327 + /* sel_ret = 0;*/ 1.328 + time(&time_before); 1.329 + time_before -= gival; 1.330 + sel_ret = -1; 1.331 + 1.332 + while (1){ 1.333 + /* see listen_port() in listen.c */ 1.334 + if(gival > 0){ 1.335 + time(&time_now); 1.336 + if(sel_ret == 0){ /* we are either just starting or did a queue run */ 1.337 + tm.tv_sec = gival; 1.338 + tm.tv_usec = 0; 1.339 + time_before = time_now; 1.340 + }else{ 1.341 + tm.tv_sec = gival - (time_now - time_before); 1.342 + tm.tv_usec = 0; 1.343 + 1.344 + /* race condition, very unlikely (but possible): */ 1.345 + if(tm.tv_sec < 0) 1.346 + tm.tv_sec = 0; 1.347 + } 1.348 + } 1.349 + 1.350 + if ((sel_ret = select(0, NULL, NULL, NULL, &tm)) < 0){ 1.351 + if(errno != EINTR){ 1.352 + logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno)); 1.353 + exit (EXIT_FAILURE); 1.354 + }else{ 1.355 + if(sighup_seen){ 1.356 + logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n"); 1.357 + 1.358 + if(argv == NULL) exit(EXIT_SUCCESS); 1.359 + 1.360 + execv(argv[0], &(argv[0])); 1.361 + logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno)); 1.362 + exit(EXIT_FAILURE); 1.363 + 1.364 + } 1.365 + } 1.366 + }else{ 1.367 + /* If select returns 0, the interval time has elapsed. 1.368 + We start a new get process */ 1.369 + int pid; 1.370 + signal(SIGCHLD, sigchld_handler); 1.371 + if((pid = fork()) == 0){ 1.372 + get_online(); 1.373 + 1.374 + _exit(EXIT_SUCCESS); 1.375 + } 1.376 + else if(pid < 0){ 1.377 + logwrite(LOG_ALERT, "could not fork for get run"); 1.378 + } 1.379 + } 1.380 + } 1.381 +} 1.382 + 1.383 +gboolean pop_before_smtp(gchar *fname) 1.384 +{ 1.385 + gboolean ok = FALSE; 1.386 + GList *resolve_list = NULL; 1.387 + get_conf *gc = read_get_conf(fname); 1.388 + guint flags = 0; 1.389 + 1.390 +#ifdef ENABLE_RESOLVER 1.391 + resolve_list = g_list_append(resolve_list, resolve_dns_a); 1.392 +#endif 1.393 + resolve_list = g_list_append(resolve_list, resolve_byname); 1.394 + 1.395 + if(strcmp(gc->protocol, "pop3") == 0){ 1.396 + DEBUG(3) debugf("attempting to login for user %s, host = %s with pop3\n", 1.397 + gc->login_user, gc->server_name); 1.398 + ok = pop3_login(gc->server_name, gc->server_port, resolve_list, 1.399 + gc->login_user, gc->login_pass, 1.400 + flags); 1.401 + }else if(strcmp(gc->protocol, "apop") == 0){ 1.402 + DEBUG(3) debugf("attempting to login for user %s, host = %s with apop\n", 1.403 + gc->login_user, gc->server_name); 1.404 + ok = pop3_login(gc->server_name, gc->server_port, resolve_list, 1.405 + gc->login_user, gc->login_pass, 1.406 + flags | POP3_FLAG_APOP); 1.407 + }else{ 1.408 + logwrite(LOG_ALERT, "get protocol %s unknown\n", gc->protocol); 1.409 + } 1.410 + return ok; 1.411 +} 1.412 + 1.413 +#endif