masqmail-0.2

annotate src/get.c @ 11:24872a9fe6e1

merged
author meillo@marmaro.de
date Mon, 27 Oct 2008 16:23:31 +0100
parents 08114f7dcc23
children f671821d8222
rev   line source
meillo@0 1 /* MasqMail
meillo@0 2 Copyright (C) 2000-2002 Oliver Kurth
meillo@0 3
meillo@0 4 This program is free software; you can redistribute it and/or modify
meillo@0 5 it under the terms of the GNU General Public License as published by
meillo@0 6 the Free Software Foundation; either version 2 of the License, or
meillo@0 7 (at your option) any later version.
meillo@0 8
meillo@0 9 This program is distributed in the hope that it will be useful,
meillo@0 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@0 12 GNU General Public License for more details.
meillo@0 13
meillo@0 14 You should have received a copy of the GNU General Public License
meillo@0 15 along with this program; if not, write to the Free Software
meillo@0 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
meillo@0 17 */
meillo@0 18
meillo@0 19 #include <sys/wait.h>
meillo@0 20 #include <sys/file.h>
meillo@0 21 #include <sys/types.h>
meillo@0 22
meillo@0 23 #include "masqmail.h"
meillo@0 24 #include "pop3_in.h"
meillo@0 25
meillo@0 26 #ifdef ENABLE_POP3
meillo@0 27
meillo@0 28 static int volatile sighup_seen = 0;
meillo@0 29
meillo@10 30 static void
meillo@10 31 sighup_handler(int sig)
meillo@0 32 {
meillo@10 33 sighup_seen = 1;
meillo@10 34 signal(SIGHUP, sighup_handler);
meillo@0 35 }
meillo@0 36
meillo@10 37 static void
meillo@10 38 sigchld_handler(int sig)
meillo@0 39 {
meillo@10 40 pid_t pid;
meillo@10 41 int status;
meillo@10 42
meillo@10 43 pid = waitpid(0, &status, 0);
meillo@10 44 if (pid > 0) {
meillo@10 45 if (WEXITSTATUS(status) != EXIT_SUCCESS)
meillo@10 46 logwrite(LOG_WARNING, "process %d exited with %d\n", pid, WEXITSTATUS(status));
meillo@10 47 if (WIFSIGNALED(status))
meillo@10 48 logwrite(LOG_WARNING, "process with pid %d got signal: %d\n", pid, WTERMSIG(status));
meillo@10 49 }
meillo@10 50 signal(SIGCHLD, sigchld_handler);
meillo@0 51 }
meillo@0 52
meillo@10 53 static int
meillo@10 54 get_lock(get_conf * gc)
meillo@0 55 {
meillo@0 56 #ifdef USE_DOTLOCK
meillo@10 57 gboolean ok = FALSE;
meillo@10 58 gchar *hitch_name;
meillo@10 59 gchar *lock_name;
meillo@0 60
meillo@10 61 /* the name of the lock is constructed from the user
meillo@10 62 and the server name, to prevent more than one connection at the same time
meillo@10 63 to the same server and the same user. This way concurrent connections
meillo@10 64 are possible to different servers or different users */
meillo@10 65 hitch_name = g_strdup_printf("%s/masqmail-get-%s@%s-%d.lock", conf.lock_dir, gc->login_user, gc->server_name, getpid());
meillo@10 66 lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name);
meillo@0 67
meillo@10 68 ok = dot_lock(lock_name, hitch_name);
meillo@10 69 if (!ok)
meillo@10 70 logwrite(LOG_WARNING, "getting mail for %s@%s is locked\n", gc->login_user, gc->server_name);
meillo@0 71
meillo@10 72 g_free(lock_name);
meillo@10 73 g_free(hitch_name);
meillo@10 74
meillo@10 75 return ok;
meillo@0 76 #else
meillo@10 77 gchar *lock_name;
meillo@10 78 int fd;
meillo@0 79
meillo@10 80 lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name);
meillo@0 81
meillo@10 82 if ((fd = open(lock_name, O_WRONLY | O_NDELAY | O_APPEND | O_CREAT, 0600)) >= 0) {
meillo@10 83 if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
meillo@10 84 close(fd);
meillo@10 85 logwrite(LOG_WARNING, "getting mail for %s@%s is locked\n", gc->login_user, gc->server_name);
meillo@10 86 fd = -1;
meillo@10 87 }
meillo@10 88 } else
meillo@10 89 logwrite(LOG_WARNING, "could not open lock %s: %s\n", lock_name, strerror(errno));
meillo@0 90
meillo@10 91 g_free(lock_name);
meillo@0 92
meillo@10 93 return fd;
meillo@0 94 #endif
meillo@0 95 }
meillo@0 96
meillo@0 97 #ifdef USE_DOTLOCK
meillo@10 98 static gboolean
meillo@10 99 get_unlock(get_conf * gc)
meillo@0 100 {
meillo@10 101 gchar *lock_name lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name);
meillo@0 102
meillo@10 103 dot_unlock(lock_name);
meillo@10 104 g_free(lock_name);
meillo@0 105
meillo@10 106 return TRUE;
meillo@0 107 }
meillo@0 108 #else
meillo@10 109 static void
meillo@10 110 get_unlock(get_conf * gc, int fd)
meillo@0 111 {
meillo@10 112 gchar *lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock", conf.lock_dir, gc->login_user, gc->server_name);
meillo@0 113
meillo@10 114 flock(fd, LOCK_UN);
meillo@10 115 close(fd);
meillo@0 116
meillo@10 117 unlink(lock_name);
meillo@10 118 g_free(lock_name);
meillo@0 119 }
meillo@0 120 #endif
meillo@0 121
meillo@10 122 gboolean
meillo@10 123 get_from_file(gchar * fname)
meillo@0 124 {
meillo@10 125 guint flags = 0;
meillo@10 126 get_conf *gc = read_get_conf(fname);
meillo@10 127 gboolean ok = TRUE;
meillo@10 128 int lock;
meillo@0 129
meillo@10 130 if (gc) {
meillo@10 131 if (!gc->do_keep)
meillo@10 132 flags |= POP3_FLAG_DELETE;
meillo@10 133 if (gc->do_uidl)
meillo@10 134 flags |= POP3_FLAG_UIDL;
meillo@10 135 if (gc->do_uidl_dele)
meillo@10 136 flags |= POP3_FLAG_UIDL_DELE;
meillo@0 137
meillo@10 138 if (!(gc->server_name)) {
meillo@10 139 logwrite(LOG_ALERT, "no server name given in %s\n", fname);
meillo@10 140 return FALSE;
meillo@10 141 }
meillo@10 142 if (!(gc->address)) {
meillo@10 143 logwrite(LOG_ALERT, "no address given in %s\n", fname);
meillo@10 144 return FALSE;
meillo@10 145 }
meillo@10 146 if (!(gc->login_user)) {
meillo@10 147 logwrite(LOG_ALERT, "no user name given in %s\n", fname);
meillo@10 148 return FALSE;
meillo@10 149 }
meillo@10 150 if (!(gc->login_pass)) {
meillo@10 151 logwrite(LOG_ALERT, "no password given in %s\n", fname);
meillo@10 152 return FALSE;
meillo@10 153 }
meillo@0 154
meillo@10 155 DEBUG(3) debugf("flags = %d\n", flags);
meillo@10 156
meillo@10 157 if ((strcmp(gc->protocol, "pop3") == 0) || (strcmp(gc->protocol, "apop") == 0)) {
meillo@10 158 pop3_base *popb = NULL;
meillo@10 159
meillo@10 160 if (strcmp(gc->protocol, "apop") == 0) {
meillo@10 161 flags |= POP3_FLAG_APOP;
meillo@10 162 DEBUG(3) debugf("attempting to get mail for user %s at host %s for %s@%s with apop\n",
meillo@10 163 gc->login_user, gc->server_name, gc->address->local_part, gc->address->domain);
meillo@10 164 } else {
meillo@10 165 DEBUG(3) debugf("attempting to get mail for user %s at host %s for %s@%s with pop3\n",
meillo@10 166 gc->login_user, gc->server_name, gc->address->local_part, gc->address->domain);
meillo@10 167 }
meillo@0 168 #ifdef USE_DOTLOCK
meillo@10 169 if ((lock = get_lock(gc))) {
meillo@0 170 #else
meillo@10 171 if ((lock = get_lock(gc)) >= 0) {
meillo@0 172 #endif
meillo@10 173 if (gc->wrapper) {
meillo@10 174 popb = pop3_in_open_child(gc->wrapper, flags);
meillo@10 175 /* quick hack */
meillo@10 176 popb->remote_host = gc->server_name;
meillo@10 177 } else {
meillo@10 178 popb = pop3_in_open(gc->server_name, gc->server_port, gc->resolve_list, flags);
meillo@10 179 }
meillo@10 180 if (popb) {
meillo@10 181 ok = pop3_get(popb, gc->login_user, gc->login_pass, gc->address, gc->return_path,
meillo@10 182 gc->max_count, gc->max_size, gc->max_size_delete);
meillo@10 183 pop3_in_close(popb);
meillo@10 184 } else {
meillo@10 185 ok = FALSE;
meillo@10 186 logwrite(LOG_ALERT, "failed to connect to host %s\n", gc->server_name);
meillo@10 187 }
meillo@10 188 #ifdef USE_DOTLOCK
meillo@10 189 get_unlock(gc);
meillo@10 190 #else
meillo@10 191 get_unlock(gc, lock);
meillo@10 192 #endif
meillo@10 193 }
meillo@10 194 } else {
meillo@10 195 logwrite(LOG_ALERT, "get protocol %s unknown\n", gc->protocol);
meillo@10 196 ok = FALSE;
meillo@10 197 }
meillo@10 198
meillo@10 199 destroy_get_conf(gc);
meillo@0 200 }
meillo@10 201 return ok;
meillo@0 202 }
meillo@0 203
meillo@10 204 gboolean
meillo@10 205 get_from_name(gchar * name)
meillo@0 206 {
meillo@10 207 gchar *fname = (gchar *) table_find(conf.get_names, name);
meillo@10 208 if (fname)
meillo@10 209 return get_from_file(fname);
meillo@10 210 return FALSE;
meillo@0 211 }
meillo@0 212
meillo@10 213 gboolean
meillo@10 214 get_all()
meillo@0 215 {
meillo@10 216 GList *get_table = conf.get_names;
meillo@10 217 GList *get_node;
meillo@10 218 void (*old_signal) (int);
meillo@0 219
meillo@10 220 old_signal = signal(SIGCHLD, SIG_DFL);
meillo@0 221
meillo@10 222 foreach(get_table, get_node) {
meillo@10 223 table_pair *pair = (table_pair *) (get_node->data);
meillo@10 224 gchar *fname = (gchar *) pair->value;
meillo@10 225 pid_t pid;
meillo@0 226
meillo@10 227 pid = fork();
meillo@10 228 if (pid == 0) {
meillo@10 229 signal(SIGCHLD, old_signal);
meillo@10 230 exit(get_from_file(fname) ? EXIT_SUCCESS : EXIT_FAILURE);
meillo@10 231 } else if (pid > 0) {
meillo@10 232 int status;
meillo@10 233 waitpid(pid, &status, 0);
meillo@10 234 if (WEXITSTATUS(status) != EXIT_SUCCESS)
meillo@10 235 logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status));
meillo@10 236 if (WIFSIGNALED(status))
meillo@10 237 logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status));
meillo@10 238 } else
meillo@10 239 logwrite(LOG_WARNING, "forking child failed: %s\n", strerror(errno));
meillo@10 240 }
meillo@0 241
meillo@10 242 signal(SIGCHLD, old_signal);
meillo@10 243
meillo@10 244 return TRUE;
meillo@0 245 }
meillo@0 246
meillo@10 247 void
meillo@10 248 get_online()
meillo@0 249 {
meillo@10 250 GList *gf_list = NULL;
meillo@10 251 gchar *connect_name = detect_online();
meillo@0 252
meillo@10 253 if (connect_name != NULL) {
meillo@10 254 void (*old_signal) (int);
meillo@0 255
meillo@10 256 old_signal = signal(SIGCHLD, SIG_DFL);
meillo@0 257
meillo@10 258 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
meillo@10 259 /* we are online! */
meillo@10 260 gf_list = (GList *) table_find(conf.online_gets, connect_name);
meillo@10 261 if (gf_list != NULL) {
meillo@10 262 GList *node;
meillo@10 263 foreach(gf_list, node) {
meillo@10 264 gchar *fname = (gchar *) (node->data);
meillo@10 265 pid_t pid;
meillo@0 266
meillo@10 267 if (fname[0] != '/')
meillo@10 268 fname = (gchar *) table_find(conf.get_names, fname);
meillo@0 269
meillo@10 270 if (fname != NULL) {
meillo@10 271 pid = fork();
meillo@10 272 if (pid == 0) {
meillo@10 273 signal(SIGCHLD, old_signal);
meillo@10 274 exit(get_from_file(fname) ? EXIT_SUCCESS : EXIT_FAILURE);
meillo@10 275 } else if (pid > 0) {
meillo@10 276 int status;
meillo@10 277 waitpid(pid, &status, 0);
meillo@10 278 if (WEXITSTATUS(status) != EXIT_SUCCESS)
meillo@10 279 logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status));
meillo@10 280 if (WIFSIGNALED(status))
meillo@10 281 logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status));
meillo@10 282 } else
meillo@10 283 logwrite(LOG_WARNING, "forking child failed: %s\n", strerror(errno));
meillo@10 284 }
meillo@10 285 }
meillo@10 286 }
meillo@10 287 signal(SIGCHLD, old_signal);
meillo@0 288 }
meillo@0 289 }
meillo@0 290
meillo@10 291 void
meillo@10 292 get_daemon(gint gival, char *argv[])
meillo@0 293 {
meillo@10 294 struct timeval tm;
meillo@10 295 time_t time_before, time_now;
meillo@10 296 int sel_ret;
meillo@0 297
meillo@10 298 /* setup handler for HUP signal: */
meillo@10 299 signal(SIGHUP, sighup_handler);
meillo@0 300
meillo@10 301 /* we can give up root privileges */
meillo@10 302 if (!conf.run_as_user) {
meillo@10 303 if (setegid(conf.mail_gid) != 0) {
meillo@10 304 logwrite(LOG_ALERT, "could not change gid to %d: %s\n", conf.mail_gid, strerror(errno));
meillo@10 305 exit(EXIT_FAILURE);
meillo@10 306 }
meillo@10 307 if (seteuid(conf.mail_uid) != 0) {
meillo@10 308 logwrite(LOG_ALERT, "could not change uid to %d: %s\n", conf.mail_uid, strerror(errno));
meillo@10 309 exit(EXIT_FAILURE);
meillo@10 310 }
meillo@10 311 }
meillo@0 312
meillo@10 313 /* sel_ret = 0; */
meillo@10 314 time(&time_before);
meillo@10 315 time_before -= gival;
meillo@10 316 sel_ret = -1;
meillo@0 317
meillo@10 318 while (1) {
meillo@10 319 /* see listen_port() in listen.c */
meillo@10 320 if (gival > 0) {
meillo@10 321 time(&time_now);
meillo@10 322 if (sel_ret == 0) { /* we are either just starting or did a queue run */
meillo@10 323 tm.tv_sec = gival;
meillo@10 324 tm.tv_usec = 0;
meillo@10 325 time_before = time_now;
meillo@10 326 } else {
meillo@10 327 tm.tv_sec = gival - (time_now - time_before);
meillo@10 328 tm.tv_usec = 0;
meillo@0 329
meillo@10 330 /* race condition, very unlikely (but possible): */
meillo@10 331 if (tm.tv_sec < 0)
meillo@10 332 tm.tv_sec = 0;
meillo@10 333 }
meillo@10 334 }
meillo@0 335
meillo@10 336 if ((sel_ret = select(0, NULL, NULL, NULL, &tm)) < 0) {
meillo@10 337 if (errno != EINTR) {
meillo@10 338 logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno));
meillo@10 339 exit(EXIT_FAILURE);
meillo@10 340 } else {
meillo@10 341 if (sighup_seen) {
meillo@10 342 logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n");
meillo@0 343
meillo@10 344 if (argv == NULL)
meillo@10 345 exit(EXIT_SUCCESS);
meillo@0 346
meillo@10 347 execv(argv[0], &(argv[0]));
meillo@10 348 logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno));
meillo@10 349 exit(EXIT_FAILURE);
meillo@0 350
meillo@10 351 }
meillo@10 352 }
meillo@10 353 } else {
meillo@10 354 /* If select returns 0, the interval time has elapsed.
meillo@10 355 We start a new get process */
meillo@10 356 int pid;
meillo@10 357 signal(SIGCHLD, sigchld_handler);
meillo@10 358 if ((pid = fork()) == 0) {
meillo@10 359 get_online();
meillo@10 360
meillo@10 361 _exit(EXIT_SUCCESS);
meillo@10 362 } else if (pid < 0) {
meillo@10 363 logwrite(LOG_ALERT, "could not fork for get run");
meillo@10 364 }
meillo@10 365 }
meillo@0 366 }
meillo@0 367 }
meillo@0 368
meillo@10 369 gboolean
meillo@10 370 pop_before_smtp(gchar * fname)
meillo@0 371 {
meillo@10 372 gboolean ok = FALSE;
meillo@10 373 GList *resolve_list = NULL;
meillo@10 374 get_conf *gc = read_get_conf(fname);
meillo@10 375 guint flags = 0;
meillo@0 376
meillo@0 377 #ifdef ENABLE_RESOLVER
meillo@10 378 resolve_list = g_list_append(resolve_list, resolve_dns_a);
meillo@0 379 #endif
meillo@10 380 resolve_list = g_list_append(resolve_list, resolve_byname);
meillo@0 381
meillo@10 382 if (strcmp(gc->protocol, "pop3") == 0) {
meillo@10 383 DEBUG(3) debugf("attempting to login for user %s, host = %s with pop3\n", gc->login_user, gc->server_name);
meillo@10 384 ok = pop3_login(gc->server_name, gc->server_port, resolve_list, gc->login_user, gc->login_pass, flags);
meillo@10 385 } else if (strcmp(gc->protocol, "apop") == 0) {
meillo@10 386 DEBUG(3) debugf ("attempting to login for user %s, host = %s with apop\n", gc->login_user, gc->server_name);
meillo@10 387 ok = pop3_login(gc->server_name, gc->server_port, resolve_list, gc->login_user, gc->login_pass, flags | POP3_FLAG_APOP);
meillo@10 388 } else {
meillo@10 389 logwrite(LOG_ALERT, "get protocol %s unknown\n", gc->protocol);
meillo@10 390 }
meillo@10 391 return ok;
meillo@0 392 }
meillo@0 393
meillo@0 394 #endif