Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / gkermit / gkermit.c
blob036575aca8fab937171f9811bbbad48121d0c6ca
1 /* G K E R M I T -- GNU Kermit */
3 /*
4 A free implementation of the Kermit file transfer protocol for UNIX.
5 If you change this software, please either (a) send changes back to the
6 Kermit Project to be considered for the base version; or (b) change the
7 strings below to show a new version number and date and to reflect the
8 person or organization responsible for the new version.
10 Sat Dec 25 19:22:54 1999
13 char *versio = "G-Kermit CU-1.00, Columbia University, 1999-12-25";
14 char *url = "http://www.columbia.edu/kermit/";
15 char *email = "kermit@columbia.edu";
17 Author:
18 Frank da Cruz
19 The Kermit Project
20 Columbia University
21 612 West 115th Street
22 New York NY 10025-7799 USA
23 http://www.columbia.edu/kermit/
24 kermit@columbia.edu
26 Copyright (C) 1999,
27 The Trustees of Columbia University in the City of New York.
29 This program is free software; you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation; either version 2 of the License, or
32 (at your option) any later version.
34 This program is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
39 You should have received a copy of the GNU General Public License
40 along with this program; if not, write to the Free Software
41 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43 #ifdef POSIX
44 char *build = "POSIX"; /* Identify which build */
45 #else
46 #ifdef SYSV
47 char *build = "SYSV";
48 #else
49 #ifdef BSD
50 char *build = "BSD";
51 #else
52 char *build = "stty";
53 #endif /* BSD */
54 #endif /* SYSV */
55 #endif /* POSIX */
57 #define _GKERMIT_C
58 #include <errno.h>
59 #include <stdio.h>
60 #include <string.h>
61 #include "gkermit.h"
63 /* Forward declarations of functions used within this module... */
65 _MYPROTOTYPE( int cmdlin, (void) ); /* Command-line parser */
66 _MYPROTOTYPE( int spacket, (char,int,int,char *) ); /* Make & send a packet */
67 _MYPROTOTYPE( int rpacket, (void) ); /* Read a packet */
68 _MYPROTOTYPE( unsigned int chk1, (char *,int) ); /* 1-byte block check */
69 _MYPROTOTYPE( unsigned int chk3, (char *,int) ); /* 3-byte CRC */
70 _MYPROTOTYPE( unsigned int chksum, (char *,int) ); /* Checksum */
71 _MYPROTOTYPE( int getpkt, (int) ); /* Fill packet data field */
72 _MYPROTOTYPE( VOID encode, (int,int) ); /* Encode a character */
73 _MYPROTOTYPE( VOID decstr, (char *) ); /* Decode a memory string */
75 /* Externs */
77 extern int zincnt; /* For buffered file i/o */
78 extern char * zinptr;
79 extern FILE * ofp; /* Output file pointer */
81 /* Global variables declared here */
83 char *cmarg, *cmarg2 = NULL; /* Send filename pointers */
84 char **cmlist = NULL; /* Pointer to file list in argv */
86 FILE * db = NULL; /* Debug log file pointer */
87 int debug = 0; /* Debugging on */
88 int failure = 0; /* Return status */
89 int retries = 0; /* Packet retry counter */
90 int sendtype = 0; /* Type of last packet sent */
91 int recvtype = 0; /* Type of last packet received */
92 int datalen = 0; /* Length of received data field */
94 /* Protocol parameters */
96 int spsiz = 90, /* Default send-packet size */
97 rpsiz = 94, /* Default short receive-packet size */
98 urpsiz = DEFRP, /* Default long receive-packet size */
99 maxrp = MAXRP, /* Maximum long receive-packet size */
100 timint = 9, /* Timeout interval I use */
101 rtimo = 7, /* Timeout I want you to use */
102 rpadn = 0, /* How much padding to send */
103 spadn = 0, /* How much padding to ask for */
104 bctr = 3, /* Block check type requested */
105 bctu = 1, /* Block check type used */
106 ebq = '&', /* 8th bit prefix */
107 ebqflg = 0, /* 8th-bit quoting flag */
108 rqf = -1, /* Flag used in 8bq negotiation */
109 rq = 0, /* Received 8bq bid */
110 sq = 'Y', /* Sent 8bq bid */
111 rpt = 0, /* Repeat count */
112 rptq = '~', /* Repeat prefix */
113 rptflg = 0, /* Repeat processing flag */
114 backup = 1, /* Back up existing files */
115 seq = 0, /* Current packet number */
116 size, /* Current size of output pkt data */
117 osize, /* Previous output packet data size */
118 maxsiz, /* Max size for building data field */
119 rln, /* Received packet length */
120 rsn, /* Received packet sequence number */
121 sndpkl; /* Length of packet being sent */
123 char spadc = 0, /* Padding character to send */
124 rpadc = 0, /* Padding character to ask for */
125 seol = CR, /* End-Of-Line character to send */
126 reol = CR, /* End-Of-Line character to look for */
127 rctlq = '#', /* Control prefix in incoming data */
128 sctlq = '#', /* Outbound control character prefix */
129 sndpkt[MAXSP+16], /* Entire packet being sent */
130 rcvpkt[MAXRP+16], /* Packet most recently received */
131 *rdatap, /* Pointer to data field of rcvpkt */
132 xxdata[MAXRP+16], /* Packet data buffer */
133 *isp = NUL, /* Input string pointer */
134 *osp = NUL, /* Output string pointer */
135 smark = '\1', /* Outbound packet-start character */
136 rmark = '\1'; /* Incoming packet-start character */
138 char * xdata = xxdata; /* Packet data field pointer */
140 /* File-related variables */
142 char filnam[MAXPATHLEN+1]; /* Name of current file. */
143 char ttname[DEVNAMLEN+1]; /* Name of communication device. */
145 int nfils; /* Number of files to send */
146 int cx = 0, cz = 0; /* File and batch interruption flags */
147 int quiet = 0; /* Suppress messages */
148 int keep = 0; /* Keep incompletely received files */
149 int streamok = 0; /* Streaming protocol negotiated */
150 int streaming = 0; /* Streaming active now */
151 int nomodes = 0; /* Don't mess with tty modes */
152 int xonxoff = 0; /* Force Xon/Xoff */
153 int noxonxoff = 0; /* Don't force Xon/Xoff */
154 int manual = 0; /* Transfer mode manual, not auto */
155 int parity = 0; /* Parity specified, 0,'e','o',etc */
156 int delay = 1; /* Initial delay before sending */
157 int text = 0; /* Flag for text/binary mode */
158 int first = 0; /* Flag for first input from file */
159 int longpackets = 0; /* Long packets negotiated */
160 int attributes = 0; /* Attribute packets negotiated */
161 int literal = 0; /* Literal filenames */
162 char start = 0; /* Starting state for automaton */
164 char **xargv; /* Global copies of argv */
165 int xargc; /* and argc */
166 char *dftty = CTTNAM; /* Default controlling terminal name */
168 char *
169 #ifdef __STDC__
170 mystrchr(char * s, char c)
171 #else
172 mystrchr(s,c) char *s, c;
173 #endif /* __STDC__ */
175 if (!s) /* strchr() replacement */
176 return(NULL); /* because strchr not portable */
177 while (*s && *s != c)
178 s++;
179 return((*s == c) ? s : NULL);
182 int /* Main Program */
183 main(argc,argv) int argc; char **argv; {
184 xargc = argc; /* Make global copies of argc */
185 xargv = argv; /* ...and argv. */
186 start = 0; /* No default start state. */
187 seq = 0; /* Packet sequence number. */
188 parity = 0; /* Initial parity. */
189 strncpy(ttname,dftty,DEVNAMLEN); /* Default device name. */
191 if (argc < 2) { /* If no args */
192 usage(); /* give usage message */
193 doexit(1); /* and quit. */
195 sysinit(); /* Set up interrupt handlers, etc */
196 if (urpsiz > MAXRP) /* In case MAXRP < DEFRP... */
197 urpsiz = MAXRP;
198 if (maxrp > 9020)
199 maxrp = 9020;
200 start = cmdlin(); /* Parse args */
201 if (start == 0 && !debug) { /* Nothing to do? */
202 fprintf(stderr,"No start state\n");
203 doexit(1);
205 if (ttopen(ttname) < 0) { /* "Open" the communication device */
206 fprintf(stderr,"Can't open terminal\n");
207 doexit(1);
209 if (ttpkt(parity) < 0) { /* Open OK, put it in packet mode */
210 printf("Can't set packet mode\n");
211 doexit(1);
212 } /* OK, do requested actions. */
213 if (start) { /* Start state */
214 if (start == 's' || start == 'r') /* If sending or getting*/
215 ttflui(); /* flush comm line input buffer */
216 gwart(); /* Do the protocol */
218 doexit(failure); /* Done, exit. */
219 return(failure); /* To shut up picky compilers. */
222 /* Functions */
224 int /* Called implicitly by protocol */
225 input() { /* to get the next packet. */
226 int x, type;
227 if (start != 0) { /* Start state in effect? */
228 type = start; /* Yes, call it a packet type, */
229 start = 0; /* nullify the start state, */
230 if (debug) fprintf(db,"input[%c]\n",(char)type);
231 return(type); /* and return the type. */
233 if (streaming && (sendtype == 'D')) { /* If streaming and sending data */
234 x = ttchk(); /* Look for return traffic */
235 if (debug)
236 fprintf(db,"input streaming ttchk %d\n",x);
237 if (x < 0)
238 errpkt("Fatal i/o error");
239 else if (x < 5)
240 return('Y'); /* If none, pretend we got an ACK */
241 timint = 4;
242 type = rpacket(); /* Something came in, read it */
243 timint = 0;
244 if (mystrchr("TQN",type))
245 errpkt("Transmission error while streaming");
246 } else {
247 type = rpacket(); /* No start state, read a packet. */
248 while (rsn != seq || /* Sequence number doesn't match, or */
249 mystrchr("TQN",type) /* Timeout, Checksum error, or NAK */
251 if (streaming)
252 errpkt("Transmission error while streaming");
253 resend(); /* Resend previous packet. */
254 type = rpacket(); /* Try to read response. */
257 if (!streaming) /* Got a good packet */
258 ttflui(); /* Flush buffer if not streaming */
259 if (debug)
260 fprintf(db,"input[%c]\n",(char)type);
261 return(type); /* Return its type */
264 VOID
265 nxtpkt() { /* Next packet */
266 retries = 0; /* Reset per-packet retry count */
267 seq = (seq + 1) & 63; /* Next packet number, mod 64 */
271 ack() { /* Acknowledge */
272 int x = 0; /* Empty acknowledgement */
273 if (!streaming || recvtype != 'D')
274 x = spacket('Y',seq,0,""); /* Send the packet */
275 nxtpkt(); /* Increment packet number */
276 return(x);
280 ack1(s) char *s; { /* Acknowledgement with data */
281 int x;
282 x = spacket('Y',seq,strlen(s),s); /* Send the packet */
283 nxtpkt(); /* Increment packet number */
284 return(x);
288 nak() { /* Negative acknowledgement */
289 int x;
290 retries++;
291 if (debug)
292 fprintf(db,"nak #%d (%d/%d)\n",seq,retries,MAXTRY);
293 if (retries > MAXTRY) { /* Check retry limit */
294 errpkt("Too many retries");
295 doexit(1);
297 x = spacket('N',seq,0,""); /* A NAK never has data */
298 return(x);
301 VOID
302 tinit() { /* Transaction Initialization */
303 osp = NULL; /* Reset output string pointer */
304 cx = cz = 0; /* File interruption flags off */
305 bctu = 1; /* Block check back to 1 */
306 ebqflg = rptflg = 0; /* 8th bit & repeat quoting off */
307 sq = 'Y'; /* Normal 8th bit quote bid */
308 rqf = -1; /* Flag that no 8-b-q bid seen yet */
309 seq = 0; /* Start off with packet zero */
310 *filnam = *sndpkt = *rcvpkt = NUL; /* Clear out string buffers */
313 VOID
314 errpkt(s) char *s; { /* Fatal error */
315 if (start == 'v' || start == 'r') /* Receiving a file? */
316 sleep(1); /* Time to soak up incoming junk. */
317 spacket('E',seq,(int)strlen(s),s); /* Send Error packet. */
318 doexit(1); /* Exit with failure status. */
322 #ifdef __STDC__
323 sinit(char c)
324 #else
325 sinit(c) char c;
326 #endif /* __STDC__ */
327 { /* Begin send */
328 char *s;
329 s = rpar(); /* Get our protocol parameters */
330 if (c == 'S') { /* Sending a file... */
331 tmsgl(versio);
332 tmsgl("Escape back to your local Kermit and give a RECEIVE command.");
333 tmsgl("");
334 tmsgl("KERMIT READY TO SEND...");
335 sleep(delay);
337 return(spacket(c,seq,strlen(s),s)); /* Send S or I packet */
341 sfile() { /* Send file header packet */
342 int x;
343 char pktnam[MAXPATHLEN];
344 if (debug)
345 fprintf(db,"sfile filnam [%s] max = %d\n",filnam,MAXPATHLEN);
346 if (zopeni(filnam) < 0) { /* Open the input file */
347 if (debug)
348 fprintf(db,"sfile error %d",errno);
349 errpkt("Failure to open file");
351 if (cmarg2) /* User-supplied name - use as-is */
352 strncpy(pktnam,cmarg2,MAXPATHLEN);
353 else /* Actual filename - convert */
354 zltor(filnam,pktnam,MAXPATHLEN);
355 cmarg2 = NULL; /* Only works for one file */
356 if (debug)
357 fprintf(db,"sfile pktnam %s\n",pktnam);
358 x = encstr(pktnam); /* Encode name */
359 if (debug)
360 fprintf(db,"sfile encstr[%s] x=%d\n",xdata,x);
361 first = 1; /* Starting condition for file */
362 maxsiz = spsiz - (bctr + 3); /* Maximum packet data field length */
363 if (spsiz > 94) maxsiz -= 4; /* Long packet has more fields */
364 nxtpkt(); /* Get next packet number */
365 return(spacket('F',seq,x,xdata)); /* Send filename */
369 sattr() { /* Build and send A packet */
370 int i, aln;
371 int binary;
372 extern long filelength;
374 nxtpkt(); /* Get next packet sequence number */
375 if (debug) fprintf(db,"sattr seq %d\n",seq);
376 i = 0; /* i = Data field character number */
377 binary = !text; /* (for notational convenience) */
379 xdata[i++] = '"';
380 if (binary) { /* Binary */
381 xdata[i++] = tochar(2); /* Two characters */
382 xdata[i++] = 'B'; /* B for Binary */
383 xdata[i++] = '8'; /* 8-bit bytes (note assumption...) */
384 } else { /* Text */
385 xdata[i++] = tochar(3); /* Three characters */
386 xdata[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
387 xdata[i++] = 'M'; /* M for carriage return */
388 xdata[i++] = 'J'; /* J for linefeed */
389 xdata[i++] = '*'; /* Encoding */
390 xdata[i++] = tochar(1); /* Length of value is 1 */
391 xdata[i++] = 'A'; /* A for ASCII */
393 if (filelength > -1L) {
394 xdata[i] = '1'; /* File length in bytes */
395 sprintf((char *) &xdata[i+2],"%ld",filelength);
396 aln = (int)strlen((char *)(xdata+i+2));
397 xdata[i+1] = tochar(aln);
398 i += aln + 2;
400 xdata[i] = NUL; /* Terminate last good field */
401 aln = (int)strlen((char *)xdata); /* Get overall length of attributes */
402 if (debug) fprintf(db,"sattr data %s\n",xdata);
403 return(spacket('A',seq,aln,xdata)); /* Send it */
405 #define FTBUFL 10 /* File type buffer */
408 gattr(s) char *s; { /* Get attributes from other Kermit */
409 char c;
410 int aln, i;
411 static char ftbuf[FTBUFL+1];
412 int retcode; /* Return code */
414 retcode = 0; /* Initialize return code. */
415 while ((c = *s++)) { /* Get attribute tag */
416 aln = xunchar(*s++); /* Length of attribute string */
417 switch (c) {
418 case '"': /* File type (text, binary, ...) */
419 for (i = 0; (i < aln) && (i < FTBUFL); i++)
420 ftbuf[i] = *s++; /* Copy it into a static string */
421 ftbuf[i] = '\0';
422 if (i < aln) s += (aln - i);
423 if ((*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I')) {
424 retcode = -1; /* Reject the file */
425 break;
427 if (*ftbuf == 'A') { /* Check received attributes. */
428 text = 1; /* Set current type to Text. */
429 } else if (*ftbuf == 'B') {
430 text = 0;
432 break;
434 default: /* Unknown attribute */
435 s += aln; /* Just skip past it */
436 break;
439 return(retcode);
444 sdata() { /* Send a data packet */
445 int x;
446 if (cx || cz) { /* Interrupted... */
447 if (debug)
448 fprintf(db,"sdata interrupted cx = %d cz = %d\n",cx,cz);
449 failure = 1;
450 return(0);
452 x = getpkt(maxsiz); /* Fill data field from input file */
453 if (x < 1) {
454 if (debug)
455 fprintf(db,"sdata getpkt = %d\n",x);
456 return(0);
458 nxtpkt(); /* Get next packet number */
459 return(spacket('D',seq,x,xdata)); /* Send the packet */
463 seof(s) char *s; { /* Send end-of-file packet */
464 if (debug) fprintf(db,"seof [%s]\n",s);
465 if (zclosi() < 0) { /* Close the file */
466 if (debug)
467 fprintf(db,"seof zclosi failure %d\n",errno);
468 errpkt("Failure to close input file");
469 } else {
470 int x;
471 nxtpkt(); /* Get next packet number */
472 x = spacket('Z',seq,strlen(s),s); /* Send EOF packet */
473 if (debug)
474 fprintf(db,"seof spacket %d\n",x);
475 return(x);
477 return(0); /* To shut up picky compilers */
481 seot() { /* Send end-of-transmission packet */
482 nxtpkt();
483 return(spacket('B',seq,0,""));
487 closof() { /* Close output file */
488 if (zcloso(cx|cz) < 0)
489 errpkt("Failure to close output file");
490 return(0);
493 int /* Frame and send a packet */
494 #ifdef __STDC__
495 spacket(char type,int n,int len,char *d)
496 #else
497 spacket(type,n,len,d) char type, *d; int n, len;
498 #endif /* __STDC__ */
500 register int i = 0;
501 int j, k, m, x;
502 char * p = sndpkt;
504 for (i = 0; i < spadn; i++) /* Do requested padding */
505 p[i] = spadc;
507 p[i++] = smark; /* Send-packet mark */
508 k = i++; /* Remember this place */
509 p[i++] = tochar(n); /* Sequence number */
510 p[i++] = type; /* Packet type */
511 j = len + bctu;
512 if ((len + bctu + 2) > 94) { /* If long packet */
513 x = j / 95; /* Use long-packet format */
514 p[k] = tochar(0);
515 p[i++] = tochar(x);
516 x = j % 95;
517 p[i++] = tochar(x);
518 p[i] = NUL; /* Terminate for header checksum */
519 p[i++] = tochar(chk1(&p[k],5)); /* Insert header checksum */
520 } else /* Short packet */
521 p[k] = tochar(j+2);
522 for (j = len; j > 0; j--) { /* Data */
523 p[i++] = *d++;
525 p[i] = NUL; /* Null-terminate */
526 m = i - k;
527 switch (bctu) { /* Block Check Type Used? */
528 case 1: /* Type 1 - 6 bit checksum */
529 p[i++] = tochar(chk1(p+k,m));
530 break;
531 case 2: /* Type 2 - 12 bit checksum */
532 j = chksum(p+1,m);
533 p[i++] = tochar((j >> 6) & 077);
534 p[i++] = tochar(j & 077);
535 break;
536 case 3: /* Type 3 - 16 bit CRC-CCITT */
537 j = chk3(p+1,m);
538 p[i++] = tochar((j >> 12) & 017);
539 p[i++] = tochar((j >> 6) & 077);
540 p[i++] = tochar(j & 077);
541 break;
543 p[i++] = seol; /* End of line */
544 p[i] = NUL; /* Null string-terminator */
545 sndpkl = i; /* Remember length. */
546 x = ttol(p,sndpkl); /* Send the packet. */
547 if (x > -1)
548 sendtype = type; /* Remember its type */
549 return(x);
553 resend() { /* Resend a packet */
554 int x;
555 if (*sndpkt) {
556 retries++;
557 if (debug) fprintf(db,"resend #%d (%d/%d)\n",seq,retries,MAXTRY);
558 if (retries > MAXTRY) { /* Check retry limit */
559 errpkt("Too many retries");
560 doexit(1);
562 x = ttol(sndpkt,sndpkl); /* Send previous packet */
563 } else {
564 x = nak(); /* or NAK if nothing sent yet. */
566 return(x);
570 rpacket() { /* Read a packet */
571 register int i = 0;
572 int j, x, type, rlnpos, rpktl; /* Local variables */
573 unsigned int c1, c2;
574 char * p = rcvpkt;
575 char pbc[5]; /* Packet block check */
577 rsn = rln = -1; /* In case of failure. */
579 *p = NUL; /* Initialize the receive buffer. */
580 j = ttinl(p,maxrp,timint,reol,rmark,0); /* Read a raw packet */
581 if (j < 5) { /* Error */
582 if (j == -1) return('T'); /* Timed out. */
583 if (j < -1) doexit(1); /* I/O error, hangup, etc. */
584 if (debug) fprintf(db,"rpacket runt");
585 return('Q'); /* Runt */
587 rpktl = j; /* Remember length. */
588 rlnpos = ++i; /* Length position. */
589 if ((j = xunchar(p[i++])) == 0) { /* Get packet length. */
590 if ((j = rlnpos+5) > rpktl) { /* Long packet */
591 if (debug) fprintf(db,"rpacket bad length");
592 return('Q'); /* Too long */
594 x = p[j]; /* Header checksum. */
595 p[j] = NUL; /* Calculate & compare. */
596 if (xunchar(x) != chk1(p+rlnpos,5)) {
597 if (debug)
598 fprintf(db,"rpacket header checksum: %u\n",x);
599 return('Q');
601 p[j] = x; /* Checksum ok, put it back. */
602 rln = xunchar(p[j-2]) * 95 + xunchar(p[j-1]) - bctu;
603 j = 3; /* Data offset. */
604 } else if (j < 3) { /* Bad length */
605 if (debug) fprintf(db,"rpacket bad xlength");
606 return('Q');
607 } else { /* Regular packet */
608 rln = j - bctu - 2; /* No extended header */
609 j = 0;
611 rsn = xunchar(p[i++]); /* Sequence number */
612 type = p[i++]; /* Packet type */
613 if (debug)
614 fprintf(db,"rpacket type=%c, seq=%02d, len=%d\n",type,rsn,rln);
615 i += j;
616 rdatap = p+i; /* The data itself */
617 j = rln + i; /* Position of block check */
618 for (x = 0; x < bctu; x++) /* Copy the block check. */
619 pbc[x] = p[j+x];
620 pbc[x] = NUL;
621 p[j] = NUL; /* Null-terminate the data */
622 datalen = j - i; /* Remember data length */
624 switch (bctu) { /* Check the block check */
625 case 1:
626 c1 = (unsigned)xunchar((unsigned)((unsigned)(*pbc) & 0xff));
627 c2 = chk1(p+rlnpos,j-rlnpos);
628 if (c1 != c2) {
629 if (debug) fprintf(db,"rpacket chk1 (0x%x:0x%x)\n",c1,c2);
630 return('Q');
632 break;
633 case 2:
634 c1 = (unsigned)xunchar(*pbc) << 6 | (unsigned)xunchar(pbc[1]);
635 c2 = chksum(p+rlnpos,j-rlnpos);
636 if (c1 != c2) {
637 if (debug) fprintf(db,"rpacket chk2 (0x%x:0x%x)\n",c1,c2);
638 return('Q');
640 break;
641 case 3:
642 c1 = ((unsigned)(xunchar((unsigned)((unsigned)*pbc & 0xff)) << 12) |
643 (unsigned)(xunchar((unsigned)((unsigned)pbc[1] & 0xff)) << 6) |
644 (unsigned)(xunchar((unsigned)((unsigned)pbc[2] & 0xff)))) &
645 0xffff;
646 c2 = chk3(p+rlnpos,j-rlnpos);
647 if (c1 != c2) {
648 if (debug) fprintf(db,"rpacket crc (0x%x:0x%x)\n",c1,c2);
649 return('Q');
651 break;
652 default:
653 errpkt("BLOCKCHECK");
655 recvtype = type; /* Remember type. */
656 return(type); /* Good packet, return type. */
659 unsigned int
660 chksum(p,len) char *p; int len; { /* Generate arithmetic checksum */
661 register unsigned int k, m;
662 m = (parity) ? 0177 : 0377;
663 for (k = 0; len-- > 0; *p++)
664 k += (unsigned)*p & m;
665 return(k);
668 unsigned int
669 chk1(packet,len) char *packet; int len; { /* Generate Type 1 block check */
670 unsigned int x;
671 x = chksum(packet,len);
672 if (debug) fprintf(db,"chksum=%u\n",x);
673 return((((x & 192) >> 6) + x) & 63);
676 unsigned int
677 chk3(s,len) char *s; int len; { /* Tableless 16-bit CRC generator */
678 register unsigned int c;
679 register ULONG q, crc = 0L;
680 while (len-- > 0) {
681 c = (unsigned)(*s++);
682 if (parity) c &= 0177;
683 q = (crc ^ c) & 017;
684 crc = (crc >> 4) ^ (q * 010201);
685 q = (crc ^ (c >> 4)) & 017;
686 crc = (crc >> 4) ^ (q * 010201);
688 if (debug) fprintf(db,"crc=%u\n",(unsigned int)(crc & 0xffff));
689 return((unsigned int)(crc & 0xffff));
693 getpkt(maxlen) int maxlen; { /* Fill a packet from file */
694 int i, next;
695 static int c;
696 static char remain[6] = { NUL, NUL, NUL, NUL, NUL, NUL };
698 if (first == 1) { /* If first time thru... */
699 first = 0; /* don't do this next time, */
700 *remain = NUL; /* discard any old leftovers. */
701 if (isp) { /* Get first byte. */
702 c = *isp++; /* Of memory string... */
703 if (!c) c = -1;
704 } else { /* or file... */
705 c = zgetc(text);
707 if (c < 0) { /* Watch out for empty file. */
708 first = -1;
709 return(size = 0);
711 } else if (first == -1 && !*remain) { /* EOF from last time? */
712 return(size = 0);
714 for (size = 0; (xdata[size] = remain[size]) != NUL; size++) ;
715 *remain = NUL;
716 if (first == -1)
717 return(size);
719 rpt = 0; /* Initialize repeat counter. */
720 while (first > -1) { /* Until end of file or string... */
721 if (isp) {
722 next = *isp++;
723 if (!next) next = -1;
724 } else {
725 next = zgetc(text);
727 if (next < 0) first = -1; /* If none, we're at EOF. */
728 osize = size; /* Remember current size. */
729 encode(c,next); /* Encode the character. */
730 c = next; /* Old next char is now current. */
732 if (size == maxlen) return(size); /* If just at end, done. */
734 if (size > maxlen) { /* Past end, must save some. */
736 for (i = 0; (remain[i] = xdata[osize+i]) != NUL; i++) ;
737 size = osize;
738 xdata[size] = NUL;
739 return(size); /* Return size. */
742 return(size); /* EOF, return size. */
746 encstr(s) char *s; { /* Fill a packet from string s. */
747 first = 1; /* Start lookahead. */
748 isp = s; /* Set input string pointer */
749 getpkt(spsiz); /* Fill a packet */
750 isp = NULL; /* Reset input string pointer */
751 return(size); /* Return data field length */
754 VOID
755 decstr(s) char *s; { /* Decode packet data into a string */
756 osp = s; /* Set output string pointer */
757 decode(datalen); /* Decode the string */
758 *osp = NUL; /* Terminate with null */
759 osp = NULL; /* Reset output string pointer */
762 VOID
763 encode(a,next) int a, next; { /* Encode character a into packet */
764 int a7, b8;
766 if (rptflg) { /* Doing run-length encoding? */
767 if (a == next) { /* Yes, got a run? */
768 if (++rpt < 94) { /* Yes, count. */
769 return;
770 } else if (rpt == 94) { /* If at maximum */
771 xdata[size++] = rptq; /* Emit prefix, */
772 xdata[size++] = tochar(rpt); /* and count, */
773 rpt = 0; /* and reset counter. */
775 } else if (rpt == 1) { /* Run broken, only two? */
776 rpt = 0; /* Yes, do the character twice */
777 encode(a,-1); /* by calling self recursively. */
778 if (size <= maxsiz) osize = size; /* Watch out for boundary. */
779 rpt = 0; /* Call self second time. */
780 encode(a,-1);
781 return;
782 } else if (rpt > 1) { /* Run broken, more than two? */
783 xdata[size++] = rptq; /* Yes, emit prefix and count */
784 xdata[size++] = tochar(++rpt);
785 rpt = 0; /* and reset counter. */
788 a7 = a & 127; /* Get low 7 bits of character */
789 b8 = a & 128; /* And "parity" bit */
791 if (ebqflg && b8) { /* If doing 8th bit prefixing */
792 xdata[size++] = ebq; /* and 8th bit on, insert prefix */
793 a = a7; /* and clear the 8th bit. */
795 if (a7 < 32 || a7 == 127) { /* If in control range */
796 xdata[size++] = sctlq; /* insert control prefix */
797 a = ctl(a); /* and make character printable. */
798 } else if (a7 == sctlq) /* If data is control prefix, */
799 xdata[size++] = sctlq; /* prefix it. */
800 else if (ebqflg && a7 == ebq) /* If doing 8th-bit prefixing, */
801 xdata[size++] = sctlq; /* ditto for 8th-bit prefix. */
802 else if (rptflg && a7 == rptq) /* If doing run-length encoding, */
803 xdata[size++] = sctlq; /* ditto for repeat prefix. */
805 xdata[size++] = a; /* Finally, emit the character. */
806 xdata[size] = NUL; /* Terminate string with null. */
810 decode(len) int len; { /* Decode packet data field */
811 unsigned int a, a7, b8; /* Local variables */
813 rpt = 0; /* Initialize repeat count. */
814 while (len-- > 0) {
815 a = *rdatap++; /* For each character, a, do... */
816 if (rptflg) { /* Repeat processing? */
817 if (a == rptq) { /* Yes, have repeat prefix? */
818 if (len-- < 1) {
819 if (debug) fprintf(db,"decode rpt error A\n");
820 return(-1);
822 rpt = xunchar(*rdatap++); /* Yes, get count */
823 if (len-- < 1) {
824 if (debug) fprintf(db,"decode rpt error B\n");
825 return(-1);
827 a = *rdatap++; /* and the following character. */
830 b8 = 0; /* Assume 8th bit not on. */
831 if (ebqflg) { /* Doing 8th-bit prefixing? */
832 if (a == ebq) { /* Yes, have 8th-bit prefix? */
833 b8 = 128; /* Yes, remember bit 8 on */
834 if (len-- < 1) {
835 if (debug) fprintf(db,"decode ebq error\n");
836 return(-1);
838 a = *rdatap++; /* and get following character. */
841 if (a == rctlq) { /* Control quote? */
842 if (len-- < 1) {
843 if (debug) fprintf(db,"decode ctl error\n");
844 return(-1);
846 a = *rdatap++; /* Yes, get next character */
847 a7 = a & 127; /* and its low 7 bits */
848 if (a7 > 62 && a7 < 96) /* Encoded control character? */
849 a = ctl(a); /* Yes, controllify. */
851 if (rpt == 0) /* Rationalize the repeat count. */
852 rpt = 1;
853 a |= b8; /* OR in the 8th bit. */
854 a &= 0xff; /* Undo any sign extension. */
856 /* The following is UNIX-specific but so is this program */
858 if (text && a == CR) /* Don't output carriage returns. */
859 continue;
860 for (; rpt > 0; rpt--) { /* Output the character. */
861 if (osp) { /* As many copies as indicated by */
862 *osp++ = a; /* the repeat count. */
863 } else {
864 putc((char)a,ofp); /* Use putc macro here to avoid */
865 if (ferror(ofp)) { /* function-call overhead. */
866 if (debug)
867 fprintf(db,"decode putc a=%u errno=%u\n",a,errno);
868 failure = 1;
869 return(-1);
874 return(0); /* Return successfully when done. */
877 VOID
878 spar(s) char *s; { /* Set protocol parameters. */
879 int k, x;
881 s--; /* Line up with field numbers. */
883 x = (rln >= 1) ? xunchar(s[1]) : 80;/* Limit on size of inbound packets */
884 spsiz = (x < 10) ? 80 : x;
886 x = (rln >= 2) ? xunchar(s[2]) : 5; /* Timeout on inbound packets */
887 if (timint > 0) /* "-b 0" overrides */
888 timint = (x < 0) ? 5 : x;
890 spadn = 0; spadc = NUL; /* Outbound Padding */
891 if (rln >= 3) {
892 spadn = xunchar(s[3]);
893 if (rln >= 4) spadc = ctl(s[4]); else spadc = 0;
895 seol = (rln >= 5) ? xunchar(s[5]) : '\r'; /* Outbound Packet Terminator */
896 if ((seol < 2) || (seol > 037)) seol = '\r';
898 x = (rln >= 6) ? s[6] : '#'; /* Control prefix */
899 rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
901 rq = (rln >= 7) ? s[7] : 0; /* 8th-bit prefix */
902 if (rq == 'Y') rqf = 1;
903 else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
904 else rqf = 0;
905 switch (rqf) {
906 case 0: ebqflg = 0; break;
907 case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
908 case 2: if ((ebqflg = (ebq == sq || sq == 'Y'))) ebq = rq;
910 x = 1; /* Block check */
911 if (rln >= 8) {
912 x = s[8] - '0';
913 if ((x < 1) || (x > 3)) x = 1;
915 if (bctr > 1 && bctr != x) x = 1;
916 bctr = x;
917 if (rln >= 9) { /* Repeat prefix */
918 rptq = s[9];
919 rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
920 } else
921 rptflg = 0;
922 k = rln;
923 if (rln >= 10) { /* Capas */
924 x = xunchar(s[10]);
925 if (x & 8) attributes = 1;
926 if (x & 2) longpackets = 1;
927 for (k = 10; (rln >= k) && (xunchar(s[k]) & 1); k++)
929 if (debug) fprintf(db,"spar attributes=%d longpackets=%d\n",
930 attributes, longpackets);
932 if (rln > k+1) { /* Long packets */
933 if (longpackets) {
934 x = xunchar(s[k+2]) * 95 + xunchar(s[k+3]);
935 spsiz = (x > MAXSP) ? MAXSP : x;
936 if (spsiz < 10) spsiz = 80;
939 #ifndef NOSTREAMING
940 if (rln > k+7) {
941 x = xunchar(s[k+8]); /* Other Kermit's WHATAMI info */
942 if (debug) fprintf(db,"spar whatami = 0x%x\n",x);
943 if (streamok > -1)
944 if (x & WMI_FLAG)
945 if (x & WMI_STREAM)
946 streamok = 1;
947 if (debug) fprintf(db,"spar streamok = %d\n",streamok);
949 #endif /* NOSTREAMING */
950 if (rln > k+8) { /* Other Kermit's system ID */
951 char buf[16];
952 int z;
953 x = xunchar(s[k+9]);
954 z = k;
955 k += (9 + x);
956 if (x > 0 && x < 16 && rln >= k) {
957 strncpy(buf,(char *)s+z+10,x);
958 buf[x] = NUL;
959 if (debug) fprintf(db,"spar sysid [%s]\n",buf);
960 if (buf[0] && !manual) { /* If transfer mode is automatic... */
961 if (!strcmp(buf,"U1")) { /* If UNIX, same as me... */
962 text = 0; /* Switch to binary mode */
963 literal = 1; /* and literal filenames */
964 if (debug) fprintf(db,"spar recognizes peer\n");
971 char * /* Send our protocol parameters */
972 rpar() {
973 int x;
974 if (rpsiz > 94)
975 xdata[1] = tochar(94); /* Biggest packet I can receive */
976 else
977 xdata[1] = tochar(rpsiz);
978 xdata[2] = tochar(rtimo); /* When I want to be timed out */
979 xdata[3] = tochar(rpadn); /* How much padding I need (none) */
980 xdata[4] = ctl(rpadc); /* Padding character I want */
981 xdata[5] = tochar(reol); /* End-Of-Line character I want */
982 xdata[6] = '#'; /* Control-Quote character I send */
984 switch (rqf) { /* 8th-bit prefix */
985 case -1:
986 case 1: if (parity) ebq = sq = '&'; break;
987 case 0:
988 case 2: break;
990 xdata[7] = sq;
992 xdata[8] = bctr + '0'; /* Block check type */
993 if (rptflg) /* Run length encoding */
994 xdata[9] = rptq; /* If receiving, agree. */
995 else
996 xdata[9] = '~';
997 xdata[10] = tochar(2+8); /* Capabilities (LP+Attributes) */
998 xdata[11] = tochar(1); /* Window size */
999 if (urpsiz > 94) {
1000 xdata[12] = (char) tochar(urpsiz / 95); /* Long packet size */
1001 xdata[13] = (char) tochar(urpsiz % 95);
1003 xdata[14] = '0'; /* No checkpointing */
1004 xdata[15] = '+';
1005 xdata[16] = '+';
1006 xdata[17] = '+';
1007 x = WMI_FLAG; /* WHATAMI info */
1008 if (literal) x |= WMI_FNAME; /* Filenames literal */
1009 if (!text) x |= WMI_FMODE; /* Text or binary mode */
1010 #ifndef NOSTREAMING
1011 if (streamok > -1) /* If streaming not disabled, */
1012 x |= WMI_STREAM; /* offer to stream. */
1013 if (debug)
1014 fprintf(db,"rpar streamok=%d whatami=%d\n",streamok,x);
1015 #endif /* NOSTREAMING */
1016 xdata[18] = tochar(x);
1017 xdata[19] = tochar(2); /* System ID lengh is 2 */
1018 xdata[20] = 'U'; /* UNIX system ID is "U1" */
1019 xdata[21] = '1';
1020 x = WMI2_FLAG; /* WHATAMI2 info */
1021 if (manual) x |= WMI2_XMODE; /* Transfer-mode is manual */
1022 xdata[22] = tochar(x);
1023 return(xdata+1); /* Return pointer length field */
1026 VOID
1027 rinit() { /* RECEIVE initialization */
1028 if (quiet) return;
1029 tmsgl(versio);
1030 tmsgl("Escape back to your local Kermit and give a SEND command.");
1031 tmsgl("");
1032 tmsgl("KERMIT READY TO RECEIVE...");
1035 VOID
1036 ginit() { /* GET initialization */
1037 if (quiet) return;
1038 tmsgl(versio);
1039 tmsgl("Escape back to your local Kermit and give a SERVER command.");
1040 tmsgl("");
1041 tmsgl("KERMIT READY TO GET...");
1045 gnfile() { /* Get name of next file to send */
1046 if (cz) /* Batch was canceled */
1047 return(0);
1048 while (nfils-- > 0) { /* Otherwise continue thru list */
1049 strncpy(filnam,*cmlist++,MAXPATHLEN);
1050 filnam[MAXPATHLEN-1] = NUL;
1051 if (zchki(filnam) > -1) /* Skip files that can't be read */
1052 return(1);
1054 return(0); /* None left */
1058 rcvfil() { /* Receive a file */
1059 char myname[MAXPATHLEN+1]; /* Local name buffer */
1060 cx = 0; /* Reset per-file cancellation flag */
1061 if (cmarg2) { /* User gave as-name? */
1062 if (debug) fprintf(db,"rcvfil as-name [%s]\n",cmarg2);
1063 strncpy(myname,cmarg2,MAXPATHLEN); /* Use it */
1064 myname[MAXPATHLEN] = NUL;
1065 if (backup) zbackup(myname); /* Handle collisions */
1066 cmarg2 = NULL; /* Undo as-name */
1067 } else {
1068 decstr(filnam); /* Decode name string */
1069 if (zrtol(filnam,myname,backup,MAXPATHLEN) < 0)
1070 errpkt("Backup file creation failure");
1071 strncpy(filnam,myname,MAXPATHLEN);
1072 filnam[MAXPATHLEN] = NUL;
1073 if (debug) fprintf(db,"rcvfil filename [%s]\n",filnam);
1075 if (zchko(myname) < 0) /* Check writability */
1076 errpkt("Write access denied");
1077 if (zopeno(myname) < 0) /* Open the output file */
1078 errpkt("Error opening output file");
1079 return(0);
1082 int /* Send a command packet */
1083 #ifdef __STDC__
1084 scmd(char t, char *s)
1085 #else
1086 scmd(t,s) char t, *s;
1087 #endif /* __STDC__ */
1089 encstr(s); /* Encode the command string */
1090 return(spacket(t,seq,size,xdata)); /* Send the packet */