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