1 /*:ts=8*/
2 /*****************************************************************************
3 * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4 *
5 *
6 * Toss FTN NetMail/EchoMail
7 *
8 *****************************************************************************
9 * Copyright (C) 1990-2002
10 * _____ _____
11 * | |___ | Martin Junius <mj@fidogate.org>
12 * | | | | | | Radiumstr. 18
13 * |_|_|_|@home| D-51069 Koeln, Germany
14 *
15 * This file is part of FIDOGATE.
16 *
17 * FIDOGATE is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License as published by the
19 * Free Software Foundation; either version 2, or (at your option) any
20 * later version.
21 *
22 * FIDOGATE is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with FIDOGATE; see the file COPYING. If not, write to the Free
29 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 *****************************************************************************/
31
32 #include "fidogate.h"
33 #include "getopt.h"
34
35 #include <signal.h>
36 #include <sys/wait.h>
37 #include <sys/types.h>
38
39 #define PROGRAM "ftntoss"
40 #define CONFIG DEFAULT_CONFIG_MAIN
41
42 /*
43 * Prototypes
44 */
45 void addtoseenby_init(void);
46 void zonegate_init(void);
47 void deleteseenby_init(void);
48 void deletepath_init(void);
49 int lon_to_kludge(Textlist *, char *, LON *);
50 void lon_to_kludge_sorted(Textlist *, char *, LON *);
51 int toss_echomail(Message *, MsgBody *, LON *, LON *, LON *, LON *);
52 void kludge_to_lon(Textlist *, LON *);
53 int node_eq_echo(Node *, Node *);
54 int node_eq_echo_pa(Node *, Node *);
55 int lon_search_echo(LON *, Node *);
56 int is_local_addr(Node *, char);
57 void do_seenby(LON *, LON *, LON *, LON *, int, Node *);
58 void do_path(LON *);
59 int do_check_path(LON *);
60 int do_bad_msg(Message *, MsgBody *);
61 Node *lon_first(LON *);
62 void do_4dpoint(LON *, LON *, Node *, Node *);
63 int do_echomail(Packet *, Message *, MsgBody *);
64 int do_unknown_area(char *, Message *, MsgBody *);
65 #ifdef DO_NOT_TOSS_NETMAIL
66 void add_via(Textlist *, Node *);
67 #endif /* DO_NOT_TOSS_NETMAIL */
68 void change_addr(Node *, Node *);
69 void do_rewrite(Message *);
70 int do_remap(Message *);
71 int check_empty(MsgBody *);
72 #ifndef SPYES
73 int do_netmail(Packet *, Message *, MsgBody *);
74 #else
75 int do_netmail(Packet *, Message *, MsgBody *, int);
76 #endif /* !SPYES */
77 int unpack(FILE *, Packet *);
78 int unpack_file(char *);
79 void prog_signal(int);
80 void short_usage(void);
81 void usage(void);
82
83 extern int authorized_new;
84 static char *areas_bbs = NULL;
85
86 void areafix_init(int);
87 int areafix_auth_check(Node *, char *, char);
88 int cmd_new_int(Node *, char *, char *);
89 int areafix_check_forbidden_area(char *);
90
91 /*
92 * Command line options
93 */
94 char g_flag = 'n'; /* Processing grade */
95 char t_flag = FALSE; /* Insecure tossing enabled */
96 char n_flag = FALSE; /* Accept EchoMail messages not */
97 /* addressed to our AKA */
98 char *O_flag = NULL; /* output packet directory */
99 char s_flag = FALSE; /* Strip CRASH, HOLD attribute */
100 int maxmsg = 0; /* Process maxmsg messages */
101 char x_flag = FALSE; /* Exit after maxmsg messages */
102 char l_flag = FALSE; /* Create lock file */
103 char p_flag = FALSE; /* -p --passthru */
104
105 static char in_dir[MAXPATH]; /* Input directory */
106 static char must_exit = FALSE; /* Flag for -x operation */
107 static int msg_count = 0; /* Counter for -m, -x operation */
108 static int severe_error = OK; /* ERROR: exit after error */
109 static int signal_exit = FALSE; /* Flag: TRUE if signal received */
110
111 short int int_uplinks = FALSE; /* Flag: TRUE if uplinks initialised */
112
113 /*
114 * Config options
115 */
116 char kill_empty = FALSE; /* config: KillEmpty */
117 char kill_unknown = FALSE; /* config: KillUnknown */
118 char kill_routed = FALSE; /* config: KillRouted */
119 char kill_insecure = FALSE; /* config: KillInsecure */
120 #ifdef FTN_ACL
121 char kill_readonly = FALSE; /* config: KillReadonly */
122 #endif /* FTN_ACL */
123 char kill_circular = FALSE; /* config: KillCircular */
124 char log_netmail = FALSE; /* config: LogNetMail */
125 char check_path = FALSE; /* config: CheckPath */
126 char dupe_check = FALSE; /* config: DupeCheck */
127 char kill_dupe = FALSE; /* config: KillDupe */
128 char kill_nomsgid = FALSE; /* config: KillNoMSGID */
129 char kill_old = FALSE; /* config: KillOld */
130 char echomail4d = FALSE; /* config: EchoMail4D */
131 char no_empty_path = FALSE; /* config: NoEmptyPath */
132 char add_other_aka = FALSE; /* config: AddOtherAKAs */
133 #ifdef FTN_ACL
134 char uplink_can_be_readonly = FALSE; /* config: UplinkCanBeReadonly */
135 #endif /* FTN_ACL */
136 char traffic_statistics = FALSE; /* config: TrafficStatistics */
137 char *traffic_statistics_file = NULL; /* config: TrafficStatisticsFile */
138 char *autocreate_line = ""; /* config: AutoCreateLine */
139 #ifndef ACTIVE_LOOKUP
140 char autocreate_ng = FALSE; /* config: AutoCreateNG */
141 #endif /* !ACTIVE_LOOKUP */
142 #ifdef DO_NOT_TOSS_NETMAIL
143 char no_rewrite = FALSE; /* config: NoRewrite */
144 #endif /* DO_NOT_TOSS_NETMAIL */
145
146 short check_point_origin_addr = FALSE;
147 /* Values checking for old messages */
148 static double max_history = 14; /* Max. number of days entry stays
149 in MSGID history database */
150 static time_t max_sec = 0;
151 static time_t now_sec = 0;
152 static time_t exp_sec = 0;
153
154 /*
155 * Global stat counts
156 */
157 static long msgs_in = 0; /* Input messages */
158 static long msgs_netmail = 0; /* Output messages NetMail */
159 static long msgs_echomail = 0; /* Output messages EchoMail */
160 static long msgs_routed = 0; /* Routed EchoMail messages */
161 static long msgs_insecure = 0; /* Insecure EchoMail messages */
162 #ifdef FTN_ACL
163 static long msgs_readonly = 0; /* EchoMail messages to readonly areas */
164 #endif /* FTN_ACL */
165 static long msgs_unknown = 0; /* Unknown EchoMail area messages */
166 static long msgs_empty = 0; /* Empty NetMail messages */
167 static long msgs_path = 0; /* Circular path */
168 static long msgs_dupe = 0; /* Dupe */
169
170 static long pkts_in = 0; /* Input packets */
171 static long pkts_bytes = 0; /* Input bytes */
172
173 static Textlist notify;
174
175 /*
176 * AddToSeenBy list
177 */
178 typedef struct st_addtoseenby {
179 char *area; /* Area pattern */
180 LON add; /* Nodes to add to SEEN-BY */
181 struct st_addtoseenby *next;
182 } AddToSeenBy;
183
184 static AddToSeenBy *addto_first = NULL;
185 static AddToSeenBy *addto_last = NULL;
186 static bool strict;
187
188 /*
189 * Init AddToSeenBy list from config file
190 */
addtoseenby_init(void)191 void addtoseenby_init(void)
192 {
193 char *s, *parea, *pnodes;
194 AddToSeenBy *p;
195
196 for (s = cf_get_string("AddToSeenBy", TRUE);
197 s && *s; s = cf_get_string("AddToSeenBy", FALSE)) {
198 BUF_COPY(buffer, s);
199 parea = xstrtok(buffer, " \t");
200 pnodes = xstrtok(NULL, "\n");
201
202 if (!parea || !pnodes)
203 continue;
204
205 p = (AddToSeenBy *) xmalloc(sizeof(AddToSeenBy));
206 p->next = NULL;
207 p->area = strsave(parea);
208 lon_init(&p->add);
209 lon_add_string(&p->add, pnodes);
210
211 if (addto_first)
212 addto_last->next = p;
213 else
214 addto_first = p;
215 addto_last = p;
216 }
217 }
218
219 /*
220 * DeleteSeenBy list
221 */
222 typedef struct st_deleteseenby {
223 LON deleteseenby; /* Nodes to delete from SEEN-BY */
224 struct st_deleteseenby *next;
225 } DeleteSeenBy;
226
227 static DeleteSeenBy *deleteseenby_first = NULL;
228 static DeleteSeenBy *deleteseenby_last = NULL;
229
230 /*
231 * Init DeleteSeenBy list from config file
232 */
deleteseenby_init(void)233 void deleteseenby_init(void)
234 {
235 char *s;
236 DeleteSeenBy *p;
237
238 for (s = cf_get_string("DeleteSeenBy", TRUE);
239 s && *s; s = cf_get_string("DeleteSeenBy", FALSE)) {
240 p = (DeleteSeenBy *) xmalloc(sizeof(DeleteSeenBy));
241 p->next = NULL;
242 lon_init(&p->deleteseenby);
243 lon_add_string(&p->deleteseenby, s);
244
245 if (deleteseenby_first)
246 deleteseenby_last->next = p;
247 else
248 deleteseenby_first = p;
249 deleteseenby_last = p;
250 }
251 }
252
253 /*
254 * DeletePath list
255 */
256 typedef struct st_deletepath {
257 LON deletepath; /* Nodes to delete from PATH */
258 struct st_deletepath *next;
259 } DeletePath;
260
261 static DeletePath *deletepath_first = NULL;
262 static DeletePath *deletepath_last = NULL;
263
264 /*
265 * Init DeletePath list from config file
266 */
deletepath_init(void)267 void deletepath_init(void)
268 {
269 char *s;
270 DeletePath *p;
271
272 for (s = cf_get_string("DeletePath", TRUE);
273 s && *s; s = cf_get_string("DeletePath", FALSE)) {
274 p = (DeletePath *) xmalloc(sizeof(DeletePath));
275 p->next = NULL;
276 lon_init(&p->deletepath);
277 lon_add_string(&p->deletepath, s);
278
279 if (deletepath_first)
280 deletepath_last->next = p;
281 else
282 deletepath_first = p;
283 deletepath_last = p;
284 }
285 }
286
287 /*
288 * Zonegate list
289 */
290
291 static ZoneGate *zonegate_first = NULL;
292 static ZoneGate *zonegate_last = NULL;
293
294 /*
295 * Init zonegate list
296 */
zonegate_init(void)297 void zonegate_init(void)
298 {
299 char *s;
300 ZoneGate *p;
301
302 for (s = cf_get_string("ZoneGate", TRUE);
303 s && *s; s = cf_get_string("ZoneGate", FALSE)) {
304 p = (ZoneGate *) xmalloc(sizeof(ZoneGate));
305 p->next = NULL;
306 lon_init(&p->seenby);
307 lon_add_string(&p->seenby, s);
308 if (p->seenby.first) {
309 p->node = p->seenby.first->node;
310 lon_remove(&p->seenby, &p->node);
311 } else
312 node_invalid(&p->node);
313
314 if (zonegate_first)
315 zonegate_last->next = p;
316 else
317 zonegate_first = p;
318 zonegate_last = p;
319 }
320 }
321
322 /*
323 * Create new SEEN-BY or ^APATH line from LON
324 */
325 #define MAX_LENGTH 76
326
lon_to_kludge(Textlist * tl,char * text,LON * lon)327 int lon_to_kludge(Textlist * tl, char *text, LON * lon)
328 {
329 LNode *p;
330 Node old;
331 char *s = NULL;
332 int n = 0;
333
334 BUF_COPY(buffer, text);
335 node_invalid(&old);
336 old.zone = cf_zone();
337
338 for (p = lon->first; p; p = p->next)
339 if (p->node.point == 0 || echomail4d) { /* Normally, no 4D Points */
340 p->node.zone = cf_zone(); /* No zone, use current one */
341 s = node_to_asc_diff(&p->node, &old);
342 old = p->node;
343
344 if (strlen_zero(buffer) + strlen_zero(s) + 1 > MAX_LENGTH) {
345 BUF_APPEND(buffer, "\r\n");
346 tl_append(tl, buffer);
347
348 node_invalid(&old);
349 old.zone = cf_zone();
350
351 s = node_to_asc_diff(&p->node, &old);
352 old = p->node;
353 BUF_COPY3(buffer, text, " ", s);
354 } else
355 BUF_APPEND2(buffer, " ", s);
356
357 n = TRUE;
358 }
359
360 BUF_APPEND(buffer, "\r\n");
361 tl_append(tl, buffer);
362
363 return n;
364 }
365
lon_to_kludge_sorted(Textlist * tl,char * text,LON * lon)366 void lon_to_kludge_sorted(Textlist * tl, char *text, LON * lon)
367 {
368 Node old;
369 char *s = NULL;
370 int i;
371
372 lon_sort(lon, FALSE);
373
374 BUF_COPY(buffer, text);
375 node_invalid(&old);
376 old.zone = cf_zone();
377
378 for (i = 0; i < lon->size; i++)
379 if (lon->sorted[i]->point == 0 || echomail4d) { /* Normally, no 4D Points */
380 lon->sorted[i]->zone = cf_zone(); /* No zone, use current one */
381 s = node_to_asc_diff(lon->sorted[i], &old);
382 old = *lon->sorted[i];
383
384 if (strlen_zero(buffer) + strlen_zero(s) + 1 > MAX_LENGTH) {
385 BUF_APPEND(buffer, "\r\n");
386 tl_append(tl, buffer);
387
388 node_invalid(&old);
389 old.zone = cf_zone();
390
391 s = node_to_asc_diff(lon->sorted[i], &old);
392 old = *lon->sorted[i];
393 BUF_COPY3(buffer, text, " ", s);
394 } else
395 BUF_APPEND2(buffer, " ", s);
396 }
397
398 BUF_APPEND(buffer, "\r\n");
399 tl_append(tl, buffer);
400
401 return;
402 }
403
404 /*
405 * Toss EchoMail, writing message to packet for each downlink
406 */
toss_echomail(Message * msg,MsgBody * body,LON * seenby,LON * path,LON * nodes,LON * passive)407 int toss_echomail(Message * msg, MsgBody * body, LON * seenby, LON * path,
408 LON * nodes, LON * passive)
409 {
410 LNode *p;
411 FILE *fp;
412 Textlist save = { NULL, NULL, 0 };
413 char is_saved;
414
415 for (p = nodes->first; p; p = p->next) {
416 is_saved = FALSE;
417
418 if (lon_search(passive, &(p->node)))
419 continue;
420
421 debug(7, "toss_echomail(): message for %s", znfp1(&p->node));
422
423 /* Check for msg addressed to zonegate */
424 if (zonegate_first) {
425 ZoneGate *pz;
426
427 for (pz = zonegate_first; pz; pz = pz->next)
428 if (node_eq(&p->node, &pz->node)) {
429 debug(7, "toss_echomail(): message is for zonegate, "
430 "stripping SEEN-BYs");
431 save = body->seenby;
432 tl_init(&body->seenby);
433 is_saved = TRUE;
434 lon_to_kludge_sorted(&body->seenby,
435 "SEEN-BY:", &pz->seenby);
436 break;
437 }
438 }
439
440 /* Rewrite message header */
441 msg->node_to = p->node;
442 #ifdef BEST_AKA
443 cf_set_best(msg->node_to.zone, msg->node_to.net, msg->node_to.node);
444 #endif /* BEST_AKA */
445 msg->node_from = cf_n_addr();
446 /* Open packet file, EchoMail, Normal */
447 fp = outpkt_open(cf_addr(), &p->node, g_flag, 'e', 'n', FALSE);
448 if (fp == NULL)
449 return severe_error = ERROR;
450 /* Write message header and body */
451 if (pkt_put_msg_hdr(fp, msg, FALSE) != OK)
452 return severe_error = ERROR;
453 if (msg_put_msgbody(fp, body) != OK)
454 return severe_error = ERROR;
455
456 if (is_saved) {
457 tl_clear(&body->seenby);
458 body->seenby = save;
459 }
460
461 msgs_echomail++;
462 }
463
464 return OK;
465 }
466
467 /*
468 * Convert SEEN-BY or ^APATH lines to LON
469 */
kludge_to_lon(Textlist * tl,LON * lon)470 void kludge_to_lon(Textlist * tl, LON * lon)
471 {
472 Node old, node;
473 Textline *l;
474 char *p;
475
476 for (l = tl->first; l; l = l->next) {
477 p = l->line;
478 /* Skip SEEN-BY:, ^APATH: or whatever, copy to buffer[] */
479 while (*p && !is_space(*p) && *p != ':')
480 p++;
481 if (*p == ':')
482 p++;
483 while (*p && is_space(*p))
484 p++;
485 BUF_COPY(buffer, p);
486 strip_crlf(buffer);
487 /* Tokenize and convert to node addresses */
488 node_invalid(&old);
489 old.zone = cf_zone();
490 for (p = strtok(buffer, " \t"); p; p = strtok(NULL, " \t"))
491 if (asc_to_node_diff(p, &node, &old) == OK) {
492 lon_add(lon, &node);
493 old = node;
494 }
495 }
496
497 return;
498 }
499
500 /*
501 * node_eq_echo() --- compare node adresses, ignoring zone
502 */
node_eq_echo(Node * a,Node * b)503 int node_eq_echo(Node * a, Node * b)
504 {
505 if (a == NULL || b == NULL)
506 return FALSE;
507
508 return a->net == b->net && a->node == b->node && a->point == b->point;
509 }
510
511 /*
512 * node_eq_echo_pa() --- compare node adresses, ignoring zone and point
513 * if a->point == 0.
514 */
node_eq_echo_pa(Node * a,Node * b)515 int node_eq_echo_pa(Node * a, Node * b)
516 {
517 if (a == NULL || b == NULL)
518 return FALSE;
519
520 return
521 a->net == b->net && a->node == b->node &&
522 (a->point == 0 || a->point == b->point);
523 }
524
525 /*
526 * Search node in SEEN-BY list, ignoring zone
527 */
lon_search_echo(LON * lon,Node * node)528 int lon_search_echo(LON * lon, Node * node)
529 {
530 LNode *p;
531
532 for (p = lon->first; p; p = p->next)
533 if (node_eq_echo(&p->node, node))
534 return TRUE;
535
536 return FALSE;
537 }
538
539 /*
540 * Check for local address
541 */
is_local_addr(Node * node,char only3d)542 int is_local_addr(Node * node, char only3d)
543 {
544 Node *n;
545 char found = FALSE;
546
547 for (n = cf_addr_trav(TRUE); n; n = cf_addr_trav(FALSE))
548 if (only3d ? node_eq_echo(node, n) : node_eq(node, n)) {
549 found = TRUE;
550 break;
551 }
552
553 return found;
554 }
555
556 /*
557 * Add nodes to SEEN-BY
558 */
do_seenby(LON * seenby,LON * nodes,LON * new,LON * passive,int cup,Node * from)559 void do_seenby(LON * seenby, LON * nodes, LON * new, LON * passive, int cup,
560 Node * from)
561 /* seenby --- nodes in SEEN-BY lines */
562 /* nodes --- nodes in AREAS.BBS */
563 /* new --- new nodes added */
564 {
565 LNode *p;
566 int j = 1;
567
568 for (p = nodes->first; p; p = p->next, j++)
569 if (!lon_search_echo(seenby, &p->node)) {
570 if (j < cup || node_eq(from, &p->node))
571 continue;
572
573 if ((NULL != passive) && !lon_search(passive, &(p->node))) {
574 lon_add(seenby, &p->node);
575 if (new)
576 lon_add(new, &p->node);
577 }
578 }
579
580 return;
581 }
582
583 /*
584 * Add current address to ^APATH
585 */
do_path(LON * path)586 void do_path(LON * path)
587 {
588 if (path->last && node_eq_echo(&path->last->node, cf_addr()))
589 /* Already there */
590 return;
591
592 lon_add(path, cf_addr());
593 return;
594 }
595
596 /*
597 * Check ^APATH for circular path
598 */
do_check_path(LON * path)599 int do_check_path(LON * path)
600 {
601 LNode *p;
602
603 for (p = path->first; p; p = p->next)
604 if (p->next) /* Don't check last node in list */
605 if (is_local_addr(&p->node, TRUE))
606 return ERROR;
607
608 return OK;
609 }
610
611 /*
612 * Save bad message
613 */
do_bad_msg(Message * msg,MsgBody * body)614 int do_bad_msg(Message * msg, MsgBody * body)
615 {
616 FILE *fp;
617
618 /* Open packet file, EchoMail, Normal */
619 fp = outpkt_open(&msg->node_from, &msg->node_to, 'b', 'a', 'd', TRUE);
620 if (fp == NULL)
621 return severe_error = ERROR;
622 /* Write message header and body */
623 if (pkt_put_msg_hdr(fp, msg, FALSE) != OK)
624 return severe_error = ERROR;
625 if (msg_put_msgbody(fp, body) != OK)
626 return severe_error = ERROR;
627
628 return OK;
629 }
630
631 /*
632 * First node in LON
633 */
lon_first(LON * lon)634 Node *lon_first(LON * lon)
635 {
636 if (lon->first)
637 return &lon->first->node;
638
639 return NULL;
640 }
641
642 /*
643 * Special SEEN-BY / PATH processing if message originates from a 4d point
644 */
do_4dpoint(LON * seenby,LON * path,Node * from,Node * addr)645 void do_4dpoint(LON * seenby, LON * path, Node * from, Node * addr)
646 {
647 /*
648 * If there is only one node in SEEN-BY, which is the same address
649 * (2d) as the sender, then replace it with the sender 4d address.
650 */
651 if (seenby->size == 1 && node_eq_echo_pa(lon_first(seenby), from))
652 *lon_first(seenby) = *from;
653
654 /*
655 * Same for PATH
656 */
657 if (path->size == 1 && node_eq_echo_pa(lon_first(path), from))
658 *lon_first(path) = *from;
659
660 /*
661 * Now make sure that also our current AKA is in SEEN-BY
662 */
663 if (!lon_search_echo(seenby, cf_addr()))
664 lon_add(seenby, cf_addr());
665
666 return;
667 }
668
669 /*
670 * SEEN-BY remove processing
671 */
do_deleteseenby(LON * seenby)672 void do_deleteseenby(LON * seenby)
673 {
674 LNode *p;
675 LON *ln;
676
677 ln = &deleteseenby_first->deleteseenby;
678
679 lon_debug(9, "do_deleteseenby(): List of SEEN-BYs for removing: ",
680 ln, FALSE);
681
682 for (p = ln->first; p; p = p->next) {
683 if (lon_search(seenby, &p->node)) {
684 debug(7, "do_deleteseenby(): Found SEEN-BY for removing: %s",
685 znf1(&p->node));
686 lon_remove(seenby, &p->node);
687 }
688 }
689 }
690
691 /*
692 * PATH remove processing
693 */
do_deletepath(LON * path)694 void do_deletepath(LON * path)
695 {
696 LNode *p;
697 LON *ln;
698
699 ln = &deleteseenby_first->deleteseenby;
700
701 lon_debug(9, "do_deletepath(): List of PATH for removing: ", ln, FALSE);
702
703 for (p = ln->first; p; p = p->next) {
704 if (lon_search(path, &p->node)) {
705 debug(7, "do_deletepath(): Found PATH for removing: %s",
706 znf1(&p->node));
707 lon_remove(path, &p->node);
708 }
709 }
710 }
711
712 /*
713 * Unknown area
714 */
do_unknown_area(char * areaname,Message * msg,MsgBody * body)715 int do_unknown_area(char *areaname, Message * msg, MsgBody * body)
716 {
717
718 fglog("unknown area %s from %s", areaname, znfp1(&msg->node_from));
719 msgs_unknown++;
720 if (!kill_unknown)
721 return do_bad_msg(msg, body);
722 return OK;
723 }
724
725 /*
726 * Process EchoMail message
727 */
do_echomail(Packet * pkt,Message * msg,MsgBody * body)728 int do_echomail(Packet * pkt, Message * msg, MsgBody * body)
729 {
730 AreasBBS *area;
731 AddToSeenBy *addto;
732 LON seenby, path, new;
733 int ret;
734 Node *node;
735 #ifdef SECURITY
736 Node node2;
737 #endif /* SECURITY */
738 char areaname[BUFSIZ];
739 char autocreate_cmd[BUFSIZ];
740 #ifndef ACTIVE_LOOKUP
741 char autocreate_ng_cmd[MAXPATH];
742 Area *autocreate_area;
743 #endif /* !ACTIVE_LOOKUP */
744 Passwd *pwd;
745
746 /*
747 * Lookup area and set zone
748 */
749 BUF_COPY(areaname, body->area + 5);
750 strip_crlf(areaname);
751 debug(5, "EchoMail AREA: %s", areaname);
752
753 #ifdef SECURITY
754 /*
755 * Security checks
756 */
757 node_invalid(&node2);
758
759 /* No Origin or MSGID address => bad */
760 if (node_eq(&node2, &msg->node_orig)) {
761 /* No origin line address => bad message */
762 fglog("bad echomail (no origin addr) area %s from %s",
763 areaname, znfp1(&msg->node_from));
764 ++msgs_insecure;
765 if (!kill_insecure)
766 return do_bad_msg(msg, body);
767 return OK;
768 }
769
770 if (check_point_origin_addr == TRUE &&
771 0 != pkt->from.point && !node_eq(&msg->node_orig, &pkt->from)) {
772 /* forged origin line address => bad mesage */
773 fglog("bad echomail (forged origin addr) area %s from %s",
774 areaname, znfp1(&msg->node_from));
775 ++msgs_insecure;
776 if (!kill_insecure)
777 return do_bad_msg(msg, body);
778 return OK;
779 }
780 #endif /* !SECURITY */
781
782 if (NULL != (pwd = passwd_lookup("packet", &msg->node_from)) &&
783 stricmp(pkt->passwd, pwd->passwd)) {
784 fglog("Insecure echomail packet from %s, area %s (%s pkt password)",
785 znfp1(&msg->node_from), areaname,
786 ('\0' == *(pkt->passwd)) ? "no" : "bad");
787 ++msgs_insecure;
788 if (!kill_insecure)
789 return do_bad_msg(msg, body);
790 return OK;
791 }
792
793 if (NULL == (area = areasbbs_lookup(areaname))) {
794
795 AreaUplink *a;
796
797 areafix_init(TRUE);
798
799 areafix_auth_check(&msg->node_from, NULL, FALSE);
800
801 if (!authorized_new) {
802 fglog
803 ("node %s not authorized to create area %s (config restriction)",
804 znfp1(&msg->node_from), areaname);
805 /* Unknown area */
806 do_unknown_area(areaname, msg, body);
807 return OK;
808 }
809
810 if (areafix_check_forbidden_area(areaname)) {
811 fglog("area %s is forbidden to create", areaname);
812 /* Unknown area */
813 do_unknown_area(areaname, msg, body);
814 return OK;
815 }
816
817 if (!int_uplinks) {
818 uplinks_init();
819 int_uplinks = TRUE;
820 }
821 a = uplinks_line_get(TRUE, &msg->node_from);
822 if (a != NULL && a->options != NULL)
823 BUF_COPY5(autocreate_cmd, areaname, " ", autocreate_line, " ",
824 a->options);
825 else
826 BUF_COPY3(autocreate_cmd, areaname, " ", autocreate_line);
827
828 if (OK != cmd_new_int(&msg->node_from, autocreate_cmd, NULL)) {
829 fglog("can't create area %s from %s (cmd_new() returned ERROR)",
830 areaname, znfp1(&msg->node_from));
831 do_unknown_area(areaname, msg, body);
832 return OK;
833 }
834
835 if (NULL == (area = areasbbs_lookup(areaname))) {
836 fglog("can't create area %s from %s (not found after creation)",
837 areaname, znfp1(&msg->node_from));
838 do_unknown_area(areaname, msg, body);
839 return OK;
840 }
841
842 fglog("created area %s from %s", areaname, znfp1(&msg->node_from));
843
844 /*
845 * Create newsgroup if needed.
846 */
847
848 #ifndef ACTIVE_LOOKUP
849 if (autocreate_ng) {
850 areas_init();
851
852 if (NULL !=
853 (autocreate_area = areas_lookup(areaname, NULL, &pkt->to))) {
854 BUF_COPY2(autocreate_ng_cmd, "%N/ngoper create ",
855 autocreate_area->group);
856 ret = run_system(autocreate_ng_cmd);
857 if (0 != ret)
858 fglog("can't create newsgroup (rc != 0)");
859 } else {
860 fglog("can't create newsgroup (not found in areas)");
861 }
862 }
863 #endif /* !ACTIVE_LOOKUP */
864 }
865
866 /* Set address for this area */
867 if (area->zone != -1)
868 cf_set_zone(area->zone);
869 if (area->addr.zone != -1)
870 cf_set_curr(&area->addr);
871
872 (area->msgs_in)++;
873
874 /*
875 * Dupe check
876 */
877 if (dupe_check) {
878 char *p, *msgid;
879 Textline *tl;
880
881 if ((p = kludge_get(&body->kludge, "MSGID", &tl))) {
882 /* ^AMSGID */
883 p = tl->line;
884 if (*p == '\001')
885 p++;
886 BUF_COPY3(buffer, area->area, " ", p);
887 strip_crlf(buffer);
888 msgid = buffer;
889 /* Replace char illegal for DBZ */
890 for (p = msgid; *p; p++)
891 if (*p == '\t' || *p == '\r' || *p == '\n')
892 *p = '_';
893 } else {
894 /* If KillNoMSGID ... */
895 if (kill_nomsgid) {
896 fglog("no ^AMSGID treated as dupe from %s(%s): %s",
897 znfp1(&msg->node_from), znfp2(&pkt->from), area->area);
898 msgs_dupe++;
899 (area->msgs_dupe)++;
900
901 if (!kill_dupe)
902 return do_bad_msg(msg, body);
903 return OK;
904 }
905
906 /* No ^AMSGID, use sender, date and checksum */
907 if (msg_parse_origin(body->origin, &msg->node_orig) == ERROR) {
908 fglog("invalid * Origin treated as dupe from %s(%s): %s",
909 znfp1(&msg->node_from), znfp2(&pkt->from), area->area);
910 msgs_dupe++;
911 (area->msgs_dupe)++;
912 if (!kill_dupe)
913 return do_bad_msg(msg, body);
914 return OK;
915 }
916
917 /* Compute CRC for strings from, to, subject */
918 crc32_init();
919 crc32_compute((unsigned char *)msg->name_from,
920 strlen(msg->name_from));
921 crc32_compute((unsigned char *)msg->name_to, strlen(msg->name_to));
922 crc32_compute((unsigned char *)msg->subject, strlen(msg->subject));
923
924 str_printf(buffer, sizeof(buffer), "%s NOMSGID: %s %s %08lx",
925 area->area, znfp1(&msg->node_orig),
926 date("%y%m%d %H%M%S", &msg->date), crc32_value());
927 msgid = buffer;
928 }
929
930 /* Check for old message (date < NOW - MaxHistory) */
931 if (kill_old) {
932 if (msg->date < exp_sec) {
933 fglog
934 ("message too old, treated as dupe: %s origin %s(%s) date %s",
935 area->area, znfp1(&msg->node_orig), znfp2(&pkt->from),
936 date(DATE_FTS_0001, &msg->date));
937 msgs_dupe++;
938 (area->msgs_dupe)++;
939 if (!kill_dupe)
940 return do_bad_msg(msg, body);
941 return OK;
942 }
943 }
944
945 /* Check for existence in MSGID history */
946 if (hi_test(msgid)) {
947 /* Dupe! */
948 fglog("dupe from %s(%s): %s", znfp1(&msg->node_from),
949 znfp2(&pkt->from), msgid);
950 msgs_dupe++;
951 (area->msgs_dupe)++;
952 if (!kill_dupe)
953 return do_bad_msg(msg, body);
954 return OK;
955 } else {
956 /* Put into MSGID history */
957 #ifdef INSECURE_DONT_PUT_INTO_DUPE_DB
958 if (node_eq(cf_addr(), &msg->node_from) ||
959 lon_search(&area->nodes, &msg->node_from))
960 #endif /* INSECURE_DONT_PUT_INTO_DUPE_DB */
961 if (hi_write(msg->date, msgid) == ERROR)
962 return ERROR;
963 }
964 }
965
966 /*
967 * Lookup area in AddToSeenBy list
968 */
969 for (addto = addto_first; addto; addto = addto->next)
970 if (wildmatch(area->area, addto->area, TRUE))
971 break;
972
973 /*
974 * Check that this message is addressed to one of our AKAs
975 */
976 if (!n_flag) {
977 if (!node_eq(&msg->node_to, cf_addr()) &&
978 !is_local_addr(&msg->node_to, FALSE)) {
979 /* Routed EchoMail */
980 fglog("routed echomail area %s from %s to %s", area->area,
981 znfp1(&msg->node_from), znfp2(&msg->node_to));
982 msgs_routed++;
983 (area->msgs_routed)++;
984 if (!kill_routed)
985 return do_bad_msg(msg, body);
986 return OK;
987 }
988 }
989
990 /*
991 * Check that origin is listed in AREAS.BBS
992 */
993 if (!t_flag) {
994 if (!node_eq(cf_addr(), &msg->node_from) &&
995 !lon_search(&area->nodes, &msg->node_from)) {
996 /* Insecure EchoMail */
997 fglog("insecure echomail area %s from %s", area->area,
998 znfp1(&msg->node_from));
999 msgs_insecure++;
1000 (area->msgs_insecure)++;
1001 if (!kill_insecure)
1002 return do_bad_msg(msg, body);
1003 return OK;
1004 }
1005 }
1006
1007 #ifdef FTN_ACL
1008 /*
1009 * Check if link is read only
1010 */
1011 if (uplink_can_be_readonly || !lon_is_uplink(&(area->nodes), area->uplinks,
1012 &(msg->node_from)))
1013 if (ftnacl_isreadonly(&msg->node_from, area->area, TYPE_ECHO)) {
1014 fglog("echomail to read only area %s from %s", area->area,
1015 znfp1(&msg->node_from));
1016
1017 tl_appendf(¬ify, "%s,Sysop,Toss Daemon,insecure echomail,\r\n\
1018 \r\n\tYour message to area %s was delete. This\r\n\
1019 area have status read-only\r\n\r\n\
1020 Your Message:\r\n\r\n\
1021 From: %s\r\n\
1022 To: %s\r\n\
1023 Subject: %s\r\n\r\n", znfp1(&msg->node_from), area->area, nf1(&msg->node_from), znfp1(&pkt->to), msg->subject);
1024
1025 msgs_readonly++;
1026 (area->msgs_readonly)++;
1027 #ifdef FTN_ACL
1028 if (!kill_readonly)
1029 #endif /* FTN_ACL */
1030 return do_bad_msg(msg, body);
1031 #ifdef FTN_ACL
1032 return OK;
1033 #endif /* FTN_ACL */
1034 }
1035 #endif /* FTN_ACL */
1036
1037 /*
1038 * SEEN-BY / ^APATH processing
1039 */
1040 lon_init(&seenby);
1041 lon_init(&path);
1042 lon_init(&new);
1043 kludge_to_lon(&body->seenby, &seenby);
1044 kludge_to_lon(&body->path, &path);
1045
1046 /* Before */
1047 lon_debug(9, "SEEN-BY: ", &seenby, FALSE);
1048 lon_debug(9, "Path : ", &path, FALSE);
1049
1050 /* Special processing if message is from a 4d point */
1051 do_4dpoint(&seenby, &path, &msg->node_from, cf_addr());
1052
1053 /* Make sure that sender/recipient are in SEEN-BY */
1054 if (!lon_search_echo(&seenby, &msg->node_from))
1055 lon_add(&seenby, &msg->node_from);
1056 if (!lon_search_echo(&seenby, &msg->node_to))
1057 lon_add(&seenby, &msg->node_to);
1058
1059 #ifdef SECURITY
1060 /* Make sure that sender is in PATH */
1061 if (NULL == path.last) {
1062 fglog("WARNING: packet hasn't ^APATH, was added %s", nf1(&pkt->from));
1063 lon_add(&path, &pkt->from);
1064 } else if (!node_eq_echo(&path.last->node, &pkt->from)) {
1065 fglog
1066 ("WARNING: last addr ^APATH (%s) isn't eq to addr in pkt header(%s)",
1067 znfp1(&path.last->node), znfp2(&pkt->from));
1068 lon_add(&path, &pkt->from);
1069 }
1070 #endif /* SECURITY */
1071
1072 /* Add nodes not already in SEEN-BY to seenby and new */
1073 do_seenby(&seenby, &area->nodes, &new, &(area->passive), area->uplinks,
1074 &msg->node_from);
1075
1076 /* Add extra nodes to SEEN-BY */
1077 if (addto)
1078 do_seenby(&seenby, &addto->add, NULL, NULL, 0, &msg->node_from);
1079
1080 /* Add all AKAs for the current zone, if AddOtherAKA is set */
1081 if (add_other_aka) {
1082 short z;
1083
1084 z = cf_zone();
1085 for (node = cf_addr_trav(FIRST); node; node = cf_addr_trav(NEXT))
1086 if (node->zone == z && !lon_search_echo(&seenby, node))
1087 lon_add(&seenby, node);
1088 }
1089
1090 /* Delete nodes from SEEN-BY */
1091 if (deleteseenby_first)
1092 do_deleteseenby(&seenby);
1093
1094 /* If not passthru area and not from our own address (point gateway
1095 * setup with Address==Uplink), add our own address to new */
1096 if (!p_flag &&
1097 !(area->flags & AREASBBS_PASSTHRU) &&
1098 !node_eq(&msg->node_from, cf_addr()))
1099 lon_add(&new, cf_addr());
1100 else if (!p_flag &&
1101 !node_eq(&msg->node_from, cf_addr()) &&
1102 lon_search(&area->nodes, cf_addr()))
1103 lon_add(&new, cf_addr());
1104
1105 /* Add our address to end of ^APATH, if not already there */
1106 do_path(&path);
1107
1108 /* Delete nodes from PATH */
1109 if (deletepath_first)
1110 do_deletepath(&path);
1111
1112 /* After */
1113 lon_debug(9, "SEEN-BY: ", &seenby, FALSE);
1114 lon_debug(9, "Path : ", &path, FALSE);
1115 lon_debug(9, "New : ", &new, FALSE);
1116
1117 /*
1118 * Check for circular ^APATH
1119 */
1120 if (check_path && do_check_path(&path) == ERROR) {
1121 /* Circular ^APATH EchoMail */
1122 fglog("circular path echomail area %s from %s to %s",
1123 area->area, znfp1(&msg->node_from), znfp2(&msg->node_to));
1124 msgs_path++;
1125 (area->msgs_path)++;
1126
1127 lon_delete(&seenby);
1128 lon_delete(&path);
1129 lon_delete(&new);
1130
1131 if (!kill_circular)
1132 return do_bad_msg(msg, body);
1133 return OK;
1134 }
1135
1136 if (!lon_is_uplink(&(area->nodes), area->uplinks, &(msg->node_from)) &&
1137 areasbbs_isstate(area->state, 'W')) {
1138 fglog("Area %s have status W, rename to bad", area->area);
1139 lon_delete(&seenby);
1140 lon_delete(&path);
1141 lon_delete(&new);
1142
1143 tl_appendf(¬ify, "%s,Sysop,Toss Daemon,insecure echomail,\r\n\
1144 \r\n\tYour message to area %s was delete. This\r\n\
1145 area have status 'W' (no traffic from uplink)\r\n\r\n\
1146 Your Message:\r\n\r\n\
1147 From: %s\r\n\
1148 To: %s\r\n\
1149 Subject: %s\r\n\r\n", znfp1(&msg->node_from), area->area, nf1(&msg->node_from), znfp1(&pkt->to), msg->subject);
1150
1151 if (!kill_circular)
1152 return do_bad_msg(msg, body);
1153 return OK;
1154
1155 }
1156
1157 if (NULL != area->state) {
1158 if (areasbbs_isstate(area->state, 'U') ||
1159 areasbbs_isstate(area->state, 'W') ||
1160 areasbbs_isstate(area->state, 'F')) {
1161 fglog("setting state 'S' for area %s", area->area);
1162 areasbbs_chstate(&(area->state), "UWF", 'S');
1163 } else if (areasbbs_isstate(area->state, 'P'))
1164 return do_bad_msg(msg, body);
1165 }
1166 area->time = time(NULL);
1167 areasbbs_changed();
1168
1169 /*
1170 * Create new SEEN-BY and ^APATH lines
1171 */
1172 tl_clear(&body->seenby);
1173 tl_clear(&body->path);
1174 lon_to_kludge_sorted(&body->seenby, "SEEN-BY:", &seenby);
1175 ret = lon_to_kludge(&body->path, "\001PATH:", &path);
1176
1177 if (no_empty_path && ret == 0)
1178 tl_clear(&body->path);
1179
1180 /*
1181 * Send message to all downlinks in new
1182 */
1183 ret = toss_echomail(msg, body, &seenby, &path, &new, &(area->passive));
1184
1185 (area->msgs_out)++;
1186 (area->msgs_size) +=
1187 sizeof(body) + sizeof(msg) + sizeof(seenby) + sizeof(path);
1188
1189 lon_delete(&seenby);
1190 lon_delete(&path);
1191 lon_delete(&new);
1192
1193 return ret;
1194 }
1195
1196 /*
1197 * Add our ^AVia line
1198 */
1199 #ifndef DO_NOT_TOSS_NETMAIL
add_via(Textlist * list,Node * gate)1200 void add_via(Textlist * list, Node * gate)
1201 {
1202 #ifndef FTS_VIA
1203 BUF_COPY5(buffer, "Via FIDOGATE/", PROGRAM, znf1(gate),
1204 date(DATE_VIA, NULL), "\r");
1205 tl_append(list, buffer);
1206 #else
1207 BUF_COPY5(buffer, "Via ", znf1(gate), " @", date(DATE_VIA, NULL),
1208 " FIDOGATE/");
1209 BUF_APPEND2(buffer, PROGRAM, "\r");
1210 tl_append(list, buffer);
1211 #endif /* !FTS_VIA */
1212 }
1213
1214 #endif /* !DO_NOT_TOSS_NETMAIL */
1215
1216 /*
1217 * Change address according to rewrite pattern
1218 */
change_addr(Node * node,Node * newpat)1219 void change_addr(Node * node, Node * newpat)
1220 {
1221 if (newpat->zone != -1)
1222 node->zone = newpat->zone;
1223 if (newpat->net != -1)
1224 node->net = newpat->net;
1225 if (newpat->node != -1)
1226 node->node = newpat->node;
1227 if (newpat->point != -1)
1228 node->point = newpat->point;
1229 }
1230
1231 /*
1232 * Perform REWRITE commands
1233 */
do_rewrite(Message * msg)1234 void do_rewrite(Message * msg)
1235 {
1236 Rewrite *r;
1237
1238 for (r = rewrite_first; r; r = r->next) {
1239 /* From */
1240 if (node_match(&msg->node_from, &r->from))
1241 if (r->type == CMD_REWRITE || (r->type == CMD_REWRITE_FROM &&
1242 wildmatch(msg->name_from, r->name,
1243 TRUE))) {
1244 fglog("rewrite(from): %s @ %s -> %s", msg->name_from,
1245 znfp1(&msg->node_from), znfp2(&r->to));
1246
1247 change_addr(&msg->node_from, &r->to);
1248 break;
1249 }
1250 /* To */
1251 if (node_match(&msg->node_to, &r->from))
1252 if (r->type == CMD_REWRITE || (r->type == CMD_REWRITE_TO &&
1253 wildmatch(msg->name_to, r->name,
1254 TRUE))) {
1255 fglog("rewrite(to): %s @ %s -> %s", msg->name_from,
1256 znfp1(&msg->node_from), znfp2(&r->to));
1257
1258 change_addr(&msg->node_from, &r->to);
1259 break;
1260 }
1261 }
1262 }
1263
1264 /*
1265 * Perform REMAP commands
1266 *
1267 * Return == TRUE: remapped to 0:0/0.0, kill message
1268 */
do_remap(Message * msg)1269 int do_remap(Message * msg)
1270 {
1271 Remap *r;
1272 Node node;
1273 char kill = FALSE;
1274
1275 for (r = remap_first; r; r = r->next)
1276 if ((r->type == CMD_REMAP_TO &&
1277 node_match(&msg->node_to, &r->from) &&
1278 wildmatch(msg->name_to, r->name, TRUE))
1279 ||
1280 (r->type == CMD_REMAP_FROM &&
1281 node_match(&msg->node_from, &r->from) &&
1282 wildmatch(msg->name_from, r->name, TRUE))
1283 ) {
1284 node = msg->node_to;
1285 change_addr(&msg->node_to, &r->to);
1286
1287 if (msg->node_to.zone == 0 && msg->node_to.net == 0 &&
1288 msg->node_to.node == 0 && msg->node_to.point == 0)
1289 kill = TRUE;
1290
1291 if (!node_eq(&node, &msg->node_to)) {
1292 if (r->type == CMD_REMAP_TO)
1293 fglog("remapto: %s @ %s -> %s", msg->name_to,
1294 znfp1(&node),
1295 !kill ? znfp2(&msg->node_to) : "KILLED");
1296 if (r->type == CMD_REMAP_FROM)
1297 fglog("remapfrom: %s @ %s -> %s", msg->name_from,
1298 znfp1(&msg->node_from),
1299 !kill ? znfp2(&msg->node_to) : "KILLED");
1300 }
1301
1302 break;
1303 }
1304
1305 return kill;
1306 }
1307
1308 /*
1309 * Check for empty NetMail
1310 *
1311 * An empty NetMail is a message comprising only ^A kludges and empty lines.
1312 */
check_empty(MsgBody * body)1313 int check_empty(MsgBody * body)
1314 {
1315 Textline *pl;
1316
1317 if (body->rfc.n)
1318 return FALSE;
1319 if (body->tear || body->origin)
1320 return FALSE;
1321 if (body->seenby.n)
1322 return FALSE;
1323
1324 for (pl = body->body.first; pl; pl = pl->next)
1325 if (pl->line[0] && pl->line[0] != '\r')
1326 return FALSE;
1327
1328 return TRUE;
1329 }
1330
1331 /*
1332 * Process NetMail message
1333 */
1334 #ifndef SPYES
do_netmail(Packet * pkt,Message * msg,MsgBody * body)1335 int do_netmail(Packet * pkt, Message * msg, MsgBody * body)
1336 #else
1337 int do_netmail(Packet * pkt, Message * msg, MsgBody * body, int forwarded)
1338 #endif /* !SPYES */
1339 {
1340 FILE *fp;
1341 char flav;
1342
1343 if (log_netmail)
1344 #ifndef SPYES
1345 fglog("MAIL: %s @ %s -> %s @ %s",
1346 msg->name_from, znfp1(&msg->node_from),
1347 msg->name_to, znfp2(&msg->node_to));
1348 #else
1349 {
1350 if (forwarded)
1351 fglog("FORWARDED MAIL: %s @ %s -> %s @ %s",
1352 msg->name_from, znfp1(&msg->node_from),
1353 msg->name_to, znfp2(&msg->node_to));
1354 else
1355 fglog("MAIL: %s @ %s -> %s @ %s",
1356 msg->name_from, znfp1(&msg->node_from),
1357 msg->name_to, znfp2(&msg->node_to));
1358 }
1359 #endif /* !SPYES */
1360
1361 /*
1362 * Check for file attach
1363 */
1364 if (msg->attr & MSG_FILE) {
1365 fglog("file attach %s", msg->subject);
1366 }
1367
1368 /*
1369 * Check for empty NetMail message addressed to one of our AKAs
1370 */
1371 if (kill_empty && check_empty(body)) {
1372 if (is_local_addr(&msg->node_to, FALSE)) {
1373 fglog("killing empty msg from %s @ %s",
1374 msg->name_from, znfp1(&msg->node_from));
1375 msgs_empty++;
1376
1377 return OK;
1378 }
1379 }
1380
1381 /*
1382 * Rewrite from/to addresses according to ROUTING rules
1383 */
1384 #ifdef DO_NOT_TOSS_NETMAIL
1385 if (!no_rewrite)
1386 do_rewrite(msg);
1387 #else
1388 do_rewrite(msg);
1389 #endif /* DO_NOT_TOSS_NETMAIL */
1390
1391 /*
1392 * Remap to address according to ROUTING rules
1393 */
1394 #ifdef DO_NOT_TOSS_NETMAIL
1395 if (!no_rewrite && do_remap(msg))
1396 #else
1397 if (do_remap(msg))
1398 #endif /* DO_NOT_TOSS_NETMAIL */
1399 {
1400 /* Kill this message, remapped to 0:0/0.0 */
1401 return OK;
1402 }
1403
1404 /*
1405 * Write to output packet
1406 */
1407 cf_set_best(msg->node_to.zone, msg->node_to.net, msg->node_to.node);
1408
1409 /* Get outbound flavor from msg attributes */
1410 flav = 'n';
1411 if (!s_flag) {
1412 if (msg->attr & MSG_HOLD)
1413 flav = 'h';
1414 if (msg->attr & MSG_CRASH)
1415 flav = 'c';
1416 }
1417
1418 #ifdef DO_NOT_TOSS_NETMAIL
1419 pkt_outdir(cf_p_netmaildir(), NULL);
1420
1421 /* dirty hack for more compatible with other soft */
1422 fp = outpkt_open(cf_addr(), &msg->node_to, 'a', 'a', 'a', FALSE);
1423 #else
1424 /* Open output packet */
1425 fp = outpkt_open(cf_addr(), &msg->node_to, g_flag, 'n', flav, FALSE);
1426 #endif /* DO_NOT_TOSS_NETMAIL */
1427
1428 if (fp == NULL)
1429 return severe_error = ERROR;
1430
1431 /* Add ftntoss ^AVia line */
1432 #ifndef DO_NOT_TOSS_NETMAIL
1433 add_via(&body->via, cf_addr());
1434 #endif /* !DO_NOT_TOSS_NETMAIL */
1435
1436 /* Write message header and body */
1437 if (pkt_put_msg_hdr(fp, msg, TRUE) != OK)
1438 return severe_error = ERROR;
1439 if (msg_put_msgbody(fp, body) != OK)
1440 return severe_error = ERROR;
1441
1442 #ifdef DO_NOT_TOSS_NETMAIL
1443 pkt_outdir(O_flag ? O_flag : cf_p_toss_route(), NULL);
1444 #endif /* DO_NOT_TOSS_NETMAIL */
1445
1446 msgs_netmail++;
1447
1448 return OK;
1449 }
1450
1451 /*
1452 * Read and process FTN packets
1453 */
unpack(FILE * pkt_file,Packet * pkt)1454 int unpack(FILE * pkt_file, Packet * pkt)
1455 {
1456 Message msg = { 0 }; /* Message header */
1457 Textlist tl; /* Textlist for message body */
1458 MsgBody body; /* Message body of FTN message */
1459 #ifdef SPYES
1460 Spy *spy; /* Spy info if avaliable */
1461 char old_subject[MSG_MAXSUBJ];
1462 #endif /* SPYES */
1463 int type;
1464
1465 /*
1466 * Initialize
1467 */
1468 tl_init(&tl);
1469 msg_body_init(&body);
1470
1471 /*
1472 * Read packet
1473 */
1474 type = pkt_get_int16(pkt_file);
1475 if (type == ERROR) {
1476 if (feof(pkt_file)) {
1477 fglog("$WARNING: premature EOF reading input packet");
1478 TMPS_RETURN(OK);
1479 }
1480
1481 fglog("ERROR: reading input packet");
1482 TMPS_RETURN(ERROR);
1483 }
1484
1485 while ((type == MSG_TYPE) && !xfeof(pkt_file)) {
1486 /*
1487 * Read message header
1488 */
1489 msg.node_from = pkt->from;
1490 msg.node_to = pkt->to;
1491
1492 if (pkt_get_msg_hdr(pkt_file, &msg, strict) == ERROR) {
1493 fglog("ERROR: reading input packet");
1494 TMPS_RETURN(ERROR);
1495 }
1496
1497 /*
1498 * Read message body
1499 */
1500 #ifdef OLD_TOSS
1501
1502 type = pkt_get_body(pkt_file, &tl);
1503
1504 if (type == ERROR) {
1505 if (feof(pkt_file)) {
1506 fglog("$WARNING: premature EOF reading input packet");
1507 } else {
1508 fglog("ERROR: reading input packet");
1509 TMPS_RETURN(ERROR);
1510 }
1511 }
1512 msgs_in++;
1513 msg_count++;
1514
1515 /*
1516 * Parse message body
1517 */
1518 if (msg_body_parse(&tl, &body) == -2)
1519 fglog("ERROR: parsing message body");
1520 #else
1521 if (pkt_get_body_parse(pkt_file, &body, &msg.node_from, &msg.node_to) !=
1522 OK) {
1523 fglog("ERROR: parsing message body");
1524 return ERROR;
1525 }
1526 msgs_in++;
1527 msg_count++;
1528 #endif
1529 /* Retrieve address information from kludges for NetMail */
1530 if (body.area == NULL) {
1531 /* Don't use point address from packet for Netmail */
1532 msg.node_from.point = 0;
1533 msg.node_to.point = 0;
1534 /* Retrieve complete address from kludges */
1535 kludge_pt_intl(&body, &msg, TRUE);
1536 msg.node_orig = msg.node_from;
1537
1538 #ifndef SPYES
1539 debug(5, "NetMail: %s -> %s",
1540 znfp1(&msg.node_from), znfp2(&msg.node_to));
1541 if (do_netmail(pkt, &msg, &body) == ERROR)
1542 TMPS_RETURN(ERROR);
1543 #else
1544 if (((spy = spyes_lookup(&msg.node_from)) != NULL) ||
1545 ((spy = spyes_lookup(&msg.node_to)) != NULL)) {
1546 debug(5, "NetMail spyes: %s -> %s, forwarded to %s",
1547 znfp1(&msg.node_from),
1548 znfp2(&msg.node_to), znfp3(&spy->forward_node));
1549 if (do_netmail(pkt, &msg, &body, FALSE) == ERROR)
1550 return ERROR;
1551 BUF_COPY(old_subject, msg.subject);
1552 str_printf(msg.subject, MSG_MAXSUBJ, "[FWD] from %s to %s: %s",
1553 znfp1(&msg.node_from),
1554 znfp2(&msg.node_to), old_subject);
1555 msg.node_to = spy->forward_node;
1556 if (do_netmail(pkt, &msg, &body, TRUE) == ERROR)
1557 return ERROR;
1558 } else {
1559 debug(5, "NetMail: %s -> %s",
1560 znfp1(&msg.node_from), znfp2(&msg.node_to));
1561 if (do_netmail(pkt, &msg, &body, FALSE) == ERROR)
1562 return ERROR;
1563 }
1564 #endif /* !SPYES */
1565 } else {
1566 /* Specially for echomail */
1567 msg.node_from = pkt->from;
1568 msg.node_to = pkt->to;
1569
1570 /* Try to get address from Origin or MSGID */
1571 if (OK != msg_parse_origin(body.origin, &msg.node_orig) &&
1572 OK != msg_parse_msgid(kludge_get(&body.kludge, "MSGID", NULL),
1573 &msg.node_orig)) {
1574 node_invalid(&msg.node_orig);
1575 }
1576
1577 debug(5, "EchoMail: %s -> %s (orig: %s)",
1578 znfp1(&msg.node_from),
1579 znfp2(&msg.node_to), znfp3(&msg.node_orig));
1580 if (do_echomail(pkt, &msg, &body) == ERROR)
1581 TMPS_RETURN(ERROR);
1582 }
1583
1584 /*
1585 * Exit if signal received
1586 */
1587 if (signal_exit) {
1588 outpkt_close();
1589 msg_count = 0;
1590 TMPS_RETURN(severe_error = ERROR);
1591 }
1592
1593 /*
1594 * Check for number of messages exceeding maxmsg
1595 */
1596 if (maxmsg && msg_count >= maxmsg) {
1597 if (x_flag)
1598 must_exit = TRUE;
1599 else
1600 outpkt_close();
1601 msg_count = 0;
1602 }
1603
1604 tmps_freeall();
1605 } /**while(type == MSG_TYPE)**/
1606
1607 TMPS_RETURN(OK);
1608 }
1609
1610 /*
1611 * Unpack one packet file
1612 */
unpack_file(char * pkt_name)1613 int unpack_file(char *pkt_name)
1614 {
1615 Packet pkt;
1616 FILE *pkt_file;
1617 TIMEINFO ti;
1618 long pkt_size;
1619
1620 /* Update time info for old messages */
1621 GetTimeInfo(&ti);
1622 now_sec = ti.time;
1623 max_sec = 24L * 3600L * max_history;
1624 exp_sec = now_sec - max_sec;
1625 if (exp_sec < 0)
1626 exp_sec = 0;
1627 debug(4, "now=%ld max=%ld, old < %ld",
1628 (long)now_sec, (long)max_sec, (long)exp_sec);
1629
1630 /* Open packet and read header */
1631 pkt_file = fopen(pkt_name, R_MODE);
1632 if (!pkt_file) {
1633 fglog("$ERROR: can't open packet %s", pkt_name);
1634 rename_bad(pkt_name);
1635 TMPS_RETURN(OK);
1636 }
1637 if (pkt_get_hdr(pkt_file, &pkt) == ERROR) {
1638 fglog("ERROR: reading header from %s", pkt_name);
1639 fclose(pkt_file);
1640 rename_bad(pkt_name);
1641 TMPS_RETURN(OK);
1642 }
1643
1644 /* Unpack it */
1645 pkt_size = check_size(pkt_name);
1646 fglog("packet %s (%ldb) from %s to %s", pkt_name, pkt_size,
1647 znfp1(&pkt.from), znfp2(&pkt.to));
1648 pkts_in++;
1649 pkts_bytes += pkt_size;
1650
1651 if (unpack(pkt_file, &pkt) == ERROR) {
1652 fglog("ERROR: processing %s", pkt_name);
1653 fclose(pkt_file);
1654 rename_bad(pkt_name);
1655 TMPS_RETURN(severe_error);
1656 }
1657
1658 fclose(pkt_file);
1659
1660 if (unlink(pkt_name)) {
1661 fglog("$ERROR: can't unlink %s", pkt_name);
1662 rename_bad(pkt_name);
1663 TMPS_RETURN(ERROR);
1664 }
1665
1666 TMPS_RETURN(OK);
1667 }
1668
1669 /*
1670 * Function called on SIGINT
1671 */
prog_signal(int signum)1672 void prog_signal(int signum)
1673 {
1674 char *name = "";
1675
1676 signal_exit = TRUE;
1677
1678 switch (signum) {
1679 case SIGHUP:
1680 name = " by SIGHUP";
1681 break;
1682 case SIGINT:
1683 name = " by SIGINT";
1684 break;
1685 case SIGQUIT:
1686 name = " by SIGQUIT";
1687 break;
1688 default:
1689 name = "";
1690 break;
1691 }
1692
1693 fglog("KILLED%s: exit forced", name);
1694 }
1695
1696 /*
1697 * Usage messages
1698 */
short_usage(void)1699 void short_usage(void)
1700 {
1701 fprintf(stderr, "usage: %s [-options] [packet ...]\n", PROGRAM);
1702 fprintf(stderr, " %s --help for more information\n", PROGRAM);
1703 }
1704
usage(void)1705 void usage(void)
1706 {
1707 fprintf(stderr, "FIDOGATE %s %s %s\n\n",
1708 version_global(), PROGRAM, version_local(VERSION));
1709
1710 fprintf(stderr, "usage: %s [-options] [packet ...]\n\n", PROGRAM);
1711 fprintf(stderr, "\
1712 options: -d --no-dupecheck disable dupe check\n\
1713 -g --grade G processing grade\n\
1714 -I --in-dir DIR set input packet directory\n\
1715 -O --out-dir DIR set output packet directory\n\
1716 -l --lock-file create lock file while processing\n\
1717 -t --insecure insecure tossing (no AREAS.BBS check)\n\
1718 -n --toss-all toss all EchoMail messages\n\
1719 -p --passthru make all areas passthru\n\
1720 -r --routing-file NAME read routing file\n\
1721 -s --strip-attribute strip crash, hold message attribute\n\
1722 -m --maxmsg N close output after N msgs\n\
1723 -x --maxmsg-exit close output and exit after -m msgs\n\
1724 -M --maxopen N set max # of open packet files\n\
1725 -b --areas-bbs NAME use alternate AREAS.BBS\n\
1726 \n\
1727 -v --verbose more verbose\n\
1728 -h --help this help\n\
1729 -c --config NAME read config file (\"\" = none)\n\
1730 -a --addr Z:N/F.P set FTN address\n\
1731 -u --uplink-addr Z:N/F.P set FTN uplink address\n\
1732 -w --wait [TIME] wait for areas.bbs and history\n\
1733 lock to be released\n");
1734 }
1735
1736 /***** main() ****************************************************************/
1737
main(int argc,char ** argv)1738 int main(int argc, char **argv)
1739 {
1740 int c;
1741 char *p;
1742 char *I_flag = NULL, *r_flag = NULL, *M_flag = NULL;
1743 char *c_flag = NULL;
1744 char *a_flag = NULL, *u_flag = NULL;
1745 char d_flag = FALSE;
1746 char *pkt_name;
1747 int w_flag = FALSE;
1748 time_t toss_start, toss_delta;
1749 AreasBBS *area;
1750 char bbslock[MAXPATH];
1751
1752 int option_index;
1753 static struct option long_options[] = {
1754 {"no-dupecheck", 1, 0, 'd'}, /* Disable dupe check */
1755 {"grade", 1, 0, 'g'}, /* grade */
1756 {"in-dir", 1, 0, 'I'}, /* Set inbound packets directory */
1757 {"lock-file", 0, 0, 'l'}, /* Create lock file while processing */
1758 {"out-dir", 1, 0, 'O'}, /* Set packet directory */
1759 {"insecure", 0, 0, 't'}, /* Insecure */
1760 {"toss-all", 0, 0, 'n'}, /* Toss all EchoMail */
1761 {"routing-file", 1, 0, 'r'}, /* Set routing file */
1762 {"strip-attribute", 0, 0, 's'}, /* Strip attribute */
1763 {"maxmsg", 1, 0, 'm'}, /* Close after N messages */
1764 {"maxmsg-exit", 0, 0, 'x'}, /* Exit after maxmsg messages */
1765 {"maxopen", 1, 0, 'M'}, /* Set max # open packet files */
1766 {"areas-bbs", 1, 0, 'b'},
1767 {"passthru", 0, 0, 'p'},
1768
1769 {"verbose", 0, 0, 'v'}, /* More verbose */
1770 {"help", 0, 0, 'h'}, /* Help */
1771 {"config", 1, 0, 'c'}, /* Config file */
1772 {"addr", 1, 0, 'a'}, /* Set FIDO address */
1773 {"uplink-addr", 1, 0, 'u'}, /* Set FIDO uplink address */
1774 {"wait", 1, 0, 'w'},
1775 {0, 0, 0, 0}
1776 };
1777
1778 /* Log name */
1779
1780 log_program(PROGRAM);
1781
1782 /* Init configuration */
1783 cf_initialize();
1784
1785 /* Parse options */
1786 while ((c = getopt_long(argc, argv, "dg:O:I:ltnr:sm:xM:b:pvhc:w:a:u:",
1787 long_options, &option_index)) != EOF)
1788 switch (c) {
1789 /***** ftntoss options *****/
1790 case 'd':
1791 d_flag = TRUE;
1792 break;
1793 case 'g':
1794 g_flag = *optarg;
1795 break;
1796 case 'I':
1797 I_flag = optarg;
1798 break;
1799 case 'l':
1800 l_flag = TRUE;
1801 break;
1802 case 'O':
1803 O_flag = optarg;
1804 break;
1805 case 't':
1806 t_flag = TRUE;
1807 break;
1808 case 'n':
1809 n_flag = TRUE;
1810 break;
1811 case 'r':
1812 r_flag = optarg;
1813 break;
1814 case 's':
1815 s_flag = TRUE;
1816 break;
1817 case 'm':
1818 maxmsg = atoi(optarg);
1819 break;
1820 case 'x':
1821 x_flag = TRUE;
1822 break;
1823 case 'M':
1824 M_flag = optarg;
1825 break;
1826 case 'b':
1827 areas_bbs = optarg;
1828 break;
1829 case 'p':
1830 p_flag = TRUE;
1831 break;
1832
1833 /***** Common options *****/
1834 case 'v':
1835 verbose++;
1836 break;
1837 case 'h':
1838 usage();
1839 return 0;
1840 break;
1841 case 'c':
1842 c_flag = optarg;
1843 break;
1844 case 'a':
1845 a_flag = optarg;
1846 break;
1847 case 'u':
1848 u_flag = optarg;
1849 break;
1850 case 'w':
1851 if (optarg)
1852 w_flag = atoi(optarg);
1853 else
1854 w_flag = WAIT;
1855 break;
1856 default:
1857 short_usage();
1858 return EX_USAGE;
1859 break;
1860 }
1861
1862 /*
1863 * Read config file
1864 */
1865 cf_read_config_file(c_flag ? c_flag : CONFIG);
1866
1867 /*
1868 * Process config options
1869 */
1870 if (a_flag)
1871 cf_set_addr(a_flag);
1872 if (u_flag)
1873 cf_set_uplink(u_flag);
1874
1875 cf_debug();
1876
1877 /*
1878 * Process optional config statements
1879 */
1880 if (cf_get_string("KillEmpty", TRUE) || cf_get_string("KillBlank", TRUE)) {
1881 debug(8, "actual: killempty true");
1882 kill_empty = TRUE;
1883 }
1884 if (cf_get_string("KillUnknown", TRUE)) {
1885 kill_unknown = TRUE;
1886 }
1887 if (cf_get_string("KillRouted", TRUE)) {
1888 kill_routed = TRUE;
1889 }
1890 if (cf_get_string("KillInsecure", TRUE)) {
1891 kill_insecure = TRUE;
1892 }
1893 #ifdef FTN_ACL
1894 if (cf_get_string("KillReadonly", TRUE)) {
1895 kill_readonly = TRUE;
1896 }
1897 #endif /* FTN_ACL */
1898 if (cf_get_string("KillCircular", TRUE)) {
1899 kill_circular = TRUE;
1900 }
1901 if (cf_get_string("LogNetMail", TRUE) || cf_get_string("Track", TRUE)) {
1902 debug(8, "actual lognetmail true");
1903 log_netmail = TRUE;
1904 }
1905 if (cf_get_string("CheckPath", TRUE)) {
1906 check_path = TRUE;
1907 }
1908 if (cf_get_string("DupeCheck", TRUE)) {
1909 if (d_flag) {
1910 debug(8, "DupeCheck disabled from command line!");
1911 dupe_check = FALSE;
1912 } else {
1913 dupe_check = TRUE;
1914 }
1915 }
1916 if (cf_get_string("KillNoMSGID", TRUE)) {
1917 kill_nomsgid = TRUE;
1918 }
1919 if (cf_get_string("KillDupe", TRUE) || cf_get_string("KillDupes", TRUE)) {
1920 debug(8, "actual KillDupe true");
1921 kill_dupe = TRUE;
1922 }
1923 if (!maxmsg && (p = cf_get_string("MaxMsg", TRUE))) {
1924 maxmsg = atoi(p);
1925 debug(8, "actual: MaxMsg %d", maxmsg);
1926
1927 }
1928 if (!M_flag && (p = cf_get_string("MaxOpenFiles", TRUE))) {
1929 M_flag = p;
1930 debug(8, "actual MaxOpenFiles %s", M_flag);
1931 }
1932 if (M_flag)
1933 outpkt_set_maxopen(atoi(M_flag));
1934 if (cf_get_string("KillOld", TRUE)) {
1935 kill_old = TRUE;
1936 }
1937 if ((p = cf_get_string("MaxHistory", TRUE))) {
1938 max_history = atof(p);
1939 if (max_history < 0)
1940 max_history = 0;
1941 debug(8, "actual MaxHistory %g", max_history);
1942 }
1943 if (cf_get_string("TossEchoMail4D", TRUE)) {
1944 echomail4d = TRUE;
1945 }
1946 if (cf_get_string("NoEmptyPath", TRUE)) {
1947 no_empty_path = TRUE;
1948 }
1949 if (cf_get_string("AddOtherAKA", TRUE) ||
1950 cf_get_string("AddOtherAKAs", TRUE)) {
1951 debug(8, "actual AddOtherAKA true");
1952 add_other_aka = TRUE;
1953 }
1954 #ifdef FTN_ACL
1955 if (cf_get_string("UplinkCanBeReadonly", TRUE)) {
1956 uplink_can_be_readonly = TRUE;
1957 }
1958 #endif /* FTN_ACL */
1959 if (cf_get_string("TrafficStatistics", TRUE)) {
1960 traffic_statistics = TRUE;
1961 }
1962 if ((p = cf_get_string("TrafficStatisticsFile", TRUE))) {
1963 traffic_statistics_file = p;
1964 }
1965 if ((p = cf_get_string("AutoCreateLine", TRUE))) {
1966 autocreate_line = p;
1967 }
1968 #ifndef ACTIVE_LOOKUP
1969 if (cf_get_string("AutoCreateNG", TRUE)) {
1970 autocreate_ng = TRUE;
1971 }
1972 #endif /* !ACTIVE_LOOKUP */
1973 if (cf_get_string("CheckPointOriginAddr", TRUE)) {
1974 check_point_origin_addr = FALSE;
1975 }
1976 #ifdef DO_NOT_TOSS_NETMAIL
1977 if (cf_get_string("NoRewrite", TRUE)) {
1978 no_rewrite = TRUE;
1979 }
1980 #endif /* DO_NOT_TOSS_NETMAIL */
1981 strict = (cf_get_string("FTNStrictPktCheck", TRUE) != NULL);
1982
1983 zonegate_init();
1984 addtoseenby_init();
1985 deleteseenby_init();
1986 deletepath_init();
1987 #ifdef SPYES
1988 spyes_init();
1989 #endif /* SPYES */
1990 #ifdef FTN_ACL
1991 ftnacl_init();
1992 #endif /* FTN_ACL */
1993
1994 tl_init(¬ify);
1995
1996 /*
1997 * Process local options
1998 */
1999 BUF_EXPAND(in_dir, I_flag ? I_flag : cf_p_pinbound());
2000 pkt_outdir(O_flag ? O_flag : cf_p_toss_toss(), NULL);
2001 pkt_baddir(O_flag ? O_flag : cf_p_toss_bad(), NULL);
2002
2003 /*
2004 * Get name of areas.bbs file from config file
2005 */
2006 if (!areas_bbs)
2007 areas_bbs = cf_get_string("AreasBBS", TRUE);
2008 if (!areas_bbs) {
2009 fprintf(stderr, "%s: no areas.bbs specified\n", PROGRAM);
2010 exit_free();
2011 return EX_USAGE;
2012 }
2013
2014 routing_init(r_flag ? r_flag : cf_p_routing());
2015 BUF_COPY2(bbslock, areas_bbs, ".lock");
2016 if (lock_path(bbslock, w_flag ? w_flag : NOWAIT) == ERROR) {
2017 exit_free();
2018 return EXIT_BUSY;
2019 }
2020 areasbbs_init(areas_bbs);
2021 passwd_init();
2022
2023 /* Install signal/exit handlers */
2024 signal(SIGHUP, prog_signal);
2025 signal(SIGINT, prog_signal);
2026 signal(SIGQUIT, prog_signal);
2027
2028 /* Start time */
2029 toss_start = time(NULL);
2030
2031 c = EXIT_OK;
2032
2033 if (optind >= argc) {
2034 /* process packet files in directory */
2035 dir_sortmode(DIR_SORTMTIME);
2036 if (dir_open(in_dir, "*.pkt", TRUE) == ERROR) {
2037 fglog("$ERROR: can't open directory %s", in_dir);
2038 unlock_path(bbslock);
2039 exit_free();
2040 return EX_OSERR;
2041 }
2042
2043 /* Lock file */
2044 if (l_flag)
2045 if (lock_program(PROGRAM, NOWAIT) == ERROR) {
2046 /* Already busy */
2047 exit_free();
2048 return EXIT_BUSY;
2049 }
2050
2051 /* Open history */
2052 if (dupe_check) {
2053 if (lock_program(cf_p_lock_history(), w_flag ? w_flag : NOWAIT) ==
2054 ERROR) {
2055
2056 /* Already busy, exit */
2057 if (l_flag) {
2058 unlock_program(PROGRAM);
2059 unlock_path(bbslock);
2060 }
2061 exit_free();
2062 return EXIT_BUSY;
2063 }
2064 hi_init_history();
2065 }
2066
2067 for (pkt_name = dir_get(TRUE); pkt_name; pkt_name = dir_get(FALSE)) {
2068 if (unpack_file(pkt_name) == ERROR) {
2069 c = EXIT_ERROR;
2070 break;
2071 }
2072 if (must_exit) {
2073 c = EXIT_CONTINUE;
2074 break;
2075 }
2076 }
2077
2078 /* Close history */
2079 if (dupe_check) {
2080 unlock_program(cf_p_lock_history());
2081 hi_close();
2082 }
2083
2084 dir_close();
2085
2086 /* Lock file */
2087 if (l_flag)
2088 unlock_program(PROGRAM);
2089 } else {
2090 /* Lock file */
2091 if (l_flag)
2092 if (lock_program(PROGRAM, NOWAIT) == ERROR) {
2093 /* Already busy */
2094 exit_free();
2095 return EXIT_BUSY;
2096 }
2097
2098 /* Open history */
2099 if (dupe_check) {
2100 if (lock_program(cf_p_lock_history(), w_flag ? w_flag : NOWAIT) ==
2101 ERROR) {
2102 /* Already busy, exit */
2103 if (l_flag) {
2104 unlock_program(PROGRAM);
2105 unlock_path(bbslock);
2106 }
2107
2108 exit_free();
2109 return EXIT_BUSY;
2110 }
2111 hi_init_history();
2112 }
2113
2114 /* Process packet files on command line */
2115 for (; optind < argc; optind++) {
2116 if (unpack_file(argv[optind]) == ERROR) {
2117 c = EXIT_ERROR;
2118 break;
2119 }
2120 if (must_exit) {
2121 c = EXIT_CONTINUE;
2122 break;
2123 }
2124 }
2125
2126 /* Close history */
2127 if (dupe_check) {
2128 unlock_program(cf_p_lock_history());
2129 hi_close();
2130 }
2131
2132 /* Lock file */
2133 if (l_flag)
2134 unlock_program(PROGRAM);
2135 }
2136
2137 outpkt_close();
2138
2139 /* Stop time */
2140 toss_delta = time(NULL) - toss_start;
2141 if (toss_delta <= 0)
2142 toss_delta = 1;
2143
2144 if (traffic_statistics) {
2145 area = areasbbs_first();
2146 for (area = areasbbs_first(); NULL != area; area = area->next) {
2147 if (0 != area->msgs_in) {
2148 if (traffic_statistics_file)
2149 log_file(traffic_statistics_file);
2150
2151 if (area->msgs_in == area->msgs_out) {
2152 fglog("area %-35s: msgs in: %-3u out: %-3u size: %li",
2153 area->area, area->msgs_in, area->msgs_out,
2154 area->msgs_size);
2155 } else {
2156 #ifndef FTN_ACL
2157 fglog
2158 ("area %-35s: msgs in: %-3u out: %-3u size: %li killed: %u/%u/%u/%u",
2159 area->area, area->msgs_in, area->msgs_out,
2160 area->msgs_size, area->msgs_routed,
2161 area->msgs_insecure, area->msgs_dupe, area->msgs_path);
2162 #else
2163 fglog
2164 ("area %-35s: msgs in: %-3u out: %-3u size: %li killed: %u/%u/%u/%u/%u",
2165 area->area, area->msgs_in, area->msgs_out,
2166 area->msgs_size, area->msgs_routed,
2167 area->msgs_insecure, area->msgs_dupe, area->msgs_path,
2168 area->msgs_readonly);
2169 #endif /* !FTN_ACL */
2170 }
2171 log_program(PROGRAM);
2172 }
2173 }
2174 }
2175
2176 if (pkts_in)
2177 fglog("pkts processed: %ld, %ld Kbyte in %ld s, %.2f Kbyte/s",
2178 pkts_in, pkts_bytes / 1024, (long)toss_delta,
2179 (double)pkts_bytes / 1024. / toss_delta);
2180
2181 if (msgs_in) {
2182 fglog("msgs processed: %ld in, %ld out (%ld mail, %ld echo)",
2183 msgs_in, msgs_netmail + msgs_echomail, msgs_netmail,
2184 msgs_echomail);
2185 fglog("msgs processed: %ld in %ld s, %.6f msgs/s", msgs_in,
2186 (long)toss_delta, (double)msgs_in / toss_delta);
2187 }
2188
2189 if (msgs_unknown || msgs_routed || msgs_insecure || msgs_empty)
2190 fglog
2191 ("msgs killed: %ld empty, %ld unknown, %ld routed, %ld insecure",
2192 msgs_empty, msgs_unknown, msgs_routed, msgs_insecure);
2193 #ifdef FTN_ACL
2194 if (msgs_readonly)
2195 fglog("msgs killed: %ld to read only areas", msgs_readonly);
2196 #endif /* FTN_ACL */
2197 if (dupe_check && msgs_dupe)
2198 fglog("msgs killed: %ld dupe", msgs_dupe);
2199 if (check_path && msgs_path)
2200 fglog("msgs killed: %ld circular path", msgs_path);
2201
2202 if (notify.n > 0)
2203 send_request(¬ify);
2204
2205 if (ERROR == areasbbs_rewrite())
2206 fglog("error while rewriting areas.bbs");
2207
2208 unlock_path(bbslock);
2209
2210 exit_free();
2211 return c;
2212 }
2213