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