1 /* G K E R M I T -- GNU Kermit */
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";
22 New York NY 10025-7799 USA
23 http://www.columbia.edu/kermit/
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
44 char *build
= "POSIX"; /* Identify which build */
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 */
77 extern int zincnt
; /* For buffered file i/o */
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 */
170 mystrchr(char * s
, char c
)
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
)
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... */
200 start
= cmdlin(); /* Parse args */
201 if (start
== 0 && !debug
) { /* Nothing to do? */
202 fprintf(stderr
,"No start state\n");
205 if (ttopen(ttname
) < 0) { /* "Open" the communication device */
206 fprintf(stderr
,"Can't open terminal\n");
209 if (ttpkt(parity
) < 0) { /* Open OK, put it in packet mode */
210 printf("Can't set packet mode\n");
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. */
224 int /* Called implicitly by protocol */
225 input() { /* to get the next packet. */
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 */
236 fprintf(db
,"input streaming ttchk %d\n",x
);
238 errpkt("Fatal i/o error");
240 return('Y'); /* If none, pretend we got an ACK */
242 type
= rpacket(); /* Something came in, read it */
244 if (mystrchr("TQN",type
))
245 errpkt("Transmission error while streaming");
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 */
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 */
260 fprintf(db
,"input[%c]\n",(char)type
);
261 return(type
); /* Return its type */
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 */
280 ack1(s
) char *s
; { /* Acknowledgement with data */
282 x
= spacket('Y',seq
,strlen(s
),s
); /* Send the packet */
283 nxtpkt(); /* Increment packet number */
288 nak() { /* Negative acknowledgement */
292 fprintf(db
,"nak #%d (%d/%d)\n",seq
,retries
,MAXTRY
);
293 if (retries
> MAXTRY
) { /* Check retry limit */
294 errpkt("Too many retries");
297 x
= spacket('N',seq
,0,""); /* A NAK never has data */
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 */
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. */
326 #endif /* __STDC__ */
329 s
= rpar(); /* Get our protocol parameters */
330 if (c
== 'S') { /* Sending a file... */
332 tmsgl("Escape back to your local Kermit and give a RECEIVE command.");
334 tmsgl("KERMIT READY TO SEND...");
337 return(spacket(c
,seq
,strlen(s
),s
)); /* Send S or I packet */
341 sfile() { /* Send file header packet */
343 char pktnam
[MAXPATHLEN
];
345 fprintf(db
,"sfile filnam [%s] max = %d\n",filnam
,MAXPATHLEN
);
346 if (zopeni(filnam
) < 0) { /* Open the input file */
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 */
357 fprintf(db
,"sfile pktnam %s\n",pktnam
);
358 x
= encstr(pktnam
); /* Encode name */
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 */
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) */
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...) */
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
);
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 */
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 */
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 */
422 if (i
< aln
) s
+= (aln
- i
);
423 if ((*ftbuf
!= 'A' && *ftbuf
!= 'B' && *ftbuf
!= 'I')) {
424 retcode
= -1; /* Reject the file */
427 if (*ftbuf
== 'A') { /* Check received attributes. */
428 text
= 1; /* Set current type to Text. */
429 } else if (*ftbuf
== 'B') {
434 default: /* Unknown attribute */
435 s
+= aln
; /* Just skip past it */
444 sdata() { /* Send a data packet */
446 if (cx
|| cz
) { /* Interrupted... */
448 fprintf(db
,"sdata interrupted cx = %d cz = %d\n",cx
,cz
);
452 x
= getpkt(maxsiz
); /* Fill data field from input file */
455 fprintf(db
,"sdata getpkt = %d\n",x
);
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 */
467 fprintf(db
,"seof zclosi failure %d\n",errno
);
468 errpkt("Failure to close input file");
471 nxtpkt(); /* Get next packet number */
472 x
= spacket('Z',seq
,strlen(s
),s
); /* Send EOF packet */
474 fprintf(db
,"seof spacket %d\n",x
);
477 return(0); /* To shut up picky compilers */
481 seot() { /* Send end-of-transmission packet */
483 return(spacket('B',seq
,0,""));
487 closof() { /* Close output file */
488 if (zcloso(cx
|cz
) < 0)
489 errpkt("Failure to close output file");
493 int /* Frame and send a packet */
495 spacket(char type
,int n
,int len
,char *d
)
497 spacket(type
,n
,len
,d
) char type
, *d
; int n
, len
;
498 #endif /* __STDC__ */
504 for (i
= 0; i
< spadn
; i
++) /* Do requested padding */
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 */
512 if ((len
+ bctu
+ 2) > 94) { /* If long packet */
513 x
= j
/ 95; /* Use long-packet format */
518 p
[i
] = NUL
; /* Terminate for header checksum */
519 p
[i
++] = tochar(chk1(&p
[k
],5)); /* Insert header checksum */
520 } else /* Short packet */
522 for (j
= len
; j
> 0; j
--) { /* Data */
525 p
[i
] = NUL
; /* Null-terminate */
527 switch (bctu
) { /* Block Check Type Used? */
528 case 1: /* Type 1 - 6 bit checksum */
529 p
[i
++] = tochar(chk1(p
+k
,m
));
531 case 2: /* Type 2 - 12 bit checksum */
533 p
[i
++] = tochar((j
>> 6) & 077);
534 p
[i
++] = tochar(j
& 077);
536 case 3: /* Type 3 - 16 bit CRC-CCITT */
538 p
[i
++] = tochar((j
>> 12) & 017);
539 p
[i
++] = tochar((j
>> 6) & 077);
540 p
[i
++] = tochar(j
& 077);
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. */
548 sendtype
= type
; /* Remember its type */
553 resend() { /* Resend a packet */
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");
562 x
= ttol(sndpkt
,sndpkl
); /* Send previous packet */
564 x
= nak(); /* or NAK if nothing sent yet. */
570 rpacket() { /* Read a packet */
572 int j
, x
, type
, rlnpos
, rpktl
; /* Local variables */
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)) {
598 fprintf(db
,"rpacket header checksum: %u\n",x
);
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");
607 } else { /* Regular packet */
608 rln
= j
- bctu
- 2; /* No extended header */
611 rsn
= xunchar(p
[i
++]); /* Sequence number */
612 type
= p
[i
++]; /* Packet type */
614 fprintf(db
,"rpacket type=%c, seq=%02d, len=%d\n",type
,rsn
,rln
);
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. */
621 p
[j
] = NUL
; /* Null-terminate the data */
622 datalen
= j
- i
; /* Remember data length */
624 switch (bctu
) { /* Check the block check */
626 c1
= (unsigned)xunchar((unsigned)((unsigned)(*pbc
) & 0xff));
627 c2
= chk1(p
+rlnpos
,j
-rlnpos
);
629 if (debug
) fprintf(db
,"rpacket chk1 (0x%x:0x%x)\n",c1
,c2
);
634 c1
= (unsigned)xunchar(*pbc
) << 6 | (unsigned)xunchar(pbc
[1]);
635 c2
= chksum(p
+rlnpos
,j
-rlnpos
);
637 if (debug
) fprintf(db
,"rpacket chk2 (0x%x:0x%x)\n",c1
,c2
);
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)))) &
646 c2
= chk3(p
+rlnpos
,j
-rlnpos
);
648 if (debug
) fprintf(db
,"rpacket crc (0x%x:0x%x)\n",c1
,c2
);
653 errpkt("BLOCKCHECK");
655 recvtype
= type
; /* Remember type. */
656 return(type
); /* Good packet, return type. */
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
;
669 chk1(packet
,len
) char *packet
; int len
; { /* Generate Type 1 block check */
671 x
= chksum(packet
,len
);
672 if (debug
) fprintf(db
,"chksum=%u\n",x
);
673 return((((x
& 192) >> 6) + x
) & 63);
677 chk3(s
,len
) char *s
; int len
; { /* Tableless 16-bit CRC generator */
678 register unsigned int c
;
679 register ULONG q
, crc
= 0L;
681 c
= (unsigned)(*s
++);
682 if (parity
) c
&= 0177;
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 */
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... */
704 } else { /* or file... */
707 if (c
< 0) { /* Watch out for empty file. */
711 } else if (first
== -1 && !*remain
) { /* EOF from last time? */
714 for (size
= 0; (xdata
[size
] = remain
[size
]) != NUL
; size
++) ;
719 rpt
= 0; /* Initialize repeat counter. */
720 while (first
> -1) { /* Until end of file or string... */
723 if (!next
) next
= -1;
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
++) ;
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 */
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 */
763 encode(a
,next
) int a
, next
; { /* Encode character a into packet */
766 if (rptflg
) { /* Doing run-length encoding? */
767 if (a
== next
) { /* Yes, got a run? */
768 if (++rpt
< 94) { /* Yes, count. */
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. */
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. */
815 a
= *rdatap
++; /* For each character, a, do... */
816 if (rptflg
) { /* Repeat processing? */
817 if (a
== rptq
) { /* Yes, have repeat prefix? */
819 if (debug
) fprintf(db
,"decode rpt error A\n");
822 rpt
= xunchar(*rdatap
++); /* Yes, get count */
824 if (debug
) fprintf(db
,"decode rpt error B\n");
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 */
835 if (debug
) fprintf(db
,"decode ebq error\n");
838 a
= *rdatap
++; /* and get following character. */
841 if (a
== rctlq
) { /* Control quote? */
843 if (debug
) fprintf(db
,"decode ctl error\n");
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. */
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. */
860 for (; rpt
> 0; rpt
--) { /* Output the character. */
861 if (osp
) { /* As many copies as indicated by */
862 *osp
++ = a
; /* the repeat count. */
864 putc((char)a
,ofp
); /* Use putc macro here to avoid */
865 if (ferror(ofp
)) { /* function-call overhead. */
867 fprintf(db
,"decode putc a=%u errno=%u\n",a
,errno
);
874 return(0); /* Return successfully when done. */
878 spar(s
) char *s
; { /* Set protocol parameters. */
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 */
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;
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 */
913 if ((x
< 1) || (x
> 3)) x
= 1;
915 if (bctr
> 1 && bctr
!= x
) x
= 1;
917 if (rln
>= 9) { /* Repeat prefix */
919 rptflg
= ((rptq
> 32 && rptq
< 63) || (rptq
> 95 && rptq
< 127));
923 if (rln
>= 10) { /* Capas */
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 */
934 x
= xunchar(s
[k
+2]) * 95 + xunchar(s
[k
+3]);
935 spsiz
= (x
> MAXSP
) ? MAXSP
: x
;
936 if (spsiz
< 10) spsiz
= 80;
941 x
= xunchar(s
[k
+8]); /* Other Kermit's WHATAMI info */
942 if (debug
) fprintf(db
,"spar whatami = 0x%x\n",x
);
947 if (debug
) fprintf(db
,"spar streamok = %d\n",streamok
);
949 #endif /* NOSTREAMING */
950 if (rln
> k
+8) { /* Other Kermit's system ID */
956 if (x
> 0 && x
< 16 && rln
>= k
) {
957 strncpy(buf
,(char *)s
+z
+10,x
);
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 */
975 xdata
[1] = tochar(94); /* Biggest packet I can receive */
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 */
986 case 1: if (parity
) ebq
= sq
= '&'; break;
992 xdata
[8] = bctr
+ '0'; /* Block check type */
993 if (rptflg
) /* Run length encoding */
994 xdata
[9] = rptq
; /* If receiving, agree. */
997 xdata
[10] = tochar(2+8); /* Capabilities (LP+Attributes) */
998 xdata
[11] = tochar(1); /* Window size */
1000 xdata
[12] = (char) tochar(urpsiz
/ 95); /* Long packet size */
1001 xdata
[13] = (char) tochar(urpsiz
% 95);
1003 xdata
[14] = '0'; /* No checkpointing */
1007 x
= WMI_FLAG
; /* WHATAMI info */
1008 if (literal
) x
|= WMI_FNAME
; /* Filenames literal */
1009 if (!text
) x
|= WMI_FMODE
; /* Text or binary mode */
1011 if (streamok
> -1) /* If streaming not disabled, */
1012 x
|= WMI_STREAM
; /* offer to stream. */
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" */
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 */
1027 rinit() { /* RECEIVE initialization */
1030 tmsgl("Escape back to your local Kermit and give a SEND command.");
1032 tmsgl("KERMIT READY TO RECEIVE...");
1036 ginit() { /* GET initialization */
1039 tmsgl("Escape back to your local Kermit and give a SERVER command.");
1041 tmsgl("KERMIT READY TO GET...");
1045 gnfile() { /* Get name of next file to send */
1046 if (cz
) /* Batch was canceled */
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 */
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 */
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");
1082 int /* Send a command packet */
1084 scmd(char t
, char *s
)
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 */