1 /*:ts=8*/
2 /*****************************************************************************
3  * FIDOGATE --- Gateway UNIX Mail/News <-> FTN NetMail/EchoMail
4  *
5  *
6  * FTN-FTN gateway for NetMail, using the %Z:N/F.P addressing in the
7  * from/to fields.
8  *****************************************************************************
9  * Copyright (C) 1990-2002
10  *  _____ _____
11  * |     |___  |   Martin Junius             <mj@fidogate.org>
12  * | | | |   | |   Radiumstr. 18
13  * |_|_|_|@home|   D-51069 Koeln, Germany
14  *
15  * This file is part of FIDOGATE.
16  *
17  * FIDOGATE is free software; you can redistribute it and/or modify it
18  * under the terms of the GNU General Public License as published by the
19  * Free Software Foundation; either version 2, or (at your option) any
20  * later version.
21  *
22  * FIDOGATE is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with FIDOGATE; see the file COPYING.  If not, write to the Free
29  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30  *****************************************************************************/
31 
32 #include "fidogate.h"
33 #include "getopt.h"
34 
35 #define PROGRAM 	"ftn2ftn"
36 #define CONFIG		DEFAULT_CONFIG_MAIN
37 
38 /*
39  * Prototypes
40  */
41 void add_via(Textlist *, Node *);
42 int do_message(Node *, Message *, MsgBody *);
43 int unpack(Node *, FILE *, Packet *);
44 int unpack_file(Node *, char *);
45 int do_outbound(Node *, Node *);
46 
47 void short_usage(void);
48 void usage(void);
49 
50 static char *o_flag = NULL;     /* -o --out-packet-file option */
51 
52 /*
53  * Zone gate addresses
54  */
55 Node gate_a;                    /* FTN address in network A */
56 Node gate_b;                    /* FTN address in network B */
57 static bool strict;
58 
59 /*
60  * Add our ^AVia line
61  */
add_via(Textlist * list,Node * gate)62 void add_via(Textlist * list, Node * gate)
63 {
64 #ifndef FTS_VIA
65     tl_appendf(list, "\001Via FIDOGATE/%s %s, %s\r",
66                PROGRAM, znf1(gate), date(DATE_VIA, NULL));
67 #else
68     tl_appendf(list, "\001Via %s @%s FIDOGATE/%s\r",
69                znf1(gate), date(DATE_VIA, NULL), PROGRAM);
70 #endif                          /* FTS_VIA */
71 }
72 
73 /*
74  * Process one message for zone gate
75  */
do_message(Node * gate,Message * msg,MsgBody * body)76 int do_message(Node * gate, Message * msg, MsgBody * body)
77 {
78     static int last_zone = -1;
79     static FILE *fp;
80     char *from, *to;
81     char *p;
82     Node node;
83 
84     from = msg->name_from;
85     to = msg->name_to;
86 
87     debug(3, "Message to: %s", to);
88 
89     p = strrchr(to, '%');
90     if (!p)
91         p = strrchr(to, '@');
92 
93     /*
94      * Check for EchoMail
95      */
96     if (body->area) {
97         fglog("ftn2ftn: skipping EchoMail");
98         return ERROR;
99     }
100 
101     /*
102      * Gateway addressing with "User Name%Z:N/F.P"
103      * "User Name@Z:N/F.P" found. Get address and push
104      * to the other side.
105      */
106     if (p && asc_to_node(p + 1, &node, FALSE) == OK) {
107         cf_set_zone(gate->zone);
108 
109         /* Add gate addresses to ^Via lines */
110         add_via(&body->via, &msg->node_to);
111         add_via(&body->via, gate);
112 
113         /* Strip % addressing */
114         *p = 0;
115         /* Add sender address to from name */
116         BUF_COPY2(buffer, "%", znf1(&msg->node_from));
117         if (strlen(from) + strlen(buffer) > MSG_MAXNAME - 1)
118             from[MSG_MAXNAME - 1 - strlen(buffer)] = 0;
119         str_append(from, MSG_MAXNAME, buffer);
120         /* Readdress */
121         msg->node_from = *gate;
122         msg->node_to = node;
123     }
124     /*
125      * Local message, simply readdress to our main AKA
126      */
127     else {
128         cf_set_zone(msg->node_to.zone);
129 
130         /* Add gate addresses to ^Via lines */
131         add_via(&body->via, &msg->node_to);
132 
133         /* Readdress */
134         msg->node_to = cf_n_addr();
135     }
136 
137     /*
138      * Write this message to the output packet
139      */
140     if (!o_flag && cf_zone() != last_zone)
141         pkt_close();
142     if (!pkt_isopen())
143         if ((fp = pkt_open(o_flag, NULL, NULL, FALSE)) == NULL)
144             return ERROR;
145     last_zone = cf_zone();
146 
147     msg->area = NULL;
148     if (pkt_put_msg_hdr(fp, msg, TRUE) != OK)
149         return ERROR;
150     if (msg_put_msgbody(fp, body) != OK)
151         return ERROR;
152 
153     return OK;
154 }
155 
156 /*
157  * Unpack and process messages
158  */
unpack(Node * gate,FILE * pkt_file,Packet * pkt)159 int unpack(Node * gate, FILE * pkt_file, Packet * pkt)
160 {
161     Message msg = { 0 };
162     Textlist tl;
163     MsgBody body;
164     int type;
165 
166     tl_init(&tl);
167     msg_body_init(&body);
168 
169     type = pkt_get_int16(pkt_file);
170     while ((type == MSG_TYPE) && !xfeof(pkt_file)) {
171         msg.node_from = pkt->from;
172         msg.node_to = pkt->to;
173         if (pkt_get_msg_hdr(pkt_file, &msg, strict) == ERROR)
174             TMPS_RETURN(ERROR);
175 
176         if (pkt_get_body_parse(pkt_file, &body, &msg.node_from, &msg.node_to) !=
177             OK) {
178             fglog("ftn2ftn: error parsing message body");
179             TMPS_RETURN(ERROR);
180         }
181         /* Retrieve address information from body */
182         kludge_pt_intl(&body, &msg, TRUE);
183 
184         if (do_message(gate, &msg, &body) != OK)
185             TMPS_RETURN(ERROR);
186     }
187 
188     /* Close packet */
189     pkt_close();
190 
191     TMPS_RETURN(OK);
192 }
193 
194 /*
195  * Unpack one packet file
196  */
unpack_file(Node * gate,char * pkt_name)197 int unpack_file(Node * gate, char *pkt_name)
198 {
199     Packet pkt;
200     FILE *pkt_file;
201 
202     debug(1, "Unpacking FTN packet %s", pkt_name);
203 
204     /*
205      * Open packet and read header
206      */
207     pkt_file = fopen(pkt_name, R_MODE);
208     if (!pkt_file) {
209         fglog("$Can't open packet %s", pkt_name);
210         exit_free();
211         exit(EX_OSERR);
212     }
213     if (pkt_get_hdr(pkt_file, &pkt) == ERROR) {
214         fglog("Error reading header from %s", pkt_name);
215         exit_free();
216         exit(EX_OSERR);
217     }
218 
219     /*
220      * Unpack it
221      */
222     if (unpack(gate, pkt_file, &pkt) != OK) {
223         fclose(pkt_file);
224         fglog("Error in unpacking %s", pkt_name);
225         exit_free();
226         exit(EX_OSERR);
227     }
228 
229     fclose(pkt_file);
230 
231     if (unlink(pkt_name)) {
232         fglog("$Could not unlink packet %s", pkt_name);
233         exit_free();
234         exit(EX_OSERR);
235     }
236 
237     return OK;
238 }
239 
240 /*
241  * Process packet for gateway address in Binkley outbound
242  */
do_outbound(Node * gate_outb,Node * gate_other)243 int do_outbound(Node * gate_outb, Node * gate_other)
244 {
245     char *name;
246 
247     /* Create BSY file */
248     if (bink_bsy_create(gate_outb, NOWAIT) == ERROR)
249         return ERROR;
250 
251     /* Find and process OUT packet file */
252     if ((name = bink_find_out(gate_outb, NULL)))
253         unpack_file(gate_other, name);
254 
255     /* Delete BSY file */
256     if (bink_bsy_delete(gate_outb) == ERROR)
257         return ERROR;
258 
259     return OK;
260 }
261 
262 /*
263  * Usage messages
264  */
short_usage(void)265 void short_usage(void)
266 {
267     fprintf(stderr, "usage: %s [-options] [packet ...]\n", PROGRAM);
268     fprintf(stderr, "       %s --help  for more information\n", PROGRAM);
269 }
270 
usage(void)271 void usage(void)
272 {
273     fprintf(stderr, "FIDOGATE %s  %s %s\n\n",
274             version_global(), PROGRAM, version_local(VERSION));
275 
276     fprintf(stderr, "usage:   %s [-options] [packet ...]\n\n", PROGRAM);
277     fprintf(stderr, "\
278 options: -A --address-a Z:N/F.P       FTN address in network A\n\
279          -B --address-b Z:N/F.P       FTN address in network B\n\
280 	 -o --out-packet-file NAME    set output packet file name\n\
281 	 -O --out-packet-dir NAME     set output packet directory\n\
282 \n\
283          -v --verbose                 more verbose\n\
284 	 -h --help                    this help\n\
285          -c --config name             read config file (\"\" = none)\n\
286 	 -a --addr Z:N/F.P            set FTN address\n\
287 	 -u --uplink-addr Z:N/F.P     set FTN uplink address\n");
288 
289     exit(0);
290 }
291 
292 /***** main() ****************************************************************/
293 
main(int argc,char ** argv)294 int main(int argc, char **argv)
295 {
296     int c;
297     char *O_flag = NULL;
298     char *c_flag = NULL;
299     char *a_flag = NULL, *u_flag = NULL;
300 
301     int option_index;
302     static struct option long_options[] = {
303         {"address-a", 1, 0, 'A'},   /* Address A */
304         {"address-b", 1, 0, 'B'},   /* Address B */
305         {"out-packet-file", 1, 0, 'o'}, /* Set packet file name */
306         {"out-dir", 1, 0, 'O'}, /* Set packet directory */
307 
308         {"verbose", 0, 0, 'v'}, /* More verbose */
309         {"help", 0, 0, 'h'},    /* Help */
310         {"config", 1, 0, 'c'},  /* Config file */
311         {"addr", 1, 0, 'a'},    /* Set FIDO address */
312         {"uplink-addr", 1, 0, 'u'}, /* Set FIDO uplink address */
313         {0, 0, 0, 0}
314     };
315 
316     log_program(PROGRAM);
317 
318     /* Init configuration */
319     cf_initialize();
320 
321     while ((c = getopt_long(argc, argv, "A:B:o:O:vhc:a:u:",
322                             long_options, &option_index)) != EOF)
323         switch (c) {
324     /***** ftn2ftn options *****/
325         case 'A':
326             if (asc_to_node(optarg, &gate_a, FALSE) != OK) {
327                 fprintf(stderr, "%s: option -A: illegal address %s\n",
328                         PROGRAM, optarg);
329                 exit_free();
330                 exit(EX_USAGE);
331             }
332             break;
333         case 'B':
334             if (asc_to_node(optarg, &gate_b, FALSE) != OK) {
335                 fprintf(stderr, "%s: option -B: illegal address %s\n",
336                         PROGRAM, optarg);
337                 exit_free();
338                 exit(EX_USAGE);
339             }
340             break;
341         case 'o':
342             /* Set packet file name */
343             o_flag = optarg;
344             break;
345         case 'O':
346             /* Set packet dir */
347             O_flag = optarg;
348             break;
349 
350     /***** Common options *****/
351         case 'v':
352             verbose++;
353             break;
354         case 'h':
355             usage();
356             exit(0);
357             break;
358         case 'c':
359             c_flag = optarg;
360             break;
361         case 'a':
362             a_flag = optarg;
363             break;
364         case 'u':
365             u_flag = optarg;
366             break;
367         default:
368             short_usage();
369             exit(EX_USAGE);
370             break;
371         }
372 
373     /*
374      * Read config file
375      */
376     cf_read_config_file(c_flag ? c_flag : CONFIG);
377 
378     /*
379      * Process config options
380      */
381     if (a_flag)
382         cf_set_addr(a_flag);
383     if (u_flag)
384         cf_set_uplink(u_flag);
385 
386     cf_debug();
387     debug(4, "gateway address A: %s", znfp1(&gate_a));
388     debug(4, "gateway address B: %s", znfp1(&gate_b));
389 
390     strict = (cf_get_string("FTNStrictPktCheck", TRUE) != NULL);
391 
392     /*
393      * Process local options
394      */
395     if (O_flag)
396         pkt_outdir(O_flag, NULL);
397     else
398         pkt_outdir(cf_p_outpkt(), NULL);
399 
400     passwd_init();
401 
402     /*
403      * Process command line file args
404      */
405     if (optind >= argc) {
406         /* Process outbound packets for both addresses */
407         do_outbound(&gate_a, &gate_b);
408         tmps_freeall();
409         do_outbound(&gate_b, &gate_a);
410         tmps_freeall();
411     } else
412         for (; optind < argc; optind++) {
413             unpack_file(&gate_a, argv[optind]);
414             tmps_freeall();
415         }
416 
417     exit_free();
418     exit(EX_OK);
419 }
420