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