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