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