Mercurial > masqmail
view src/get.c @ 189:dc89737b27aa
removed the pop-before-smtp (smtp-after-pop) function
this kind of authentication is superseded by SMTP AUTH today
removing it is a step towards removing the POP stuff completely
If you still rely on pop-before-smtp, stay with 0.2.x
or run an arbitrary pop client before
author | meillo@marmaro.de |
---|---|
date | Thu, 15 Jul 2010 10:33:53 +0200 |
parents | f671821d8222 |
children |
line wrap: on
line source
/* MasqMail Copyright (C) 2000-2002 Oliver Kurth This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <sys/wait.h> #include <sys/file.h> #include <sys/types.h> #include "masqmail.h" #include "pop3_in.h" #ifdef ENABLE_POP3 static int volatile sighup_seen = 0; static void sighup_handler(int sig) { sighup_seen = 1; signal(SIGHUP, sighup_handler); } static void sigchld_handler(int sig) { pid_t pid; int status; pid = waitpid(0, &status, 0); if (pid > 0) { if (WEXITSTATUS(status) != EXIT_SUCCESS) logwrite(LOG_WARNING, "process %d exited with %d\n", pid, WEXITSTATUS(status)); if (WIFSIGNALED(status)) logwrite(LOG_WARNING, "process with pid %d got signal: %d\n", pid, WTERMSIG(status)); } signal(SIGCHLD, sigchld_handler); } static int get_lock(get_conf * gc) { #ifdef USE_DOTLOCK gboolean ok = FALSE; gchar *hitch_name; gchar *lock_name; /* the name of the lock is constructed from the user and the server name, to prevent more than one connection at the same time to the same server and the same user. This way concurrent connections are possible to different servers or different users */ hitch_name = g_strdup_printf("%s/masqmail-get-%s@%s-%d.lock", conf.lock_dir, gc->login_user, gc->server_name, getpid()); lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name); ok = dot_lock(lock_name, hitch_name); if (!ok) logwrite(LOG_WARNING, "getting mail for %s@%s is locked\n", gc->login_user, gc->server_name); g_free(lock_name); g_free(hitch_name); return ok; #else gchar *lock_name; int fd; lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name); if ((fd = open(lock_name, O_WRONLY | O_NDELAY | O_APPEND | O_CREAT, 0600)) >= 0) { if (flock(fd, LOCK_EX | LOCK_NB) != 0) { close(fd); logwrite(LOG_WARNING, "getting mail for %s@%s is locked\n", gc->login_user, gc->server_name); fd = -1; } } else logwrite(LOG_WARNING, "could not open lock %s: %s\n", lock_name, strerror(errno)); g_free(lock_name); return fd; #endif } #ifdef USE_DOTLOCK static gboolean get_unlock(get_conf * gc) { gchar *lock_name lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name); dot_unlock(lock_name); g_free(lock_name); return TRUE; } #else static void get_unlock(get_conf * gc, int fd) { gchar *lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name); flock(fd, LOCK_UN); close(fd); unlink(lock_name); g_free(lock_name); } #endif gboolean get_from_file(gchar * fname) { guint flags = 0; get_conf *gc = read_get_conf(fname); gboolean ok = TRUE; int lock; if (gc) { if (!gc->do_keep) flags |= POP3_FLAG_DELETE; if (gc->do_uidl) flags |= POP3_FLAG_UIDL; if (gc->do_uidl_dele) flags |= POP3_FLAG_UIDL_DELE; if (!(gc->server_name)) { logwrite(LOG_ALERT, "no server name given in %s\n", fname); return FALSE; } if (!(gc->address)) { logwrite(LOG_ALERT, "no address given in %s\n", fname); return FALSE; } if (!(gc->login_user)) { logwrite(LOG_ALERT, "no user name given in %s\n", fname); return FALSE; } if (!(gc->login_pass)) { logwrite(LOG_ALERT, "no password given in %s\n", fname); return FALSE; } DEBUG(3) debugf("flags = %d\n", flags); if ((strcmp(gc->protocol, "pop3") == 0) || (strcmp(gc->protocol, "apop") == 0)) { pop3_base *popb = NULL; if (strcmp(gc->protocol, "apop") == 0) { flags |= POP3_FLAG_APOP; DEBUG(3) debugf("attempting to get mail for user %s at host %s for %s@%s with apop\n", gc->login_user, gc->server_name, gc->address->local_part, gc->address->domain); } else { DEBUG(3) debugf("attempting to get mail for user %s at host %s for %s@%s with pop3\n", gc->login_user, gc->server_name, gc->address->local_part, gc->address->domain); } #ifdef USE_DOTLOCK if ((lock = get_lock(gc))) { #else if ((lock = get_lock(gc)) >= 0) { #endif if (gc->wrapper) { popb = pop3_in_open_child(gc->wrapper, flags); /* quick hack */ popb->remote_host = gc->server_name; } else { popb = pop3_in_open(gc->server_name, gc->server_port, gc->resolve_list, flags); } if (popb) { ok = pop3_get(popb, gc->login_user, gc->login_pass, gc->address, gc->return_path, gc->max_count, gc->max_size, gc->max_size_delete); pop3_in_close(popb); } else { ok = FALSE; logwrite(LOG_ALERT, "failed to connect to host %s\n", gc->server_name); } #ifdef USE_DOTLOCK get_unlock(gc); #else get_unlock(gc, lock); #endif } } else { logwrite(LOG_ALERT, "get protocol %s unknown\n", gc->protocol); ok = FALSE; } destroy_get_conf(gc); } return ok; } gboolean get_from_name(gchar * name) { gchar *fname = (gchar *) table_find(conf.get_names, name); if (fname) return get_from_file(fname); return FALSE; } gboolean get_all() { GList *get_table = conf.get_names; GList *get_node; void (*old_signal) (int); old_signal = signal(SIGCHLD, SIG_DFL); foreach(get_table, get_node) { table_pair *pair = (table_pair *) (get_node->data); gchar *fname = (gchar *) pair->value; pid_t pid; pid = fork(); if (pid == 0) { signal(SIGCHLD, old_signal); exit(get_from_file(fname) ? EXIT_SUCCESS : EXIT_FAILURE); } else if (pid > 0) { int status; waitpid(pid, &status, 0); if (WEXITSTATUS(status) != EXIT_SUCCESS) logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status)); if (WIFSIGNALED(status)) logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status)); } else logwrite(LOG_WARNING, "forking child failed: %s\n", strerror(errno)); } signal(SIGCHLD, old_signal); return TRUE; } void get_online() { GList *gf_list = NULL; gchar *connect_name = detect_online(); if (connect_name != NULL) { void (*old_signal) (int); old_signal = signal(SIGCHLD, SIG_DFL); logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name); /* we are online! */ gf_list = (GList *) table_find(conf.online_gets, connect_name); if (gf_list != NULL) { GList *node; foreach(gf_list, node) { gchar *fname = (gchar *) (node->data); pid_t pid; if (fname[0] != '/') fname = (gchar *) table_find(conf.get_names, fname); if (fname != NULL) { pid = fork(); if (pid == 0) { signal(SIGCHLD, old_signal); exit(get_from_file(fname) ? EXIT_SUCCESS : EXIT_FAILURE); } else if (pid > 0) { int status; waitpid(pid, &status, 0); if (WEXITSTATUS(status) != EXIT_SUCCESS) logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status)); if (WIFSIGNALED(status)) logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status)); } else logwrite(LOG_WARNING, "forking child failed: %s\n", strerror(errno)); } } } signal(SIGCHLD, old_signal); } } void get_daemon(gint gival, char *argv[]) { struct timeval tm; time_t time_before, time_now; int sel_ret; /* setup handler for HUP signal: */ signal(SIGHUP, sighup_handler); /* we can give up root privileges */ if (!conf.run_as_user) { if (setegid(conf.mail_gid) != 0) { logwrite(LOG_ALERT, "could not change gid to %d: %s\n", conf.mail_gid, strerror(errno)); exit(EXIT_FAILURE); } if (seteuid(conf.mail_uid) != 0) { logwrite(LOG_ALERT, "could not change uid to %d: %s\n", conf.mail_uid, strerror(errno)); exit(EXIT_FAILURE); } } /* sel_ret = 0; */ time(&time_before); time_before -= gival; sel_ret = -1; while (1) { /* see listen_port() in listen.c */ if (gival > 0) { time(&time_now); if (sel_ret == 0) { /* we are either just starting or did a queue run */ tm.tv_sec = gival; tm.tv_usec = 0; time_before = time_now; } else { tm.tv_sec = gival - (time_now - time_before); tm.tv_usec = 0; /* race condition, very unlikely (but possible): */ if (tm.tv_sec < 0) tm.tv_sec = 0; } } if ((sel_ret = select(0, NULL, NULL, NULL, &tm)) < 0) { if (errno != EINTR) { logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno)); exit(EXIT_FAILURE); } else { if (sighup_seen) { logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n"); if (argv == NULL) exit(EXIT_SUCCESS); execv(argv[0], &(argv[0])); logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } } } else { /* If select returns 0, the interval time has elapsed. We start a new get process */ int pid; signal(SIGCHLD, sigchld_handler); if ((pid = fork()) == 0) { get_online(); _exit(EXIT_SUCCESS); } else if (pid < 0) { logwrite(LOG_ALERT, "could not fork for get run"); } } } } #endif