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