1 /*:ts=8*/
2 /*****************************************************************************
3  * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4  *
5  * $Id: ftn2rfc.c,v 4.65 2004/08/22 20:19:12 n0ll Exp $
6  *
7  * Convert FTN mail packets to RFC mail and news batches
8  *
9  *****************************************************************************
10  * Copyright (C) 1990-2004
11  *  _____ _____
12  * |     |___  |   Martin Junius             <mj.at.n0ll.dot.net>
13  * | | | |   | |   Radiumstr. 18
14  * |_|_|_|@home|   D-51069 Koeln, Germany
15  *
16  * This file is part of FIDOGATE.
17  *
18  * FIDOGATE is free software; you can redistribute it and/or modify it
19  * under the terms of the GNU General Public License as published by the
20  * Free Software Foundation; either version 2, or (at your option) any
21  * later version.
22  *
23  * FIDOGATE is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with FIDOGATE; see the file COPYING.  If not, write to the Free
30  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31  *****************************************************************************/
32 
33 #include "fidogate.h"
34 #include "getopt.h"
35 
36 #include <pwd.h>
37 #include <fcntl.h>
38 #include <sys/wait.h>
39 
40 
41 
42 #define PROGRAM 	"ftn2rfc"
43 #define VERSION 	"$Revision: 4.65 $"
44 #define CONFIG		DEFAULT_CONFIG_GATE
45 
46 
47 
48 /* Prototypes */
49 char   *get_from		(Textlist *, Textlist *);
50 char   *get_reply_to		(Textlist *);
51 char   *get_to			(Textlist *);
52 char   *get_cc			(Textlist *);
53 char   *get_bcc			(Textlist *);
54 Area   *news_msg		(char *);
55 int	unpack			(FILE *, Packet *);
56 int	rename_bad		(char *);
57 int	unpack_file		(char *);
58 
59 void	short_usage		(void);
60 void	usage			(void);
61 
62 
63 
64 /* Command line options */
65 int n_flag = FALSE;
66 int t_flag = FALSE;
67 
68 char in_dir[MAXPATH];
69 
70 
71 /* X-FTN flags
72  *    f    X-FTN-From
73  *    t    X-FTN-To
74  *    T    X-FTN-Tearline
75  *    O    X-FTN-Origin
76  *    V    X-FTN-Via
77  *    D    X-FTN-Domain
78  *    S    X-FTN-Seen-By
79  *    P    X-FTN-Path      */
80 int x_ftn_f = FALSE;
81 int x_ftn_t = FALSE;
82 int x_ftn_T = FALSE;
83 int x_ftn_O = FALSE;
84 int x_ftn_V = FALSE;
85 int x_ftn_D = FALSE;
86 int x_ftn_S = FALSE;
87 int x_ftn_P = FALSE;
88 
89 
90 /* TrackerMail */
91 static char *tracker_mail_to = NULL;
92 
93 /* MSGID handling */
94 static int no_unknown_msgid_zones    = FALSE;
95 static int no_messages_without_msgid = FALSE;
96 
97 /* Use * Origin line for Organization header */
98 static int use_origin_for_organization = FALSE;
99 
100 /* Don't bounce message from FTN address not listed in HOSTS */
101 static int ignore_hosts = FALSE;
102 
103 /* Newsgroup name for unknown FTN areas (NULL = don't gate) */
104 static char *ftn_junk_group = NULL;
105 
106 /* Address for Errors-To header (NULL = none) */
107 static char *errors_to = NULL;
108 
109 /* Do not allow RFC addresses (chars !, &, @) in FTN to field */
110 static int no_address_in_to_field = FALSE;
111 
112 /* Character conversion */
113 static int netmail_8bit = FALSE;
114 static int netmail_qp   = FALSE;
115 
116 /* Use FTN to address (cvt to Internet address) for mail_to */
117 static int use_ftn_to_address = FALSE;
118 
119 /* Kill split messages with ^ASPLIT kludge */
120 static int kill_split = FALSE;
121 
122 /* Write single news article files, not one big news batch */
123 static int single_articles = FALSE;
124 
125 /* Charset stuff */
126 static char *default_charset_def = NULL;
127 static char *default_charset_out = NULL;
128 static char *netmail_charset_def = NULL;
129 static char *netmail_charset_out = NULL;
130 static int netmail_charset_use_1st = FALSE;
131 
132 /* String to add to news Path header */
133 static char *news_path_tail = "not-for-mail";
134 
135 
136 
137 /*
138  * Get header for
139  *   - From/Reply-To/UUCPFROM
140  *   - To
141  *   - Cc
142  *   - Bcc
143  */
get_from(Textlist * rfc,Textlist * kludge)144 char *get_from(Textlist *rfc, Textlist *kludge)
145 {
146     char *p, *q;
147     Node dummy;
148 
149     p = rfcheader_get(rfc, "From");
150     if(!p)
151     {
152 	if( (p = kludge_get(kludge, "REPLYADDR", NULL)) )
153 	    if( (q = strchr(p,'%')) || (q = strchr(p,'@')) )
154 		if(znfp_parse_partial(q+1, &dummy) == OK)
155 		    return NULL;
156     }
157     if(!p)
158 	p = rfcheader_get(rfc, "UUCPFROM");
159 
160     return p;
161 }
162 
get_reply_to(Textlist * tl)163 char *get_reply_to(Textlist *tl)
164 {
165     return rfcheader_get(tl, "Reply-To");
166 }
167 
get_to(Textlist * tl)168 char *get_to(Textlist *tl)
169 {
170     return rfcheader_get(tl, "To");
171 }
172 
get_cc(Textlist * tl)173 char *get_cc(Textlist *tl)
174 {
175     return rfcheader_get(tl, "Cc");
176 }
177 
get_bcc(Textlist * tl)178 char *get_bcc(Textlist *tl)
179 {
180     return rfcheader_get(tl, "Bcc");
181 }
182 
183 
184 
185 /*
186  * Test for EchoMail, return Area entry.
187  */
news_msg(char * line)188 Area *news_msg(char *line)
189 {
190     char *p;
191     Area *pa;
192     static Area area;
193 
194     if(line)
195     {
196 	/* Message is FIDO EchoMail */
197 	strip_crlf(line);
198 
199 	for(p=line+strlen("AREA:"); *p && is_space(*p); p++);
200 	debug(7, "FIDO Area: %s", p);
201 	pa = areas_lookup(p, NULL);
202 	if(pa)
203 	{
204 	    debug(7, "Found: %s %s Z%d", pa->area, pa->group, pa->zone);
205 	    return pa;
206 	}
207 
208 	/* Area not found */
209 	area.next  	  = NULL;
210 	area.area  	  = p;
211 	area.group 	  = NULL;
212 	area.zone         = 0;
213 	node_invalid(&area.addr);
214 	area.origin       = NULL;
215 	area.distribution = NULL;
216 	area.flags        = 0;
217 	area.rfc_lvl      = -1;
218 	area.maxsize      = -1;
219 	tl_init(&area.x_hdr);
220 
221 	return &area;
222     }
223 
224     /* Message is FIDO NetMail */
225     return NULL;
226 }
227 
228 
229 
230 /*
231  * Check for 8bit characters in message body
232  */
check_8bit(Textlist * tl)233 int check_8bit(Textlist *tl)
234 {
235     Textline *pl;
236     char *p;
237 
238     for(pl=tl->first; pl; pl=pl->next)
239 	for(p=pl->line; *p && *p!='\r'; p++)
240 	    if(*p & 0x80)
241 		return TRUE;
242 
243     return FALSE;
244 }
245 
246 #ifdef AI_5
247 /*
248  * Check for 8bit characters in any string
249  */
check_8bit_s(char * s,int len)250 int check_8bit_s(char *s, int len)
251 {
252     char *p;
253 
254     if(!s)
255 	return FALSE;
256 
257     for(p=s; (int)(p-s)<len && *p!='\0'; p++)
258 	if(*p & 0x80)
259 	    return TRUE;
260 
261     return FALSE;
262 }
263 #endif
264 
265 
266 /*
267  * Check for valid domain name string
268  */
check_valid_domain(char * s)269 int check_valid_domain(char *s)
270 {
271     if(!*s)
272 	return FALSE;
273     while(*s)
274     {
275 	if(!isalnum(*s) && *s!='-' && *s!='.')
276 	    return FALSE;
277 	s++;
278     }
279     return TRUE;
280 }
281 
282 
283 
284 /*
285  * Read and convert FTN mail packet
286  */
unpack(FILE * pkt_file,Packet * pkt)287 int unpack(FILE *pkt_file, Packet *pkt)
288 {
289     Message msg;			/* Message header */
290     RFCAddr addr_from, addr_to;
291     Textlist tl;			/* Textlist for message body */
292     MsgBody body;			/* Message body of FTN message */
293     int lines;				/* Lines in message body */
294     Area *area;				/* Area entry for EchoMail */
295     int type;
296     Textline *pl;
297     char *p, *s;
298     char *msgbody_rfc_from;		/* RFC header From */
299     char *msgbody_rfc_reply_to;		/* RFC header Reply-To */
300     char *msgbody_rfc_to;		/* RFC header To */
301     char *msgbody_rfc_cc;		/* RFC header Cc */
302     char *msgbody_rfc_bcc;		/* RFC header Bcc */
303     char mail_to[MAXINETADDR];		/* Addressee of mail */
304     char x_orig_to[MAXINETADDR];
305     char *from_line, *to_line;		/* From:, To: */
306     char *reply_to_line;		/* Reply-To: */
307     char *id_line, *ref_line;		/* Message-ID:, References: */
308     char *cc_line, *bcc_line;		/* Cc:, Bcc: */
309     char *thisdomain, *uplinkdomain;	/* FQDN addr this node, uplink,  */
310     char *origindomain;			/*           node in Origin line */
311     char *gateway;			/* ^AGATEWAY */
312     Textlist theader;			/* RFC headers */
313     Textlist tbody;    			/* RFC message body */
314     int uucp_flag;			/* To == UUCP or GATEWAY */
315     int ret;
316     int rfc_lvl, rfc_lines;
317     char *split_line;
318     int cvt8 = 0;			/* AREA_8BIT | AREA_QP */
319     char *cs_def, *cs_in, *cs_out;	/* Charset def, in(=FTN), out(=RFC) */
320     char *cs_save;
321 
322 
323     /*
324      * Initialize
325      */
326     tl_init(&tl);
327     tl_init(&theader);
328     tl_init(&tbody);
329     msg_body_init(&body);
330     ret = OK;
331 
332     /*
333      * Read packet
334      */
335     type = pkt_get_int16(pkt_file);
336     if(type == ERROR)
337     {
338 	if(feof(pkt_file))
339 	{
340 	    logit("WARNING: premature EOF reading input packet");
341 	    return OK;
342 	}
343 
344 	logit("ERROR: reading input packet");
345 	return ERROR;
346     }
347 
348     while(type == MSG_TYPE)
349     {
350 	x_orig_to[0] = 0;
351 	tl_clear(&theader);
352 	tl_clear(&tbody);
353 
354 	/*
355 	 * Read message header
356 	 */
357 	msg.node_from = pkt->from;
358 	msg.node_to   = pkt->to;
359 	if( pkt_get_msg_hdr(pkt_file, &msg) == ERROR )
360 	{
361 	    logit("ERROR: reading input packet");
362 	    ret = ERROR;
363 	    break;
364 	}
365 
366 	/* Strip spaces at end of line */
367 	strip_space(msg.name_from);
368 	strip_space(msg.name_to);
369 	strip_space(msg.subject);
370 
371 	/* Replace empty subject */
372 	if (!*msg.subject)
373 	    BUF_COPY(msg.subject, "(no subject)");
374 
375 	/*
376 	 * Read message body
377 	 */
378 	type = pkt_get_body(pkt_file, &tl);
379 	if(type == ERROR)
380 	{
381 	    if(feof(pkt_file))
382 	    {
383 		logit("WARNING: premature EOF reading input packet");
384 	    }
385 	    else
386 	    {
387 		logit("ERROR: reading input packet");
388 		ret = ERROR;
389 		tl_clear(&theader);
390 		tl_clear(&tbody);
391 		tl_clear(&tl);
392 		msg_body_clear(&body);
393 		break;
394 	    }
395 	}
396 
397 	/*
398 	 * Parse message body
399 	 */
400 	if( msg_body_parse(&tl, &body) == -2 )
401 	    logit("ERROR: parsing message body");
402 	/* Retrieve address information from kludges for NetMail */
403 	if(body.area == NULL)
404 	{
405 	    /* Don't use point address from packet for Netmail */
406 	    msg.node_from.point = 0;
407 	    msg.node_to  .point = 0;
408 	    /* Retrieve complete address from kludges */
409 	    kludge_pt_intl(&body, &msg, FALSE);
410 	    msg.node_orig = msg.node_from;
411 	}
412 	else
413 	{
414 	    /* Retrieve address information from * Origin line */
415 	    if(msg_parse_origin(body.origin, &msg.node_orig) == ERROR)
416 		/* No * Origin line address, use header */
417 		node_invalid(&msg.node_orig);
418 	}
419 	debug(7, "FIDO sender (from/origin): %s", znfp1(&msg.node_orig));
420 
421 	/*
422 	 * strip_crlf() all kludge and RFC lines
423 	 */
424 	for(pl=body.kludge.first; pl; pl=pl->next)
425 	    strip_crlf(pl->line);
426 	for(pl=body.rfc.first; pl; pl=pl->next)
427 	    strip_crlf(pl->line);
428 
429 	/*
430 	 * X-Split header line
431 	 */
432 	split_line = NULL;
433 	if( (p = kludge_get(&body.kludge, "SPLIT", NULL)) )
434 	{
435 	    split_line = p;
436 	}
437 	else if( (p = kludge_get(&body.body, "SPLIT", NULL)) )
438 	{
439 	    strip_crlf(p);
440 	    split_line = p;
441 	}
442 
443 	/*
444 	 * Remove empty first line after RFC headers and empty last line
445 	 */
446 	if( body.rfc.first && (pl = body.body.first) )
447 	{
448 	    if(pl->line[0] == '\r')
449 		tl_delete(&body.body, pl);
450 	}
451 	if( (pl = body.body.last) )
452 	{
453 	    if(pl->line[0] == '\r')
454 		tl_delete(&body.body, pl);
455 	}
456 
457 
458 	/*
459 	 * Check for mail or news.
460 	 *
461 	 * area == NULL  -  NetMail
462 	 * area != NULL  -  EchoMail
463 	 */
464 	if( (area = news_msg(body.area)) )
465 	{
466 	    cvt8 = area->flags & (AREA_8BIT | AREA_QP);
467 
468 	    /* Set AKA according to area's zone */
469 	    cf_set_zone(area->zone);
470 
471 	    /* Skip, if unknown and FTNJunkGroup not set */
472 	    if(!area->group && !ftn_junk_group)
473 	    {
474 		logit("unknown area %s", area->area);
475 		tl_clear(&theader);
476 		tl_clear(&tbody);
477 		tl_clear(&tl);
478 		msg_body_clear(&body);
479 		continue;
480 	    }
481 	}
482 	else
483 	{
484 	    cvt8 = 0;
485 	    if(netmail_8bit)
486 		cvt8 |= AREA_8BIT;
487 	    if(netmail_qp)
488 		cvt8 |= AREA_QP;
489 
490 	    /* Set AKA according to sender's zone */
491 	    cf_set_zone(msg.node_orig.zone!=-1
492 			? msg.node_orig.zone
493 			: msg.node_from.zone  );
494 	}
495 
496 	/*
497 	 * Check for 8bit characters in message body. If none are
498 	 * found, don't use the quoted-printable encoding or 8bit.
499 	 */
500 #ifndef AI_5
501 	if(!check_8bit(&body.body))
502 #else
503 	if( !(check_8bit(&body.body)                         ||
504 	      check_8bit_s(body.origin, sizeof(body.origin)) ||
505 	      check_8bit_s(body.tear, sizeof(body.tear))     ||
506 	      check_8bit_s(msg.subject, sizeof(msg.subject))) )
507 #endif
508 	    cvt8 &= ~(AREA_QP | AREA_8BIT);
509 
510 	/*
511 	 * Check for Content-Transfer-Encoding in RFC headers or ^ARFC kludges
512 	 */
513 	if( (p = rfcheader_get(&body.rfc, "Content-Transfer-Encoding"))  ||
514 	    (p = kludge_get(&body.kludge,
515 			    "RFC-Content-Transfer-Encoding", NULL))        )
516 	{
517 	    strip_space(p);
518 	    if(strieq(p, "7bit"))
519 		cvt8 = 0;
520 	    if(strieq(p, "8bit"))
521 		cvt8 = AREA_8BIT;
522 	    if(strieq(p, "quoted-printable"))
523 		cvt8 = AREA_QP;
524 	}
525 	debug(5, "cvt8:%s%s",
526 	      (cvt8 & AREA_8BIT ? " 8bit" : ""),
527 	      (cvt8 & AREA_QP   ? " quoted-printable" : ""));
528 
529 	/*
530 	 * Convert message body
531 	 */
532 
533 	/* charset input (=FTN message) and output (=RFC message) */
534 	cs_save = NULL;
535 	cs_def  = NULL;
536 	cs_in   = NULL;
537 	cs_out  = NULL;
538 
539 	if(area)				/* EchoMail -> News */
540 	{
541 	    if(area->charset)
542 	    {
543 		cs_save = strsave(area->charset);
544 		cs_def  = strtok(cs_save, ":");
545 		s       = strtok(NULL, ":");
546 		cs_out  = strtok(NULL, ":");
547 	    }
548 	}
549 	else					/* NetMail -> Mail */
550 	{
551 	    cs_def  = netmail_charset_def;
552 	    cs_out  = netmail_charset_out;
553 	}
554 	/* defaults */
555 	if(!cs_def)
556 	    cs_def = default_charset_def;
557 	if(!cs_def)
558 	    cs_def = CHARSET_STDFTN;
559 	if(!cs_out)
560 	    cs_out = default_charset_out;
561 	if(cvt8==0 || !cs_out)
562 	    cs_out = CHARSET_STD7BIT;
563 
564 	if( (p = kludge_get(&body.kludge, "CHRS", NULL)) )
565 	    cs_in = charset_chrs_name(p);
566 	else if( (p = kludge_get(&body.kludge, "CHARSET", NULL)) )
567 	    cs_in = charset_chrs_name(p);
568 	if(!cs_in)
569 	    cs_in = cs_def;
570 	charset_set_in_out(cs_in, cs_out);
571 	/**FIXME: if ERROR is returned, use first matching alias for cs_in**/
572 
573 	/* ^ARFC level and line break flag */
574 	rfc_lvl   = 0;
575 	rfc_lines = FALSE;
576 	if( (p = kludge_get(&body.kludge, "RFC", NULL)) )
577 	{
578 	    s = strtok(p, " \t");
579 	    if(s)
580 		rfc_lvl = atoi(s);
581 	    s = strtok(NULL, " \t");
582 	    if(s && !stricmp(s, "lines"))
583 		rfc_lines = TRUE;
584 	    if(s && atoi(s)==0)
585 		rfc_lines = TRUE;
586 	}
587 
588 	lines = 0;
589 	for(pl=body.body.first; pl; pl=pl->next)
590 	{
591 	    p = pl->line;
592 	    if(*p == '\001')			/* Kludge in message body */
593 	    {
594 		if(strnieq(p + 1, "CHRS: ", 6))
595 		    if( (s = charset_chrs_name(p + 6)) )
596 			cs_in = s;
597 		if(strnieq(p + 1, "CHARSET: ", 9))
598 		    if( (s = charset_chrs_name(p + 9)) )
599 			cs_in = s;
600 		/**FIXME: change in/out charset if needed**/
601 	    }
602 	    else				/* Normal line */
603 	    {
604 		msg_xlate_line(buffer, sizeof(buffer), p, cvt8 & AREA_QP);
605 		if(rfc_lines)
606 		{
607 		    tl_append(&tbody, buffer);
608 		    lines++;
609 		}
610 		else
611 		    lines += msg_format_buffer(buffer, &tbody);
612 	    }
613 	}
614 
615 
616 	/*
617 	 * Convert FTN from/to addresses to RFCAddr struct
618 	 */
619 	if(!cs_in)
620 	    cs_in = cs_def;
621 	charset_set_in_out(cs_in, CHARSET_STD7BIT);
622 	addr_from = rfcaddr_from_ftn(msg.name_from, &msg.node_orig);
623 	addr_to   = rfcaddr_from_ftn(msg.name_to,   &msg.node_to  );
624 
625 	uucp_flag = FALSE;
626 	if(!stricmp(addr_to.real, "UUCP")    ||
627 	   !stricmp(addr_to.real, "GATEWAY")   )
628 	{
629 	    /* Don't output UUCP or GATEWAY as real name */
630 	    uucp_flag = TRUE;
631 	}
632 
633 	/*
634 	 * RFC address headers from text body
635 	 */
636 	msgbody_rfc_from     = get_from    (&body.rfc, &body.kludge);
637 	msgbody_rfc_to       = get_to      (&body.rfc);
638 	msgbody_rfc_reply_to = get_reply_to(&body.rfc);
639 	msgbody_rfc_cc       = get_cc      (&body.rfc);
640 	msgbody_rfc_bcc      = get_bcc     (&body.rfc);
641 
642 	/*
643 	 * If kill_split is set, skip messages with ^ASPLIT
644 	 */
645 	if(kill_split)
646 	{
647 	    /* ^A SPLIT */
648 	    if( (p = kludge_get(&body.kludge, "SPLIT", NULL)) )
649 	    {
650 		logit("skipping split message, origin=%s", znfp1(&msg.node_orig));
651 		tl_clear(&theader);
652 		tl_clear(&tbody);
653 		tl_clear(&tl);
654 		msg_body_clear(&body);
655 		continue;
656 	    }
657 	}
658 
659 	/*
660 	 * If -g flag is set for area and message seems to come from
661 	 * another gateway, skip it.
662 	 */
663 	if(area && (area->flags & AREA_NOGATE))
664 	{
665 	    if(msgbody_rfc_from)
666 	    {
667 		logit("skipping message from gateway, area %s, origin=%s",
668 		    area->area, znfp1(&msg.node_orig));
669 		tl_clear(&theader);
670 		tl_clear(&tbody);
671 		tl_clear(&tl);
672 		msg_body_clear(&body);
673 		continue;
674 	    }
675 
676 	    /* GIGO */
677 	    if( (p = kludge_get(&body.kludge, "PID", NULL))  &&
678 	       !strnicmp(p, "GIGO", 4)                         )
679 	    {
680 		logit("skipping message from gateway (GIGO), area %s, origin=%s",
681 		    area->area, znfp1(&msg.node_orig));
682 		tl_clear(&theader);
683 		tl_clear(&tbody);
684 		tl_clear(&tl);
685 		msg_body_clear(&body);
686 		continue;
687 	    }
688 
689 	    /* Broken FidoZerb message splitting */
690 	    if( (p = kludge_get(&body.kludge, "X-FZ-SPLIT", NULL)) )
691 	    {
692 		logit("skipping message from gateway (X-FZ-SPLIT), area %s, origin=%s",
693 		    area->area, znfp1(&msg.node_orig));
694 		tl_clear(&theader);
695 		tl_clear(&tbody);
696 		tl_clear(&tl);
697 		msg_body_clear(&body);
698 		continue;
699 	    }
700 	}
701 
702 	/*
703 	 * Do alias checking on both from and to names
704 	 */
705 	if(!msgbody_rfc_from)
706 	{
707 	    Alias *a;
708 
709 	    debug(7, "Checking for alias: %s",
710 		  s_rfcaddr_to_asc(&addr_from, TRUE));
711 	    /**FIXME: why _strict()?**/
712 	    a = alias_lookup_strict(&msg.node_orig, NULL, addr_from.real);
713 	    if(a)
714 	    {
715 		if(a->userdom)
716 		{
717 		    debug(7, "Alias found: %s@%s %s %s", a->username, a->userdom,
718 			  znfp1(&a->node), a->fullname);
719 		    BUF_COPY(addr_from.addr, a->userdom);
720 		}
721 		else
722 		    debug(7, "Alias found: %s %s %s", a->username,
723 		          znfp1(&a->node), a->fullname);
724 		BUF_COPY(addr_from.user, a->username);
725 #ifdef ALIASES_ARE_LOCAL
726 		BUF_COPY(addr_from.addr, cf_fqdn());
727 #endif
728 	    }
729 	}
730 	if(!msgbody_rfc_to)
731 	{
732 	    Alias *a;
733 
734 	    debug(7, "Checking for alias: %s",
735 		  s_rfcaddr_to_asc(&addr_to, TRUE));
736 	    /**FIXME: why _strict()?**/
737 	    a = alias_lookup_strict(&msg.node_to, NULL, addr_to.real);
738 	    if(a)
739 	    {
740 		if(a->userdom)
741 		{
742 		    debug(7, "Alias (AI2) found: %s@%s %s \"%s\"",
743 			  a->username, a->userdom,
744 			  znfp1(&a->node), a->fullname);
745 		    /*BUF_COPY(addr_to.addr, a->userdom);*/
746 		    BUF_COPY  (mail_to, a->username);
747 		    BUF_APPEND(mail_to, "@");
748 		    BUF_APPEND(mail_to, a->userdom);
749 		}
750 		else
751 		{
752 		    debug(7, "Alias (old) found: %s %s \"%s\"",
753 			  a->username,
754 		          znfp1(&a->node), a->fullname);
755 		    BUF_COPY(mail_to, a->username);
756 		}
757 	    }
758 	    else
759 		BUF_COPY(mail_to, addr_to.user);
760 	}
761 
762 	/* Special handling for -t flag (insecure): Messages with To
763 	 * line will be bounced */
764 	if(area==NULL && t_flag && msgbody_rfc_to)
765 	{
766 	    debug(1, "Insecure message with To line");
767 	    logit("BOUNCE: insecure mail from %s",
768 		s_rfcaddr_to_asc(&addr_from, TRUE));
769 	    bounce_mail("insecure", &addr_from, &msg, msgbody_rfc_to, &tbody);
770 	    tl_clear(&theader);
771 	    tl_clear(&tbody);
772 	    tl_clear(&tl);
773 	    continue;
774 	}
775 
776 	/* There are message trackers out there in FIDONET. Most of
777 	 * they can't handle addressing the gateway so we send mail
778 	 * from "MsgTrack..." etc. to TrackerMail.  */
779 	if(tracker_mail_to)
780 	    if(   !strnicmp(addr_from.user, "MsgTrack", 8)
781 	       || !strnicmp(addr_from.user, "Reflex_Netmail_Policeman", 24)
782 	       || !strnicmp(addr_from.user, "TrackM", 6)
783 	       || !strnicmp(addr_from.user, "ITrack", 6)
784 	       || !strnicmp(addr_from.user, "O/T-Track", 9)
785 	       /* || whatever ... */		                            )
786 	    {
787 		debug(1, "Mail from FIDO message tracker");
788 		BUF_COPY(x_orig_to, mail_to);
789 		BUF_COPY(mail_to  , tracker_mail_to);
790 		/* Reset uucp_flag to avoid bouncing of these messages */
791 		uucp_flag = FALSE;
792 	    }
793 
794 
795 	thisdomain   = s_ftn_to_inet(cf_addr(),      TRUE);
796 	uplinkdomain = s_ftn_to_inet(&msg.node_from, TRUE);
797 	origindomain = msg.node_orig.zone != -1
798 	    ? s_ftn_to_inet(&msg.node_orig, TRUE) : FTN_INVALID_DOMAIN;
799 
800 	/* Bounce mail from nodes not registered in HOSTS, but allow
801 	 * mail to local users.  */
802 	if(addr_is_restricted() && !ignore_hosts &&
803 	   area==NULL && msgbody_rfc_to && !addr_is_domain(msgbody_rfc_to))
804 	{
805 	    Host *h;
806 
807 	    /* Lookup host */
808 	    if( (h = hosts_lookup(&msg.node_orig, NULL)) == NULL )
809 	    {
810 		/* Not registered in HOSTS */
811 		debug(1, "Not a registered node: %s",
812 		      znfp1(&msg.node_orig));
813 		logit("BOUNCE: mail from unregistered %s",
814 		    s_rfcaddr_to_asc(&addr_from, TRUE));
815 		bounce_mail("restricted", &addr_from, &msg,
816 			    msgbody_rfc_to, &tbody);
817 		tl_clear(&theader);
818 		tl_clear(&tbody);
819 		tl_clear(&tl);
820 		msg_body_clear(&body);
821 		continue;
822 	    }
823 
824 	    /* Bounce, if host is down */
825 	    if(h->flags & HOST_DOWN)
826 	    {
827 		debug(1, "Registered node is down: %s",
828 		      znfp1(&msg.node_orig));
829 		logit("BOUNCE: mail from down %s",
830 		    s_rfcaddr_to_asc(&addr_from, TRUE));
831 		bounce_mail("down", &addr_from, &msg,
832 			    msgbody_rfc_to, &tbody);
833 		tl_clear(&theader);
834 		tl_clear(&tbody);
835 		tl_clear(&tl);
836 		msg_body_clear(&body);
837 		continue;
838 	    }
839 	}
840 
841 	/*
842 	 * Check for address in mail_to
843 	 */
844 	if(area==NULL)
845 	{
846 	    if( strchr(mail_to, '@') || strchr(mail_to, '%') ||
847 	        strchr(mail_to, '!')                            )
848 	    {
849 		if(no_address_in_to_field)
850 		{
851 		    debug(1, "Message with address in mail_to: %s", mail_to);
852 		    logit("BOUNCE: mail from %s with address in to field: %s",
853 			s_rfcaddr_to_asc(&addr_from, TRUE), mail_to           );
854 		    bounce_mail("addrinto",
855 				&addr_from, &msg, msgbody_rfc_to, &tbody);
856 		    tl_clear(&theader);
857 		    tl_clear(&tbody);
858 		    tl_clear(&tl);
859 		    msg_body_clear(&body);
860 		    continue;
861 		}
862 		else
863 		    if( (p = strchr(msg.name_to, '@')) ||
864 			(p = strchr(msg.name_to, '%'))    )
865 			if(check_valid_domain(p+1))
866 			    /* Copy again to avoid "..." */
867 			    BUF_COPY(mail_to, msg.name_to);
868 	    }
869 	}
870 
871 	/*
872 	 * Check for UUCP / GATEWAY, add address to mail without To line
873 	 */
874 	if(area==NULL && !msgbody_rfc_to &&
875 	   !strchr(mail_to, '@') && !strchr(mail_to, '%') &&
876 	   !strchr(mail_to, '!')			    )
877 	{
878 	    if(uucp_flag)
879 	    {
880 		/* Addressed to `UUCP' or `GATEWAY', but no To: line */
881 		debug(1, "Message to `UUCP' or `GATEWAY' without To line");
882 		logit("BOUNCE: mail from %s without To line",
883 		    s_rfcaddr_to_asc(&addr_from, TRUE));
884 		bounce_mail("noto", &addr_from, &msg, msgbody_rfc_to, &tbody);
885 		tl_clear(&theader);
886 		tl_clear(&tbody);
887 		tl_clear(&tl);
888 		msg_body_clear(&body);
889 		continue;
890 	    }
891 
892 	    BUF_APPEND(mail_to, "@");
893 	    if(use_ftn_to_address)
894 		/* Add @ftn-to-host */
895 		BUF_APPEND(mail_to, addr_to.addr);
896 	    else
897 		/* Add @host.domain to local address */
898 		BUF_APPEND(mail_to, cf_fqdn());
899 	}
900 
901 	/* Construct string for From: header line */
902 	if(msgbody_rfc_from) {
903 	    RFCAddr rfc;
904 
905 	    rfc = rfcaddr_from_rfc(msgbody_rfc_from);
906 	    if(!rfc.real[0])
907 		BUF_COPY(rfc.real, addr_from.real);
908 
909 	    addr_from = rfc;
910 	}
911 	from_line = s_rfcaddr_to_asc(&addr_from, TRUE);
912 
913 	/* Construct Reply-To line */
914 	reply_to_line = msgbody_rfc_reply_to;
915 
916 	/* Construct string for To:/X-Comment-To: header line */
917 	if(msgbody_rfc_to) {
918 	    if(strchr(msgbody_rfc_to, '(') || strchr(msgbody_rfc_to, '<') ||
919 	       !*addr_to.real || uucp_flag                                   )
920 		to_line = s_printf("%s", msgbody_rfc_to);
921 	    else
922 		to_line = s_printf("%s (%s)", msgbody_rfc_to, addr_to.real);
923 	}
924 	else {
925 	    if(area)
926 	    {
927 		if(!strcmp(addr_to.user, "All")  ||
928 		   !strcmp(addr_to.user, "Alle") ||
929 		   !strcmp(addr_to.user, "*.*")  ||
930 		   !strcmp(addr_to.user, "*")      )
931 		    to_line = NULL;
932 		else
933 		    to_line = s_printf("(%s)", addr_to.real);
934 	    }
935 	    else
936 		to_line = s_printf("%s", mail_to);
937 	}
938 
939 	/* Construct Cc/Bcc header lines */
940 	cc_line  = msgbody_rfc_to ? msgbody_rfc_cc  : NULL;
941 	bcc_line = msgbody_rfc_to ? msgbody_rfc_bcc : NULL;
942 
943 	/* Construct Message-ID and References header lines */
944 	id_line  = NULL;
945 	ref_line = NULL;
946 
947 	if( (p = kludge_get(&body.kludge, "ORIGID", NULL)) )
948 	    id_line = s_msgid_convert_origid(p, FALSE);
949 	else if( (p = kludge_get(&body.kludge, "Message-Id", NULL)) )
950 	    id_line = s_msgid_convert_origid(p, FALSE);
951 	else if( (p = kludge_get(&body.kludge, "RFC-Message-ID", NULL)) )
952 	    id_line = s_msgid_convert_origid(p, FALSE);
953 	if(!id_line)
954 	{
955 	    int id_zone;
956 
957 	    if( (p = kludge_get(&body.kludge, "MSGID", NULL)) )
958 	    {
959 		if(!strncmp(p, "<NOMSGID_", 9))
960 		{
961 		    logit("MSGID: %s, not gated", p);
962 		    tl_clear(&theader);
963 		    tl_clear(&tbody);
964 		    tl_clear(&tl);
965 		    msg_body_clear(&body);
966 		    continue;
967 		}
968 		id_line = s_msgid_fido_to_rfc(p, &id_zone);
969 		if(no_unknown_msgid_zones)
970 		    if(id_zone>=-1 && !cf_zones_check(id_zone))
971 		    {
972 			logit("MSGID %s: malformed or unknown zone, not gated", p);
973 			tl_clear(&theader);
974 			tl_clear(&tbody);
975 			tl_clear(&tl);
976 			msg_body_clear(&body);
977 			continue;
978 		    }
979 	    }
980 	    else
981 	    {
982 		if(no_messages_without_msgid)
983 		{
984 		    logit("MSGID: none, not gated");
985 		    tl_clear(&theader);
986 		    tl_clear(&tbody);
987 		    tl_clear(&tl);
988 		    msg_body_clear(&body);
989 		    continue;
990 		}
991 		id_line = s_msgid_default(&msg);
992 	    }
993 	}
994 	/* Can't happen, but who knows ... ;-) */
995 	if(!id_line)
996 	{
997 	    logit("ERROR: id_line==NULL, strange.");
998 	    tl_clear(&theader);
999 	    tl_clear(&tbody);
1000 	    tl_clear(&tl);
1001 	    msg_body_clear(&body);
1002 	    continue;
1003 	}
1004 
1005 	if( (p = kludge_get(&body.kludge, "ORIGREF", NULL)) )
1006 	    ref_line = s_msgid_convert_origid(p, FALSE);
1007 	if(!ref_line)
1008 	    if( (p = kludge_get(&body.kludge, "REPLY", NULL)) )
1009 		ref_line = s_msgid_fido_to_rfc(p, NULL);
1010 
1011 	/* ^AGATEWAY */
1012 	gateway = kludge_get(&body.kludge, "GATEWAY", NULL);
1013 
1014 
1015 	/*
1016 	 * Output RFC mail/news header
1017 	 */
1018 
1019 	/* Different header for mail and news */
1020 	if(area==NULL) {			/* Mail */
1021 	    logit("MAIL: %s -> %s", from_line, to_line);
1022 
1023 	    tl_appendf(&theader,
1024 		       "From %s %s\n", s_rfcaddr_to_asc(&addr_from, FALSE),
1025 		       date(DATE_FROM, NULL) );
1026 	    tl_appendf(&theader,
1027 		"Received: by %s (FIDOGATE %s)\n",
1028 		thisdomain, version_global()                            );
1029 	    tl_appendf(&theader,
1030 		"\tid AA%05d; %s\n",
1031 		getpid(), date(NULL, NULL) );
1032 	}
1033 	else 					/* News */
1034 	{
1035 	    if(!strcmp(thisdomain, uplinkdomain))	/* this == uplink */
1036 		tl_appendf(&theader,
1037 			   "Path: %s!%s!%s\n",
1038 			   thisdomain, origindomain, news_path_tail);
1039 	    else
1040 		tl_appendf(&theader,
1041 			   "Path: %s!%s!%s!%s\n",
1042 			   thisdomain, uplinkdomain, origindomain,
1043 			   news_path_tail                         );
1044 	}
1045 
1046 	/* Common header */
1047 	tl_appendf(&theader, "Date: %s\n", date(NULL, &msg.date));
1048 	tl_appendf(&theader, "From: %s\n", from_line);
1049 	if(reply_to_line)
1050 	    tl_appendf(&theader, "Reply-To: %s\n", reply_to_line);
1051 #ifndef AI_5
1052 	msg_xlate_line(buffer, sizeof(buffer), msg.subject, 0);
1053 #else
1054 	msg_xlate_line(buffer, sizeof(buffer), msg.subject, cvt8);
1055 #endif
1056 	tl_appendf(&theader, "Subject: %s\n", buffer);
1057 	tl_appendf(&theader, "Message-ID: %s\n", id_line);
1058 
1059 	/* Different header for mail and news */
1060 	if(area==NULL) {			/* Mail */
1061 	    if(ref_line)
1062 		tl_appendf(&theader, "In-Reply-To: %s\n", ref_line);
1063 	    tl_appendf(&theader, "To: %s\n", to_line);
1064 	    if(cc_line)
1065 		tl_appendf(&theader, "Cc: %s\n", cc_line);
1066 	    if(bcc_line)
1067 		tl_appendf(&theader, "Bcc: %s\n", bcc_line);
1068 	    if(*x_orig_to)
1069 		tl_appendf(&theader, "X-Orig-To: %s\n", x_orig_to);
1070 	    if(errors_to)
1071 		tl_appendf(&theader, "Errors-To: %s\n", errors_to);
1072 	    /* FTN ReturnReceiptRequest -> Return-Receipt-To */
1073 	    if(msg.attr & MSG_RRREQ)
1074 		tl_appendf(&theader, "Return-Receipt-To: %s\n",
1075 				 s_rfcaddr_to_asc(&addr_from, FALSE)   );
1076 	}
1077 	else 					/* News */
1078 	{
1079 	    if(ref_line)
1080 		tl_appendf(&theader, "References: %s\n", ref_line);
1081 	    tl_appendf(&theader, "Newsgroups: %s\n",
1082 			     area->group ? area->group : ftn_junk_group);
1083 	    if(!area->group)
1084 		tl_appendf(&theader, "X-FTN-Area: %s\n", area->area);
1085 	    if(area->distribution)
1086 		tl_appendf(&theader, "Distribution: %s\n",
1087 				 area->distribution               );
1088 	    if(to_line)
1089 		tl_appendf(&theader, "X-Comment-To: %s\n", to_line);
1090 	}
1091 
1092 	/* Common header */
1093 	p = NULL;
1094 	if(use_origin_for_organization && body.origin)
1095 	{
1096 	    strip_crlf(body.origin);
1097 #ifndef AI_5
1098 	    msg_xlate_line(buffer, sizeof(buffer), body.origin, 0);
1099 #else
1100 	    msg_xlate_line(buffer, sizeof(buffer), body.origin, cvt8);
1101 #endif
1102 	    if((p = strrchr(buffer, '(')))
1103 		*p = 0;
1104 	    strip_space(buffer);
1105 	    p = buffer + strlen(" * Origin: ");
1106 	    while(is_blank(*p))
1107 		p++;
1108 	    if(!*p)
1109 		p = NULL;
1110 	}
1111 	if(!p)
1112 	    p = cf_p_organization();
1113 	tl_appendf(&theader, "Organization: %s\n", p);
1114 
1115 	tl_appendf(&theader, "Lines: %d\n", lines);
1116 	if(gateway)
1117 	    tl_appendf(&theader, "X-Gateway: FIDO %s [FIDOGATE %s], %s\n",
1118 		       cf_fqdn(), version_global(), gateway               );
1119 	else
1120 	    tl_appendf(&theader, "X-Gateway: FIDO %s [FIDOGATE %s]\n",
1121 		       cf_fqdn(), version_global()                       );
1122 
1123 	if(area==NULL)
1124 	{
1125 	    if(x_ftn_f)
1126 		tl_appendf(&theader, "X-FTN-From: %s @ %s\n",
1127 			   addr_from.real, znfp1(&msg.node_orig));
1128 	    if(x_ftn_t)
1129 		tl_appendf(&theader, "X-FTN-To: %s @ %s\n",
1130 			   addr_to.real, znfp1(&msg.node_to));
1131 	}
1132 
1133 	if(x_ftn_T  &&  body.tear && !strncmp(body.tear, "--- ", 4))
1134 	{
1135 	    strip_crlf(body.tear);
1136 #ifndef AI_5
1137 	    msg_xlate_line(buffer, sizeof(buffer), body.tear, 0);
1138 #else
1139 	    msg_xlate_line(buffer, sizeof(buffer), body.tear, cvt8);
1140 #endif
1141 	    tl_appendf(&theader, "X-FTN-Tearline: %s\n", buffer+4);
1142 	}
1143 	if(!use_origin_for_organization  &&  x_ftn_O  &&  body.origin)
1144 	{
1145 	    strip_crlf(body.origin);
1146 #ifndef AI_5
1147 	    msg_xlate_line(buffer, sizeof(buffer), body.origin, 0);
1148 #else
1149 	    msg_xlate_line(buffer, sizeof(buffer), body.origin, cvt8);
1150 #endif
1151 	    p = buffer + strlen(" * Origin: ");
1152 	    while(is_blank(*p))
1153 		p++;
1154 	    tl_appendf(&theader, "X-FTN-Origin: %s\n", p);
1155 	}
1156 	if(x_ftn_V)
1157 	    for(pl=body.via.first; pl; pl=pl->next)
1158 	    {
1159 		p = pl->line;
1160 		strip_crlf(p);
1161 		msg_xlate_line(buffer, sizeof(buffer), p+1, 0);
1162 		tl_appendf(&theader, "X-FTN-Via: %s\n", buffer+4);
1163 	    }
1164 	if(x_ftn_D)
1165 	    tl_appendf(&theader, "X-FTN-Domain: Z%d@%s\n",
1166 		       cf_zone(), cf_zones_ftn_domain(cf_zone()));
1167 	if(x_ftn_S)
1168 	    for(pl=body.seenby.first; pl; pl=pl->next)
1169 	    {
1170 		p = pl->line;
1171 		strip_crlf(p);
1172 		tl_appendf(&theader, "X-FTN-Seen-By: %s\n", p + 9);
1173 	    }
1174 	if(x_ftn_P)
1175 	    for(pl=body.path.first; pl; pl=pl->next)
1176 	    {
1177 		p = pl->line;
1178 		strip_crlf(p);
1179 		tl_appendf(&theader, "X-FTN-Path: %s\n", p + 7);
1180 	    }
1181 
1182 	if(split_line)
1183 	    tl_appendf(&theader, "X-SPLIT: %s\n", split_line);
1184 
1185 	/* MIME header */
1186 	tl_appendf(&theader, "MIME-Version: 1.0\n");
1187 	tl_appendf(&theader, "Content-Type: text/plain; charset=%s\n",
1188 		   cvt8 ? cs_out : CHARSET_STD7BIT);
1189 	tl_appendf(&theader, "Content-Transfer-Encoding: %s\n",
1190 		   cvt8 ? ((cvt8 & AREA_QP) ? "quoted-printable" : "8bit")
1191 		        : "7bit");
1192 
1193 	if(cs_save)
1194 	    xfree(cs_save);
1195 
1196 	/* Add extra headers */
1197 	if(area)
1198 	    for(pl=area->x_hdr.first; pl; pl=pl->next)
1199 		tl_appendf(&theader, "%s\n", pl->line);
1200 
1201 	tl_appendf(&theader, "\n");
1202 
1203 	/* Write header and message body to output file */
1204 	if(area) {
1205 	    if(!mail_file('n'))
1206 		if(mail_open('n') == ERROR)
1207 		{
1208 		    ret = ERROR;
1209 		    break;
1210 		}
1211 
1212 	    if(!single_articles)
1213 		/* News batch */
1214 		fprintf(mail_file('n'), "#! rnews %ld\n",
1215 			tl_size(&theader) + tl_size(&tbody) );
1216 	    tl_print(&theader, mail_file('n'));
1217 	    tl_print(&tbody,   mail_file('n'));
1218 
1219 	    if(single_articles)
1220 		mail_close('n');
1221 	}
1222 	else
1223 	{
1224 	    if(mail_open('m') == ERROR)
1225 	    {
1226 		ret = ERROR;
1227 		break;
1228 	    }
1229 
1230 	    /* Mail message */
1231 	    tl_print(&theader, mail_file('m'));
1232 	    tl_print(&tbody,   mail_file('m'));
1233 	    /* Close mail */
1234 	    mail_close('m');
1235 	}
1236 
1237 	tl_clear(&theader);
1238 	tl_clear(&tbody);
1239 	tl_clear(&tl);
1240 	msg_body_clear(&body);
1241 	tmps_freeall();
1242     } /**while(type == MSG_TYPE)**/
1243 
1244     if(mail_file('n'))
1245 	mail_close('n');
1246 
1247     TMPS_RETURN(ret);
1248 }
1249 
1250 
1251 
1252 /*
1253  * Unpack one packet file
1254  */
unpack_file(char * pkt_name)1255 int unpack_file(char *pkt_name)
1256 {
1257     Packet pkt;
1258     FILE *pkt_file;
1259 
1260     /* Open packet and read header */
1261     pkt_file = fopen(pkt_name, R_MODE);
1262     if(!pkt_file) {
1263 	logit("$ERROR: can't open packet %s", pkt_name);
1264 	if(n_flag)
1265 	    return ERROR;
1266 	else
1267 	{
1268 	    rename_bad(pkt_name);
1269 	    return OK;
1270 	}
1271     }
1272     if(pkt_get_hdr(pkt_file, &pkt) == ERROR)
1273     {
1274 	logit("ERROR: reading header from %s", pkt_name);
1275 	if(n_flag)
1276 	    return ERROR;
1277 	else
1278 	{
1279 	    rename_bad(pkt_name);
1280 	    return OK;
1281 	}
1282     }
1283 
1284     /* * Unpack it */
1285     logit("packet %s (%ldb) from %s to %s", pkt_name, check_size(pkt_name),
1286 	znfp1(&pkt.from), znfp2(&pkt.to) );
1287 
1288     if(unpack(pkt_file, &pkt) == ERROR)
1289     {
1290 	logit("ERROR: processing %s", pkt_name);
1291 	if(n_flag)
1292 	    return ERROR;
1293 	else
1294 	{
1295 	    rename_bad(pkt_name);
1296 	    return OK;
1297 	}
1298     }
1299 
1300     fclose(pkt_file);
1301 
1302     if(!n_flag && unlink(pkt_name)==ERROR) {
1303 	logit("$ERROR: can't unlink packet %s", pkt_name);
1304 	rename_bad(pkt_name);
1305 	return OK;
1306     }
1307 
1308     return OK;
1309 }
1310 
1311 
1312 
1313 /*
1314  * Usage messages
1315  */
short_usage(void)1316 void short_usage(void)
1317 {
1318     fprintf(stderr, "usage: %s [-options] [packet ...]\n", PROGRAM);
1319     fprintf(stderr, "       %s --help  for more information\n", PROGRAM);
1320 }
1321 
1322 
usage(void)1323 void usage(void)
1324 {
1325     fprintf(stderr, "FIDOGATE %s  %s %s\n\n",
1326 	    version_global(), PROGRAM, version_local(VERSION) );
1327 
1328     fprintf(stderr, "usage:   %s [-options] [packet ...]\n\n", PROGRAM);
1329     fprintf(stderr, "\
1330 options: -1 --single-articles         write single news articles, not batch\n\
1331          -I --in-dir name             set input packet directory\n\
1332          -i --ignore-hosts            do not bounce unknown host\n\
1333          -l --lock-file               create lock file while processing\n\
1334          -n --no-remove               don't remove/rename input packet file\n\
1335 	 -t --insecure                process insecure packets\n\
1336          -x --exec-program name       exec program after processing\n\
1337 \n\
1338 	 -v --verbose                 more verbose\n\
1339 	 -h --help                    this help\n\
1340          -c --config name             read config file (\"\" = none)\n\
1341 	 -a --addr Z:N/F.P            set FTN address\n\
1342 	 -u --uplink-addr Z:N/F.P     set FTN uplink address\n");
1343 
1344     exit(0);
1345 }
1346 
1347 
1348 
1349 /***** main() ****************************************************************/
1350 
main(int argc,char ** argv)1351 int main(int argc, char **argv)
1352 {
1353     int c, ret;
1354     char *execprog = NULL;
1355     int l_flag=FALSE;
1356     char *I_flag=NULL;
1357     char *c_flag=NULL;
1358     char *a_flag=NULL, *u_flag=NULL;
1359     char *pkt_name;
1360     char *p;
1361 
1362     int option_index;
1363     static struct option long_options[] =
1364     {
1365 	{ "single-articles", 0, 0, '1'},/* Write single article files */
1366 	{ "in-dir",       1, 0, 'I'},	/* Set inbound packets directory */
1367 	{ "ignore-hosts", 0, 0, 'i'},	/* Do not bounce unknown hosts */
1368 	{ "lock-file",    0, 0, 'l'},	/* Create lock file while processing */
1369 	{ "no-remove",    0, 0, 'n'},	/* Don't remove/rename packet file */
1370 	{ "insecure",     0, 0, 't'},	/* Toss insecure packets */
1371 	{ "exec-program", 1, 0, 'x'},	/* Exec program after processing */
1372 
1373 	{ "verbose",      0, 0, 'v'},	/* More verbose */
1374 	{ "help",         0, 0, 'h'},	/* Help */
1375 	{ "config",       1, 0, 'c'},	/* Config file */
1376 	{ "addr",         1, 0, 'a'},	/* Set FIDO address */
1377 	{ "uplink-addr",  1, 0, 'u'},	/* Set FIDO uplink address */
1378 	{ 0,              0, 0, 0  }
1379     };
1380 
1381     log_program(PROGRAM);
1382 
1383     /* Init configuration */
1384     cf_initialize();
1385 
1386 
1387     while ((c = getopt_long(argc, argv, "1itI:lnx:vhc:a:u:",
1388 			    long_options, &option_index     )) != EOF)
1389 	switch (c) {
1390 	/***** ftn2rfc options *****/
1391 	case '1':
1392 	    /* Write single article files */
1393 	    single_articles = TRUE;
1394 	    break;
1395 	case 'I':
1396 	    /* Inbound packets directory */
1397 	    I_flag = optarg;
1398 	    break;
1399 	case 'i':
1400 	    /* Don't bounce unknown hosts */
1401 	    ignore_hosts = TRUE;
1402 	    break;
1403         case 'l':
1404             /* Lock file */
1405 	    l_flag = TRUE;
1406             break;
1407 	case 'n':
1408 	    /* Don't remove/rename input packet file */
1409 	    n_flag = TRUE;
1410 	    break;
1411 	case 't':
1412 	    /* Insecure */
1413 	    t_flag = TRUE;
1414 	    break;
1415         case 'x':
1416             /* Exec program after unpack */
1417             execprog = optarg;
1418             break;
1419 
1420 	/***** Common options *****/
1421 	case 'v':
1422 	    verbose++;
1423 	    break;
1424 	case 'h':
1425 	    usage();
1426 	    exit(0);
1427 	    break;
1428 	case 'c':
1429 	    c_flag = optarg;
1430 	    break;
1431 	case 'a':
1432 	    a_flag = optarg;
1433 	    break;
1434 	case 'u':
1435 	    u_flag = optarg;
1436 	    break;
1437 	default:
1438 	    short_usage();
1439 	    exit(EX_USAGE);
1440 	    break;
1441 	}
1442 
1443     /* Read config file */
1444     cf_read_config_file(c_flag ? c_flag : CONFIG);
1445 
1446     /* Process config options */
1447     if(a_flag)
1448 	cf_set_addr(a_flag);
1449     if(u_flag)
1450 	cf_set_uplink(u_flag);
1451 
1452     cf_i_am_a_gateway_prog();
1453     cf_debug();
1454 
1455     /* Process local options */
1456     BUF_EXPAND(in_dir, I_flag ? I_flag : cf_p_pinbound());
1457 
1458     /* Initialize mail_dir[], news_dir[] output directories */
1459     BUF_EXPAND(mail_dir, DEFAULT_OUTRFC_MAIL);
1460     BUF_EXPAND(news_dir, DEFAULT_OUTRFC_NEWS);
1461 
1462     /* Process optional config statements */
1463     if(cf_get_string("DotNames", TRUE))
1464     {
1465 	debug(8, "config: DotNames");
1466 	rfcaddr_dot_names(TRUE);
1467     }
1468     if( (p = cf_get_string("X-FTN", TRUE)) )
1469     {
1470 	debug(8, "config: X-FTN %s", p);
1471 	while(*p)
1472 	{
1473 	    switch(*p)
1474 	    {
1475 	    case 'f':    x_ftn_f = TRUE;  break;
1476 	    case 't':    x_ftn_t = TRUE;  break;
1477 	    case 'T':    x_ftn_T = TRUE;  break;
1478 	    case 'O':    x_ftn_O = TRUE;  break;
1479 	    case 'V':    x_ftn_V = TRUE;  break;
1480 	    case 'D':    x_ftn_D = TRUE;  break;
1481 	    case 'S':    x_ftn_S = TRUE;  break;
1482 	    case 'P':    x_ftn_P = TRUE;  break;
1483 	    }
1484 	    p++;
1485 	}
1486     }
1487     if( (p = cf_get_string("BounceCCMail", TRUE)) )
1488     {
1489 	debug(8, "config: BounceCCMail %s", p);
1490 	bounce_set_cc(p);
1491     }
1492     if( (p = cf_get_string("TrackerMail", TRUE)) )
1493     {
1494 	debug(8, "config: TrackerMail %s", p);
1495 	tracker_mail_to = p;
1496     }
1497     if(cf_get_string("KillUnknownMSGIDZone", TRUE))
1498     {
1499 	debug(8, "config: KillUnknownMSGIDZone");
1500 	no_unknown_msgid_zones = TRUE;
1501     }
1502     if(cf_get_string("KillNoMSGID", TRUE))
1503     {
1504 	debug(8, "config: KillNoMSGID");
1505 	no_messages_without_msgid = TRUE;
1506     }
1507     if(cf_get_string("UseOriginForOrganization", TRUE))
1508     {
1509 	debug(8, "config: UseOriginForOrganzation");
1510 	use_origin_for_organization = TRUE;
1511     }
1512     if(cf_get_string("HostsRestricted", TRUE))
1513     {
1514 	debug(8, "config: HostsRestricted");
1515 	addr_restricted(TRUE);
1516     }
1517     if( (p = cf_get_string("FTNJunkGroup", TRUE)) )
1518     {
1519 	debug(8, "config: FTNJunkGroup %s", p);
1520 	ftn_junk_group = p;
1521     }
1522     if( (p = cf_get_string("ErrorsTo", TRUE)) )
1523     {
1524 	debug(8, "config: ErrorsTo %s", p);
1525 	ftn_junk_group = p;
1526     }
1527     if(cf_get_string("NoAddressInToField", TRUE))
1528     {
1529 	debug(8, "config: NoAddressInToField");
1530 	no_address_in_to_field = TRUE;
1531     }
1532     if(cf_get_string("NetMail8bit", TRUE))
1533     {
1534 	debug(8, "config: NetMail8bit");
1535 	netmail_8bit = TRUE;
1536     }
1537     if(cf_get_string("NetMailQuotedPrintable", TRUE) ||
1538        cf_get_string("NetMailQP", TRUE)                )
1539     {
1540 	debug(8, "config: NetMailQP");
1541 	netmail_qp = TRUE;
1542     }
1543     if(cf_get_string("UseFTNToAddress", TRUE))
1544     {
1545 	debug(8, "config: UseFTNToAddress");
1546 	use_ftn_to_address = TRUE;
1547     }
1548     if(cf_get_string("KillSplit", TRUE))
1549     {
1550 	debug(8, "config: KillSplit");
1551 	kill_split = TRUE;
1552     }
1553     if(cf_get_string("SingleArticles", TRUE))
1554     {
1555 	debug(8, "config: SingleArticles");
1556 	single_articles = TRUE;
1557     }
1558     if( (p = cf_get_string("RFCAddrMode", TRUE)) )
1559     {
1560 	int m = 0;
1561 
1562 	switch(*p)
1563 	{
1564 	case '(': case 'p': case '0':
1565 	    m = 0;				/* user@do.main (Real Name) */
1566 	    break;
1567 	case '<': case 'a': case '1':
1568 	    m = 1;				/* Real Name <user@do.main> */
1569 	    break;
1570 	}
1571 	rfcaddr_mode(m);
1572 	debug(8, "config: RFCAddrMode %d", m);
1573     }
1574     if( (p = cf_get_string("DefaultCharset", TRUE)) )
1575     {
1576 	debug(8, "config: DefaultCharset %s", p);
1577 	default_charset_def = strtok(p, ":");
1578 	strtok(NULL, ":");
1579 	default_charset_out = strtok(NULL, ":");
1580     }
1581     if( (p = cf_get_string("NetMailCharset", TRUE)) )
1582     {
1583 	debug(8, "config: NetMailCharset %s", p);
1584 	netmail_charset_def = strtok(p, ":");
1585 	strtok(NULL, ":");
1586 	netmail_charset_out = strtok(NULL, ":");
1587     }
1588     if( (p = cf_get_string("NewsPathTail", TRUE)) )
1589     {
1590 	/* <FIDOGATE_CONFIG>
1591 	 * <CMD>     NewsPathTail
1592 	 * <PARA>    STRING
1593 	 * <DEFAULT> "not-for-mail"
1594 	 * <DESC>    The STRING which FIDOGATE's ftn2rfc adds to the
1595 	 *           Path header, normally "not-for-mail". If gated
1596 	 *           messages are not generally exported to the Usenet,
1597 	 *           setting it to "fidogate!not-for-mail" makes
1598 	 *           the INN newsfeeds entry easier and less error-prone.
1599 	 */
1600 	debug(8, "config: NewsPathTail %s", p);
1601 	news_path_tail = p;
1602     }
1603     if(cf_get_string("NetMailCharsetUse1st", TRUE))
1604     {
1605 	debug(8, "config: NetMailCharsetUse1st");
1606 	netmail_charset_use_1st = TRUE;
1607     }
1608     if(cf_get_string("DontIgnore0x8d", TRUE)   ||
1609        cf_get_string("DontIgnoreSoftCR", TRUE)   )
1610     {
1611 	debug(8, "config: DontIgnore0x8d");
1612 	msg_ignore_0x8d = FALSE;
1613     }
1614 
1615     /* Init various modules */
1616     areas_init();
1617     hosts_init();
1618     alias_init();
1619     charset_init();
1620 
1621     /* If called with -l lock option, try to create lock FILE */
1622     if(l_flag)
1623 	if(lock_program(PROGRAM, NOWAIT) == ERROR)
1624 	    exit(EXIT_BUSY);
1625 
1626     ret = EXIT_OK;
1627 
1628     if(optind >= argc)
1629     {
1630 	/* process packet files in input directory */
1631 	dir_sortmode(DIR_SORTMTIME);
1632 	if(dir_open(in_dir, "*.pkt", TRUE) == ERROR)
1633 	{
1634 	    logit("$ERROR: can't open directory %s", in_dir);
1635 	    if(l_flag)
1636 		unlock_program(PROGRAM);
1637 	    exit(EX_OSERR);
1638 	}
1639 
1640 	for(pkt_name=dir_get(TRUE); pkt_name; pkt_name=dir_get(FALSE))
1641 	{
1642 	    if(unpack_file(pkt_name) != OK)
1643 		ret = EXIT_ERROR;
1644 	    tmps_freeall();
1645 	}
1646 
1647 	dir_close();
1648     }
1649     else
1650     {
1651 	/* Process packet files on command line */
1652 	for(; optind<argc; optind++)
1653 	{
1654 	    if(unpack_file(argv[optind]) != OK)
1655 		ret = EXIT_ERROR;
1656 	    tmps_freeall();
1657 	}
1658     }
1659 
1660 
1661     /* Execute given command, if option -x set.  */
1662     if(execprog)
1663     {
1664 	int retx;
1665 
1666 	BUF_EXPAND(buffer, execprog);
1667 	debug(4, "Command: %s", buffer);
1668 	retx = run_system(buffer);
1669 	debug(4, "Exit code=%d", retx);
1670 	if(retx != EXIT_OK)
1671 	    ret = EXIT_ERROR;
1672     }
1673 
1674     if(l_flag)
1675 	unlock_program(PROGRAM);
1676 
1677     exit(ret);
1678 }
1679