masqmail-0.2

view src/get.c @ 3:8c55886cacd8

man pages will be maintained in troff now
author meillo@marmaro.de
date Fri, 26 Sep 2008 21:40:10 +0200
parents
children 26e34ae9a3e3
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
31 void sighup_handler(int sig)
32 {
33 sighup_seen = 1;
34 signal(SIGHUP, sighup_handler);
35 }
37 static
38 void 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",
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 }
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;
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);
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);
79 g_free(lock_name);
80 g_free(hitch_name);
82 return ok;
83 #else
84 gchar *lock_name;
85 int fd;
87 lock_name = g_strdup_printf("%s/masqmail-get-%s@%s.lock",
88 conf.lock_dir, gc->login_user, gc->server_name);
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));
102 g_free(lock_name);
104 return fd;
105 #endif
106 }
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);
116 dot_unlock(lock_name);
118 g_free(lock_name);
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);
129 flock(fd, LOCK_UN);
130 close(fd);
132 unlink(lock_name);
133 g_free(lock_name);
134 }
135 #endif
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;
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;
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 }
162 DEBUG(3) debugf("flags = %d\n", flags);
164 if((strcmp(gc->protocol, "pop3") == 0) || (strcmp(gc->protocol, "apop") == 0)){
165 pop3_base *popb = NULL;
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 }
212 destroy_get_conf(gc);
213 }
214 return ok;
215 }
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 }
225 gboolean get_all()
226 {
227 GList *get_table = conf.get_names;
228 GList *get_node;
229 void (*old_signal)(int);
231 old_signal = signal(SIGCHLD, SIG_DFL);
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;
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 }
253 signal(SIGCHLD, old_signal);
255 return TRUE;
256 }
258 void get_online()
259 {
260 GList *gf_list = NULL;
261 gchar *connect_name = detect_online();
263 if(connect_name != NULL){
264 void (*old_signal)(int);
266 old_signal = signal(SIGCHLD, SIG_DFL);
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;
277 if(fname[0] != '/')
278 fname = (gchar *)table_find(conf.get_names, fname);
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 }
301 void get_daemon(gint gival, char *argv[])
302 {
303 struct timeval tm;
304 time_t time_before, time_now;
305 int sel_ret;
307 /* setup handler for HUP signal: */
308 signal(SIGHUP, sighup_handler);
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 }
324 /* sel_ret = 0;*/
325 time(&time_before);
326 time_before -= gival;
327 sel_ret = -1;
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;
341 /* race condition, very unlikely (but possible): */
342 if(tm.tv_sec < 0)
343 tm.tv_sec = 0;
344 }
345 }
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");
355 if(argv == NULL) exit(EXIT_SUCCESS);
357 execv(argv[0], &(argv[0]));
358 logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno));
359 exit(EXIT_FAILURE);
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();
371 _exit(EXIT_SUCCESS);
372 }
373 else if(pid < 0){
374 logwrite(LOG_ALERT, "could not fork for get run");
375 }
376 }
377 }
378 }
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;
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);
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 }
410 #endif