1 /*
2 * binkleyforce -- unix FTN mailer project
3 *
4 * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * $Id: outb_scan.c,v 1.1.1.1 2004/09/09 09:52:38 kstepanenkov Exp $
12 */
13
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "util.h"
18 #include "outbound.h"
19
20 s_exttab outtab[] =
21 {
22 { ".iut", TYPE_NETMAIL, FLAVOR_IMMED, ACTION_UNLINK },
23 { ".cut", TYPE_NETMAIL, FLAVOR_CRASH, ACTION_UNLINK },
24 { ".dut", TYPE_NETMAIL, FLAVOR_DIRECT, ACTION_UNLINK },
25 { ".out", TYPE_NETMAIL, FLAVOR_NORMAL, ACTION_UNLINK },
26 { ".hut", TYPE_NETMAIL, FLAVOR_HOLD, ACTION_UNLINK },
27 { ".ikt", TYPE_NETMAIL, FLAVOR_IMMED, ACTION_UNLINK },
28 { ".ckt", TYPE_NETMAIL, FLAVOR_CRASH, ACTION_UNLINK },
29 { ".dkt", TYPE_NETMAIL, FLAVOR_DIRECT, ACTION_UNLINK },
30 { ".pkt", TYPE_NETMAIL, FLAVOR_NORMAL, ACTION_UNLINK },
31 { ".hkt", TYPE_NETMAIL, FLAVOR_HOLD, ACTION_UNLINK },
32 { ".ilo", TYPE_FLOFILE, FLAVOR_IMMED, ACTION_NOTHING },
33 { ".clo", TYPE_FLOFILE, FLAVOR_CRASH, ACTION_NOTHING },
34 { ".dlo", TYPE_FLOFILE, FLAVOR_DIRECT, ACTION_NOTHING },
35 { ".flo", TYPE_FLOFILE, FLAVOR_NORMAL, ACTION_NOTHING },
36 { ".hlo", TYPE_FLOFILE, FLAVOR_HOLD, ACTION_NOTHING },
37 { ".req", TYPE_REQUEST, FLAVOR_NONE, ACTION_NOTHING },
38 { NULL, 0, 0, 0 }
39 };
40
41 s_exttab exttab[] =
42 {
43 { ".tic", TYPE_TICFILE, FLAVOR_NORMAL, ACTION_TRUNCATE },
44 { ".su?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
45 { ".mo?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
46 { ".tu?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
47 { ".we?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
48 { ".th?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
49 { ".fr?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
50 { ".sa?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE },
51 { NULL, 0, 0, 0 }
52 };
53
54 /*****************************************************************************
55 * Devide full outbound path on "root" directory, there other oubound
56 * directories created, and main outbound directory name
57 *
58 * Arguments:
59 * path pointer to the null-terminated outbound path string
60 * out_root pointer to the pointer for the resulting root directory
61 * out_main pointer to the pointer for the resulting main outbound
62 * name w/o path
63 *
64 * Return value:
65 * Zero on success (*out_root and *out_main must be freed)
66 */
out_get_root(const char * path,char ** out_root,char ** out_main)67 int out_get_root(const char *path, char **out_root, char **out_main)
68 {
69 char *p, *outb;
70
71 ASSERT(path != NULL && out_root != NULL && out_main != NULL);
72
73 *out_root = NULL;
74 *out_main = NULL;
75
76 outb = (char *)xstrcpy(path);
77
78 p = outb + strlen(outb) - 1;
79 if( *p == DIRSEPCHR )
80 *p = '\0';
81
82 /* Ohh.. where is no full path for outbound directory */
83 if( (p=strrchr(outb, DIRSEPCHR)) == NULL )
84 {
85 free(outb);
86 return -1;
87 }
88
89 *p = '\0';
90 *out_main = xstrcpy(p+1);
91 *out_root = xstrcat(outb, "/");
92
93 DEB((D_OUTBOUND, "out_getroot: out_root \"%s\", out_main \"%s\"",
94 *out_root, *out_main));
95
96 return 0;
97 }
98
99 /*****************************************************************************
100 * Scan Binkley Style Outbound directory, for each file for requested
101 * addresses call callback function
102 *
103 * Arguments:
104 * callback pointer to the callback information structure
105 * fa_list pointer to the requested addresses list
106 * addr current address (most time it is partially filled)
107 * path path for the outbound to scan
108 * point point number for the current outbound
109 *
110 * Return value:
111 * Zero on success
112 */
out_scan_bso_dir(s_outbound_callback_data * callback,const s_falist * fa_list,s_faddr * addr,const char * path,int point)113 static int out_scan_bso_dir(s_outbound_callback_data *callback,
114 const s_falist *fa_list, s_faddr *addr, const char *path, int point)
115 {
116 DIR *dir;
117 struct dirent *dirent;
118 char *p;
119 const s_falist *alst;
120
121 ASSERT(callback);
122 ASSERT(callback->dest);
123 ASSERT(addr && path);
124
125 DEB((D_OUTBOUND, "out_scan_bso_dir: BSO: scan dir \"%s\"", path));
126
127 if( (dir=opendir(path)) == NULL )
128 {
129 logerr("can't open outbound directory \"%s\"", path);
130 return(1);
131 }
132
133 while( (dirent=readdir(dir)) != NULL )
134 {
135 if( strlen(dirent->d_name) == 12 &&
136 strspn(dirent->d_name, "0123456789abcdefABCDEF") == 8 )
137 {
138 if((strncasecmp(dirent->d_name+8, ".PNT", 4) != 0) &&
139 ( strncasecmp(dirent->d_name+8, ".REQ", 4) != 0) &&
140 ( strncasecmp(dirent->d_name+10, "UT", 2) != 0) &&
141 ( strncasecmp(dirent->d_name+10, "LO", 2) != 0) ) continue;
142 if( point == 0 && strncasecmp(dirent->d_name+8, ".PNT", 4) == 0 )
143 {
144 DEB((D_OUTBOUND, "scan_dir: BSO: found point directory \"%s\"",
145 dirent->d_name));
146
147 /*
148 * Congratulation, we found point's direcory
149 */
150 sscanf(dirent->d_name, "%04x%04x", &addr->net, &addr->node);
151 for( alst = fa_list; alst; alst = alst->next )
152 if( addr->net == alst->addr.net
153 && addr->node == alst->addr.node )
154 break;
155
156 if( alst || !fa_list )
157 {
158 p = string_concat(path, dirent->d_name, "/", NULL);
159 out_scan_bso_dir(callback, fa_list, addr, p, 1);
160 if( p ) { free(p); p = NULL; }
161 }
162 }
163 else
164 {
165 if( point )
166 {
167 sscanf(dirent->d_name, "%08x", &addr->point);
168 }
169 else
170 {
171 addr->point = 0;
172 sscanf(dirent->d_name, "%04x%04x", &addr->net, &addr->node);
173 }
174
175 /* Check, does we really need in this file? */
176 for( alst = fa_list; alst && ftn_addrcomp(*addr, alst->addr);
177 alst = alst->next );
178
179 if( alst || !fa_list )
180 {
181 callback->path = string_concat(path, dirent->d_name, NULL);
182 callback->addr = *addr;
183 callback->type = OUTB_TYPE_BSO;
184 callback->flavor = -1;
185 callback->callback(callback);
186 if( callback->path )
187 free(callback->path);
188 }
189 }
190 }
191 }
192
193 closedir(dir);
194
195 return(0);
196 }
197
out_scan_bso(s_outbound_callback_data * callback,const s_falist * mailfor,const char * path)198 static int out_scan_bso(s_outbound_callback_data *callback,
199 const s_falist *mailfor, const char *path)
200 {
201 DIR *dir;
202 struct dirent *dirent;
203 const s_falist *alst;
204 s_faddr addr;
205 char *newpath;
206 char *out_root = NULL; /* Root for outbound directories tree */
207 char *out_main = NULL; /* Main outbound directory name */
208 int len;
209
210 ASSERT(path);
211
212 if( out_get_root(path, &out_root, &out_main) )
213 return -1;
214
215 ASSERT(out_root && out_main);
216
217 if( (dir = opendir(out_root)) == NULL )
218 {
219 logerr("can't open outbound directory \"%s\"", out_root);
220 free(out_root); free(out_main);
221 return -1;
222 }
223
224 /* Scan outbound (only 4D) */
225 while( (dirent = readdir(dir)) )
226 {
227 memset(&addr, '\0', sizeof(s_faddr));
228 if( strcmp(dirent->d_name, out_main) == 0 )
229 {
230 /* Our main outbound */
231 s_cval_entry *cfptr = conf_first(cf_address);
232 if( cfptr )
233 addr.zone = cfptr->d.falist.addr.zone;
234 else
235 addr.zone = 666;
236 }
237 else if( strncmp(dirent->d_name, out_main, len=strlen(out_main)) == 0
238 && dirent->d_name[len] == '.'
239 && strspn(dirent->d_name+len+1,"0123456789abcdefABCDEF") == 3 )
240 {
241 /* Ooutbound with zone ext. (like /outbound.308/) */
242 sscanf(dirent->d_name+len+1, "%03x", &addr.zone);
243 }
244
245 if( addr.zone )
246 {
247 for( alst = mailfor;
248 alst && addr.zone != alst->addr.zone;
249 alst = alst->next );
250
251 if( alst || mailfor == NULL )
252 {
253 newpath = string_concat(out_root, dirent->d_name, "/", NULL);
254 out_scan_bso_dir(callback, mailfor, &addr, newpath, 0);
255 free(newpath);
256 }
257 }
258 }
259
260 closedir(dir);
261
262 free(out_root);
263 free(out_main);
264
265 return 0;
266 }
267
out_parse_name_lbox(s_faddr * addr,const char * filename)268 static int out_parse_name_lbox(s_faddr *addr, const char *filename)
269 {
270 s_faddr tmp;
271
272 ASSERT(addr && filename);
273
274 memset(&tmp, '\0', sizeof(s_faddr));
275 if( sscanf(filename, "%d.%d.%d.%d",
276 &tmp.zone, &tmp.net, &tmp.node, &tmp.point) == 4 )
277 {
278 *addr = tmp;
279 return 0;
280 }
281
282 return -1;
283 }
284
out_scan_fbox_dir(s_outbound_callback_data * callback,const char * path,s_faddr addr,int flavor)285 static int out_scan_fbox_dir(s_outbound_callback_data *callback,
286 const char *path, s_faddr addr, int flavor)
287 {
288 DIR *dir;
289 struct dirent *dirent;
290
291 if( (dir = opendir(path)) == NULL )
292 {
293 logerr("can't open filebox directory \"%s\"", path);
294 return -1;
295 }
296
297 while( (dirent = readdir(dir)) )
298 {
299 callback->path = string_concat(path, dirent->d_name, NULL);
300 if( is_regfile(callback->path) )
301 {
302 callback->addr = addr;
303 callback->type = OUTB_TYPE_FBOX;
304 callback->flavor = flavor;
305 callback->callback(callback);
306 }
307 free(callback->path);
308 callback->path = NULL;
309 }
310
311 closedir(dir);
312
313 return 0;
314 }
315
out_scan_lbox(s_outbound_callback_data * callback,const s_falist * mailfor,const char * path)316 static int out_scan_lbox(s_outbound_callback_data *callback,
317 const s_falist *mailfor, const char *path)
318 {
319 DIR *dir;
320 struct dirent *dirent;
321 const s_falist *alst;
322 s_faddr addr;
323 char *newpath;
324
325 if( (dir = opendir(path)) == NULL )
326 {
327 logerr("can't open filebox directory \"%s\"", path);
328 return -1;
329 }
330
331 while( (dirent = readdir(dir)) )
332 {
333 if( out_parse_name_lbox(&addr, dirent->d_name) == 0 )
334 {
335 if( mailfor )
336 {
337 /* Scan only this fileboxes */
338 for( alst = mailfor;
339 alst && ftn_addrcomp(addr, alst->addr);
340 alst = alst->next );
341 if( alst )
342 {
343 newpath = string_concat(path, dirent->d_name, "/", NULL);
344 (void)out_scan_fbox_dir(callback, newpath, addr, FLAVOR_HOLD);
345 free(newpath);
346 }
347 }
348 else
349 {
350 /* Scan all fileboxes */
351 newpath = string_concat(path, dirent->d_name, "/", NULL);
352 (void)out_scan_fbox_dir(callback, newpath, addr, FLAVOR_HOLD);
353 free(newpath);
354 }
355 }
356 }
357
358 closedir(dir);
359
360 return 0;
361 }
362
363 /*****************************************************************************
364 * Parse file name from AmigaDos Style Outbound
365 *
366 * Arguments:
367 * name pointer to the null-terminated file name
368 * addr pointer to the memory where to store resulting address
369 *
370 * Return value:
371 * Zero on success
372 */
out_parse_name_aso(s_faddr * addr,const char * filename)373 int out_parse_name_aso(s_faddr *addr, const char *filename)
374 {
375 s_faddr tmp;
376
377 ASSERT(addr && filename);
378
379 memset(&tmp, '\0', sizeof(s_faddr));
380 if( sscanf(filename, "%d.%d.%d.%d.%*s", &tmp.zone,
381 &tmp.net, &tmp.node, &tmp.point) == 4 )
382 {
383 *addr = tmp;
384 return 0;
385 }
386
387 return -1;
388 }
389
out_scan_aso(s_outbound_callback_data * callback,const s_falist * mailfor,const char * path)390 static int out_scan_aso(s_outbound_callback_data *callback,
391 const s_falist *mailfor, const char *path)
392 {
393 DIR *dir;
394 struct dirent *dirent;
395 const s_falist *alst;
396 s_faddr addr = { FALSE, 0, 0, 0, 0, "" };
397 #ifdef DEBUG
398 char abuf[BF_MAXADDRSTR+1];
399 #endif
400
401 ASSERT(callback);
402 ASSERT(callback->dest);
403 ASSERT(path);
404
405 DEB((D_OUTBOUND, "out_scandir_aso: scan dir \"%s\"", path));
406
407 if( (dir = opendir(path)) == NULL )
408 {
409 logerr("can't open outbound directory \"%s\"", path);
410 return -1;
411 }
412
413 while( (dirent = readdir(dir)) )
414 {
415 memset(&addr, '\0', sizeof(s_faddr));
416
417 if( out_parse_name_aso(&addr, dirent->d_name) == 0 )
418 {
419 DEB((D_OUTBOUND, "out_scandir_aso: file \"%s\" for address %s",
420 dirent->d_name, ftn_addrstr(abuf, addr)));
421
422 for( alst = mailfor; alst && ftn_addrcomp(addr, alst->addr);
423 alst = alst->next );
424
425 if( alst || !mailfor )
426 {
427 callback->path = string_concat(path, dirent->d_name, NULL);
428 callback->addr = addr;
429 callback->type = OUTB_TYPE_ASO;
430 callback->flavor = -1;
431 callback->callback(callback);
432 if( callback->path )
433 free(callback->path);
434 }
435 }
436 }
437
438 closedir(dir);
439
440 return 0;
441 }
442
443 /* ------------------------------------------------------------------------- */
444 /* Scan outbound for addresses fa_list, use handler proc */
445 /* ------------------------------------------------------------------------- */
out_scan(s_outbound_callback_data * callback,const s_falist * fa_list)446 int out_scan(s_outbound_callback_data *callback, const s_falist *fa_list)
447 {
448 const s_falist *alst;
449 s_faddr addr = { FALSE, 0, 0, 0, 0, "" };
450 s_cval_entry *cfptr;
451 char *path;
452
453 ASSERT(callback);
454 ASSERT(callback->callback);
455 ASSERT(callback->dest);
456
457 /*
458 * 1st - try out 4D outbound
459 */
460 path = conf_string(cf_outbound_directory);
461 if( path && *path )
462 (void)out_scan_bso(callback, fa_list, path);
463
464 /*
465 * 2th - Scan domain outbounds
466 */
467 for( cfptr = conf_first(cf_domain); cfptr; cfptr = conf_next(cfptr) )
468 {
469 memset(&addr, '\0', sizeof(s_faddr));
470 for( alst = fa_list; alst; alst = alst->next )
471 {
472 if( cfptr->d.domain.zone == alst->addr.zone
473 || alst->addr.zone == -1 )
474 {
475 addr.zone = cfptr->d.domain.zone;
476 out_scan_bso_dir(callback, fa_list, &addr,
477 cfptr->d.domain.path, 0);
478 break;
479 }
480 }
481 }
482
483 /*
484 * 3th - Scan AmigaDOS outbound
485 */
486 path = conf_string(cf_amiga_outbound_directory);
487 if( path && *path )
488 (void)out_scan_aso(callback, fa_list, path);
489
490 /*
491 * 4th - Scan personal fileboxes
492 */
493 if( fa_list )
494 {
495 /* Scan only listed fileboxes */
496 for( cfptr = conf_first(cf_filebox); cfptr; cfptr = conf_next(cfptr) )
497 {
498 for( alst = fa_list; alst; alst = alst->next )
499 {
500 if( !ftn_addrcomp(alst->addr, cfptr->d.filebox.addr) )
501 out_scan_fbox_dir(callback, cfptr->d.filebox.path,
502 cfptr->d.filebox.addr, cfptr->d.filebox.flavor);
503 }
504 }
505 }
506 else
507 {
508 /* Scan all fileboxes */
509 for( cfptr = conf_first(cf_filebox); cfptr; cfptr = conf_next(cfptr) )
510 out_scan_fbox_dir(callback, cfptr->d.filebox.path,
511 cfptr->d.filebox.addr, cfptr->d.filebox.flavor);
512 }
513
514 /*
515 * 5th - Scan "long" fileboxes
516 */
517 path = conf_string(cf_filebox_directory);
518 if( path && *path )
519 (void)out_scan_lbox(callback, fa_list, path);
520
521 return(0);
522 }
523