xref: /netbsd-src/external/bsd/ekermit/dist/kermit.c (revision 250ad67d8ece5c4fa0200159a0183f377ebff96b)
1a704a161Sapb #define KERMIT_C
2a704a161Sapb /*
3a704a161Sapb   Embedded Kermit protocol module
4a704a161Sapb   Version: 1.7
5a704a161Sapb   Most Recent Update: Mon Jun  6 15:36:26 2011
6a704a161Sapb 
7a704a161Sapb   No stdio or other runtime library calls, no system calls, no system
8a704a161Sapb   includes, no static data, and no global variables in this module.
9a704a161Sapb 
10a704a161Sapb   Warning: you can't use debug() in any routine whose argument list
11a704a161Sapb   does not include "struct k_data * k".  Thus most routines in this
12a704a161Sapb   module include this arg, even if they don't use it.
13a704a161Sapb 
14a704a161Sapb   Author: Frank da Cruz.
15a704a161Sapb   As of version 1.6 of 30 March 2011, E-Kermit is Open Source software under
16a704a161Sapb   the Revised 3-Clause BSD license which follows.  E-Kermit 1.6 is identical
17a704a161Sapb   to version 1.51 except for the new license.
18a704a161Sapb 
19a704a161Sapb   Author: Frank da Cruz.
20a704a161Sapb 
21a704a161Sapb   Copyright (C) 1995, 2011,
22a704a161Sapb   Trustees of Columbia University in the City of New York.
23a704a161Sapb   All rights reserved.
24a704a161Sapb 
25a704a161Sapb   Redistribution and use in source and binary forms, with or without
26a704a161Sapb   modification, are permitted provided that the following conditions are met:
27a704a161Sapb 
28a704a161Sapb   * Redistributions of source code must retain the above copyright notice,
29a704a161Sapb     this list of conditions and the following disclaimer.
30a704a161Sapb 
31a704a161Sapb   * Redistributions in binary form must reproduce the above copyright notice,
32a704a161Sapb     this list of conditions and the following disclaimer in the documentation
33a704a161Sapb     and/or other materials provided with the distribution.
34a704a161Sapb 
35a704a161Sapb   * Neither the name of Columbia University nor the names of its contributors
36a704a161Sapb     may be used to endorse or promote products derived from this software
37a704a161Sapb     without specific prior written permission.
38a704a161Sapb 
39a704a161Sapb   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
40a704a161Sapb   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41a704a161Sapb   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42a704a161Sapb   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
43a704a161Sapb   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
44a704a161Sapb   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
45a704a161Sapb   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46a704a161Sapb   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47a704a161Sapb   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48a704a161Sapb   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49a704a161Sapb   POSSIBILITY OF SUCH DAMAGE.
50a704a161Sapb */
51a704a161Sapb #include "cdefs.h"			/* C language defs for all modules */
52a704a161Sapb #include "debug.h"			/* Debugging */
53a704a161Sapb #include "kermit.h"			/* Kermit protocol definitions */
54a704a161Sapb 
55a704a161Sapb #define zgetc() \
56a704a161Sapb ((--(k->zincnt))>=0)?((int)(*(k->zinptr)++)&0xff):(*(k->readf))(k)
57a704a161Sapb 
58a704a161Sapb /* See cdefs.h for meaning of STATIC, ULONG, and UCHAR */
59a704a161Sapb 
60a704a161Sapb STATIC ULONG stringnum(UCHAR *, struct k_data *);
61a704a161Sapb STATIC UCHAR * numstring(ULONG, UCHAR *, int, struct k_data *);
62a704a161Sapb int STATIC spkt(char, short, int, UCHAR *, struct k_data *);
63a704a161Sapb int STATIC ack(struct k_data *, short, UCHAR * text);
64a704a161Sapb int STATIC nak(struct k_data *, short, short);
65a704a161Sapb int STATIC chk1(UCHAR *, struct k_data *);
66a704a161Sapb STATIC USHORT chk2(UCHAR *, struct k_data *);
67a704a161Sapb #ifdef F_CRC
68a704a161Sapb STATIC USHORT chk3(UCHAR *, struct k_data *);
69a704a161Sapb #endif /* F_CRC */
70a704a161Sapb void STATIC spar(struct k_data *, UCHAR *, int);
71a704a161Sapb int STATIC rpar(struct k_data *, char);
72a704a161Sapb int STATIC decode(struct k_data *, struct k_response *, short, UCHAR *);
73a704a161Sapb #ifdef F_AT
74a704a161Sapb int STATIC gattr(struct k_data *, UCHAR *, struct k_response *);
75a704a161Sapb int STATIC sattr(struct k_data *, struct k_response *);
76a704a161Sapb #endif /* F_AT */
77a704a161Sapb #ifndef RECVONLY
78a704a161Sapb int STATIC sdata(struct k_data *, struct k_response *);
79a704a161Sapb #endif /* RECVONLY */
80a704a161Sapb void STATIC epkt(char *, struct k_data *);
81a704a161Sapb int STATIC getpkt(struct k_data *, struct k_response *);
82a704a161Sapb int STATIC encstr(UCHAR *, struct k_data *, struct k_response *);
83a704a161Sapb void STATIC decstr(UCHAR *, struct k_data *, struct k_response *);
84a704a161Sapb void STATIC encode(int, int, struct k_data *);
85a704a161Sapb int STATIC nxtpkt(struct k_data *);
86a704a161Sapb int STATIC resend(struct k_data *);
87a704a161Sapb #ifdef DEBUG
88a704a161Sapb int xerror(void);
89a704a161Sapb #endif /* DEBUG */
90a704a161Sapb 
91a704a161Sapb int					/* The kermit() function */
kermit(short f,struct k_data * k,short r_slot,int len,char * msg,struct k_response * r)92a704a161Sapb kermit(short f,				/* Function code */
93a704a161Sapb        struct k_data *k,		/* The control struct */
94a704a161Sapb        short r_slot,			/* Received packet slot number */
95a704a161Sapb        int len,				/* Length of packet in slot */
96a704a161Sapb        char *msg,			/* Message for error packet */
97a704a161Sapb        struct k_response *r) {		/* Response struct */
98a704a161Sapb 
99a704a161Sapb     int i, j, rc;			/* Workers */
100a704a161Sapb     int datalen;                        /* Length of packet data field */
101a704a161Sapb     UCHAR *p;                           /* Pointer to packet data field */
102a704a161Sapb     UCHAR *q;                           /* Pointer to data to be checked */
103a704a161Sapb     UCHAR *s;				/* Worker string pointer */
104a704a161Sapb     UCHAR c, t;                         /* Worker chars */
105a704a161Sapb     UCHAR pbc[4];                       /* Copy of packet block check */
106a704a161Sapb     short seq, prev;			/* Copies of sequence numbers */
107a704a161Sapb     short chklen;                       /* Length of packet block check */
108a704a161Sapb #ifdef F_CRC
109a704a161Sapb     unsigned int crc;                   /* 16-bit CRC */
110a704a161Sapb #endif /* F_CRC */
111a704a161Sapb     int ok;
112a704a161Sapb 
113a704a161Sapb     debug(DB_MSG,"----------",0,0);	/* Marks each entry */
114a704a161Sapb     debug(DB_LOG,"f",0,f);
115a704a161Sapb     debug(DB_LOG,"state",0,k->state);
116a704a161Sapb     debug(DB_LOG,"zincnt",0,(k->zincnt));
117a704a161Sapb 
118a704a161Sapb     if (f == K_INIT) {			/* Initialize packet buffers etc */
119a704a161Sapb 
120a704a161Sapb 	k->version = (UCHAR *)VERSION;	/* Version of this module */
121a704a161Sapb         r->filename[0] = '\0';		/* No filename yet. */
122a704a161Sapb         r->filedate[0] = '\0';		/* No filedate yet. */
123a704a161Sapb         r->filesize = 0L;               /* No filesize yet. */
124a704a161Sapb 	r->sofar = 0L;			/* No bytes transferred yet */
125a704a161Sapb 
126a704a161Sapb         for (i = 0; i < P_WSLOTS; i++) { /* Packet info for each window slot */
127a704a161Sapb 	    freerslot(k,i);
128a704a161Sapb 	    freesslot(k,i);
129a704a161Sapb 	}
130a704a161Sapb #ifdef F_TSW
131a704a161Sapb         for (i = 0; i < 64; i++) {	/* Packet finder array */
132a704a161Sapb 	    k->r_pw[i] = -1;		/* initialized to "no packets yet" */
133a704a161Sapb 	    k->s_pw[i] = -1;		/* initialized to "no packets yet" */
134a704a161Sapb 	}
135a704a161Sapb #endif /* F_TSW */
136a704a161Sapb 
137a704a161Sapb /* Initialize the k_data structure */
138a704a161Sapb 
139a704a161Sapb 	for (i = 0; i < 6; i++)
140a704a161Sapb 	  k->s_remain[i] = '\0';
141a704a161Sapb 
142a704a161Sapb         k->state    = R_WAIT;		/* Beginning protocol state */
143a704a161Sapb 	r->status   = R_WAIT;
144a704a161Sapb 	k->what     = W_RECV;		/* Default action */
145a704a161Sapb 	k->s_first  = 1;		/* Beginning of file */
146a704a161Sapb         k->r_soh    = k->s_soh = SOH;	/* Packet start */
147a704a161Sapb         k->r_eom    = k->s_eom = CR;	/* Packet end */
148a704a161Sapb         k->s_seq    = k->r_seq =  0;	/* Packet sequence number */
149a704a161Sapb         k->s_type   = k->r_type = 0;	/* Packet type */
150a704a161Sapb         k->r_timo   = P_R_TIMO;		/* Timeout interval for me to use */
151a704a161Sapb         k->s_timo   = P_S_TIMO;		/* Timeout for other Kermit to use */
152a704a161Sapb         k->r_maxlen = P_PKTLEN;         /* Maximum packet length */
153a704a161Sapb         k->s_maxlen = P_PKTLEN;         /* Maximum packet length */
154a704a161Sapb         k->window   = P_WSLOTS;		/* Maximum window slots */
155a704a161Sapb         k->wslots   = 1;		/* Current window slots */
156a704a161Sapb 	k->zincnt   = 0;
157a704a161Sapb 	k->dummy    = 0;
158a704a161Sapb 	k->filename = (UCHAR *)0;
159a704a161Sapb 
160a704a161Sapb         /* Parity must be filled in by the caller */
161a704a161Sapb 
162a704a161Sapb         k->retry  = P_RETRY;            /* Retransmission limit */
163a704a161Sapb         k->s_ctlq = k->r_ctlq = '#';    /* Control prefix */
164a704a161Sapb         k->ebq    = 'Y';		/* 8th-bit prefix negotiation */
165a704a161Sapb 	k->ebqflg = 0;			/* 8th-bit prefixing flag */
166a704a161Sapb         k->rptq   = '~';		/* Send repeat prefix */
167a704a161Sapb         k->rptflg = 0;                  /* Repeat counts negotiated */
168a704a161Sapb 	k->s_rpt  = 0;			/* Current repeat count */
169a704a161Sapb         k->capas  = 0                   /* Capabilities */
170a704a161Sapb #ifdef F_LP
171a704a161Sapb           | CAP_LP                      /* Long packets */
172a704a161Sapb #endif /* F_LP */
173a704a161Sapb #ifdef F_SW
174a704a161Sapb             | CAP_SW                    /* Sliding windows */
175a704a161Sapb #endif /* F_SW */
176a704a161Sapb #ifdef F_AT
177a704a161Sapb               | CAP_AT                  /* Attribute packets */
178a704a161Sapb #endif /* F_AT */
179a704a161Sapb                 ;
180a704a161Sapb 
181a704a161Sapb 	k->opktbuf[0] = '\0';		/* No packets sent yet. */
182a704a161Sapb 	k->opktlen = 0;
183a704a161Sapb 
184a704a161Sapb #ifdef F_CRC
185a704a161Sapb /* This is the only way to initialize these tables -- no static data. */
186a704a161Sapb 
187a704a161Sapb         k->crcta[ 0] =       0;		/* CRC generation table A */
188a704a161Sapb         k->crcta[ 1] =  010201;
189a704a161Sapb         k->crcta[ 2] =  020402;
190a704a161Sapb         k->crcta[ 3] =  030603;
191a704a161Sapb         k->crcta[ 4] =  041004;
192a704a161Sapb         k->crcta[ 5] =  051205;
193a704a161Sapb         k->crcta[ 6] =  061406;
194a704a161Sapb         k->crcta[ 7] =  071607;
195a704a161Sapb         k->crcta[ 8] = 0102010;
196a704a161Sapb         k->crcta[ 9] = 0112211;
197a704a161Sapb         k->crcta[10] = 0122412;
198a704a161Sapb         k->crcta[11] = 0132613;
199a704a161Sapb         k->crcta[12] = 0143014,
200a704a161Sapb         k->crcta[13] = 0153215;
201a704a161Sapb         k->crcta[14] = 0163416;
202a704a161Sapb         k->crcta[15] = 0173617;
203a704a161Sapb 
204a704a161Sapb         k->crctb[ 0] =       0;        /* CRC table B */
205a704a161Sapb         k->crctb[ 1] =  010611;
206a704a161Sapb         k->crctb[ 2] =  021422;
207a704a161Sapb         k->crctb[ 3] =  031233;
208a704a161Sapb         k->crctb[ 4] =  043044;
209a704a161Sapb         k->crctb[ 5] =  053655;
210a704a161Sapb         k->crctb[ 6] =  062466;
211a704a161Sapb         k->crctb[ 7] =  072277;
212a704a161Sapb         k->crctb[ 8] = 0106110;
213a704a161Sapb         k->crctb[ 9] = 0116701;
214a704a161Sapb         k->crctb[10] = 0127532;
215a704a161Sapb         k->crctb[11] = 0137323;
216a704a161Sapb         k->crctb[12] = 0145154;
217a704a161Sapb         k->crctb[13] = 0155745;
218a704a161Sapb         k->crctb[14] = 0164576;
219a704a161Sapb         k->crctb[15] = 0174367;
220a704a161Sapb #endif /* F_CRC */
221a704a161Sapb 
222a704a161Sapb 	return(X_OK);
223a704a161Sapb 
224a704a161Sapb #ifndef RECVONLY
225a704a161Sapb     } else if (f == K_SEND) {
226a704a161Sapb 	if (rpar(k,'S') != X_OK)	/* Send S packet with my parameters */
227a704a161Sapb 	  return(X_ERROR);		/* I/O error, quit. */
228a704a161Sapb 	k->state = S_INIT;		/* All OK, switch states */
229a704a161Sapb 	r->status = S_INIT;
230a704a161Sapb 	k->what = W_SEND;		/* Act like a sender */
231a704a161Sapb         return(X_OK);
232a704a161Sapb #endif /* RECVONLY */
233a704a161Sapb 
234a704a161Sapb     } else if (f == K_STATUS) {         /* Status report requested. */
235a704a161Sapb         return(X_STATUS);               /* File name, date, size, if any. */
236a704a161Sapb 
237a704a161Sapb     } else if (f == K_QUIT) {           /* You told me to quit */
238a704a161Sapb         return(X_DONE);                 /* so I quit. */
239a704a161Sapb 
240a704a161Sapb     } else if (f == K_ERROR) {          /* Send an error packet... */
241a704a161Sapb         epkt(msg,k);
242a704a161Sapb 	k->closef(k,0,(k->state == S_DATA) ? 1 : 2); /* Close file */
243a704a161Sapb         return(X_DONE);                 /* and quit. */
244a704a161Sapb 
245a704a161Sapb     } else if (f != K_RUN) {            /* Anything else is an error. */
246a704a161Sapb         return(X_ERROR);
247a704a161Sapb     }
248a704a161Sapb     if (k->state == R_NONE)             /* (probably unnecessary) */
249a704a161Sapb       return(X_OK);
250a704a161Sapb 
251a704a161Sapb /* If we're in the protocol, check to make sure we got a new packet */
252a704a161Sapb 
253a704a161Sapb     debug(DB_LOG,"r_slot",0,r_slot);
254a704a161Sapb     debug(DB_LOG,"len",0,len);
255a704a161Sapb 
256a704a161Sapb     if (r_slot < 0)			/* We should have a slot here */
257a704a161Sapb       return(K_ERROR);
258a704a161Sapb     else
259a704a161Sapb       k->ipktinfo[r_slot].len = len;	/* Copy packet length to ipktinfo. */
260a704a161Sapb 
261a704a161Sapb     if (len < 4) {			/* Packet obviously no good? */
262a704a161Sapb #ifdef RECVONLY
263a704a161Sapb 	return(nak(k,k->r_seq,r_slot)); /* Send NAK for the packet we want */
264a704a161Sapb #else
265a704a161Sapb 	if (k->what == W_RECV)		/* If receiving */
266a704a161Sapb 	  return(nak(k,k->r_seq,r_slot)); /* Send NAK for the packet we want */
267a704a161Sapb 	else				/* If sending */
268a704a161Sapb 	  return(resend(k));		/* retransmit last packet. */
269a704a161Sapb #endif /* RECVONLY */
270a704a161Sapb     }
271a704a161Sapb 
272a704a161Sapb /* Parse the packet */
273a704a161Sapb 
274a704a161Sapb     if (k->what == W_RECV) {		/* If we're sending ACKs */
275a704a161Sapb 	switch(k->cancel) {		/* Get cancellation code if any */
276a704a161Sapb 	  case 0: s = (UCHAR *)0;   break;
277a704a161Sapb 	  case 1: s = (UCHAR *)"X"; break;
278a704a161Sapb 	  case 2: s = (UCHAR *)"Z"; break;
279a704a161Sapb 	}
280a704a161Sapb     }
281a704a161Sapb     p = &(k->ipktbuf[0][r_slot]);	/* Point to it */
282a704a161Sapb 
283a704a161Sapb     q = p;                              /* Pointer to data to be checked */
284a704a161Sapb     k->ipktinfo[r_slot].len = xunchar(*p++); /* Length field */
285a704a161Sapb     seq = k->ipktinfo[r_slot].seq = xunchar(*p++); /* Sequence number */
286a704a161Sapb     t = k->ipktinfo[r_slot].typ = *p++;	/* Type */
287a704a161Sapb 
288a704a161Sapb     if (
289a704a161Sapb #ifndef RECVONLY
290a704a161Sapb 	(k->what == W_RECV) &&		/* Echo (it happens), ignore */
291a704a161Sapb #endif /* RECVONLY */
292a704a161Sapb 	(t == 'N' || t  == 'Y')) {
293a704a161Sapb         freerslot(k,r_slot);
294a704a161Sapb         return(X_OK);
295a704a161Sapb     }
296a704a161Sapb     k->ipktinfo[r_slot].dat = p;	/* Data field, maybe */
297a704a161Sapb #ifdef F_LP
298a704a161Sapb     if (k->ipktinfo[r_slot].len == 0) {	/* Length 0 means long packet */
299a704a161Sapb         c = p[2];                       /* Get header checksum */
300a704a161Sapb         p[2] = '\0';
301a704a161Sapb         if (xunchar(c) != chk1(p-3,k)) {  /* Check it */
302a704a161Sapb             freerslot(k,r_slot);	/* Bad */
303a704a161Sapb 	    debug(DB_MSG,"HDR CHKSUM BAD",0,0);
304a704a161Sapb #ifdef RECVONLY
305a704a161Sapb 	    return(nak(k,k->r_seq,r_slot)); /* Send NAK */
306a704a161Sapb #else
307a704a161Sapb 	    if (k->what == W_RECV)
308a704a161Sapb 	      return(nak(k,k->r_seq,r_slot)); /* Send NAK */
309a704a161Sapb 	    else
310a704a161Sapb 	      return(resend(k));
311a704a161Sapb #endif /* RECVONLY */
312a704a161Sapb         }
313a704a161Sapb 	debug(DB_MSG,"HDR CHKSUM OK",0,0);
314a704a161Sapb         p[2] = c;                       /* Put checksum back */
315a704a161Sapb 	/* Data length */
316a704a161Sapb         datalen = xunchar(p[0])*95 + xunchar(p[1]) - ((k->bctf) ? 3 : k->bct);
317a704a161Sapb         p += 3;                         /* Fix data pointer */
318a704a161Sapb         k->ipktinfo[r_slot].dat = p;	/* Permanent record of data pointer */
319a704a161Sapb     } else {                            /* Regular packet */
320a704a161Sapb #endif /* F_LP */
321a704a161Sapb         datalen = k->ipktinfo[r_slot].len - k->bct - 2; /* Data length */
322a704a161Sapb #ifdef F_LP
323a704a161Sapb     }
324a704a161Sapb #endif /* F_LP */
325a704a161Sapb #ifdef F_CRC
326a704a161Sapb     if (k->bctf) {			/* FORCE 3 */
327a704a161Sapb 	chklen = 3;
328a704a161Sapb     } else {
329a704a161Sapb 	if (t == 'S' || k->state == S_INIT) { /* S-packet was retransmitted? */
330a704a161Sapb 	    if (q[10] == '5') {		/* Block check type requested is 5 */
331a704a161Sapb 		k->bctf = 1;		/* FORCE 3 */
332a704a161Sapb 		chklen = 3;
333a704a161Sapb 	    }
334a704a161Sapb 	    chklen = 1;			/* Block check is always type 1 */
335a704a161Sapb 	    datalen = k->ipktinfo[r_slot].len - 3; /* Data length */
336a704a161Sapb 	} else {
337a704a161Sapb 	    chklen = k->bct;
338a704a161Sapb 	}
339a704a161Sapb     }
340a704a161Sapb #else
341a704a161Sapb     chklen = 1;				/* Block check is always type 1 */
342a704a161Sapb     datalen = k->ipktinfo[r_slot].len - 3; /* Data length */
343a704a161Sapb #endif /* F_CRC */
344a704a161Sapb     debug(DB_LOG,"bct",0,(k->bct));
345a704a161Sapb     debug(DB_LOG,"datalen",0,datalen);
346a704a161Sapb     debug(DB_LOG,"chkalen",0,chklen);
347a704a161Sapb 
348a704a161Sapb #ifdef F_CRC
349a704a161Sapb     for (i = 0; i < chklen; i++)        /* Copy the block check */
350a704a161Sapb       pbc[i] = p[datalen+i];
351a704a161Sapb     pbc[i] = '\0';			/* Null-terminate block check string */
352a704a161Sapb #else
353a704a161Sapb     pbc[0] = p[datalen];
354a704a161Sapb     pbc[1] = '\0';
355a704a161Sapb #endif /* F_CRC */
356a704a161Sapb     p[datalen] = '\0';			/* and the packet DATA field. */
357a704a161Sapb #ifdef F_CRC
358a704a161Sapb     switch (chklen) {                   /* Check the block check  */
359a704a161Sapb       case 1:				/* Type 1, 6-bit checksum */
360a704a161Sapb #endif /* F_CRC */
361a704a161Sapb 	ok = (xunchar(*pbc) == chk1(q,k));
362a704a161Sapb #ifdef DEBUG
363a704a161Sapb 	if (ok && xerror()) ok = 0;
364a704a161Sapb #endif /* DEBUG */
365a704a161Sapb 	if (!ok) {
366a704a161Sapb 	    freerslot(k,r_slot);
367a704a161Sapb #ifdef RECVONLY
368a704a161Sapb 	    nak(k,k->r_seq,r_slot);
369a704a161Sapb #else
370a704a161Sapb 	    if (k->what == W_RECV)
371a704a161Sapb 	      nak(k,k->r_seq,r_slot);
372a704a161Sapb 	    else
373a704a161Sapb 	      resend(k);
374a704a161Sapb #endif /* RECVONLY */
375a704a161Sapb 	    return(X_OK);
376a704a161Sapb 	}
377a704a161Sapb #ifdef F_CRC
378a704a161Sapb 	break;
379a704a161Sapb 
380a704a161Sapb       case 2:                         /* Type 2, 12-bit checksum */
381a704a161Sapb 	i = xunchar(*pbc) << 6 | xunchar(pbc[1]);
382a704a161Sapb 	ok = (i == chk2(q,k));
383a704a161Sapb #ifdef DEBUG
384a704a161Sapb 	if (ok && xerror()) ok = 0;
385a704a161Sapb #endif /* DEBUG */
386a704a161Sapb 	if (!ok) {			/* No match */
387a704a161Sapb 	    if (t == 'E') {		/* Allow E packets to have type 1 */
388a704a161Sapb 		int j;
389a704a161Sapb 		j = datalen;
390a704a161Sapb 		p[j++] = pbc[0];
391a704a161Sapb 		p[j] = '\0';
392a704a161Sapb 		if (xunchar(pbc[1]) == chk1(q,k))
393a704a161Sapb 		  break;
394a704a161Sapb 		else
395a704a161Sapb 		  p[--j] = '\0';
396a704a161Sapb 	    }
397a704a161Sapb 	    freerslot(k,r_slot);
398a704a161Sapb #ifdef RECVONLY
399a704a161Sapb 	    nak(k,k->r_seq,r_slot);
400a704a161Sapb #else
401a704a161Sapb 	    if (k->what == W_RECV)
402a704a161Sapb 	      nak(k,k->r_seq,r_slot);
403a704a161Sapb 	    else
404a704a161Sapb 	      resend(k);
405a704a161Sapb #endif /* RECVONLY */
406a704a161Sapb 	    return(X_OK);
407a704a161Sapb 	}
408a704a161Sapb 	break;
409a704a161Sapb 
410a704a161Sapb       case 3:				/* Type 3, 16-bit CRC */
411a704a161Sapb 	crc = (xunchar(pbc[0]) << 12)
412a704a161Sapb 	  | (xunchar(pbc[1]) << 6)
413a704a161Sapb 	    | (xunchar(pbc[2]));
414a704a161Sapb 	ok = (crc == chk3(q,k));
415a704a161Sapb #ifdef DEBUG
416a704a161Sapb 	if (ok && xerror()) {
417a704a161Sapb 	    ok = 0;
418a704a161Sapb 	    debug(DB_MSG,"CRC ERROR INJECTED",0,0);
419a704a161Sapb 	}
420a704a161Sapb #endif /* DEBUG */
421a704a161Sapb 	if (!ok) {
422a704a161Sapb 	    debug(DB_LOG,"CRC ERROR t",0,t);
423a704a161Sapb 	    if (t == 'E') {		/* Allow E packets to have type 1 */
424a704a161Sapb 		int j;
425a704a161Sapb 		j = datalen;
426a704a161Sapb 		p[j++] = pbc[0];
427a704a161Sapb 		p[j++] = pbc[1];
428a704a161Sapb 		p[j] = '\0';
429a704a161Sapb 		if (xunchar(pbc[2]) == chk1(q,k))
430a704a161Sapb 		  break;
431a704a161Sapb 		else { j -=2; p[j] = '\0'; }
432a704a161Sapb 	    }
433a704a161Sapb 	    freerslot(k,r_slot);
434a704a161Sapb #ifdef RECVONLY
435a704a161Sapb 	    nak(k,k->r_seq,r_slot);
436a704a161Sapb #else
437a704a161Sapb 	    if (k->what == W_RECV)
438a704a161Sapb 	      nak(k,k->r_seq,r_slot);
439a704a161Sapb 	    else
440a704a161Sapb 	      resend(k);
441a704a161Sapb #endif /* RECVONLY */
442a704a161Sapb 	    return(X_OK);
443a704a161Sapb 	}
444a704a161Sapb     }
445a704a161Sapb #endif /* F_CRC */
446a704a161Sapb     if (t == 'E')			/* (AND CLOSE FILES?) */
447a704a161Sapb       return(X_ERROR);
448a704a161Sapb 
449a704a161Sapb     prev = k->r_seq - 1;		/* Get sequence of previous packet */
450a704a161Sapb     if (prev < 0)
451a704a161Sapb       prev = 63;
452a704a161Sapb 
453a704a161Sapb     debug(DB_LOG,"Seq",0,seq);
454a704a161Sapb     debug(DB_LOG,"Prev",0,prev);
455a704a161Sapb 
456a704a161Sapb     if (seq == k->r_seq) {		/* Is this the packet we want? */
457a704a161Sapb 	k->ipktinfo[r_slot].rtr = 0;	/* Yes */
458a704a161Sapb     } else {
459a704a161Sapb         freerslot(k,r_slot);		/* No, discard it. */
460a704a161Sapb 
461a704a161Sapb         if (seq == prev) {              /* If it's the previous packet again */
462a704a161Sapb 	    debug(DB_LOG,"PREVIOUS PKT RETRIES",0,
463a704a161Sapb 		  (long)(k->ipktinfo[r_slot].rtr));
464a704a161Sapb             if (k->ipktinfo[r_slot].rtr++ > k->retry) { /* Count retries */
465a704a161Sapb                 epkt("Too many retries", k); /* Too may */
466a704a161Sapb                 return(X_ERROR);	/* Give up */
467a704a161Sapb             } else {			/* Otherwise */
468a704a161Sapb 		return(resend(k));	/* Send old outbound packet buffer */
469a704a161Sapb             }
470a704a161Sapb #ifdef RECVONLY
471a704a161Sapb 	} else {
472a704a161Sapb 	    return(nak(k,k->r_seq,r_slot));
473a704a161Sapb #else
474a704a161Sapb         } else if (k->what == W_RECV) {	/* Otherwise NAK the one we want */
475a704a161Sapb 	    return(nak(k,k->r_seq,r_slot));
476a704a161Sapb 	} else {			/* or whatever... */
477a704a161Sapb 	    return(resend(k));
478a704a161Sapb #endif /* RECVONLY */
479a704a161Sapb 	}
480a704a161Sapb     }
481a704a161Sapb #ifndef RECVONLY
482a704a161Sapb     if (k->what == W_SEND) {		/* Sending, check for ACK */
483a704a161Sapb 	if (t != 'Y') {			/* Not an ACK */
484a704a161Sapb 	    debug(DB_LOG,"t!=Y t",0,t);
485a704a161Sapb 	    freerslot(k,r_slot);	/* added 2004-06-30 -- JHD */
486a704a161Sapb 	    return(resend(k));
487a704a161Sapb 	}
488a704a161Sapb 	if (k->state == S_DATA) {	/* ACK to Data packet?*/
489a704a161Sapb 	    if (k->cancel ||		/* Cancellation requested by caller? */
490a704a161Sapb 		*p == 'X' || *p == 'Z') { /* Or by receiver? */
491a704a161Sapb 		k->closef(k,*p,1);	  /* Close input file*/
492a704a161Sapb 		nxtpkt(k);		  /* Next packet sequence number */
493a704a161Sapb 		if ((rc = spkt('Z',k->s_seq,0,(UCHAR *)0,k)) != X_OK)
494a704a161Sapb 		  return(rc);
495a704a161Sapb 		if (*p == 'Z' || k->cancel == I_GROUP) { /* Cancel Group? */
496a704a161Sapb 		    debug(DB_MSG,"Group Cancel (Send)",0,0);
497a704a161Sapb 		    while (*(k->filelist)) { /* Go to end of file list */
498a704a161Sapb 			debug(DB_LOG,"Skip",*(k->filelist),0);
499a704a161Sapb 			(k->filelist)++;
500a704a161Sapb 		    }
501a704a161Sapb 		}
502a704a161Sapb 		k->state = S_EOF;	/* Wait for ACK to EOF */
503a704a161Sapb 		r->status = S_EOF;
504a704a161Sapb 		k->r_seq = k->s_seq;	/* Sequence number of packet we want */
505a704a161Sapb 		return(X_OK);
506a704a161Sapb 	    }
507a704a161Sapb 	}
508a704a161Sapb 	freerslot(k,r_slot);		/* It is, free the ACK. */
509a704a161Sapb     }
510a704a161Sapb #endif /* RECVONLY */
511a704a161Sapb 
512a704a161Sapb /* Now we have an incoming packet with the expected sequence number. */
513a704a161Sapb 
514a704a161Sapb     debug(DB_CHR,"Packet OK",0,t);
515a704a161Sapb     debug(DB_LOG,"State",0,k->state);
516a704a161Sapb 
517a704a161Sapb     switch (k->state) {                 /* Kermit protocol state switcher */
518a704a161Sapb 
519a704a161Sapb #ifndef RECVONLY
520a704a161Sapb       case S_INIT:			/* Got other Kermit's parameters */
521a704a161Sapb       case S_EOF:			/* Got ACK to EOF packet */
522a704a161Sapb 	nxtpkt(k);			/* Get next packet number etc */
523a704a161Sapb 	if (k->state == S_INIT) {	/* Got ACK to S packet? */
524a704a161Sapb 	    spar(k,p,datalen);		/* Set negotiated parameters */
525a704a161Sapb 	    debug(DB_CHR,"Parity",0,k->parity);
526a704a161Sapb 	    debug(DB_LOG,"Ebqflg",0,(k->ebqflg));
527a704a161Sapb 	    debug(DB_CHR,"Ebq",0,(k->ebq));
528a704a161Sapb 	}
529a704a161Sapb 	k->filename = *(k->filelist);	/* Get next filename */
530a704a161Sapb 	if (k->filename) {		/* If there is one */
531a704a161Sapb 	    int i;
532a704a161Sapb 	    for (i = 0; i < FN_MAX; i++) { /* Copy name to result struct */
533a704a161Sapb 		r->filename[i] = k->filename[i];
534a704a161Sapb 		if (!(r->filename[i]))
535a704a161Sapb 		    break;
536a704a161Sapb 	    }
537a704a161Sapb 	    (k->filelist)++;
538a704a161Sapb 	    debug(DB_LOG,"Filename",k->filename,0);
539a704a161Sapb 	    if ((rc = (k->openf)(k,k->filename,1)) != X_OK) /* Try to open */
540a704a161Sapb 	      return(rc);
541a704a161Sapb 	    encstr(k->filename,k,r);	/* Encode the name for transmission */
542a704a161Sapb 	    if ((rc = spkt('F',k->s_seq,-1,k->xdata,k)) != X_OK)
543a704a161Sapb 	      return(rc);		/* Send F packet */
544a704a161Sapb 	    r->sofar = 0L;
545a704a161Sapb 	    k->state = S_FILE;		/* Wait for ACK */
546a704a161Sapb 	    r->status = S_FILE;
547a704a161Sapb 	} else {			/* No more files - we're done */
548a704a161Sapb 	    if ((rc = spkt('B',k->s_seq,0,(UCHAR *)0,k)) != X_OK)
549a704a161Sapb 	      return(rc);		/* Send EOT packet */
550a704a161Sapb 	    k->state = S_EOT;		/* Wait for ACK */
551a704a161Sapb 	    r->status = S_EOT;
552a704a161Sapb 	}
553a704a161Sapb 	k->r_seq = k->s_seq;		/* Sequence number of packet we want */
554a704a161Sapb 	return(X_OK);			/* Return to control program */
555a704a161Sapb 
556a704a161Sapb       case S_FILE:			/* Got ACK to F packet */
557a704a161Sapb 	nxtpkt(k);			/* Get next packet number etc */
558a704a161Sapb #ifdef F_AT
559a704a161Sapb 	if (k->capas & CAP_AT) {	/* A-packets negotiated? */
560a704a161Sapb 	    if ((rc = sattr(k,r)) != X_OK) /* Yes, send Attribute packet */
561a704a161Sapb 	      return(rc);
562a704a161Sapb 	    k->state = S_ATTR;		/* And wait for its ACK */
563a704a161Sapb 	    r->status = S_ATTR;
564a704a161Sapb 	} else
565a704a161Sapb #endif /* F_AT */
566a704a161Sapb 	  if (sdata(k,r) == 0) {	/* No A packets - send first data */
567a704a161Sapb 	    /* File is empty so send EOF packet */
568a704a161Sapb 	    if ((rc = spkt('Z',k->s_seq,0,(UCHAR *)0,k)) != X_OK)
569a704a161Sapb 	      return(rc);
570a704a161Sapb 	    k->closef(k,*p,1);		/* Close input file*/
571a704a161Sapb 	    k->state = S_EOF;		/* Wait for ACK to EOF */
572a704a161Sapb 	    r->status = S_EOF;
573a704a161Sapb 	} else {			/* Sent some data */
574a704a161Sapb 	    k->state = S_DATA;		/* Wait for ACK to first data */
575a704a161Sapb 	    r->status = S_DATA;
576a704a161Sapb 	}
577a704a161Sapb 	k->r_seq = k->s_seq;		/* Sequence number to wait for */
578a704a161Sapb 	return(X_OK);
579a704a161Sapb 
580a704a161Sapb       case S_ATTR:			/* Got ACK to A packet */
581a704a161Sapb       case S_DATA:			/* Got ACK to D packet */
582a704a161Sapb 	nxtpkt(k);			/* Get next packet number */
583a704a161Sapb 	if (k->state == S_ATTR) {
584a704a161Sapb 	    /* CHECK ATTRIBUTE RESPONSE */
585a704a161Sapb 	    /* IF REJECTED do the right thing... */
586a704a161Sapb 	    k->state = S_DATA;
587a704a161Sapb 	    r->status = S_DATA;
588a704a161Sapb 	}
589a704a161Sapb 	rc = sdata(k,r);		/* Send first or next data packet */
590a704a161Sapb 
591a704a161Sapb 	debug(DB_LOG,"Seq",0,(k->s_seq));
592a704a161Sapb 	debug(DB_LOG,"sdata()",0,rc);
593a704a161Sapb 
594a704a161Sapb 	if (rc == 0) {			/* If there was no data to send */
595a704a161Sapb 	    if ((rc = spkt('Z',k->s_seq,0,(UCHAR *)0,k)) != X_OK)
596a704a161Sapb 	      return(rc);		/* Send EOF */
597a704a161Sapb 	    k->closef(k,*p,1);		/* Close input file*/
598a704a161Sapb 	    k->state = S_EOF;		/* And wait for ACK */
599a704a161Sapb 	    r->status = S_EOF;
600a704a161Sapb 	}				/* Otherwise stay in data state */
601a704a161Sapb 	k->r_seq = k->s_seq;		/* Sequence number to wait for */
602a704a161Sapb 	return(X_OK);
603a704a161Sapb 
604a704a161Sapb       case S_EOT:			/* Get ACK to EOT packet */
605a704a161Sapb         return(X_DONE);			/* (or X_ERROR) */
606a704a161Sapb #endif /* RECVONLY */
607a704a161Sapb 
608a704a161Sapb       case R_WAIT:                      /* Waiting for the S packet */
609a704a161Sapb         if (t == 'S') {                 /* Got it */
610a704a161Sapb             spar(k,p,datalen);          /* Set parameters from it */
611a704a161Sapb             rc = rpar(k,'Y');		/* ACK with my parameters */
612a704a161Sapb 	    debug(DB_LOG,"rpar rc",0,rc);
613a704a161Sapb             if (rc != X_OK)
614a704a161Sapb               return(X_ERROR);          /* I/O error, quit. */
615a704a161Sapb             k->state = R_FILE;          /* All OK, switch states */
616a704a161Sapb             r->status = R_FILE;
617a704a161Sapb         } else {                        /* Wrong kind of packet, send NAK */
618a704a161Sapb             epkt("Unexpected packet type",k);
619a704a161Sapb             rc = X_ERROR;
620a704a161Sapb         }
621a704a161Sapb         freerslot(k,r_slot);		/* Free packet slot */
622a704a161Sapb         return(rc);
623a704a161Sapb 
624a704a161Sapb       case R_FILE:                      /* Want an F or B packet */
625a704a161Sapb         if (t == 'F') {                 /* File name */
626a704a161Sapb             if ((rc = decode(k, r, 0, p)) == X_OK) /* Decode and save */
627a704a161Sapb               k->state = R_ATTR;        /* Switch to next state */
628a704a161Sapb 	    r->status = k->state;
629a704a161Sapb 	    debug(DB_LOG,"R_FILE decode rc",0,rc);
630a704a161Sapb 	    debug(DB_LOG,"R_FILE FILENAME",r->filename,0);
631a704a161Sapb             if (rc == X_OK) {		/* All OK so far */
632a704a161Sapb 		r->filedate[0] = '\0';	/* No file date yet */
633a704a161Sapb 		r->filesize = 0L;	/* Or file size */
634a704a161Sapb 		r->sofar = 0L;		/* Or bytes transferred yet */
635a704a161Sapb 		rc = ack(k, k->r_seq, r->filename); /* so ACK the F packet */
636a704a161Sapb 	    } else {
637a704a161Sapb 		epkt("Filename error",k); /* Error decoding filename */
638a704a161Sapb 	    }
639a704a161Sapb         } else if (t == 'B') {          /* Break, end of transaction */
640a704a161Sapb             freerslot(k,r_slot);
641a704a161Sapb             rc = (ack(k, k->r_seq, (UCHAR *)0) == X_OK) ? X_DONE : X_ERROR;
642a704a161Sapb 
643a704a161Sapb         } else {
644a704a161Sapb             epkt("Unexpected packet type",k);
645a704a161Sapb             rc = X_ERROR;
646a704a161Sapb         }
647a704a161Sapb         freerslot(k,r_slot);
648a704a161Sapb         return(rc);
649a704a161Sapb 
650a704a161Sapb       case R_ATTR:                      /* Want A, D, or Z packet */
651a704a161Sapb #ifdef F_AT
652a704a161Sapb         if (t == 'A') {                 /* Attribute packet */
653a704a161Sapb 	    int x;
654a704a161Sapb             x = gattr(k, p, r);		/* Read the attributes */
655a704a161Sapb 	    if (x > -1)
656a704a161Sapb 	      k->binary = x;
657a704a161Sapb             freerslot(k,r_slot);
658a704a161Sapb             ack(k, k->r_seq, (UCHAR *) "Y"); /* Always accept the file */
659a704a161Sapb             return(X_OK);
660a704a161Sapb         } else
661a704a161Sapb #endif /* F_AT */
662a704a161Sapb 	  if (t == 'D') {		/* First data packet */
663a704a161Sapb             k->obufpos = 0;             /* Initialize output buffer */
664a704a161Sapb 	    k->filename = r->filename;
665a704a161Sapb 	    r->sofar = 0L;
666a704a161Sapb             if ((rc = (*(k->openf))(k,r->filename, 2)) == X_OK) {
667a704a161Sapb                 k->state = R_DATA;      /* Switch to Data state */
668a704a161Sapb 		r->status = k->state;
669a704a161Sapb                 rc = decode(k, r, 1, p); /* Write out first data packet */
670a704a161Sapb                 freerslot(k,r_slot);
671a704a161Sapb             } else {
672a704a161Sapb                 epkt("File refused or can't be opened", k);
673a704a161Sapb                 freerslot(k,r_slot);
674a704a161Sapb                 return(rc);
675a704a161Sapb             }
676a704a161Sapb             if (rc == X_OK)
677a704a161Sapb               rc = ack(k, k->r_seq, s);
678a704a161Sapb             else
679a704a161Sapb               epkt("Error writing data", k);
680a704a161Sapb             return(rc);
681a704a161Sapb 	} else if (t == 'Z') {		/* Empty file */
682a704a161Sapb 	    debug(DB_LOG,"R_ATTR empty file",r->filename,0);
683a704a161Sapb             k->obufpos = 0;             /* Initialize output buffer */
684a704a161Sapb 	    k->filename = r->filename;
685a704a161Sapb 	    r->sofar = 0L;		/* Open and close the file */
686a704a161Sapb             if ((rc = (*(k->openf))(k,r->filename, 2)) == X_OK) {
687a704a161Sapb 		if (((rc = (*(k->closef))(k,*p,2)) == X_OK)) {
688a704a161Sapb 		    k->state = R_FILE;
689a704a161Sapb 		    rc = ack(k, k->r_seq, s);
690a704a161Sapb 		} else {
691a704a161Sapb 		    epkt("Error closing empty file", k);
692a704a161Sapb 		    freerslot(k,r_slot);
693a704a161Sapb 		    return(rc);
694a704a161Sapb 		}
695a704a161Sapb             } else {
696a704a161Sapb                 epkt("File refused or can't be opened", k);
697a704a161Sapb                 freerslot(k,r_slot);
698a704a161Sapb                 return(rc);
699a704a161Sapb             }
700a704a161Sapb 	    r->status = k->state;
701a704a161Sapb             freerslot(k,r_slot);
702a704a161Sapb 
703a704a161Sapb         } else {
704a704a161Sapb             epkt("Unexpected packet type",k);
705a704a161Sapb             return(X_ERROR);
706a704a161Sapb         }
707a704a161Sapb         break;
708a704a161Sapb 
709a704a161Sapb       case R_DATA:                      /* Want a D or Z packet */
710a704a161Sapb 	debug(DB_CHR,"R_DATA t",0,t);
711a704a161Sapb         if (t == 'D') {                 /* Data */
712a704a161Sapb             rc = decode(k, r, 1, p);	/* Decode it */
713a704a161Sapb             freerslot(k,r_slot);
714a704a161Sapb         } else if (t == 'Z') {          /* End of file */
715a704a161Sapb 	    debug(DB_CHR,"R_DATA",0,t);
716a704a161Sapb             if (k->obufpos > 0) {       /* Flush output buffer */
717a704a161Sapb                 rc = (*(k->writef))(k,k->obuf,k->obufpos);
718a704a161Sapb 		debug(DB_LOG,"R_DATA writef rc",0,rc);
719a704a161Sapb 		r->sofar += k->obufpos;
720a704a161Sapb                 k->obufpos = 0;
721a704a161Sapb             }
722a704a161Sapb             if (((rc = (*(k->closef))(k,*p,2)) == X_OK) && (rc == X_OK))
723a704a161Sapb               k->state = R_FILE;
724a704a161Sapb 	    debug(DB_LOG,"R_DATA closef rc",0,rc);
725a704a161Sapb 	    r->status = k->state;
726a704a161Sapb             freerslot(k,r_slot);
727a704a161Sapb         } else {
728a704a161Sapb             epkt("Unexpected packet type",k);
729a704a161Sapb             return(X_ERROR);
730a704a161Sapb         }
731a704a161Sapb         if (rc == X_OK)
732a704a161Sapb           rc = ack(k, k->r_seq, s);
733a704a161Sapb         else
734a704a161Sapb           epkt(t == 'Z' ? "Can't close file" : "Error writing data",k);
735a704a161Sapb         return(rc);
736a704a161Sapb 
737a704a161Sapb       case R_ERROR:                     /* Canceled from above */
738a704a161Sapb       default:
739a704a161Sapb         epkt(msg,k);
740a704a161Sapb         return(X_ERROR);
741a704a161Sapb     }
742a704a161Sapb     return(X_ERROR);
743a704a161Sapb }
744a704a161Sapb 
745a704a161Sapb /* Utility routines */
746a704a161Sapb 
747a704a161Sapb UCHAR *
getrslot(struct k_data * k,short * n)748a704a161Sapb getrslot(struct k_data *k, short *n) {   /* Find a free packet buffer */
749a704a161Sapb     register int i;
750a704a161Sapb /*
751a704a161Sapb   Note: We don't clear the retry count here.
752a704a161Sapb   It is cleared only after the NEXT packet arrives, which
753a704a161Sapb   indicates that the other Kermit got our ACK for THIS packet.
754a704a161Sapb */
755a704a161Sapb     for (i = 0; i < P_WSLOTS; i++) {    /* Search */
756a704a161Sapb         if (k->ipktinfo[i].len < 1) {
757a704a161Sapb             *n = i;                     /* Slot number */
758a704a161Sapb             k->ipktinfo[i].len = -1;	/* Mark it as allocated but not used */
759a704a161Sapb             k->ipktinfo[i].seq = -1;
760a704a161Sapb             k->ipktinfo[i].typ = SP;
761a704a161Sapb             /* k->ipktinfo[i].rtr =  0; */  /* (see comment above) */
762a704a161Sapb             k->ipktinfo[i].dat = (UCHAR *)0;
763a704a161Sapb             return(&(k->ipktbuf[0][i]));
764a704a161Sapb         }
765a704a161Sapb     }
766a704a161Sapb     *n = -1;
767a704a161Sapb     return((UCHAR *)0);
768a704a161Sapb }
769a704a161Sapb 
770a704a161Sapb void					/* Initialize a window slot */
freerslot(struct k_data * k,short n)771a704a161Sapb freerslot(struct k_data *k, short n) {
772a704a161Sapb     k->ipktinfo[n].len = 0;		/* Packet length */
773a704a161Sapb #ifdef COMMENT
774a704a161Sapb     k->ipktinfo[n].seq = 0;		/* Sequence number */
775a704a161Sapb     k->ipktinfo[n].typ = (char)0;	/* Type */
776a704a161Sapb     k->ipktinfo[n].rtr = 0;		/* Retry count */
777a704a161Sapb     k->ipktinfo[n].flg = 0;		/* Flags */
778a704a161Sapb #endif /* COMMENT */
779a704a161Sapb }
780a704a161Sapb 
781a704a161Sapb UCHAR *
getsslot(struct k_data * k,short * n)782a704a161Sapb getsslot(struct k_data *k, short *n) {   /* Find a free packet buffer */
783a704a161Sapb #ifdef COMMENT
784a704a161Sapb     register int i;
785a704a161Sapb     for (i = 0; i < P_WSLOTS; i++) {    /* Search */
786a704a161Sapb         if (k->opktinfo[i].len < 1) {
787a704a161Sapb             *n = i;                     /* Slot number */
788a704a161Sapb             k->opktinfo[i].len = -1;	/* Mark it as allocated but not used */
789a704a161Sapb             k->opktinfo[i].seq = -1;
790a704a161Sapb             k->opktinfo[i].typ = SP;
791a704a161Sapb             k->opktinfo[i].rtr =  0;
792a704a161Sapb             k->opktinfo[i].dat = (UCHAR *)0;
793a704a161Sapb             return(&(k->opktbuf[0][i]));
794a704a161Sapb         }
795a704a161Sapb     }
796a704a161Sapb     *n = -1;
797a704a161Sapb     return((UCHAR *)0);
798a704a161Sapb #else
799a704a161Sapb     *n = 0;
800a704a161Sapb     return(k->opktbuf);
801a704a161Sapb #endif /* COMMENT */
802a704a161Sapb }
803a704a161Sapb 
804a704a161Sapb void                                    /* Initialize a window slot */
freesslot(struct k_data * k,short n)805a704a161Sapb freesslot(struct k_data * k, short n) {
806a704a161Sapb     k->opktinfo[n].len = 0;		/* Packet length */
807a704a161Sapb     k->opktinfo[n].seq = 0;		/* Sequence number */
808a704a161Sapb     k->opktinfo[n].typ = (char)0;	/* Type */
809a704a161Sapb     k->opktinfo[n].rtr = 0;		/* Retry count */
810a704a161Sapb     k->opktinfo[n].flg = 0;		/* Flags */
811a704a161Sapb }
812a704a161Sapb 
813a704a161Sapb /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
814a704a161Sapb 
815a704a161Sapb STATIC int
chk1(UCHAR * pkt,struct k_data * k)816a704a161Sapb chk1(UCHAR *pkt, struct k_data * k) {
817a704a161Sapb     register unsigned int chk;
818a704a161Sapb     chk = chk2(pkt,k);
819a704a161Sapb     chk = (((chk & 0300) >> 6) + chk) & 077;
820a704a161Sapb     return((int) chk);
821a704a161Sapb }
822a704a161Sapb 
823a704a161Sapb /*  C H K 2  --  Numeric sum of all the bytes in the packet, 12 bits.  */
824a704a161Sapb 
825a704a161Sapb STATIC USHORT
chk2(UCHAR * pkt,struct k_data * k)826a704a161Sapb chk2(UCHAR *pkt,struct k_data * k) {
827a704a161Sapb     register USHORT chk;
828a704a161Sapb     for (chk = 0; *pkt != '\0'; pkt++)
829a704a161Sapb       chk += *pkt;
830a704a161Sapb     return(chk);
831a704a161Sapb }
832a704a161Sapb 
833a704a161Sapb #ifdef F_CRC
834a704a161Sapb 
835a704a161Sapb /*  C H K 3  --  Compute a type-3 Kermit block check.  */
836a704a161Sapb /*
837a704a161Sapb  Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
838a704a161Sapb  table.  Assumes the argument string contains no embedded nulls.
839a704a161Sapb */
840a704a161Sapb STATIC USHORT
chk3(UCHAR * pkt,struct k_data * k)841a704a161Sapb chk3(UCHAR *pkt, struct k_data * k) {
842a704a161Sapb     register USHORT c, crc;
843a704a161Sapb     for (crc = 0; *pkt != '\0'; pkt++) {
844a704a161Sapb #ifdef COMMENT
845a704a161Sapb         c = crc ^ (long)(*pkt);
846a704a161Sapb         crc = (crc >> 8) ^ (k->crcta[(c & 0xF0) >> 4] ^ k->crctb[c & 0x0F]);
847a704a161Sapb #else
848a704a161Sapb 	c = crc ^ (*pkt);
849a704a161Sapb        crc = (crc >> 8) ^ ((k->crcta[(c & 0xF0) >> 4]) ^ (k->crctb[c & 0x0F]));
850a704a161Sapb #endif	/*  COMMENT */
851a704a161Sapb     }
852a704a161Sapb     return(crc);
853a704a161Sapb }
854a704a161Sapb #endif /* F_CRC */
855a704a161Sapb 
856a704a161Sapb /*   S P K T  --  Send a packet.  */
857a704a161Sapb /*
858a704a161Sapb   Call with packet type, sequence number, data length, data, Kermit struct.
859a704a161Sapb   Returns:
860a704a161Sapb     X_OK on success
861a704a161Sapb     X_ERROR on i/o error
862a704a161Sapb */
863a704a161Sapb STATIC int
spkt(char typ,short seq,int len,UCHAR * data,struct k_data * k)864a704a161Sapb spkt(char typ, short seq, int len, UCHAR * data, struct k_data * k) {
865a704a161Sapb 
866a704a161Sapb     unsigned int crc;                   /* For building CRC */
867a704a161Sapb     int i, j, lenpos, m, n, x;		/* Workers */
868a704a161Sapb     UCHAR * s, * buf;
869a704a161Sapb 
870a704a161Sapb     debug(DB_LOG,"spkt len 1",0,len);
871a704a161Sapb     if (len < 0) {			/* Calculate data length ourselves? */
872a704a161Sapb 	len = 0;
873a704a161Sapb 	s = data;
874a704a161Sapb 	while (*s++) len++;
875a704a161Sapb     }
876a704a161Sapb     debug(DB_LOG,"spkt len 2",0,len);
877a704a161Sapb     buf = k->opktbuf;			/* Where to put packet (FOR NOW) */
878a704a161Sapb 
879a704a161Sapb     i = 0;                              /* Packet buffer position */
880a704a161Sapb     buf[i++] = k->s_soh;		/* SOH */
881a704a161Sapb     lenpos = i++;			/* Remember this place */
882a704a161Sapb     buf[i++] = tochar(seq);		/* Sequence number */
883a704a161Sapb     buf[i++] = typ;			/* Packet type */
884a704a161Sapb     j = len + k->bct;
885a704a161Sapb #ifdef F_LP
886a704a161Sapb     if ((len + k->bct + 2) > 94) {	/* If long packet */
887a704a161Sapb 	buf[lenpos] = tochar(0);	/* Put blank in LEN field */
888a704a161Sapb 	buf[i++] = tochar(j / 95);	/* Make extended header: Big part */
889a704a161Sapb 	buf[i++] = tochar(j % 95);	/* and small part of length. */
890a704a161Sapb         buf[i] = NUL;			/* Terminate for header checksum */
891a704a161Sapb         buf[i++] = tochar(chk1(&buf[lenpos],k)); /* Insert header checksum */
892a704a161Sapb     } else {				/* Short packet */
893a704a161Sapb #endif /* F_LP */
894a704a161Sapb 	buf[lenpos] = tochar(j+2);	/* Single-byte length in LEN field */
895a704a161Sapb #ifdef F_LP
896a704a161Sapb     }
897a704a161Sapb #endif /* F_LP */
898a704a161Sapb     if (data)                           /* Copy data, if any */
899a704a161Sapb       for ( ; len--; i++)
900a704a161Sapb         buf[i] = *data++;
901a704a161Sapb     buf[i] = '\0';
902a704a161Sapb 
903a704a161Sapb #ifdef F_CRC
904a704a161Sapb     switch (k->bct) {                   /* Add block check */
905a704a161Sapb       case 1:                           /* 1 = 6-bit chksum */
906a704a161Sapb 	buf[i++] = tochar(chk1(&buf[lenpos],k));
907a704a161Sapb         break;
908a704a161Sapb       case 2:                           /* 2 = 12-bit chksum */
909a704a161Sapb         j = chk2(&buf[lenpos],k);
910a704a161Sapb #ifdef XAC
911a704a161Sapb 	/* HiTech's XAC compiler silently ruins the regular code. */
912a704a161Sapb 	/* An intermediate variable provides a work-around. */
913a704a161Sapb 	/* 2004-06-29 -- JHD */
914a704a161Sapb 	{
915a704a161Sapb 	    USHORT jj;
916a704a161Sapb 	    jj = (j >> 6) & 077; buf[i++] = tochar(jj);
917a704a161Sapb 	    jj = j & 077;        buf[i++] = tochar(jj);
918a704a161Sapb 	}
919a704a161Sapb #else
920a704a161Sapb         buf[i++] = (unsigned)tochar((j >> 6) & 077);
921a704a161Sapb         buf[i++] = (unsigned)tochar(j & 077);
922a704a161Sapb #endif /* XAC */
923a704a161Sapb         break;
924a704a161Sapb       case 3:                           /* 3 = 16-bit CRC */
925a704a161Sapb         crc = chk3(&buf[lenpos],k);
926a704a161Sapb #ifdef XAC
927a704a161Sapb 	/* HiTech's XAC compiler silently ruins the above code. */
928a704a161Sapb 	/* An intermediate variable provides a work-around. */
929a704a161Sapb 	/* 2004-06-29 -- JHD */
930a704a161Sapb 	{
931a704a161Sapb 	    USHORT jj;
932a704a161Sapb 	    jj = (crc >> 12) & 0x0f; buf[i++] = tochar(jj);
933a704a161Sapb 	    jj = (crc >>  6) & 0x3f; buf[i++] = tochar(jj);
934a704a161Sapb 	    jj =  crc        & 0x3f; buf[i++] = tochar(jj);
935a704a161Sapb 	}
936a704a161Sapb #else
937a704a161Sapb         buf[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
938a704a161Sapb         buf[i++] = (unsigned)tochar((crc >> 6) & 077);
939a704a161Sapb         buf[i++] = (unsigned)tochar(crc & 077);
940a704a161Sapb #endif /* XAC */
941a704a161Sapb         break;
942a704a161Sapb     }
943a704a161Sapb #else
944a704a161Sapb     buf[i++] = tochar(chk1(&buf[lenpos],k));
945a704a161Sapb #endif /* F_CRC */
946a704a161Sapb 
947a704a161Sapb     buf[i++] = k->s_eom;		/* Packet terminator */
948a704a161Sapb     buf[i] = '\0';			/* String terminator */
949a704a161Sapb     k->s_seq = seq;                     /* Remember sequence number */
950a704a161Sapb 
951a704a161Sapb     k->opktlen = i;			/* Remember length for retransmit */
952a704a161Sapb 
953a704a161Sapb #ifdef DEBUG
954a704a161Sapb /* CORRUPT THE PACKET SENT BUT NOT THE ONE WE SAVE */
955a704a161Sapb     if (xerror()) {
956a704a161Sapb 	UCHAR p[P_PKTLEN+8];
957a704a161Sapb 	int i;
958a704a161Sapb 	for (i = 0; i < P_PKTLEN; i++)
959a704a161Sapb 	  if (!(p[i] = buf[i]))
960a704a161Sapb 	    break;
961a704a161Sapb 	p[i-2] = 'X';
962a704a161Sapb 	debug(DB_PKT,"XPKT",(char *)&p[1],0);
963a704a161Sapb 	return((*(k->txd))(k,p,k->opktlen)); /* Send it. */
964a704a161Sapb     }
965a704a161Sapb     debug(DB_PKT,"SPKT",(char *)&buf[1],0);
966a704a161Sapb #endif /* DEBUG */
967a704a161Sapb 
968a704a161Sapb     return((*(k->txd))(k,buf,k->opktlen)); /* Send it. */
969a704a161Sapb }
970a704a161Sapb 
971a704a161Sapb /*  N A K  --  Send a NAK (negative acknowledgement)  */
972a704a161Sapb 
973a704a161Sapb STATIC int
nak(struct k_data * k,short seq,short slot)974a704a161Sapb nak(struct k_data * k, short seq, short slot) {
975a704a161Sapb     int rc;
976a704a161Sapb     rc = spkt('N', seq, 0, (UCHAR *)0, k);
977a704a161Sapb     if (k->ipktinfo[slot].rtr++ > k->retry)
978a704a161Sapb       rc = X_ERROR;
979a704a161Sapb     return(rc);
980a704a161Sapb }
981a704a161Sapb 
982a704a161Sapb /*  A C K  --  Send an ACK (positive acknowledgement)  */
983a704a161Sapb 
984a704a161Sapb STATIC int
ack(struct k_data * k,short seq,UCHAR * text)985a704a161Sapb ack(struct k_data * k, short seq, UCHAR * text) {
986a704a161Sapb     int len, rc;
987a704a161Sapb     len = 0;
988a704a161Sapb     if (text) {                         /* Get length of data */
989a704a161Sapb         UCHAR *p;
990a704a161Sapb         p = text;
991a704a161Sapb         for ( ; *p++; len++) ;
992a704a161Sapb     }
993a704a161Sapb     rc = spkt('Y', seq, len, text, k);  /* Send the packet */
994a704a161Sapb     debug(DB_LOG,"ack spkt rc",0,rc);
995a704a161Sapb     if (rc == X_OK)                     /* If OK */
996a704a161Sapb       k->r_seq = (k->r_seq + 1) % 64;   /* bump the packet number */
997a704a161Sapb     return(rc);
998a704a161Sapb }
999a704a161Sapb 
1000a704a161Sapb /*  S P A R  --  Set parameters requested by other Kermit  */
1001a704a161Sapb 
1002a704a161Sapb STATIC void
spar(struct k_data * k,UCHAR * s,int datalen)1003a704a161Sapb spar(struct k_data * k, UCHAR *s, int datalen) {
1004a704a161Sapb     int x, y;
1005a704a161Sapb     UCHAR c;
1006a704a161Sapb 
1007a704a161Sapb     s--;                                /* Line up with field numbers. */
1008a704a161Sapb 
1009a704a161Sapb     if (datalen >= 1)                   /* Max packet length to send */
1010a704a161Sapb       k->s_maxlen = xunchar(s[1]);
1011a704a161Sapb 
1012a704a161Sapb     if (datalen >= 2)                   /* Timeout on inbound packets */
1013a704a161Sapb       k->r_timo = xunchar(s[2]);
1014a704a161Sapb 
1015a704a161Sapb     /* No padding */
1016a704a161Sapb 
1017a704a161Sapb     if (datalen >= 5)                   /* Outbound Packet Terminator */
1018a704a161Sapb       k->s_eom = xunchar(s[5]);
1019a704a161Sapb 
1020a704a161Sapb     if (datalen >= 6)                   /* Incoming control prefix */
1021a704a161Sapb       k->r_ctlq = s[6];
1022a704a161Sapb 
1023a704a161Sapb     if (datalen >= 7) {                 /* 8th bit prefix */
1024a704a161Sapb         k->ebq = s[7];
1025a704a161Sapb         if ((s[7] > 32 && s[7] < 63) || (s[7] > 95 && s[7] < 127)) {
1026a704a161Sapb 	    if (!k->parity)		/* They want it */
1027a704a161Sapb 	      k->parity = 1;		/* Set parity to something nonzero */
1028a704a161Sapb 	    k->ebqflg = 1;
1029a704a161Sapb 	} else if (s[7] == 'Y' && k->parity) {
1030a704a161Sapb 	    k->ebqflg = 1;
1031a704a161Sapb 	    k->ebq = '&';
1032a704a161Sapb 	} else if (s[7] == 'N') {
1033a704a161Sapb 	    /* WHAT? */
1034a704a161Sapb 	}
1035a704a161Sapb     }
1036a704a161Sapb     if (datalen >= 8) {                 /* Block check */
1037a704a161Sapb         k->bct = s[8] - '0';
1038a704a161Sapb #ifdef F_CRC
1039a704a161Sapb         if ((k->bct < 1) || (k->bct > 3))
1040a704a161Sapb #endif /* F_CRC */
1041a704a161Sapb 	  k->bct = 1;
1042a704a161Sapb 	if (k->bctf) k->bct = 3;
1043a704a161Sapb     }
1044a704a161Sapb     if (datalen >= 9) {                 /* Repeat counts */
1045a704a161Sapb         if ((s[9] > 32 && s[9] < 63) || (s[9] > 95 && s[9] < 127)) {
1046a704a161Sapb             k->rptq = s[9];
1047a704a161Sapb             k->rptflg = 1;
1048a704a161Sapb         }
1049a704a161Sapb     }
1050a704a161Sapb     if (datalen >= 10) {                /* Capability bits */
1051a704a161Sapb         x = xunchar(s[10]);
1052a704a161Sapb 
1053a704a161Sapb #ifdef F_LP                             /* Long packets */
1054a704a161Sapb         if (!(x & CAP_LP))
1055a704a161Sapb #endif /* F_LP */
1056a704a161Sapb           k->capas &= ~CAP_LP;
1057a704a161Sapb 
1058a704a161Sapb #ifdef F_SW                             /* Sliding Windows */
1059a704a161Sapb         if (!(x & CAP_SW))
1060a704a161Sapb #endif /* F_SW */
1061a704a161Sapb           k->capas &= ~CAP_SW;
1062a704a161Sapb 
1063a704a161Sapb #ifdef F_AT                             /* Attributes */
1064a704a161Sapb         if (!(x & CAP_AT))
1065a704a161Sapb #endif /* F_AT */
1066a704a161Sapb           k->capas &= ~CAP_AT;
1067a704a161Sapb 
1068a704a161Sapb #ifdef F_RS                             /* Recovery */
1069a704a161Sapb         if (!(x & CAP_RS))
1070a704a161Sapb #endif /* F_RS */
1071a704a161Sapb           k->capas &= ~CAP_RS;
1072a704a161Sapb 
1073a704a161Sapb #ifdef F_LS                             /* Locking shifts */
1074a704a161Sapb         if (!(x & CAP_LS))
1075a704a161Sapb #endif /* F_LS */
1076a704a161Sapb           k->capas &= ~CAP_LS;
1077a704a161Sapb 
1078a704a161Sapb         /* In case other Kermit sends addt'l capas fields ... */
1079a704a161Sapb 
1080a704a161Sapb         for (y = 10; (xunchar(s[y]) & 1) && (datalen >= y); y++) ;
1081a704a161Sapb     }
1082a704a161Sapb 
1083a704a161Sapb #ifdef F_LP                             /* Long Packets */
1084a704a161Sapb     if (k->capas & CAP_LP) {
1085a704a161Sapb         if (datalen > y+1) {
1086a704a161Sapb             x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
1087a704a161Sapb             k->s_maxlen = (x > P_PKTLEN) ? P_PKTLEN : x;
1088a704a161Sapb             if (k->s_maxlen < 10)
1089a704a161Sapb               k->s_maxlen = 60;
1090a704a161Sapb         }
1091a704a161Sapb     }
1092a704a161Sapb #endif /* F_LP */
1093a704a161Sapb 
1094a704a161Sapb     debug(DB_LOG,"S_MAXLEN",0,k->s_maxlen);
1095a704a161Sapb 
1096a704a161Sapb #ifdef F_SW
1097a704a161Sapb     if (k->capas & CAP_SW) {
1098a704a161Sapb         if (datalen > y) {
1099a704a161Sapb             x = xunchar(s[y+1]);
1100a704a161Sapb             k->window = (x > P_WSLOTS) ? P_WSLOTS : x;
1101a704a161Sapb             if (k->window < 1)          /* Watch out for bad negotiation */
1102a704a161Sapb               k->window = 1;
1103a704a161Sapb             if (k->window > 1)
1104a704a161Sapb               if (k->window > k->retry)   /* Retry limit must be greater */
1105a704a161Sapb                 k->retry = k->window + 1; /* than window size. */
1106a704a161Sapb         }
1107a704a161Sapb     }
1108a704a161Sapb #endif /* F_SW */
1109a704a161Sapb }
1110a704a161Sapb 
1111a704a161Sapb /*  R P A R  --  Send my parameters to other Kermit  */
1112a704a161Sapb 
1113a704a161Sapb STATIC int
rpar(struct k_data * k,char type)1114a704a161Sapb rpar(struct k_data * k, char type) {
1115a704a161Sapb     UCHAR *d;
1116a704a161Sapb     int rc, len;
1117a704a161Sapb #ifdef F_CRC
1118a704a161Sapb     short b;
1119a704a161Sapb #endif /* F_CRC */
1120a704a161Sapb 
1121a704a161Sapb     d = k->ack_s;                       /* Where to put it */
1122a704a161Sapb     d[ 0] = tochar(94);                 /* Maximum short-packet length */
1123a704a161Sapb     d[ 1] = tochar(k->s_timo);          /* When I want to be timed out */
1124a704a161Sapb     d[ 2] = tochar(0);                  /* How much padding I need */
1125a704a161Sapb     d[ 3] = ctl(0);                     /* Padding character I want */
1126a704a161Sapb     d[ 4] = tochar(k->r_eom);           /* End-of message character I want */
1127a704a161Sapb     d[ 5] = k->s_ctlq;                  /* Control prefix I send */
1128a704a161Sapb     if ((k->ebq == 'Y') && (k->parity)) /* 8th-bit prefix */
1129a704a161Sapb       d[ 6] = k->ebq = '&';           /* I need to request it */
1130a704a161Sapb     else                                /* else just agree with other Kermit */
1131a704a161Sapb       d[ 6] = k->ebq;
1132a704a161Sapb     if (k->bctf)			/* Block check type */
1133a704a161Sapb       d[7] = '5';			/* FORCE 3 */
1134a704a161Sapb     else
1135a704a161Sapb       d[7] = k->bct + '0';		/* Normal */
1136a704a161Sapb     d[ 8] = k->rptq;			/* Repeat prefix */
1137a704a161Sapb     d[ 9] = tochar(k->capas);           /* Capability bits */
1138a704a161Sapb     d[10] = tochar(k->window);          /* Window size */
1139a704a161Sapb 
1140a704a161Sapb #ifdef F_LP
1141a704a161Sapb     d[11] = tochar(k->r_maxlen / 95);   /* Long packet size, big part */
1142a704a161Sapb     d[12] = tochar(k->r_maxlen % 95);   /* Long packet size, little part */
1143a704a161Sapb     d[13] = '\0';			/* Terminate the init string */
1144a704a161Sapb     len = 13;
1145a704a161Sapb #else
1146a704a161Sapb     d[11] = '\0';
1147a704a161Sapb     len = 11;
1148a704a161Sapb #endif /* F_LP */
1149a704a161Sapb 
1150a704a161Sapb #ifdef F_CRC
1151a704a161Sapb     if (!(k->bctf)) {			/* Unless FORCE 3 */
1152a704a161Sapb 	b = k->bct;
1153a704a161Sapb 	k->bct = 1;			/* Always use block check type 1 */
1154a704a161Sapb     }
1155a704a161Sapb #endif /* F_CRC */
1156a704a161Sapb     switch (type) {
1157a704a161Sapb       case 'Y':				/* This is an ACK for packet 0 */
1158a704a161Sapb 	rc = ack(k,0,d);
1159a704a161Sapb 	break;
1160a704a161Sapb       case 'S':				/* It's an S packet */
1161a704a161Sapb 	rc = spkt('S', 0, len, d, k);
1162a704a161Sapb 	break;
1163a704a161Sapb       default:
1164a704a161Sapb 	rc = -1;
1165a704a161Sapb     }
1166a704a161Sapb #ifdef F_CRC
1167a704a161Sapb     if (!(k->bctf)) {			/* Unless FORCE 3 */
1168a704a161Sapb 	k->bct = b;
1169a704a161Sapb     }
1170a704a161Sapb #endif /* F_CRC */
1171a704a161Sapb     return(rc);                         /* Pass along return code. */
1172a704a161Sapb }
1173a704a161Sapb 
1174a704a161Sapb /*  D E C O D E  --  Decode data field of Kermit packet - binary mode only */
1175a704a161Sapb /*
1176a704a161Sapb   Call with:
1177a704a161Sapb     k = kermit data structure
1178a704a161Sapb     r = kermit response structure
1179a704a161Sapb     f = function code
1180a704a161Sapb       0 = decode filename
1181a704a161Sapb       1 = decode file data
1182a704a161Sapb     inbuf = pointer to packet data to be decoded
1183a704a161Sapb   Returns:
1184a704a161Sapb     X_OK on success
1185a704a161Sapb     X_ERROR if output function fails
1186a704a161Sapb */
1187a704a161Sapb STATIC int
decode(struct k_data * k,struct k_response * r,short f,UCHAR * inbuf)1188a704a161Sapb decode(struct k_data * k, struct k_response * r, short f, UCHAR *inbuf) {
1189a704a161Sapb 
1190a704a161Sapb     register unsigned int a, a7;        /* Current character */
1191a704a161Sapb     unsigned int b8;                    /* 8th bit */
1192a704a161Sapb     int rpt;                            /* Repeat count */
1193a704a161Sapb     int rc;				/* Return code */
1194a704a161Sapb     UCHAR *p;
1195a704a161Sapb 
1196a704a161Sapb     rc = X_OK;
1197a704a161Sapb     rpt = 0;                            /* Initialize repeat count. */
1198a704a161Sapb     if (f == 0)                         /* Output function... */
1199a704a161Sapb       p = r->filename;
1200a704a161Sapb 
1201a704a161Sapb     while ((a = *inbuf++ & 0xFF) != '\0') { /* Character loop */
1202a704a161Sapb         if (k->rptflg && a == k->rptq) { /* Got a repeat prefix? */
1203a704a161Sapb             rpt = xunchar(*inbuf++ & 0xFF); /* Yes, get the repeat count, */
1204a704a161Sapb             a = *inbuf++ & 0xFF;        /* and get the prefixed character. */
1205a704a161Sapb         }
1206a704a161Sapb         b8 = 0;                         /* 8th-bit value */
1207a704a161Sapb         if (k->parity && (a == k->ebq)) { /* Have 8th-bit prefix? */
1208a704a161Sapb             b8 = 0200;                  /* Yes, flag the 8th bit */
1209a704a161Sapb             a = *inbuf++ & 0x7F;        /* and get the prefixed character. */
1210a704a161Sapb         }
1211a704a161Sapb         if (a == k->r_ctlq) {           /* If control prefix, */
1212a704a161Sapb             a  = *inbuf++ & 0xFF;       /* get its operand */
1213a704a161Sapb             a7 = a & 0x7F;              /* and its low 7 bits. */
1214a704a161Sapb             if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Controllify */
1215a704a161Sapb               a = ctl(a);               /* if in control range. */
1216a704a161Sapb         }
1217a704a161Sapb         a |= b8;                        /* OR in the 8th bit */
1218a704a161Sapb 
1219a704a161Sapb         if (rpt == 0) rpt = 1;          /* If no repeats, then one */
1220a704a161Sapb 
1221a704a161Sapb         for (; rpt > 0; rpt--) {        /* Output the char 'rpt' times */
1222a704a161Sapb             if (f == 0) {
1223a704a161Sapb                 *p++ = (UCHAR) a;       /* to memory */
1224a704a161Sapb             } else {                    /* or to file */
1225a704a161Sapb                 k->obuf[k->obufpos++] = (UCHAR) a; /* Deposit the byte */
1226a704a161Sapb                 if (k->obufpos == k->obuflen) { /* Buffer full? */
1227a704a161Sapb                     rc = (*(k->writef))(k,k->obuf,k->obuflen); /* Dump it. */
1228a704a161Sapb 		    r->sofar += k->obuflen;
1229a704a161Sapb 		    if (rc != X_OK) break;
1230a704a161Sapb                     k->obufpos = 0;
1231a704a161Sapb                 }
1232a704a161Sapb             }
1233a704a161Sapb         }
1234a704a161Sapb     }
1235a704a161Sapb     if (f == 0)                         /* If writing to memory */
1236a704a161Sapb       *p = '\0';			/* terminate the string */
1237a704a161Sapb     return(rc);
1238a704a161Sapb }
1239a704a161Sapb 
1240a704a161Sapb STATIC ULONG				/* Convert decimal string to number  */
stringnum(UCHAR * s,struct k_data * k)1241a704a161Sapb stringnum(UCHAR *s, struct k_data * k) {
1242a704a161Sapb     long n;
1243a704a161Sapb     n = 0L;
1244a704a161Sapb     while (*s == SP)
1245a704a161Sapb       s++;
1246a704a161Sapb     while(*s >= '0' && *s <= '9')
1247a704a161Sapb       n = n * 10 + (*s++ - '0');
1248a704a161Sapb     return(n);
1249a704a161Sapb }
1250a704a161Sapb 
1251a704a161Sapb STATIC UCHAR *				/* Convert number to string */
numstring(ULONG n,UCHAR * buf,int buflen,struct k_data * k)1252a704a161Sapb numstring(ULONG n, UCHAR * buf, int buflen, struct k_data * k) {
1253a704a161Sapb     int i, x;
1254a704a161Sapb     buf[buflen - 1] = '\0';
1255a704a161Sapb     for (i = buflen - 2; i > 0; i--) {
1256a704a161Sapb 	x = n % 10L;
1257a704a161Sapb 	buf[i] = x + '0';
1258a704a161Sapb 	n /= 10L;
1259a704a161Sapb 	if (!n)
1260a704a161Sapb 	  break;
1261a704a161Sapb     }
1262a704a161Sapb     if (n) {
1263a704a161Sapb 	return((UCHAR *)0);
1264a704a161Sapb     }
1265a704a161Sapb     if (i > 0) {
1266a704a161Sapb 	UCHAR * p, * s;
1267a704a161Sapb 	s = &buf[i];
1268a704a161Sapb 	p = buf;
1269a704a161Sapb 	while ((*p++ = *s++)) ;
1270a704a161Sapb 	*(p-1) = '\0';
1271a704a161Sapb     }
1272a704a161Sapb     return((UCHAR *)buf);
1273a704a161Sapb }
1274a704a161Sapb 
1275a704a161Sapb #ifdef F_AT
1276a704a161Sapb 
1277a704a161Sapb /*
1278a704a161Sapb   G A T T R  --  Read incoming attributes.
1279a704a161Sapb 
1280a704a161Sapb   Returns:
1281a704a161Sapb    -1 if no transfer mode (text/binary) was announced.
1282a704a161Sapb     0 if text was announced.
1283a704a161Sapb     1 if binary was announced.
1284a704a161Sapb */
1285a704a161Sapb 
1286a704a161Sapb #define SIZEBUFL 32                     /* For number conversions */
1287a704a161Sapb 
1288a704a161Sapb STATIC int
gattr(struct k_data * k,UCHAR * s,struct k_response * r)1289a704a161Sapb gattr(struct k_data * k, UCHAR * s, struct k_response * r) {
1290a704a161Sapb     long fsize, fsizek;                 /* File size */
1291a704a161Sapb     UCHAR c;                            /* Workers */
1292a704a161Sapb     int aln, i, rc;
1293a704a161Sapb 
1294*250ad67dSmrg     UCHAR sizebuf[SIZEBUFL+1];
1295a704a161Sapb 
1296a704a161Sapb     rc = -1;
1297a704a161Sapb     while ((c = *s++)) {		/* Get attribute tag */
1298a704a161Sapb         aln = xunchar(*s++);            /* Length of attribute string */
1299a704a161Sapb         switch (c) {
1300a704a161Sapb           case '!':                     /* File length in K */
1301a704a161Sapb 	  case '"':			/* File type */
1302a704a161Sapb             for (i = 0; (i < aln) && (i < SIZEBUFL); i++) /* Copy it */
1303a704a161Sapb               sizebuf[i] = *s++;
1304a704a161Sapb             sizebuf[i] = '\0';           /* Terminate with null */
1305a704a161Sapb             if (i < aln) s += (aln - i); /* If field was too long for buffer */
1306a704a161Sapb 	    if (c == '!') {		     /* Length */
1307a704a161Sapb 		fsizek = stringnum(sizebuf,k); /* Convert to number */
1308a704a161Sapb 	    } else {			     /* Type */
1309a704a161Sapb 		if (sizebuf[0] == 'A')	     /* Text */
1310a704a161Sapb 		  rc = 0;
1311a704a161Sapb 		else if (sizebuf[0] == 'B')  /* Binary */
1312a704a161Sapb 		  rc = 1;
1313a704a161Sapb 		debug(DB_LOG,"gattr rc",0,rc);
1314a704a161Sapb 		debug(DB_LOG,"gattr size",sizebuf,0);
1315a704a161Sapb 	    }
1316a704a161Sapb             break;
1317a704a161Sapb 
1318a704a161Sapb           case '#':                     /* File creation date */
1319a704a161Sapb             for (i = 0; (i < aln) && (i < DATE_MAX); i++)
1320a704a161Sapb               r->filedate[i] = *s++;    /* Copy it into a static string */
1321a704a161Sapb             if (i < aln) s += (aln - i);
1322a704a161Sapb             r->filedate[i] = '\0';
1323a704a161Sapb             break;
1324a704a161Sapb 
1325a704a161Sapb           case '1':                     /* File length in bytes */
1326a704a161Sapb             for (i = 0; (i < aln) && (i < SIZEBUFL); i++) /* Copy it */
1327a704a161Sapb               sizebuf[i] = *s++;
1328a704a161Sapb             sizebuf[i] = '\0';           /* Terminate with null */
1329a704a161Sapb             if (i < aln) s += (aln - i);
1330a704a161Sapb             fsize = stringnum(sizebuf,k); /* Convert to number */
1331a704a161Sapb             break;
1332a704a161Sapb 
1333a704a161Sapb 	  default:			/* Unknown attribute */
1334a704a161Sapb 	    s += aln;			/* Just skip past it */
1335a704a161Sapb 	    break;
1336a704a161Sapb         }
1337a704a161Sapb     }
1338a704a161Sapb     if (fsize > -1L) {			/* Remember the file size */
1339a704a161Sapb         r->filesize = fsize;
1340a704a161Sapb     } else if (fsizek > -1L) {
1341a704a161Sapb         r->filesize = fsizek * 1024L;
1342a704a161Sapb     }
1343a704a161Sapb     debug(DB_LOG,"gattr r->filesize",0,(r->filesize));
1344a704a161Sapb     debug(DB_LOG,"gattr r->filedate=",r->filedate,0);
1345a704a161Sapb     return(rc);
1346a704a161Sapb }
1347a704a161Sapb 
1348a704a161Sapb #define ATTRLEN 48
1349a704a161Sapb 
1350a704a161Sapb STATIC int
sattr(struct k_data * k,struct k_response * r)1351a704a161Sapb sattr(struct k_data *k, struct k_response *r) {	/* Build and send A packet */
1352a704a161Sapb     int i, x, aln;
1353a704a161Sapb     short tmp;
1354a704a161Sapb     long filelength;
1355a704a161Sapb     UCHAR datebuf[DATE_MAX], * p;
1356a704a161Sapb 
1357a704a161Sapb     debug(DB_LOG,"sattr k->zincnt 0",0,(k->zincnt));
1358a704a161Sapb 
1359a704a161Sapb     tmp = k->binary;
1360a704a161Sapb     filelength = (*(k->finfo))
1361a704a161Sapb 	(k,k->filename,datebuf,DATE_MAX,&tmp,k->xfermode);
1362a704a161Sapb     k->binary = tmp;
1363a704a161Sapb 
1364a704a161Sapb     debug(DB_LOG,"sattr filename: ",k->filename,0);
1365a704a161Sapb     debug(DB_LOG,"sattr filedate: ",datebuf,0);
1366a704a161Sapb     debug(DB_LOG,"sattr filelength",0,filelength);
1367a704a161Sapb     debug(DB_LOG,"sattr binary",0,(k->binary));
1368a704a161Sapb 
1369a704a161Sapb     i = 0;
1370a704a161Sapb 
1371a704a161Sapb     k->xdata[i++] = '"';
1372a704a161Sapb     if (k->binary) {			/* Binary */
1373a704a161Sapb 	k->xdata[i++] = tochar(2);	/*  Two characters */
1374a704a161Sapb 	k->xdata[i++] = 'B';		/*  B for Binary */
1375a704a161Sapb 	k->xdata[i++] = '8';		/*  8-bit bytes (note assumption...) */
1376a704a161Sapb     } else {				/* Text */
1377a704a161Sapb 	k->xdata[i++] = tochar(3);	/*  Three characters */
1378a704a161Sapb 	k->xdata[i++] = 'A';		/*  A = (extended) ASCII with CRLFs */
1379a704a161Sapb 	k->xdata[i++] = 'M';		/*  M for carriage return */
1380a704a161Sapb 	k->xdata[i++] = 'J';		/*  J for linefeed */
1381a704a161Sapb 	k->xdata[i++] = '*';		/* Encoding */
1382a704a161Sapb 	k->xdata[i++] = tochar(1);	/* Length of value is 1 */
1383a704a161Sapb 	k->xdata[i++] = 'A';		/* A for ASCII */
1384a704a161Sapb     }
1385a704a161Sapb     if (filelength > -1L) {		/* File length in bytes */
1386a704a161Sapb 	UCHAR lenbuf[16];
1387a704a161Sapb 	r->filesize = filelength;
1388a704a161Sapb 	p = numstring(filelength,lenbuf,16,k);
1389a704a161Sapb 	if (p) {
1390a704a161Sapb 	    for (x = 0; p[x]; x++) ;	/* Get length of length string */
1391a704a161Sapb 	    if (i + x < ATTRLEN - 3) {	/* Don't overflow buffer */
1392a704a161Sapb 		k->xdata[i++] = '1';	/* Length-in-Bytes attribute */
1393a704a161Sapb 		k->xdata[i++] = tochar(x);
1394a704a161Sapb 		while (*p)
1395a704a161Sapb 		  k->xdata[i++] = *p++;
1396a704a161Sapb 	    }
1397a704a161Sapb 	}
1398a704a161Sapb     }
1399a704a161Sapb     debug(DB_LOG,"sattr DATEBUF: ",datebuf,0);
1400a704a161Sapb 
1401a704a161Sapb     if (datebuf[0]) {			/* File modtime */
1402a704a161Sapb 	p = datebuf;
1403a704a161Sapb 	for (x = 0; p[x]; x++) ;	/* Length of modtime */
1404a704a161Sapb 	if (i + x < ATTRLEN - 3) {	/* If it will fit */
1405a704a161Sapb 	    k->xdata[i++] = '#';	/* Add modtime attribute */
1406a704a161Sapb 	    k->xdata[i++] = tochar(x);	/* Its length */
1407a704a161Sapb 	    while (*p)			/* And itself */
1408a704a161Sapb 	      k->xdata[i++] = *p++;
1409a704a161Sapb 	    /* Also copy modtime to result struct */
1410a704a161Sapb 	    for (x = 0; x < DATE_MAX-1 && datebuf[x]; x++)
1411a704a161Sapb 	      r->filedate[x] = datebuf[x];
1412a704a161Sapb 	    r->filedate[x] = '\0';
1413a704a161Sapb 	}
1414a704a161Sapb     }
1415a704a161Sapb     k->xdata[i++] = '@';		/* End of Attributes */
1416a704a161Sapb     k->xdata[i++] = ' ';
1417a704a161Sapb     k->xdata[i] = '\0';			/* Terminate attribute string */
1418a704a161Sapb     debug(DB_LOG,"sattr k->xdata: ",k->xdata,0);
1419a704a161Sapb     return(spkt('A',k->s_seq,-1,k->xdata,k));
1420a704a161Sapb }
1421a704a161Sapb #endif /* F_AT */
1422a704a161Sapb 
1423a704a161Sapb STATIC int
getpkt(struct k_data * k,struct k_response * r)1424a704a161Sapb getpkt(struct k_data *k, struct k_response *r) { /* Fill a packet from file */
1425a704a161Sapb     int i, next, rpt, maxlen;
1426a704a161Sapb     static int c;			/* PUT THIS IN STRUCT */
1427a704a161Sapb 
1428a704a161Sapb     debug(DB_LOG,"getpkt k->s_first",0,(k->s_first));
1429a704a161Sapb     debug(DB_LOG,"getpkt k->s_remain=",k->s_remain,0);
1430a704a161Sapb 
1431a704a161Sapb     maxlen = k->s_maxlen - k->bct - 3;	/* Maximum data length */
1432a704a161Sapb     if (k->s_first == 1) {		/* If first time thru...  */
1433a704a161Sapb 	k->s_first = 0;			/* don't do this next time, */
1434a704a161Sapb 	k->s_remain[0] = '\0';		/* discard any old leftovers. */
1435a704a161Sapb 	if (k->istring) {		/* Get first byte. */
1436a704a161Sapb 	    c = *(k->istring)++;	/* Of memory string... */
1437a704a161Sapb 	    if (!c) c = -1;
1438a704a161Sapb 	} else {			/* or file... */
1439a704a161Sapb #ifdef DEBUG
1440a704a161Sapb 	    k->zincnt = -1234;
1441a704a161Sapb 	    k->dummy = 0;
1442a704a161Sapb #endif /* DEBUG */
1443a704a161Sapb 	    c = zgetc();
1444a704a161Sapb 
1445a704a161Sapb #ifdef DEBUG
1446a704a161Sapb 	    if (k->dummy) debug(DB_LOG,"DUMMY CLOBBERED (A)",0,0);
1447a704a161Sapb #endif /* DEBUG */
1448a704a161Sapb 	}
1449a704a161Sapb 	if (c < 0) {			/* Watch out for empty file. */
1450a704a161Sapb 	    debug(DB_CHR,"getpkt first c",0,c);
1451a704a161Sapb 	    k->s_first = -1;
1452a704a161Sapb 	    return(k->size = 0);
1453a704a161Sapb 	}
1454a704a161Sapb 	r->sofar++;
1455a704a161Sapb 	debug(DB_LOG,"getpkt first c",0,c);
1456a704a161Sapb     } else if (k->s_first == -1 && !k->s_remain[0]) { /* EOF from last time? */
1457a704a161Sapb         return(k->size = 0);
1458a704a161Sapb     }
1459a704a161Sapb     for (k->size = 0;
1460a704a161Sapb 	 (k->xdata[k->size] = k->s_remain[k->size]) != '\0';
1461a704a161Sapb 	 (k->size)++)
1462a704a161Sapb       ;
1463a704a161Sapb     k->s_remain[0] = '\0';
1464a704a161Sapb     if (k->s_first == -1)
1465a704a161Sapb       return(k->size);
1466a704a161Sapb 
1467a704a161Sapb     rpt = 0;				/* Initialize repeat counter. */
1468a704a161Sapb     while (k->s_first > -1) {		/* Until end of file or string... */
1469a704a161Sapb 	if (k->istring) {
1470a704a161Sapb 	    next = *(k->istring)++;
1471a704a161Sapb 	    if (!next) next = -1;
1472a704a161Sapb 	} else {
1473a704a161Sapb #ifdef DEBUG
1474a704a161Sapb 	    k->dummy = 0;
1475a704a161Sapb #endif /* DEBUG */
1476a704a161Sapb 	    next = zgetc();
1477a704a161Sapb #ifdef DEBUG
1478a704a161Sapb 	    if (k->dummy) debug(DB_LOG,"DUMMY CLOBBERED B",0,k->dummy);
1479a704a161Sapb #endif /* DEBUG */
1480a704a161Sapb 	}
1481a704a161Sapb 	if (next < 0) {			/* If none, we're at EOF. */
1482a704a161Sapb 	    k->s_first = -1;
1483a704a161Sapb 	} else {			/* Otherwise */
1484a704a161Sapb 	    r->sofar++;			/* count this byte */
1485a704a161Sapb 	}
1486a704a161Sapb         k->osize = k->size;		/* Remember current size. */
1487a704a161Sapb         encode(c,next,k);		/* Encode the character. */
1488a704a161Sapb 	/* k->xdata[k->size] = '\0'; */
1489a704a161Sapb 	c = next;			/* Old next char is now current. */
1490a704a161Sapb 
1491a704a161Sapb         if (k->size == maxlen)		/* Just at end, done. */
1492a704a161Sapb 	  return(k->size);
1493a704a161Sapb 
1494a704a161Sapb         if (k->size > maxlen) {		/* Past end, must save some. */
1495a704a161Sapb             for (i = 0;
1496a704a161Sapb 		 (k->s_remain[i] = k->xdata[(k->osize)+i]) != '\0';
1497a704a161Sapb 		 i++)
1498a704a161Sapb 	      ;
1499a704a161Sapb             k->size = k->osize;
1500a704a161Sapb             k->xdata[k->size] = '\0';
1501a704a161Sapb             return(k->size);		/* Return size. */
1502a704a161Sapb         }
1503a704a161Sapb     }
1504a704a161Sapb     return(k->size);			/* EOF, return size. */
1505a704a161Sapb }
1506a704a161Sapb 
1507a704a161Sapb #ifndef RECVONLY
1508a704a161Sapb STATIC int
sdata(struct k_data * k,struct k_response * r)1509a704a161Sapb sdata(struct k_data *k,struct k_response *r) { /* Send a data packet */
1510a704a161Sapb     int len, rc;
1511a704a161Sapb     if (k->cancel) {			/* Interrupted */
1512a704a161Sapb 	debug(DB_LOG,"sdata interrupted k->cancel",0,(k->cancel));
1513a704a161Sapb 	return(0);
1514a704a161Sapb     }
1515a704a161Sapb     len = getpkt(k,r);			/* Fill data field from input file */
1516a704a161Sapb     debug(DB_LOG,"sdata getpkt",0,len);
1517a704a161Sapb     if (len < 1)
1518a704a161Sapb       return(0);
1519a704a161Sapb     rc = spkt('D',k->s_seq,len,k->xdata,k); /* Send the packet */
1520a704a161Sapb     debug(DB_LOG,"sdata spkt",0,rc);
1521a704a161Sapb     return((rc == X_ERROR) ? rc : len);
1522a704a161Sapb }
1523a704a161Sapb #endif /* RECVONLY */
1524a704a161Sapb 
1525a704a161Sapb /*  E P K T  --  Send a (fatal) Error packet with the given message  */
1526a704a161Sapb 
1527a704a161Sapb STATIC void
epkt(char * msg,struct k_data * k)1528a704a161Sapb epkt(char * msg, struct k_data * k) {
1529a704a161Sapb     if (!(k->bctf)) {			/* Unless FORCE 3 */
1530a704a161Sapb 	k->bct = 1;
1531a704a161Sapb     }
1532a704a161Sapb     (void) spkt('E', 0, -1, (UCHAR *) msg, k);
1533a704a161Sapb }
1534a704a161Sapb 
1535a704a161Sapb STATIC int				/* Fill a packet from string s. */
encstr(UCHAR * s,struct k_data * k,struct k_response * r)1536a704a161Sapb encstr(UCHAR * s, struct k_data * k, struct k_response *r) {
1537a704a161Sapb     k->s_first = 1;			/* Start lookahead. */
1538a704a161Sapb     k->istring = s;			/* Set input string pointer */
1539a704a161Sapb     getpkt(k,r);			/* Fill a packet */
1540a704a161Sapb     k->istring = (UCHAR *)0;		/* Reset input string pointer */
1541a704a161Sapb     k->s_first = 1;			/* "Rewind" */
1542a704a161Sapb     return(k->size);			/* Return data field length */
1543a704a161Sapb }
1544a704a161Sapb 
1545a704a161Sapb /* Decode packet data into a string */
1546a704a161Sapb 
1547a704a161Sapb STATIC void
decstr(UCHAR * s,struct k_data * k,struct k_response * r)1548a704a161Sapb decstr(UCHAR * s, struct k_data * k, struct k_response * r) {
1549a704a161Sapb     k->ostring = s;			/* Set output string pointer  */
1550a704a161Sapb     (void) decode(k, r, 0, s);
1551a704a161Sapb     *(k->ostring) = '\0';		/* Terminate with null */
1552a704a161Sapb     k->ostring = (UCHAR *)0;		/* Reset output string pointer */
1553a704a161Sapb }
1554a704a161Sapb 
1555a704a161Sapb STATIC void
encode(int a,int next,struct k_data * k)1556a704a161Sapb encode(int a, int next, struct k_data * k) { /* Encode character into packet */
1557a704a161Sapb     int a7, b8, maxlen;
1558a704a161Sapb 
1559a704a161Sapb     maxlen = k->s_maxlen - 4;
1560a704a161Sapb     if (k->rptflg) {			/* Doing run-length encoding? */
1561a704a161Sapb 	if (a == next) {		/* Yes, got a run? */
1562a704a161Sapb 	    if (++(k->s_rpt) < 94) {	/* Yes, count. */
1563a704a161Sapb 		return;
1564a704a161Sapb 	    } else if (k->s_rpt == 94) { /* If at maximum */
1565a704a161Sapb 	    	k->xdata[(k->size)++] = k->rptq; /* Emit prefix, */
1566a704a161Sapb 		k->xdata[(k->size)++] = tochar(k->s_rpt); /* and count, */
1567a704a161Sapb 		k->s_rpt = 0;		/* and reset counter. */
1568a704a161Sapb 	    }
1569a704a161Sapb 	} else if (k->s_rpt == 1) {	/* Run broken, only two? */
1570a704a161Sapb 	    k->s_rpt = 0;		/* Yes, do the character twice */
1571a704a161Sapb 	    encode(a,-1,k);		/* by calling self recursively. */
1572a704a161Sapb 	    if (k->size <= maxlen)	/* Watch boundary. */
1573a704a161Sapb 	      k->osize = k->size;
1574a704a161Sapb 	    k->s_rpt = 0;		/* Call self second time. */
1575a704a161Sapb 	    encode(a,-1,k);
1576a704a161Sapb 	    return;
1577a704a161Sapb 	} else if (k->s_rpt > 1) {	/* Run broken, more than two? */
1578a704a161Sapb 	    k->xdata[(k->size)++] = k->rptq; /* Yes, emit prefix and count */
1579a704a161Sapb 	    k->xdata[(k->size)++] = tochar(++(k->s_rpt));
1580a704a161Sapb 	    k->s_rpt = 0;		/* and reset counter. */
1581a704a161Sapb 	}
1582a704a161Sapb     }
1583a704a161Sapb     a7 = a & 127;			/* Get low 7 bits of character */
1584a704a161Sapb     b8 = a & 128;			/* And "parity" bit */
1585a704a161Sapb 
1586a704a161Sapb     if (k->ebqflg && b8) {		/* If doing 8th bit prefixing */
1587a704a161Sapb 	k->xdata[(k->size)++] = k->ebq; /* and 8th bit on, insert prefix */
1588a704a161Sapb 	a = a7;				/* and clear the 8th bit. */
1589a704a161Sapb     }
1590a704a161Sapb     if (a7 < 32 || a7 == 127) {		   /* If in control range */
1591a704a161Sapb         k->xdata[(k->size)++] = k->s_ctlq; /* insert control prefix */
1592a704a161Sapb         a = ctl(a);			 /* and make character printable. */
1593a704a161Sapb     } else if (a7 == k->s_ctlq)		 /* If data is control prefix, */
1594a704a161Sapb       k->xdata[(k->size)++] = k->s_ctlq; /* prefix it. */
1595a704a161Sapb     else if (k->ebqflg && a7 == k->ebq)  /* If doing 8th-bit prefixing, */
1596a704a161Sapb       k->xdata[(k->size)++] = k->s_ctlq; /* ditto for 8th-bit prefix. */
1597a704a161Sapb     else if (k->rptflg && a7 == k->rptq) /* If doing run-length encoding, */
1598a704a161Sapb       k->xdata[(k->size)++] = k->s_ctlq; /* ditto for repeat prefix. */
1599a704a161Sapb 
1600a704a161Sapb     k->xdata[(k->size)++] = a;		/* Finally, emit the character. */
1601a704a161Sapb     k->xdata[(k->size)] = '\0';		/* Terminate string with null. */
1602a704a161Sapb }
1603a704a161Sapb 
1604a704a161Sapb STATIC int
nxtpkt(struct k_data * k)1605a704a161Sapb nxtpkt(struct k_data * k) {		/* Get next packet to send */
1606a704a161Sapb     k->s_seq = (k->s_seq + 1) & 63;	/* Next sequence number */
1607a704a161Sapb     k->xdata = k->xdatabuf;
1608a704a161Sapb     return(0);
1609a704a161Sapb }
1610a704a161Sapb 
1611a704a161Sapb STATIC int
resend(struct k_data * k)1612a704a161Sapb resend(struct k_data * k) {
1613a704a161Sapb     UCHAR * buf;
1614a704a161Sapb     if (!k->opktlen)			/* Nothing to resend */
1615a704a161Sapb       return(X_OK);
1616a704a161Sapb     buf = k->opktbuf;
1617a704a161Sapb     debug(DB_PKT,">PKT",&buf[1],k->opktlen);
1618a704a161Sapb     return((*(k->txd))(k,buf,k->opktlen));
1619a704a161Sapb }
1620