1 /*:ts=8*/
2 /*****************************************************************************
3  * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4  *
5  * $Id: packet.c,v 4.21 2004/08/22 20:19:11 n0ll Exp $
6  *
7  * Functions to read/write packets and messages
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 
35 
36 
37 /*
38  * Outbound packets: directory, name, temp. name, file
39  */
40 static char packet_dir [MAXPATH];
41 static char packet_bad [MAXPATH];
42 static char packet_name[MAXPATH];
43 static char packet_tmp [MAXPATH];
44 static FILE *packet_file = NULL;
45 static Node packet_node = { -1, -1, -1, -1, "" };
46 static int packet_bsy = FALSE;
47 
48 static char *pkt_newname	(char *);
49 static FILE *pkt_open_node	(Node *, char *, int);
50 static FILE *pkt_create		(Node *);
51 
52 
53 /*
54  * Set output packet directory
55  */
pkt_outdir(char * dir1,char * dir2)56 void pkt_outdir(char *dir1, char *dir2)
57 {
58     BUF_EXPAND(packet_dir, dir1);
59     if(dir2)
60     {
61 	BUF_APPEND(packet_dir, "/" );
62 	BUF_APPEND(packet_dir, dir2);
63     }
64 }
65 
66 /*
67  * Return packet_dir[] name
68  */
pkt_get_outdir(void)69 char *pkt_get_outdir(void)
70 {
71     return packet_dir;
72 }
73 
74 
75 
76 /*
77  * Set bad packet directory
78  */
pkt_baddir(char * dir1,char * dir2)79 void pkt_baddir(char *dir1, char *dir2)
80 {
81     BUF_EXPAND(packet_bad, dir1);
82     if(dir2)
83     {
84 	BUF_APPEND(packet_bad, "/" );
85 	BUF_APPEND(packet_bad, dir2);
86     }
87 }
88 
89 /*
90  * Return packet_bad[] name
91  */
pkt_get_baddir(void)92 char *pkt_get_baddir(void)
93 {
94     return packet_bad;
95 }
96 
97 
98 
99 /*
100  * Return packet name / temp name
101  */
pkt_name(void)102 char *pkt_name(void)
103 {
104     return packet_name;
105 }
106 
pkt_tmpname(void)107 char *pkt_tmpname(void)
108 {
109     return packet_tmp;
110 }
111 
112 
113 
114 /*
115  * Return open status (packet_file != NULL)
116  */
pkt_isopen(void)117 int pkt_isopen(void)
118 {
119     return packet_file != NULL;
120 }
121 
122 
123 
124 /*
125  * Get name for new packet
126  */
pkt_newname(char * name)127 static char *pkt_newname(char *name)
128 {
129     if(name)
130     {
131 	BUF_COPY(packet_name, name);
132 	BUF_COPY(packet_tmp , name);
133     }
134     else
135     {
136 	long n = sequencer(DEFAULT_SEQ_PKT);
137 	str_printf(packet_name, sizeof(packet_name),
138 		   "%s/%08ld.pkt", packet_dir, n);
139 	str_printf(packet_tmp , sizeof(packet_tmp),
140 		   "%s/%08ld.tmp", packet_dir, n);
141     }
142 
143     return packet_name;
144 }
145 
146 
147 
148 /*
149  * Open .OUT packet in Binkley outbound
150  */
151 #define MAX_COUNT 50
152 
pkt_open_node(Node * node,char * flav,int bsy)153 static FILE *pkt_open_node(Node *node, char *flav, int bsy)
154 {
155     char *out;
156     FILE *fp;
157     long pos;
158     Packet pkt;
159     int count;
160 
161     /* Name of .OUT file */
162     out = bink_find_out(node, flav);
163     if(!out)
164 	return NULL;
165     /* Create directory if necessary */
166     if(bink_mkdir(node) == ERROR)
167 	return NULL;
168 
169     packet_bsy = bsy;
170     if(bsy)
171 	if(bink_bsy_create(node, WAIT) == ERROR)
172 	    return NULL;
173 
174     pkt_newname(out);
175 
176     /*
177      * Open and lock OUT packet
178      */
179     count = 0;
180     do
181     {
182 	count++;
183 	/*
184 	 * Check count and give up, if too many retries
185 	 */
186 	if(count >= MAX_COUNT)
187 	{
188 	    fp = NULL;
189 	    break;
190 	}
191 
192 	/* Open OUT file for append, creating empty one if necessary */
193 	debug(4, "Open OUT file in append mode");
194 	fp = fopen(out, A_MODE);
195 	if(fp == NULL)
196 	{
197 	    /* If this failed we're out of luck ... */
198 	    logit("$ERROR: can't open OUT file %s", out);
199 	    break;
200 	}
201 
202 	/* Reopen in read/write mode */
203 	debug(4, "Reopen OUT file in read/write mode");
204 	fclose(fp);
205 	fp = fopen(out, RP_MODE);
206 	if(fp == NULL)
207 	{
208 	    /* OUT file deleted in the meantime - retry */
209 	    debug(4, "OUT file deleted, retrying");
210 	    continue;
211 	}
212 	chmod(out, PACKET_MODE);
213 
214 	/* Lock it, waiting for lock to be granted */
215 	debug(4, "Locking OUT file");
216 	if(lock_file(fp))
217 	{
218 	    /* Lock error ... */
219 	    logit("$ERROR: can't lock OUT file %s", out);
220 	    fclose(fp);
221 	    fp = NULL;
222 	    break;
223 	}
224 
225 	/* Lock succeeded, but the OUT file may have been deleted */
226 	if(access(out, F_OK) == -1)
227 	{
228 	    debug(4, "OUT file deleted, retrying");
229 	    fclose(fp);
230 	    fp = NULL;
231 	}
232     }
233     while(fp == NULL);
234 
235     /*
236      * fp==NULL is an error in the do ... while loop
237      */
238     if(fp == NULL)
239     {
240 	if(bsy)
241 	    bink_bsy_delete(node);
242 	return NULL;
243     }
244 
245     /*
246      * Test, whether this is a new empty packet, or an already existing one.
247      */
248     /* Seek to EOF */
249     if(fseek(fp, 0L, SEEK_END) == -1)
250     {
251 	/* fseek() error ... */
252 	logit("$ERROR: fseek EOF OUT file %s failed", out);
253 	if(bsy)
254 	    bink_bsy_delete(node);
255 	fclose(fp);
256 	return NULL;
257     }
258     if( (pos = ftell(fp)) == -1L )
259     {
260 	/* ftell() error ... */
261 	logit("$ERROR: ftell OUT file %s failed", out);
262 	if(bsy)
263 	    bink_bsy_delete(node);
264 	fclose(fp);
265 	return NULL;
266     }
267 
268     if(pos == 0L)
269     {
270 	Passwd *pwd;
271 
272 	/*
273 	 * This is a new packet file
274 	 */
275 	debug(4, "%s is a new packet, writing header", out);
276 
277 	pkt.from = cf_n_addr();
278 	pkt.to   = *node;
279 	pkt.time = time(NULL);
280 	/* Password */
281 	pwd = passwd_lookup("packet", node);
282 	BUF_COPY(pkt.passwd, pwd ? pwd->passwd : "");
283 
284 	/* Rest is filled in by pkt_put_hdr() */
285 	if(pkt_put_hdr(fp, &pkt) == ERROR)
286 	{
287 	    logit("$ERROR: can't write to packet file %s", out);
288 	    if(bsy)
289 		bink_bsy_delete(node);
290 	    fclose(fp);
291 	    return NULL;
292 	}
293     }
294     else
295     {
296 	/*
297 	 * This is an already existing packet file: seek to end of file
298 	 * - 2, there must be a terminating 0-word. Start writing new data
299 	 * at the EOF - 2 position.
300 	 */
301 	debug(4, "%s already exists, seek to EOF-2", out);
302 
303 	if(fseek(fp, -2L, SEEK_END) == -1)
304 	{
305 	    /* fseek() error ... */
306 	    logit("$ERROR: fseek EOF-2 OUT file %s failed", out);
307 	    if(bsy)
308 		bink_bsy_delete(node);
309 	    fclose(fp);
310 	    return NULL;
311 	}
312 	if( pkt_get_int16(fp) != 0L )
313 	{
314 	    logit("$ERROR: malformed packet %s, no terminating 0-word", out);
315 	    if(bsy)
316 		bink_bsy_delete(node);
317 	    fclose(fp);
318 	    return NULL;
319 	}
320 	if(fseek(fp, -2L, SEEK_END) == -1)
321 	{
322 	    /* fseek() error ... */
323 	    logit("$ERROR: fseek EOF-2 OUT file %s failed", out);
324 	    if(bsy)
325 		bink_bsy_delete(node);
326 	    fclose(fp);
327 	    return NULL;
328 	}
329     }
330 
331     packet_file = fp;
332     packet_node = *node;
333 
334     return fp;
335 }
336 
337 
338 
339 /*
340  * Create new packet
341  */
pkt_create(Node * to)342 static FILE *pkt_create(Node *to)
343 {
344     Packet pkt;
345     Passwd *pwd;
346 
347     if((packet_file = fopen(packet_tmp, W_MODE)) == NULL)
348     {
349 	logit("$ERROR: pkt_open(): can't create packet %s", packet_tmp);
350 	return NULL;
351     }
352 
353     /*
354      * Change mode to PACKET_MODE
355      */
356     chmod(packet_tmp, PACKET_MODE);
357 
358     debug(4, "New packet file %s (tmp %s)", packet_name, packet_tmp);
359 
360     /*
361      * Write packet header
362      */
363     pkt.from = cf_n_addr();
364     pkt.to   = *to;
365     pkt.time = time(NULL);
366     /* Password */
367     pwd = passwd_lookup("packet", to);
368     BUF_COPY(pkt.passwd, pwd ? pwd->passwd : "");
369 
370     /* Rest is filled in by pkt_put_hdr() */
371     if(pkt_put_hdr(packet_file, &pkt) == ERROR)
372     {
373 	logit("$ERROR: can't write to packet file %s", packet_tmp);
374 	return NULL;
375     }
376 
377     return packet_file;
378 }
379 
380 
381 
382 /*
383  * Create new packet file
384  */
pkt_open(char * name,Node * node,char * flav,int bsy)385 FILE *pkt_open(char *name, Node *node, char *flav, int bsy)
386 {
387     if(name && !name[0])
388 	name = NULL;
389 
390     if(node && !name)
391 	/*
392 	 * Open packet in Binkley outbound
393 	 */
394 	return pkt_open_node(node, flav, bsy);
395     else
396     {
397 	/*
398 	 * Open packet in FIDOGATE outbound directory or named packet
399 	 */
400 	pkt_newname(name);
401 	return pkt_create( node ? node : cf_uplink() );
402     }
403 
404     /**NOT REACHED**/
405     return NULL;
406 }
407 
408 
409 
410 /*
411  * Write end of packet to packet file, close and rename it.
412  */
pkt_close(void)413 int pkt_close(void)
414 {
415     int ret = OK;
416 
417     if(packet_file)
418     {
419 	/* End of packet */
420 	pkt_put_int16(packet_file, 0);
421 	ret = fclose(packet_file);
422 
423 	packet_file = NULL;
424 
425 	if(packet_node.zone != -1)
426 	{
427 	    if(packet_bsy)
428 		bink_bsy_delete(&packet_node);
429 	    packet_bsy = FALSE;
430 	    packet_node.zone = -1;
431 	}
432 
433 	/* Rename .tmp -> .pkt, if not the same name */
434 	if( strcmp(packet_tmp, packet_name) )
435 	    if(rename(packet_tmp, packet_name) == ERROR)
436 	    {
437 		logit("$ERROR: can't rename %s to %s", packet_tmp, packet_name);
438 		ret = ERROR;
439 	    }
440     }
441 
442     return ret;
443 }
444 
445 
446 
447 /*
448  * Read null-terminated string from packet file
449  */
pkt_get_string(FILE * fp,char * buf,int nbytes)450 int pkt_get_string(FILE *fp, char *buf, int nbytes)
451 {
452     int c, i;
453 
454     for(i=0; TRUE; i++)
455     {
456 	c = getc(fp);
457 	if(c==0 || c==EOF)
458 	    break;
459 	if(i >= nbytes-1)
460 	    break;
461 	buf[i] = c;
462     }
463     buf[i] = 0;
464 
465     return c!=0 ? ERROR : OK;
466 }
467 
468 
469 
470 /*
471  * Return date of message in UNIX format (secs after the epoche)
472  *
473  * Understood formats: see FTS-0001 (actually using getdate.y parser)
474  */
pkt_get_date(FILE * fp)475 time_t pkt_get_date(FILE *fp)
476 {
477     /*
478      * Allow some characters more in the date string.
479      */
480     char buf[MSG_MAXDATE + 10];
481 
482     /*
483      * Treat FTN date as a 0-terminated string. Actually it's a fixed
484      * string with exactly 19 chars + 0-char.
485      */
486     buf[0] = 0;
487     pkt_get_string(fp, buf, sizeof(buf));
488 
489     return parsedate(buf, NULL);
490 }
491 
492 
493 
494 /*
495  * Read message header from packet file
496  */
pkt_get_msg_hdr(FILE * fp,Message * msg)497 int pkt_get_msg_hdr(FILE *fp, Message *msg)
498 {
499     msg->node_from.node = pkt_get_int16(fp);
500     msg->node_to  .node = pkt_get_int16(fp);
501     msg->node_from.net  = pkt_get_int16(fp);
502     msg->node_to  .net  = pkt_get_int16(fp);
503     msg->node_orig      = msg->node_from;
504     msg->attr           = pkt_get_int16(fp);
505     msg->cost           = pkt_get_int16(fp);
506     msg->date           = pkt_get_date(fp);
507 
508     pkt_get_string( fp, msg->name_to  , sizeof(msg->name_to  ) );
509     pkt_get_string( fp, msg->name_from, sizeof(msg->name_from) );
510     pkt_get_string( fp, msg->subject  , sizeof(msg->subject  ) );
511 
512     msg->area = NULL;
513 
514     if(verbose >= 6)
515 	pkt_debug_msg_hdr(stderr, msg, "Reading ");
516 
517     return ferror(fp);
518 }
519 
520 
521 
522 /*
523  * Debug output of message header
524  */
pkt_debug_msg_hdr(FILE * out,Message * msg,char * txt)525 void pkt_debug_msg_hdr(FILE *out, Message *msg, char *txt)
526 {
527     fprintf(out, "%sFTN message header:\n", txt);
528     fprintf(out, "    From: %-36s @ %s\n",
529 	    msg->name_from, znfp1(&msg->node_from));
530     fprintf(out, "    To  : %-36s @ %s\n",
531 	    msg->name_to  , znfp1(&msg->node_to));
532     fprintf(out, "    Subj: %s\n", msg->subject);
533     fprintf(out, "    Date: %s\n",
534 	    msg->date!=-1 ? date(NULL, &msg->date) : "LOCAL" );
535     fprintf(out, "    Attr: %04x\n", msg->attr);
536 }
537 
538 
539 
540 /*
541  * Write string to packet in null-terminated format.
542  */
pkt_put_string(FILE * fp,char * s)543 int pkt_put_string(FILE *fp, char *s)
544 {
545     fputs(s, fp);
546     putc(0, fp);
547 
548     return ferror(fp);
549 }
550 
551 
552 
553 /*
554  * Write line to packet, replacing \n with \r\n
555  */
pkt_put_line(FILE * fp,char * s)556 int pkt_put_line(FILE *fp, char *s)
557 {
558     for(; *s; s++)
559     {
560 	if(*s == '\n')
561 	    putc('\r', fp);
562 	putc(*s, fp);
563     }
564 
565     return ferror(fp);
566 }
567 
568 
569 
570 /*
571  * Write 16-bit integer in 80x86 format, i.e. low byte first,
572  * then high byte. Machine independent function.
573  */
pkt_put_int16(FILE * fp,int value)574 int pkt_put_int16(FILE *fp, int value)
575 {
576     putc(value & 0xff, fp);
577     putc((value >> 8) & 0xff, fp);
578 
579     return ferror(fp);
580 }
581 
582 
583 
584 /*
585  * Write date/time in FTS-0001 format
586  */
pkt_put_date(FILE * pkt,time_t t)587 int pkt_put_date(FILE *pkt, time_t t)
588 {
589     static time_t last = -1;
590 
591     if(t == -1)
592     {
593 	/* No valid time, use local time */
594 	debug(7, "using local time");
595 	t = time(NULL);
596 	/* Kludge to avoid the same date/time */
597 	if(t == last)
598 	    t += 2;
599 	last = t;
600     }
601 
602     /* Date according to FTS-0001 */
603     pkt_put_string(pkt, date(DATE_FTS_0001, &t) );
604 
605     return ferror(pkt);
606 }
607 
608 
609 
610 /*
611  * Write message header to packet.
612  */
613 static int force_fmpt0 = FALSE;
614 static int force_intl  = TRUE;
615 
pkt_set_forcefmpt0(int f)616 void pkt_set_forcefmpt0(int f)
617 {
618     force_fmpt0 = f;
619 }
620 
pkt_set_forceintl(int f)621 void pkt_set_forceintl(int f)
622 {
623     force_intl = f;
624 }
625 
626 
pkt_put_msg_hdr(FILE * pkt,Message * msg,int kludge_flag)627 int pkt_put_msg_hdr(FILE *pkt, Message *msg, int kludge_flag)
628     /* kludge_flag --- TRUE: write AREA/^AINTL,^AFMPT,^ATOPT */
629 {
630     if(verbose >= 6)
631 	pkt_debug_msg_hdr(stderr, msg, "Writing ");
632 
633     /*
634      * Write message header
635      */
636     pkt_put_int16 (pkt, MSG_TYPE           );
637     pkt_put_int16 (pkt, msg->node_from.node);
638     pkt_put_int16 (pkt, msg->node_to  .node);
639     pkt_put_int16 (pkt, msg->node_from.net );
640     pkt_put_int16 (pkt, msg->node_to  .net );
641     pkt_put_int16 (pkt, msg->attr          );
642     pkt_put_int16 (pkt, msg->cost          );
643 
644     pkt_put_date  (pkt, msg->date          );
645     pkt_put_string(pkt, msg->name_to       );
646     pkt_put_string(pkt, msg->name_from     );
647     pkt_put_string(pkt, msg->subject       );
648 
649     if(!kludge_flag)
650 	return ferror(pkt);
651 
652     /*
653      * Write area tag / zone, point adressing kludges
654      */
655     if(msg->area)
656 	fprintf(pkt, "AREA:%s\r\n", msg->area);
657     else
658     {
659 	if(force_intl                           ||
660 	   cf_zone()    != msg->node_from.zone  ||
661 	   cf_defzone() != msg->node_from.zone  ||
662 	   cf_zone()    != msg->node_to  .zone  ||
663 	   cf_defzone() != msg->node_to  .zone     )
664 	{
665 	    Node tmpf, tmpt;
666 
667 	    tmpf = msg->node_from; tmpf.point = 0; tmpf.domain[0] = 0;
668 	    tmpt = msg->node_to;   tmpt.point = 0; tmpt.domain[0] = 0;
669 	    fprintf(pkt, "\001INTL %s %s\r\n", znf1(&tmpt), znf2(&tmpf));
670 	}
671 
672 	if(force_fmpt0 || msg->node_from.point)
673 	    fprintf(pkt, "\001FMPT %d\r\n", msg->node_from.point);
674 	if(msg->node_to  .point)
675 	    fprintf(pkt, "\001TOPT %d\r\n", msg->node_to  .point);
676     }
677 
678     return ferror(pkt);
679 }
680 
681 
682 
683 /*
684  * Read 16-bit integer in 80x86 format, i.e. low byte first,
685  * then high byte. Machine independent function.
686  */
pkt_get_int16(FILE * fp)687 long pkt_get_int16(FILE *fp)
688 {
689     int c;
690     unsigned val;
691 
692     if((c = getc(fp)) == EOF)
693 	return ERROR;
694     val	 = c;
695     if((c = getc(fp)) == EOF)
696 	return ERROR;
697     val |= c << 8;
698 
699     return val;
700 }
701 
702 
703 
704 /*
705  * Read n bytes from file stream
706  */
pkt_get_nbytes(FILE * fp,char * buf,int n)707 int pkt_get_nbytes(FILE *fp, char *buf, int n)
708 {
709     int c;
710 
711     while(n--)
712     {
713 	if((c = getc(fp)) == EOF)
714 	    return ERROR;
715 	*buf++ = c;
716     }
717 
718     return ferror(fp);
719 }
720 
721 
722 
723 /*
724  * Read packet header from file
725  */
pkt_get_hdr(FILE * fp,Packet * pkt)726 int pkt_get_hdr(FILE *fp, Packet *pkt)
727 {
728     long val;
729     struct tm t;
730     int ozone, dzone;
731     int cw, swap;
732     char xpkt[4];
733 
734     node_clear(&pkt->from);
735     node_clear(&pkt->to);
736     pkt->time      = -1;
737     pkt->baud      = 0;
738     pkt->version   = 0;
739     pkt->product_l = 0;
740     pkt->product_h = 0;
741     pkt->rev_min   = 0;
742     pkt->rev_maj   = 0;
743     pkt->passwd[0] = 0;
744     pkt->capword   = 0;
745 
746     /* Set zone to default, i.e. use the zone from your FIRST aka
747      * specified in fidogate.conf */
748     pkt->from.zone = pkt->to.zone = cf_defzone();
749 
750     /* Orig node */
751     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
752     pkt->from.node = val;
753     /* Dest node */
754     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
755     pkt->to.node = val;
756     /* Year */
757     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
758     t.tm_year = val - 1900;
759     /* Month */
760     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
761     t.tm_mon = val;
762     /* Day */
763     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
764     t.tm_mday = val;
765     /* Hour */
766     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
767     t.tm_hour = val;
768     /* Minute */
769     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
770     t.tm_min = val;
771     /* Second */
772     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
773     t.tm_sec = val;
774     t.tm_wday = -1;
775     t.tm_yday = -1;
776     t.tm_isdst = -1;
777     pkt->time = mktime(&t);
778     /* Baud */
779     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
780     pkt->baud = val;
781     /* Version --- MUST BE PKT_VERSION (2) */
782     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
783     if(val != PKT_VERSION)
784 	return ERROR;
785     pkt->version = val;
786     /* Orig net */
787     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
788     pkt->from.net = val;
789     /* Dest net */
790     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
791     pkt->to.net = val;
792     /* Prod code lo */
793     if((val = getc(fp)) == ERROR)           return ERROR;
794     pkt->product_l = val;
795     /* Revision major */
796     if((val = getc(fp)) == ERROR)           return ERROR;
797     pkt->rev_maj = val;
798     /* Password */
799     if(pkt_get_nbytes(fp, pkt->passwd, PKT_MAXPASSWD) == ERROR)  return ERROR;
800     pkt->passwd[PKT_MAXPASSWD] = 0;
801     /* Orig zone (FTS-0001 optional, QMail) */
802     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
803     ozone = val;
804     if(ozone)
805 	pkt->from.zone = ozone;
806     /* Dest zone (FTS-0001 optional, QMail) */
807     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
808     dzone = val;
809     if(dzone)
810 	pkt->to.zone = dzone;
811     /* Spare (auxNet in FSC-0048) */
812     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
813     /* Cap word byte-swapped copy */
814     if((val = getc(fp)) == ERROR)           return ERROR;
815     swap = val << 8;
816     if((val = getc(fp)) == ERROR)           return ERROR;
817     swap |= val;
818     /* Prod code hi */
819     if((val = getc(fp)) == ERROR)           return ERROR;
820     pkt->product_h = val;
821     /* Revision minor */
822     if((val = getc(fp)) == ERROR)           return ERROR;
823     pkt->rev_min = val;
824     /* Cap word */
825     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
826     cw = val;
827     if(cw && cw == swap)	/* 2+ packet according to FSC-0039 */
828 	debug(9, "Packet: type 2+");
829     else
830 	cw = 0;
831     pkt->capword = cw;
832     /* Orig zone (FSC-0039) */
833     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
834     if(cw && val)
835     {
836 	pkt->from.zone = val;
837 	if(ozone != val)
838 	    debug(9, "Packet: different zones %d (FTS-0001) / %ld (FSC-0039)",
839 		  ozone, val);
840     }
841     /* Dest zone (FSC-0039) */
842     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
843     if(cw && val)
844     {
845 	pkt->to.zone = val;
846 	if(dzone != val)
847 	    debug(9, "Packet: different zones %d (FTS-0001) / %ld (FSC-0039)",
848 		  dzone, val);
849     }
850     /* Orig point (FSC-0039) */
851     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
852     if(cw)
853 	pkt->from.point = val;
854     /* Dest point (FSC-0039) */
855     if((val = pkt_get_int16(fp)) == ERROR)  return ERROR;
856     if(cw)
857 	pkt->to.point = val;
858     /* Prod specific data */
859     if(pkt_get_nbytes(fp, xpkt, 4) == ERROR)  return ERROR;
860 
861     if(verbose >= 3)
862 	pkt_debug_hdr(stderr, pkt, "Reading ");
863 
864     return ferror(fp);
865 }
866 
867 
868 
869 /*
870  * Debug output of packet header
871  */
pkt_debug_hdr(FILE * out,Packet * pkt,char * txt)872 void pkt_debug_hdr(FILE *out, Packet *pkt, char *txt)
873 {
874     fprintf(out, "%sFTN packet header:\n", txt);
875     fprintf(out, "    From: %s\n", znfp1(&pkt->from));
876     fprintf(out, "    To  : %s\n", znfp2(&pkt->to));
877     fprintf(out, "    Date: %s\n", date(NULL, &pkt->time));
878     fprintf(out, "    Baud: %d\n", pkt->baud);
879     fprintf(out, "    Prod: %02x %02x\n", pkt->product_h, pkt->product_l);
880     fprintf(out, "    Rev : %d.%d\n", pkt->rev_maj, pkt->rev_min);
881     fprintf(out, "    Pass: \"%s\"\n", pkt->passwd);
882     fprintf(out, "    Capw: %04x\n", pkt->capword & 0xffff);
883 }
884 
885 
886 
887 /*
888  * Write string to packet, padded with 0 bytes to length n
889  */
pkt_put_string_padded(FILE * fp,char * s,int n)890 int pkt_put_string_padded(FILE *fp, char *s, int n)
891 {
892     int i;
893     for(i=0; *s && i<n; s++, i++)
894 	putc(*s, fp);
895     for(; i<n; i++)
896 	putc(0, fp);
897 
898     return ferror(fp);
899 }
900 
901 
902 
903 /*
904  * Write packet header to file. This function always writes a 2+
905  * (FSC-0039) header.
906  */
pkt_put_hdr(FILE * fp,Packet * pkt)907 int pkt_put_hdr(FILE *fp, Packet *pkt)
908 {
909     struct tm *tm;
910     int swap;
911 
912     /*
913      * Fill rest of Packet structure
914      */
915     pkt->baud      = 0;
916     pkt->version   = PKT_VERSION;
917     pkt->product_l = PRODUCT_CODE;
918     pkt->product_h = 0;
919     pkt->rev_min   = version_minor();
920     pkt->rev_maj   = version_major();
921     pkt->capword   = 0x0001;		/* Designates packet type 2+ */
922     swap           = 0x0100;		/* Byte swapped capability word */
923     tm = localtime(&pkt->time);
924 
925     if(verbose >= 3)
926 	pkt_debug_hdr(stderr, pkt, "Writing ");
927 
928     /*
929      * Write the actual header
930      */
931     pkt_put_int16        (fp, pkt->from.node);
932     pkt_put_int16        (fp, pkt->to  .node);
933     pkt_put_int16        (fp, tm->tm_year+1900);
934     pkt_put_int16        (fp, tm->tm_mon);
935     pkt_put_int16        (fp, tm->tm_mday);
936     pkt_put_int16        (fp, tm->tm_hour);
937     pkt_put_int16        (fp, tm->tm_min);
938     pkt_put_int16        (fp, tm->tm_sec);
939     pkt_put_int16        (fp, pkt->baud);
940     pkt_put_int16        (fp, pkt->version);
941     pkt_put_int16        (fp, pkt->from.net);
942     pkt_put_int16        (fp, pkt->to  .net);
943     putc                 (    pkt->product_l, fp);
944     putc                 (    pkt->rev_maj,   fp);
945     pkt_put_string_padded(fp, pkt->passwd, PKT_MAXPASSWD);
946     pkt_put_int16        (fp, pkt->from.zone);
947     pkt_put_int16        (fp, pkt->to  .zone);
948     pkt_put_int16        (fp, 0 /* Spare */ );
949     pkt_put_int16        (fp, swap);
950     putc                 (    pkt->product_h, fp);
951     putc                 (    pkt->rev_min,   fp);
952     pkt_put_int16        (fp, pkt->capword);
953     pkt_put_int16        (fp, pkt->from.zone);
954     pkt_put_int16        (fp, pkt->to  .zone);
955     pkt_put_int16        (fp, pkt->from.point);
956     pkt_put_int16        (fp, pkt->to  .point);
957     fputs                (    "XPKT", fp);	/* Like SQUISH */
958 
959     return ferror(fp);
960 }
961