source: trunk/third/kermit/ckcfns.c @ 10780

Revision 10780, 102.2 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10779, which included commits to RCS files with non-trunk default branches.
Line 
1char *fnsv = "C-Kermit functions, 6.0.133, 6 Sep 96";
2
3/*  C K C F N S  --  System-independent Kermit protocol support functions.  */
4
5/*  ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */
6
7/*
8  Author: Frank da Cruz <fdc@columbia.edu>,
9  Columbia University Academic Information Systems, New York City.
10
11  Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
12  York.  The C-Kermit software may not be, in whole or in part, licensed or
13  sold for profit as a software product itself, nor may it be included in or
14  distributed with commercial products or otherwise distributed by commercial
15  concerns to their clients or customers without written permission of the
16  Office of Kermit Development and Distribution, Columbia University.  This
17  copyright notice must not be removed, altered, or obscured.
18*/
19/*
20 System-dependent primitives defined in:
21
22   ck?tio.c -- terminal i/o
23   cx?fio.c -- file i/o, directory structure
24*/
25#include "ckcsym.h"                     /* Needed for Stratus VOS */
26#include "ckcasc.h"                     /* ASCII symbols */
27#include "ckcdeb.h"                     /* Debug formats, typedefs, etc. */
28#include "ckcker.h"                     /* Symbol definitions for Kermit */
29#include "ckcxla.h"                     /* Character set symbols */
30
31#ifdef OS2
32#include <io.h>
33#endif /* OS2 */
34
35#ifdef VMS
36#include <errno.h>
37#endif /* VMS */
38
39/* Externals from ckcmai.c */
40extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
41 rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
42extern int pktnum, bctr, bctu, bctl, fmask, clfils, sbufnum, protocol,
43 size, osize, spktl, nfils, warn, timef, spsizf, sndtyp, rcvtyp, success;
44extern int parity, turn, network, what, whatru, fsecs, justone, slostart,
45 delay, displa, xflg, mypadn, remfile, moving;
46extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize, sendstart, rs_len;
47extern long filrej, oldcps, cps, ccu, ccp;
48extern int fblksiz, frecl, frecfm, forg, fcctrl;
49extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
50extern int hcflg, binary, fncnv, b_save, f_save, server, cxseen, czseen;
51extern int nakstate, discard, rejection, local;
52extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
53extern int fnspath, fnrpath;
54extern int atcapr, atcapb, atcapu;
55extern int lpcapr, lpcapb, lpcapu;
56extern int swcapr, swcapb, swcapu;
57extern int lscapr, lscapb, lscapu;
58extern int rscapr, rscapb, rscapu;
59extern int rptena, rptmin;
60extern int sseqtbl[];
61extern int numerrs;
62extern long rptn;
63extern int maxtry;
64extern int stdouf;
65extern int sendmode;
66#ifdef OS2
67extern struct zattr iattr;
68#endif /* OS2 */
69
70#ifndef NOCSETS
71extern int tcharset, fcharset;
72extern int ntcsets;
73extern struct csinfo tcsinfo[], fcsinfo[];
74#endif /* NOCSETS */
75
76extern int
77  atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
78  attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
79
80extern int bigsbsiz, bigrbsiz;
81extern char *versio;
82extern char whoareu[], * cksysid;
83
84#ifndef NOSERVER
85extern int ngetpath;
86extern char * getpath[];
87#endif /* NOSERVER */
88
89#ifdef DYNAMIC
90  extern CHAR *srvcmd;
91#else
92  extern CHAR srvcmd[];
93#endif /* DYNAMIC */
94extern CHAR padch, mypadc, eol, seol, feol, ctlq, myctlq, sstate, myrptq;
95extern CHAR *data, padbuf[], stchr, mystch;
96extern CHAR *srvptr;
97extern CHAR *rdatap;
98extern char *cmarg, *cmarg2, *hlptxt, **cmlist, filnam[], fspec[];
99
100#ifndef NOMSEND
101extern struct filelist * filehead, * filenext;
102extern int addlist;
103#endif /* NOMSEND */
104
105_PROTOTYP( CHAR *rpar, (void) );
106_PROTOTYP( int lslook, (unsigned int b) );      /* Locking Shift Lookahead */
107_PROTOTYP( int szeof, (CHAR *s) );
108_PROTOTYP( VOID fnlist, (void) );
109_PROTOTYP( static int nxtdir, (void) );
110_PROTOTYP( static int nxtdel, (void) );
111
112/* International character sets */
113
114#ifndef NOCSETS
115/* Pointers to translation functions */
116#ifdef CK_ANSIC
117extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
118extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
119#else
120extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
121extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
122#endif /* CK_ANSIC */
123_PROTOTYP( CHAR (*rx), (CHAR) );        /* Input translation function */
124_PROTOTYP( CHAR (*sx), (CHAR) );        /* Output translation function */
125_PROTOTYP( CHAR ident, (CHAR) );        /* Identity translation function */
126#endif /* NOCSETS */
127
128/* Windowing things */
129
130extern int rseqtbl[];                   /* Rec'd-packet sequence # table */
131
132/* (PWP) external def. of things used in buffered file input and output */
133
134#ifdef DYNAMIC
135extern char *zinbuffer, *zoutbuffer;
136#else
137extern char zinbuffer[], zoutbuffer[];
138#endif
139extern char *zinptr, *zoutptr;
140extern int zincnt, zoutcnt;
141
142extern long crcta[], crctb[];           /* CRC-16 generation tables */
143
144/*
145  Variables defined in this module but shared by other modules.
146*/
147
148long crc16 = 0L;                        /* File CRC = \v(crc16) */
149int docrc = 1;
150int xfrbel = 1;
151
152char * rf_err = "Error receiving file"; /* rcvfil() error message */
153
154#ifdef CK_SPEED
155short ctlp[256] = {             /* Control-Prefix table */
156  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C0  */
157  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G0  */
158  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
159  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* DEL */
160  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C1  */
161  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G1  */
162  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
163  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1  /* 255 */
164};
165#endif /* CK_SPEED */
166
167int sndsrc;             /* Flag for where to get names of files to send: */
168                                        /* -1: znext() function */
169                                        /*  0: stdin */
170                                        /* >0: list in cmlist */
171
172int  memstr;                            /* Flag for input from memory string */
173int  funcstr;                           /* Flag for input from function */
174int  bestlen = 0;
175int  maxsend = 0;
176
177#ifdef pdp11
178CHAR myinit[32];                        /* Copy of my Send-Init data */
179#else
180CHAR myinit[100];                       /* Copy of my Send-Init data */
181#endif /* pdp11 */
182
183/* Variables local to this module */
184
185#ifdef TLOG
186#ifndef XYZ_INTERNAL
187static
188#endif /* XYZ_INTERNAL */
189char *fncnam[] = {
190  "rename", "replace", "backup", "append", "discard", "ask", "update", ""
191};
192#endif /* TLOG */
193
194static char *memptr;                    /* Pointer for memory strings */
195
196#ifdef CK_ANSI
197static int (*funcptr)(char *);          /* Pointer for function strings */
198#else
199static int (*funcptr)();
200#endif /* CK_ANSI */
201
202#ifdef pdp11
203static char cmdstr[50];                 /* System command string. */
204#else
205static char cmdstr[256];
206#endif /* pdp11 */
207
208static int drain;                       /* For draining stacked-up ACKs. */
209
210static int first;                       /* Flag for first char from input */
211static CHAR t;                          /* Current character */
212#ifdef COMMENT
213static CHAR next;                       /* Next character */
214#endif /* COMMENT */
215
216static int ebqsent = 0;                 /* 8th-bit prefix bid that I sent */
217static int lsstate = 0;                 /* Locking shift state */
218static int lsquote = 0;                 /* Locking shift quote */
219
220#ifdef datageneral
221extern int quiet;
222#endif
223
224/*  E N C S T R  --  Encode a string from memory. */
225
226/*
227  Call this instead of getpkt() if source is a string, rather than a file.
228  Note: Character set translation is never done in this case.
229*/
230
231#ifdef COMMENT
232#define ENCBUFL 200
233#ifndef pdp11
234CHAR encbuf[ENCBUFL];
235#else
236/* This is gross, but the pdp11 root segment is out of space */
237/* Will allocate it in ckuusr.c. */
238extern CHAR encbuf[];
239#endif /* pdp11 */
240#endif /* COMMENT */
241
242/*
243  Encode packet data from a string in memory rather than from a file.
244  Returns 0 on success, -1 if the string could not be completely encoded
245  into the currently negotiated data field length.
246*/
247int
248encstr(s) CHAR* s; {
249#ifdef COMMENT
250    int m; char *p;
251    CHAR *dsave;
252
253    if (!s) s = (CHAR *)"";
254    if ((m = (int)strlen((char *)s)) > ENCBUFL) {
255        debug(F111,"encstr string too long for buffer",s,ENCBUFL);
256        s[ENCBUFL] = '\0';
257    }
258    if (m > spsiz-bctl-3) {
259        debug(F111,"encstr string too long for packet",s,spsiz-bctl-3);
260        s[spsiz-bctl-3] = '\0';
261    }
262    m = memstr; p = memptr;             /* Save these. */
263
264    memptr = (char *)s;                 /* Point to the string. */
265    memstr = 1;                         /* Flag memory string as source. */
266    first = 1;                          /* Initialize character lookahead. */
267    dsave = data;                       /* Boy is this ugly... */
268    data = encbuf + 7;                  /* Why + 7?  See spack()... */
269    *data = NUL;                        /* In case s is empty */
270    getpkt(spsiz,0);                    /* Fill a packet from the string. */
271    data = dsave;                       /* (sorry...) */
272    memstr = m;                         /* Restore memory string flag */
273    memptr = p;                         /* and pointer */
274    first = 1;                          /* Put this back as we found it. */
275    return(0);
276#else
277/*
278  Recoded 30 Jul 94 to use the regular data buffer and the negotiated
279  maximum packet size.  Previously we were limited to the length of encbuf[].
280  Also, to return a failure code if the entire encoded string would not fit.
281*/
282    int m, rc, slen; char *p;
283    if (!s) s = (CHAR *)"";             /* Watch out for null pointers. */
284    slen = strlen((char *)s);           /* Length of source string. */
285    rc = 0;                             /* Return code. */
286    m = memstr; p = memptr;             /* Save these. */
287    memptr = (char *)s;                 /* Point to the string. */
288    memstr = 1;                         /* Flag memory string as source. */
289    first = 1;                          /* Initialize character lookahead. */
290    *data = NUL;                        /* In case s is empty */
291    getpkt(spsiz,0);                    /* Fill a packet from the string. */
292
293    if (
294#ifdef COMMENT
295        *memptr
296#else
297        memptr < (char *)(s + slen)
298#endif /* COMMENT */
299        ) {                             /* This means we didn't encode */
300        rc = -1;                        /* the whole string. */
301        debug(F101,"encstr string too big","",size);
302    } else
303      debug(F101,"encstr fits OK, size","",size);
304    memstr = m;                         /* Restore memory string flag */
305    memptr = p;                         /* and pointer */
306    first = 1;                          /* Put this back as we found it. */
307    return(rc);
308#endif /* COMMENT */
309}
310
311#ifdef COMMENT
312/*
313  We don't use this routine any more -- the code has been incorporated
314  directly into getpkt() to reduce per-character function call overhead.
315  Also, watch out: this routine hasn't been updated since it was commented
316  out a long time ago.
317*/
318/* E N C O D E - Kermit packet encoding procedure */
319
320VOID
321encode(a) CHAR a; {                     /* The current character */
322    int a7;                             /* Low order 7 bits of character */
323    int b8;                             /* 8th bit of character */
324 
325#ifndef NOCSETS
326    if (!binary && sx) a = (*sx)(a);    /* Translate. */
327#endif /* NOCSETS */
328
329    if (rptflg) {                       /* Repeat processing? */
330        if (a == next && (first == 0)) { /* Got a run... */
331            if (++rpt < 94)             /* Below max, just count */
332                return;
333            else if (rpt == 94) {       /* Reached max, must dump */
334                data[size++] = rptq;
335                data[size++] = tochar(rpt);
336                rptn += rpt;            /* Count, for stats */
337                rpt = 0;
338            }
339        } else if (rpt == 1) {          /* Run broken, only 2? */
340            rpt = 0;                    /* Yes, reset repeat flag & count. */
341            encode(a);                  /* Do the character twice. */
342            if (size <= maxsize) osize = size;
343            rpt = 0;
344            encode(a);
345            return;
346        } else if (rpt > 1) {           /* More than two */
347            data[size++] = rptq;        /* Insert the repeat prefix */
348            data[size++] = tochar(++rpt); /* and count. */
349            rptn += rpt;
350            rpt = 0;                    /* Reset repeat counter. */
351        }
352    }
353    a7 = a & 0177;                      /* Isolate ASCII part */
354    b8 = a & 0200;                      /* and 8th (parity) bit. */
355
356    if (ebqflg && b8) {                 /* Do 8th bit prefix if necessary. */
357        data[size++] = ebq;
358        a = a7;
359    }
360    if ((a7 < SP) || (a7==DEL)) {       /* Do control prefix if necessary */
361        data[size++] = myctlq;
362        a = ctl(a);
363    }
364    if (a7 == myctlq)                   /* Prefix the control prefix */
365        data[size++] = myctlq;
366
367    if ((rptflg) && (a7 == rptq))       /* If it's the repeat prefix, */
368        data[size++] = myctlq;          /* quote it if doing repeat counts. */
369
370    if ((ebqflg) && (a7 == ebq))        /* Prefix the 8th bit prefix */
371        data[size++] = myctlq;          /* if doing 8th-bit prefixes */
372
373    data[size++] = a;                   /* Finally, insert the character */
374    data[size] = '\0';                  /* itself, and mark the end. */
375}
376#endif /* COMMENT */
377
378/*  Output functions passed to 'decode':  */
379
380int                            /*  Put character in server command buffer  */
381#ifdef CK_ANSIC
382putsrv(char c)
383#else
384putsrv(c) register char c;
385#endif /* CK_ANSIC */
386/* putsrv */ {
387    *srvptr++ = c;
388    *srvptr = '\0';             /* Make sure buffer is null-terminated */
389    return(0);
390}
391
392int                                     /*  Output character to console.  */
393#ifdef CK_ANSIC
394puttrm(char c)
395#else
396puttrm(c) register char c;
397#endif /* CK_ANSIC */
398/* puttrm */ {
399#ifndef NOSPL   
400    extern char * qbufp;                /* If REMOTE QUERY active, */
401    extern int query, qbufn;            /* also store response in */
402    if (query && qbufn++ < 1024) {      /* query buffer. */
403        *qbufp++ = c;
404        *qbufp = NUL;
405    } /* else */                        /* else means don't display */
406#endif /* NOSPL */
407    conoc(c);
408    return(0);
409}
410
411int                                     /*  Output char to file. */
412#ifdef CK_ANSIC
413putfil(char c)
414#else
415putfil(c) register char c;
416#endif /* CK_ANSIC */
417/* putfil */ {
418    if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
419        czseen = 1;                     /* If write error... */
420        debug(F101,"putfil zchout write error, setting czseen","",1);
421        return(-1);
422    }
423    return(0);
424}
425
426/* D E C O D E  --  Kermit packet decoding procedure */
427
428/*
429 Call with string to be decoded and an output function.
430 Returns 0 on success, -1 on failure (e.g. disk full).
431
432 This is the "inner loop" when receiving files, and must be coded as
433 efficiently as possible.  Note some potential problems:  if a packet
434 is badly formed, having a prefixed sequence ending prematurely, this
435 function, as coded, could read past the end of the packet.  This has
436 never happened, thus the additional (time-consuming) tests have not
437 been added.
438*/
439
440static CHAR *xdbuf;     /* Global version of decode()'s buffer pointer */
441                        /* for use by translation functions. */
442
443/* Function for pushing a character onto decode()'s input stream. */
444
445VOID
446#ifdef CK_ANSIC
447zdstuff(CHAR c)
448#else
449zdstuff(c) CHAR c;
450#endif /* CK_ANSIC */
451/* zdstuff */ {
452    xdbuf--;                            /* Back up the pointer. */
453    *xdbuf = c;                         /* Stuff the character. */
454}
455
456int
457#ifdef CK_ANSIC
458decode(CHAR *buf, int (*fn)(char), int xlate)
459#else
460decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
461#endif /* CK_ANSIC */
462/* decode */ {
463    register unsigned int a, a7, a8, b8; /* Various copies of current char */
464    int t;                              /* Int version of character */
465    int ssflg;                          /* Character was single-shifted */
466    int ccpflg;                         /* For Ctrl-unprefixing stats */
467    long z;
468    CHAR c;
469/*
470  Catch the case in which we are asked to decode into a file that is not open,
471  for example, if the user interrupted the transfer, but the other Kermit
472  keeps sending.
473*/
474    if ((cxseen || czseen || discard) && (fn == putfil))
475      return(0);
476
477    xdbuf = buf;                        /* Make global copy of pointer. */
478    rpt = 0;                            /* Initialize repeat count. */
479
480    while ((a = *xdbuf++ & 0xFF) != '\0') { /* Get next character. */
481        if (a == rptq && rptflg) {      /* Got a repeat prefix? */
482            rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
483            rptn += rpt;
484            a = *xdbuf++ & 0xFF;        /* and get the prefixed character. */
485        }
486        b8 = lsstate ? 0200 : 0;        /* 8th-bit value from SHIFT-STATE */
487        if (ebqflg && a == ebq) {       /* Have 8th-bit prefix? */
488            b8 ^= 0200;                 /* Yes, invert the 8th bit's value, */
489            ssflg = 1;                  /* remember we did this, */
490            a = *xdbuf++ & 0xFF;        /* and get the prefixed character. */
491        } else ssflg = 0;
492
493        ccpflg = 0;
494        if (a == ctlq) {                /* If control prefix, */
495            a  = *xdbuf++ & 0xFF;       /* get its operand */
496            a7 = a & 0x7F;              /* and its low 7 bits. */
497            if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
498                a = ctl(a);             /* if in control range. */
499                a7 = a & 0x7F;
500                ccpflg = 1;             /* Note that we did this */
501                ccp++;                  /* Count for stats */
502            }
503        } else a7 = a & 0x7f;           /* Not control quote */
504
505        if (a7 < 32 || a7 == 127) {     /* Control character? */
506            if (!ccpflg) ccu++;         /* A bare one, count it */
507            if (lscapu) {               /* If doing locking shifts... */
508                if (lsstate)            /* If SHIFTED */
509                  a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
510                else                    /* otherwise */
511                  a8 = a | b8;          /* OR in 8th bit */
512                /* If we're not in a quoted sequence */
513                if (!lsquote && (!lsstate || !ssflg)) {
514                    if (a8 == DLE) {    /* Check for DLE quote */
515                        lsquote = 1;    /* prefixed by single shift! */
516                        continue;
517                    } else if (a8 == SO) { /* Check for Shift-Out */
518                        lsstate = 1;    /* SHIFT-STATE = SHIFTED */
519                        continue;
520                    } else if (a8 == SI) { /* or Shift-In */
521                        lsstate = 0;    /* SHIFT-STATE = UNSHIFTED */
522                        continue;
523                    }
524                } else lsquote = 0;
525            }
526        }
527        a |= b8;                        /* OR in the 8th bit */
528        if (rpt == 0) rpt = 1;          /* If no repeats, then one */
529        if (!binary) {                  /* If in text mode, */
530            if (feol && a == CR) continue; /* Convert CRLF to newline char */
531            if (feol && a == LF) a = feol;
532
533#ifndef NOCSETS                         /* Character-set translation */
534#ifdef KANJI                            /* For Kanji transfers, */
535            if (tcharset != TC_JEUC)    /* postpone translation. */
536#endif /* KANJI */
537              if (xlate && rx) a = (*rx)((CHAR) a); /* Translate charset */
538#endif /* NOCSETS */
539        }
540        if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */
541            for (; rpt > 0; rpt--) {    /* Output the char RPT times */
542#ifndef NOCSETS
543#ifdef KANJI
544                if (!binary && tcharset == TC_JEUC &&
545                    fcharset != FC_JEUC) { /* Translating from J-EUC */
546                    if (ffc == 0L) xkanjf();
547                    if (xkanji(a,fn) < 0)  /* to something else? */
548                      return(-1);
549                    else t = 1;
550                } else
551#endif /* KANJI */
552#endif /* NOCSETS */
553#ifdef OS2
554                  if (xflg && !remfile) { /* Write to virtual screen */
555                      char _a;
556                      _a = a & fmask;
557                      t = conoc(_a);
558                      if (t < 1) t = -1;
559                  } else
560#endif /* OS2 */
561                    t = zmchout(a & fmask); /* zmchout is a macro */
562                if (t < 0) {
563                    debug(F101,"decode _write error - errno","",errno);
564                    return(-1);
565                }
566#ifdef COMMENT
567                if (ffc == 0 && filcnt <= 1) {
568                    debug(F101,"decode new file, filcnt","",filcnt);
569                    debug(F101,"decode crc16","",crc16);
570                    crc16 = 0L;         /* Should already have been done */
571                }
572#endif /* COMMENT */
573                ffc++;                  /* Count the character */
574                if (docrc && !xflg && !remfile) { /* Update file CRC */
575                    c = a;              /* Force conversion to unsigned char */
576                    z = crc16 ^ (long)c;
577                    crc16 = (crc16 >> 8) ^
578                      (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
579                }
580            }
581        } else {                        /* Output to something else. */
582            a &= fmask;                 /* Apply file mask */
583            for (; rpt > 0; rpt--) {    /* Output the char RPT times */
584                if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
585#ifdef COMMENT
586/*
587  This was causing the server to count extra bytes that were part of
588  server command packets, like FINISH.
589*/
590                ffc++;
591#endif /* COMMENT */
592            }
593        }
594    }
595    return(0);
596}
597
598/*  G E T P K T -- Fill a packet data field  */
599
600/*
601 Gets characters from the current source -- file or memory string.
602 Encodes the data into the packet, filling the packet optimally.
603 Set first = 1 when calling for the first time on a given input stream
604 (string or file).
605
606 Call with:
607 bufmax -- current send-packet size
608 xlate  -- flag: 0 to skip character-set translation, 1 to translate
609
610 Uses global variables:
611 t     -- current character.
612 first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
613 next  -- next character (not used any more).
614 data  -- pointer to the packet data buffer.
615 size  -- number of characters in the data buffer.
616 memstr - flag that input is coming from a memory string instead of a file.
617 memptr - pointer to string in memory.
618 (*sx)()  character set translation function
619
620Returns the size as value of the function, and also sets global "size",
621and fills (and null-terminates) the global data array.  Returns 0 upon eof.
622
623Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
624Incorporates old getchx() and encode() inline to reduce function calls,
625uses buffered input for much-improved efficiency, and clears up some
626confusion with line termination (CRLF vs LF vs CR).
627
628Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
629May 1991.
630*/
631
632/*
633  Lookahead function to decide whether locking shift is worth it.  Looks at
634  the next four input characters to see if all of their 8th bits match the
635  argument.  Call with 0 or 0200.  Returns 1 if so, 0 if not.  If we don't
636  happen to have at least 4 more characters waiting in the input buffer,
637  returns 1.  Note that zinptr points two characters ahead of the current
638  character because of repeat-count lookahead.
639*/
640
641#ifdef KANJI
642int
643kgetf(
644#ifdef CK_ANSIC
645      VOID
646#endif /* CK_ANSIC */
647      ) {
648    if (funcstr)
649      return((*funcptr)());
650    else
651      return(zminchar());
652}
653
654int
655kgetm(
656#ifdef CK_ANSIC
657      VOID
658#endif /* CK_ANSIC */
659      ) {
660    int x;
661    if (x = *memptr++) return(x);
662    else return(-1);
663}
664#endif /* KANJI */
665
666int
667lslook(b) unsigned int b; {             /* Locking Shift Lookahead */
668    int i;
669    if (zincnt < 3)                     /* If not enough chars in buffer, */
670      return(1);                        /* force shift-state switch. */
671    b &= 0200;                          /* Force argument to proper form. */
672    for (i = -1; i < 3; i++)            /* Look at next 5 characters to */
673      if (((*(zinptr+i)) & 0200) != b)  /* see if all their 8th bits match.  */
674        return(0);                      /* They don't. */
675    return(1);                          /* They do. */
676}
677
678int
679getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
680    register CHAR rt = t, rnext;          /* Register shadows of the globals */
681    register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
682    register int x;                     /* Loop index. */
683    register int a7;                    /* Low 7 bits of character */
684
685    static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
686
687    CHAR xxls, xxdl, xxrc, xxss, xxcq;  /* Pieces of prefixed sequence */
688    int n;                              /* worker */
689
690    long z;                             /* A long worker (for CRC) */
691/*
692  Assume bufmax is the receiver's total receive-packet buffer length.
693  Our whole packet has to fit into it, so we adjust the data field length.
694  We also decide optimally whether it is better to use a short-format or
695  long-format packet when we're near the borderline.
696*/
697    n = bufmax - 5;                     /* Space for Data and Checksum */
698    if (n > 92 && n < 96) n = 92;       /* "Short" Long packets don't pay */
699    if (n > 92 && lpcapu == 0)          /* If long packets needed, */
700      n = 92;                           /* make sure they've been negotiated */
701    bufmax = n - bctl;                  /* Space for data */
702    if (n > 92) bufmax -= 3;            /* Long packet needs header chksum */
703
704    if (first == 1) {             /* If first character of this file... */
705        if (!memstr && ! funcstr)       /* and real file... */
706          ffc = 0L;                     /* reset file character counter */
707        first = 0;                      /* Next character won't be first */
708        *leftover = '\0';               /* Discard any interrupted leftovers */
709
710        /* get first character of file into rt, watching out for null file */
711
712#ifndef NOCSETS
713#ifdef KANJI
714        if (!binary && tcharset == TC_JEUC && xlate) {
715            x = zkanjf();
716            if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
717                first = -1;
718                size = 0;
719                if (x == -2) {
720                    debug(F100,"getpkt(zkanji): input error","",0);
721                    cxseen = 1;
722                } else debug(F100,"getpkt(zkanji): empty string/file","",0);
723                return (0);
724            }
725            rt = x;
726            if (!memstr) {
727                ffc++;
728                if (docrc && what == W_SEND) { /* Accumulate file crc */
729                    z = crc16 ^ (long)rt;
730                    crc16 = (crc16 >> 8) ^
731                      (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
732                }               
733            }
734        } else {
735#endif /* KANJI */
736#endif /* not NOCSETS */
737        if (memstr) {                   /* Reading data from memory string */
738            if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
739                first = -1;
740                size = 0;
741                debug(F100,"getpkt: empty string","",0);
742                return (0);
743            }
744
745        } else if (funcstr) {           /* Reading data from a function */
746
747            if ((x = (*funcptr)()) < 0) { /* End of input  */
748                first = -1;
749                size = 0;
750                debug(F100,"getpkt: empty input function","",0); /* Empty */
751                return(0);
752            }
753            ffc++;                      /* Count a file character */
754            rt = (CHAR) x;              /* Convert int to char */
755            debug(F101,"getpkt funcstr","",rt);
756
757        } else {                        /* Reading data from a file */
758
759            if ((x = zminchar()) < 0) { /* End of file or input error */
760                first = -1;
761                size = 0;
762                if (x == -2) {          /* Error */
763                    debug(F100,"getpkt: input error","",0);
764                    cxseen = 1;         /* Interrupt the file transfer */
765                } else {
766                    debug(F100,"getpkt empty file","",0);
767                }
768                return(0);
769            }
770            ffc++;                      /* Count a file character */
771            rt = (CHAR) x;              /* Convert int to char */
772            debug(F101,"getpkt 1st char","",rt);
773            if (docrc && what == W_SEND) {      /* Accumulate file crc */
774                z = crc16 ^ (long)rt;
775                crc16 = (crc16 >> 8) ^
776                  (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
777            }           
778        }
779#ifndef NOCSETS
780#ifdef KANJI
781        }
782#endif /* KANJI */
783#endif /* not NOCSETS */
784
785        rt &= fmask;                    /* Apply SET FILE BYTESIZE mask */
786        debug(F101,"getpkt fmask","",fmask);
787        debug(F101,"getpkt new rt","",rt);
788
789#ifndef NOCSETS
790        if (xlate) {
791            debug(F101,"getpkt about to call translate function","",rt);
792            debug(F101,"tcharset","",tcharset);
793            debug(F101,"fcharset","",fcharset);
794        }
795#ifdef KANJI
796        if (tcharset != TC_JEUC)
797#endif /* KANJI */
798          if (!binary && sx && xlate) {
799              rt = (*sx)(rt); /* Translate */
800              debug(F101," translate function returns","",rt);
801          }
802#endif /* not NOCSETS */
803
804        /* PWP: handling of feol is done later (in the while loop)... */
805
806    } else if ((first == -1) && (*leftover == '\0')) { /* EOF from last time */
807        debug(F101,"getpkt eof crc16","",crc16);
808        debug(F101,"getpkt eof ffc","",ffc);
809        return(size = 0);
810    }
811/*
812  Here we handle characters that were encoded for the last packet but
813  did not fit, and so were saved in the "leftover" array.
814*/
815    dp = data;                          /* Point to packet data buffer */
816    for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* Copy leftovers */
817        ;
818    *leftover = '\0';                   /* Delete leftovers */
819    if (first == -1)                    /* Handle EOF */
820      return(size = (dp - data));
821 
822/* Now fill up the rest of the packet. */
823
824    rpt = 0;                            /* Initialize character repeat count */
825
826    while (first > -1) {                /* Until EOF... */
827#ifndef NOCSETS
828#ifdef KANJI
829        if (!binary && xlate && tcharset == TC_JEUC) {
830            if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
831                first = -1;
832                if (x == -2) cxseen = 1;
833            } else if (!memstr) ffc++;
834            rnext = (CHAR) (x & fmask);
835        } else {
836#endif /* KANJI */
837#endif /* not NOCSETS */
838        if (memstr) {                   /* Get next char from memory string */
839            if ((x = *memptr++) == '\0') /* End of string means EOF */
840              first = -1;               /* Flag EOF for next time. */
841            rnext = (CHAR) (x & fmask); /* Apply file mask */
842        } else if (funcstr) {           /* Get next char from function */
843            if ((x = (*funcptr)()) < 0) /* End of string means EOF */
844              first = -1;               /* Flag EOF for next time. */
845            rnext = (CHAR) (x & fmask); /* Apply file mask */
846        } else {
847            if ((x = zminchar()) < 0) { /* Real file, check for EOF */
848                first = -1;             /* Flag eof for next time. */
849                if (x == -2) cxseen = 1; /* If error, cancel this file. */
850            } else {
851                ffc++;          /* Count the character */
852                if (docrc && what == W_SEND) {  /* Accumulate file crc */
853                    z = crc16 ^ (long)((CHAR)x & 0xff);
854                    crc16 = (crc16 >> 8) ^
855                      (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
856                }               
857            }
858            rnext = (CHAR) (x & fmask); /* Apply file mask */
859        }
860#ifndef NOCSETS
861#ifdef KANJI
862        }
863#endif /* KANJI */
864#endif /* not NOCSETS */
865
866#ifndef NOCSETS
867#ifdef KANJI
868        if (tcharset != TC_JEUC)
869#endif /* KANJI */
870            if (!binary && sx && xlate) {
871                rnext = (*sx)(rnext); /* Translate */
872                debug(F101,"getpkt xlated rnext to","",rnext);
873            }
874#endif /* not NOCSETS */
875
876        odp = dp;                       /* Remember where we started. */
877        xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
878
879/*
880  Now encode the character according to the options that are in effect:
881    ctlp[]: whether this control character needs prefixing.
882    binary: text or binary mode.
883    rptflg: repeat counts enabled.
884    ebqflg: 8th-bit prefixing enabled.
885    lscapu: locking shifts enabled.
886*/
887        if (rptflg) {                   /* Repeat processing is on? */
888            if (
889                /*
890                 * If the next char is really CRLF, then we cannot
891                 * be doing a repeat (unless CR,CR,LF which becomes
892                 * "~ <n-1> CR CR LF", which is OK but not most efficient).
893                 * I just plain don't worry about this case.  The actual
894                 * conversion from NL to CRLF is done after the rptflg if...
895                 */
896            (binary || (feol && (rnext != feol))) &&
897
898            (rt == rnext) && (first == 0)) { /* Got a run... */
899                if (++rpt < 94) {       /* Below max, just count */
900                    continue;           /* go back and get another */
901                }
902                else if (rpt == 94) {   /* Reached max, must dump */
903                    xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
904                    rptn += rpt;        /* Accumulate it for statistics */
905                    rpt = 0;            /* And reset it */
906                }
907            } else if (rpt > 1) {       /* More than two */
908                xxrc = (CHAR) tochar(++rpt); /* and count. */
909                rptn += rpt;
910                rpt = 0;                /* Reset repeat counter. */
911            }
912            /*
913              If (rpt == 1) we must encode exactly two characters.
914              This is done later, after the first character is encoded.
915            */
916        }
917
918        if (!binary && feol && (rt == feol)) { /* It's the newline character */
919            if (lscapu && lsstate) {    /* If SHIFT-STATE is SHIFTED */
920                if (ebqflg) {           /* If single shifts enabled, */
921                    *dp++ = (CHAR) ebq; /* insert a single shift. */
922                } else {                /* Otherwise must shift in. */
923                    *dp++ = myctlq;     /* Insert shift-out code */
924                    *dp++ = 'O';
925                    lsstate = 0;        /* Change shift state */
926                }
927            }
928#ifdef CK_SPEED
929            if (ctlp[CR]) {
930                *dp++ = myctlq;         /* Insert carriage return directly */
931                *dp++ = 'M';
932                ccp++;
933            } else {
934                *dp++ = CR;             /* Perhaps literally */
935                ccu++;
936            }
937#else /* !CK_SPEED */
938            *dp++ = myctlq;             /* Insert carriage return directly */
939            *dp++ = 'M';
940            ccp++;
941#endif /* CK_SPEED */
942            rt = LF;                    /* Now make next char be linefeed. */
943        }
944/*
945  Now handle the 8th bit of the file character.  If we have an 8-bit
946  connection, we preserve the 8th bit.  If we have a 7-bit connection,
947  we employ either single or locking shifts (if they are enabled).
948*/
949        a7 = rt & 0177;                 /* Get low 7 bits of character */
950        if (rt & 0200) {                /* 8-bit character? */
951            if (lscapu) {               /* Locking shifts enabled? */
952                if (!lsstate) {         /* Not currently shifted? */
953                    x = lslook(0200);   /* Look ahead */
954                    if (x != 0 || ebqflg == 0) { /* Locking shift decision */
955                        xxls = 'N';        /* Need locking shift-out */
956                        lsstate = 1;       /* and change to shifted state */
957                    } else if (ebqflg) {   /* Not worth it */
958                        xxss = (CHAR) ebq; /* Use single shift */
959                    }
960                }
961                rt = (CHAR) a7;         /* Replace character by 7-bit value */
962            } else if (ebqflg) {        /* 8th bit prefixing is on? */
963                xxss = (CHAR) ebq;      /* Insert single shift */
964                rt = (CHAR) a7;         /* Replace character by 7-bit value */
965            }
966/*
967  In case we have a 7-bit connection and this is an 8-bit character, AND
968  neither locking shifts nor single shifts are enabled, then the character's
969  8th bit will be destroyed in transmission, and a block check error will
970  occur.
971*/
972        } else if (lscapu) {            /* 7-bit character */
973
974            if (lsstate) {              /* Comes while shifted out? */
975                x = lslook(0);          /* Yes, look ahead */
976                if (x || ebqflg == 0) { /* Time to shift in. */
977                    xxls = 'O';         /* Set shift-in code */
978                    lsstate = 0;        /* Exit shifted state */
979                } else if (ebqflg) {    /* Not worth it, stay shifted out */
980                    xxss = (CHAR) ebq;  /* Insert single shift */
981                }
982            }
983        }
984        /* If data character is significant to locking shift protocol... */
985        if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
986          xxdl = 'P';                   /* Insert datalink escape */
987
988        if (
989#ifdef CK_SPEED
990            /*
991              Thwart YET ANOTHER unwanted, unneeded, and unloved sign
992              extension.  This one was particularly nasty because it prevented
993              255 (Telnet IAC) from being prefixed on some platforms -- e.g.
994              VMS with VAX C -- but not others, thus causing file transfers to
995              fail on Telnet connections by sending bare IACs.  Not to mention
996              the stray memory reference.  Whoever thought it was a good idea
997              for characters to be signed (by default or at all) should have
998              thunk again.  (Sep 96)
999            */
1000            ctlp[(rt & 0xff)]           /* Lop off any "sign" extension */
1001#else
1002            (a7 < SP) || (a7 == DEL)
1003#endif /* CK_SPEED */
1004            ) {                         /* Do control prefixing if necessary */
1005            xxcq = myctlq;              /* The prefix */
1006            ccp++;                      /* Count it */
1007            rt = (CHAR) ctl(rt);        /* Uncontrollify the character */
1008        }
1009#ifdef CK_SPEED
1010        else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
1011          ccu++;
1012#endif /* CK_SPEED */
1013
1014        if (a7 == myctlq)               /* Always prefix the control prefix */
1015          xxcq = myctlq;
1016
1017        if ((rptflg) && (a7 == rptq))   /* If it's the repeat prefix, */
1018          xxcq = myctlq;                /* prefix it if doing repeat counts */
1019
1020        if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th-bit prefix */
1021          xxcq = myctlq;                /* if doing 8th-bit prefixes */
1022
1023/* Now construct the entire sequence */
1024
1025        if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
1026        odp2 = dp;                                  /* (Save this place) */
1027        if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
1028        if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
1029        if (xxss) { *dp++ = (CHAR) ebq; }           /* Single shift */
1030        if (xxcq) { *dp++ = myctlq; }               /* Control prefix */
1031        *dp++ = rt;                     /* Finally, the character itself */
1032
1033        if (rpt == 1) {                 /* Exactly two copies? */
1034            rpt = 0;
1035            p2 = dp;                    /* Save place temporarily */
1036            for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
1037              *dp++ = *p1;
1038            if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
1039        }
1040        rt = rnext;                     /* Next character is now current. */
1041
1042/* Done encoding the character.  Now take care of packet buffer overflow. */
1043
1044        if ((dp-data) >= bufmax) {      /* If too big, save some for next. */
1045            size = (dp-data);           /* Calculate the size. */
1046            *dp = '\0';                 /* Mark the end. */
1047            if ((dp-data) > bufmax) {   /* if packet is overfull */
1048                /* copy the part that doesn't fit into the leftover buffer, */
1049                /* taking care not to split a prefixed sequence. */
1050                for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
1051                    ;
1052                debug(F111,"getpkt leftover",leftover,size);
1053                debug(F101,"getpkt osize","",(odp-data));
1054                size = (odp-data);      /* Return truncated packet. */
1055                *odp = '\0';            /* Mark the new end */
1056            }
1057            t = rt;                     /* save for next time */
1058#ifdef COMMENT
1059            next = rnext;       
1060#endif /* COMMENT */
1061            return(size);
1062        }
1063    }                                   /* Otherwise, keep filling. */
1064
1065    size = (dp-data);                   /* End of file */
1066    *dp = '\0';                         /* Mark the end of the data. */
1067    debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
1068    return(size);                    /* return partially filled last packet. */
1069}
1070
1071/*  T I N I T  --  Initialize a transaction  */
1072
1073int
1074tinit() {
1075    int x;
1076
1077#ifdef CK_TIMERS
1078    extern int rttflg;
1079#endif /* CK_TIMERS */
1080    extern int rcvtimo;
1081    extern char whoareu[];
1082
1083    if (server)
1084      moving  = 0;
1085    bestlen = 0;
1086    maxsend = 0;
1087    debug(F101,"tinit bestlen","",bestlen);
1088    whoareu[0] = NUL;
1089    debug(F100,"tinit setting justone=0","",0);
1090    justone = 0;
1091
1092#ifndef NOCSETS
1093    if (tcharset == TC_TRANSP) {        /* Character set translation */
1094        rx = sx = NULL;                 /* Transparent, no translation */
1095#ifdef KANJI
1096    } else if (tcharset == TC_JEUC) {
1097        rx = sx = NULL;                 /* Transparent, no translation */     
1098#endif /* KANJI */
1099    } else {                            /* otherwise */
1100        rx = xlr[tcharset][fcharset];   /* Input translation function */
1101        sx = xls[tcharset][fcharset];   /* Output translation function */
1102    }
1103    debug(F101,"tinit tcharset","",tcharset);
1104    debug(F101,"tinit fcharset","",fcharset);
1105#ifdef COMMENT
1106    debug(F101,"tinit sx   ","",sx);
1107    debug(F101,"tinit rx   ","",rx);
1108#endif /* COMMENT */
1109#endif /* NOCSETS */
1110    myinit[0] = '\0';                   /* Haven't sent init string yet */
1111    retrans = 0;                        /* Packet retransmission count */
1112    sndtyp = 0;                         /* No previous packet */
1113    xflg = 0;                           /* Reset x-packet flag */
1114    memstr = 0;                         /* Reset memory-string flag */
1115    memptr = NULL;                      /*  and buffer pointer */
1116    funcstr = 0;                        /* Reset "read from function" flag */
1117    funcptr = NULL;                     /*  and function pointer */
1118    bctu = bctl = 1;                    /* Reset block check type to 1 */
1119    autopar = 0;                        /* Automatic parity detection flag */
1120    rqf = -1;                           /* Reset 8th-bit-quote request flag */
1121    ebq = MYEBQ;                        /* Reset 8th-bit quoting stuff */
1122    ebqflg = 0;                         /* 8th bit quoting not enabled */
1123    ebqsent = 0;                        /* No 8th-bit prefix bid sent yet */
1124    sq = 'Y';                           /* 8th-bit prefix bid I usually send */
1125    binary = b_save;                    /* Back to what user last said */
1126    fncnv = f_save;                     /* ... */
1127    pktnum = 0;                         /* Initial packet number to send */
1128    cxseen = czseen = discard = 0;      /* Reset interrupt flags */
1129    *filnam = '\0';                     /* Clear file name */
1130    spktl = 0;                          /* And its length */
1131    nakstate = 0;                       /* Assume not in a NAK'ing state */
1132    numerrs = 0;                        /* Transmission error counter */
1133    if (server)                         /* If acting as server, */
1134      timint = srvtim;                  /* Use server timeout interval. */
1135    else                                /* Otherwise */
1136      timint = chktimo(rtimo,timef);    /* Begin by using local value */
1137
1138#ifdef CK_TIMERS
1139    if (rttflg)                         /* Using round-trip timers? */
1140      rttinit();
1141#else
1142    rcvtimo = timint;
1143#endif /* CK_TIMERS */
1144
1145    spsiz = spsizr;                     /* Initial send-packet size */
1146    wslots = 1;                         /* One window slot */
1147    wslotn = 1;                         /* No window negotiated yet */
1148    winlo = 0;                          /* Packet 0 is at window-low */
1149    x = mksbuf(1);                      /* Make a 1-slot send-packet buffer */
1150    if (x < 0) return(x);
1151    x = getsbuf(0);                     /* Allocate first send-buffer. */
1152    debug(F101,"tinit getsbuf","",x);
1153    if (x < 0) return(x);
1154    dumpsbuf();
1155    x = mkrbuf(wslots);                 /* & a 1-slot receive-packet buffer. */
1156    if (x < 0) return(x);
1157    what = W_NOTHING;                   /* Doing nothing so far... */
1158    lsstate = 0;                        /* Initialize locking shift state */
1159    whatru = 0;
1160    return(0);
1161}
1162
1163VOID
1164pktinit() {                             /* Initialize packet sequence */
1165    pktnum = 0;                         /* number & window low. */
1166    winlo = 0;
1167}
1168
1169/*  R I N I T  --  Respond to S or I packet  */
1170
1171VOID
1172rinit(d) CHAR *d; {
1173    char *tp;
1174    ztime(&tp);
1175    tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
1176    tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
1177    tlog(F110,"Collision action:", fncnam[fncact],0);
1178    tlog(F100,"","",0);
1179    filcnt = filrej = 0;                /* Init file counters */
1180    spar(d);
1181    ack1(rpar());
1182#ifdef datageneral
1183    if ((local) && (!quiet))            /* Only do this if local & not quiet */
1184        consta_mt();                    /* Start the asynch read task */
1185#endif /* datageneral */
1186}
1187
1188
1189/*  R E S E T C  --  Reset per-transaction character counters */
1190
1191VOID
1192resetc() {
1193    rptn = 0;                           /* Repeat counts */
1194    fsecs = flci = flco = 0L;           /* File chars in and out */
1195    tfc = tlci = tlco = 0L;             /* Total file, line chars in & out */
1196    ccu = ccp = 0L;                     /* Control-char statistics */
1197#ifdef COMMENT
1198    fsize = -1L;                        /* File size */
1199#else
1200    if (what != W_SEND)
1201      fsize = -1L;
1202    debug(F101,"resetc fsize","",fsize);
1203#endif /* COMMENT */
1204    timeouts = retrans = 0;             /* Timeouts, retransmissions */
1205    spackets = rpackets = 0;            /* Packet counts out & in */
1206    crunched = 0;                       /* Crunched packets */
1207    wcur = 0;                           /* Current window size */
1208    wmax = 0;                           /* Maximum window size used */
1209}
1210
1211/*  S I N I T  --  Get & verify first file name, then send Send-Init packet */
1212/*
1213 Returns:
1214   1 if send operation begins successfully
1215   0 if send operation fails
1216*/
1217#ifdef DYNAMIC
1218char *cmargbuf = NULL;
1219#else
1220char cmargbuf[256];
1221#endif /* DYNAMIC */
1222char *cmargp[2];
1223
1224VOID
1225fnlist() {
1226    sndsrc = nfils;                     /* Source for filenames */
1227#ifdef DYNAMIC
1228    if (!cmargbuf && !(cmargbuf = malloc(256)))
1229        fatal("fnlist: no memory for cmargbuf");
1230#endif /* DYNAMIC */
1231    cmargbuf[0] = NUL;                  /* Initialize name buffer */
1232
1233    debug(F101,"sinit nfils","",nfils);
1234    debug(F110,"sinit cmarg",cmarg,0);
1235    debug(F110,"sinit cmarg2",cmarg2,0);
1236    if (nfils == 0) {                   /* Sending from stdin or memory. */
1237        if ((cmarg2 != NULL) && (*cmarg2)) {
1238            cmarg = cmarg2;             /* If F packet, "as-name" is used */
1239            cmarg2 = "";                /* if provided */
1240        } else cmarg = "stdin";         /* otherwise just use "stdin" */
1241        strcpy(cmargbuf,cmarg);
1242        cmargp[0] = cmargbuf;
1243        cmargp[1] = "";
1244        cmlist = cmargp;
1245        nfils = 1;
1246    }
1247}
1248
1249int
1250sinit() {
1251    int x;                              /* Worker int */
1252    char *tp, *xp, *m;                  /* Worker string pointers */
1253/*
1254  The DECC prototype for sleep() moved from <signal.h> to <unistd.h>
1255  in DECC 5.2, but rather than pull in an entire header file (that might
1256  not even be there), potentially involving unwanted conflicts, just do this:
1257*/ 
1258#ifdef __DECC
1259#ifndef __DECC_VER                      /* This exists only in 5.0 and above */
1260    _PROTOTYP( int sleep, (unsigned) );
1261#else
1262#if __DECC_VER < 50200000
1263    _PROTOTYP( int sleep, (unsigned) );
1264#endif /* __DECC_VER */
1265#endif /* __DECC_VER */
1266#endif /* __DECC */
1267
1268    filcnt = filrej = 0;                /* Initialize file counters */
1269    fnlist();
1270
1271    if (nfils < 0) {
1272        xp = cmarg;
1273    } else {
1274#ifndef NOMSEND
1275        if (addlist)
1276          xp = filehead->fl_name;
1277        else
1278#endif /* NOMSEND */
1279          xp = *cmlist;
1280    }
1281    x = gnfile();                       /* Get first filename. */
1282    m = NULL;                           /* Error message pointer */
1283    debug(F101,"sinit gnfil","",x);
1284    switch (x) {
1285      case -5: m = "Too many files match wildcard"; break;
1286      case -4: m = "Cancelled"; break;
1287      case -3: m = "Read access denied"; break;
1288      case -2: m = "File is not readable"; break;
1289      case -1: m = iswild(filnam) ? "No files match" : "File not found";
1290        break;
1291      case  0: m = "No filespec given!"; break;
1292      default:
1293        break;
1294    }
1295    debug(F101,"sinit nfils","",nfils);
1296    debug(F110,"sinit filnam",filnam,0);
1297    if (x < 1) {                        /* Didn't get a file. */
1298        if (server)                     /* Doing GET command */
1299          errpkt((CHAR *)m);            /* so send Error packet. */
1300        else                            /* Doing SEND command */
1301          screen(SCR_EM,0,0l,m);        /* so print message. */
1302        tlog(F110,xp,m,0L);             /* Make transaction log entry. */
1303        freerbuf(rseqtbl[0]);           /* Free the buffer the GET came in. */
1304        return(0);                      /* Return failure code */
1305    }
1306    if (!local && !server && delay > 0) /* OS-9 sleep(0) == infinite */
1307      sleep(delay);                     /* Delay if requested */
1308#ifdef datageneral
1309    if ((local) && (!quiet))            /* Only do this if local & not quiet */
1310        consta_mt();                    /* Start the asynch read task */
1311#endif /* datageneral */
1312    freerbuf(rseqtbl[0]);               /* Free the buffer the GET came in. */
1313    sipkt('S');                         /* Send the Send-Init packet. */
1314    ztime(&tp);                         /* Get current date/time */
1315    tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
1316    tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
1317    tlog(F100,"","",0);
1318    debug(F111,"sinit ok",filnam,0);
1319    return(1);
1320}
1321
1322int
1323#ifdef CK_ANSIC
1324sipkt(char c)                           /* Send S or I packet. */
1325#else
1326sipkt(c) char c;
1327#endif
1328/* sipkt */ {
1329    CHAR *rp; int k;
1330    debug(F101,"sipkt pktnum","",pktnum);
1331    k = sseqtbl[pktnum];                /* Find slot for this packet */
1332    debug(F101,"sipkt k","",k);
1333    if (k < 0) {                        /* No slot? */
1334        k = getsbuf(winlo = pktnum);    /* Make one. */
1335        debug(F101,"sipkt getsbuf","",k);   
1336    }
1337    ttflui();                           /* Flush pending input. */
1338    rp = rpar();                        /* Get protocol parameters. */
1339    return(spack(c,pktnum,(int)strlen((char *)rp),rp)); /* Send them. */
1340}
1341
1342/*  X S I N I T  --  Retransmit S-packet  */
1343/*
1344  For use in the GET-SEND sequence, when we start to send, but receive another
1345  copy of the GET command because the receiver didn't get our S packet.
1346  This retransmits the S packet and frees the receive buffer for the ACK.
1347  This special case is necessary because packet number zero is being re-used.
1348*/
1349VOID
1350xsinit() {
1351    int k;
1352    k = rseqtbl[0];
1353    debug(F101,"xsinit k","",k);
1354    if (k > -1)
1355      freerbuf(k);
1356    resend(0);
1357}
1358
1359/*  R C V F I L -- Receive a file  */
1360
1361/*
1362  Incoming filename is in data field of F packet.
1363  This function decodes it into the srvcmd buffer, substituting an
1364  alternate "as-name", if one was given.
1365  Then it does any requested transformations (like converting to
1366  lowercase), and finally if a file of the same name already exists,
1367  takes the desired collision action.
1368*/
1369char ofn1[CKMAXPATH+1];                 /* Buffer for output file name */
1370char * ofn2;                            /* Pointer to backup file name */
1371int ofn1x;                              /* Flag output file already exists */
1372int opnerr;                             /* Flag for open error */
1373
1374int                                     /* Returns success ? 1 : 0 */
1375rcvfil(n) char *n; {
1376#ifdef OS2
1377#ifdef __32BIT__
1378    char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
1379#endif /* __32BIT__ */
1380#endif /* OS2 */
1381#ifdef DTILDE
1382    char *dirp, *tilde_expand();
1383#endif /* DTILDE */
1384    int dirflg;
1385
1386    opnerr = 0;
1387    ofn2 = NULL;                        /* No new name (yet) */
1388    lsstate = 0;                        /* Cancel locking-shift state */
1389    srvptr = srvcmd;                    /* Decode file name from packet. */
1390    decode(rdatap,putsrv,0);            /* Don't xlate charsets. */
1391    if (*srvcmd == '\0')                /* Watch out for null F packet. */
1392      strcpy((char *)srvcmd,"NONAME");
1393#ifdef DTILDE
1394    if (*srvcmd == '~') {
1395        dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
1396        if (*dirp != '\0') strcpy((char *)srvcmd,dirp);
1397    }
1398#else
1399#ifdef OS2
1400    if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
1401      strcat((char *)srvcmd,"NONAME");
1402#endif /* OS2 */
1403#endif /* DTILDE */
1404    screen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
1405    debug(F110,"rcvfil",(char *)srvcmd,0); /* Debug log entry */
1406    debug(F110,"rcvfil cmarg2",cmarg2,0);
1407    tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
1408    if (cmarg2) {                       /* Check for alternate name */
1409        if (*cmarg2) {
1410            debug(F110,"rcvfil substituting cmarg2",cmarg2,0);
1411            strcpy((char *)srvcmd,cmarg2); /* Got one, use it. */
1412        }
1413    }
1414    cmarg2 = "";                        /* Done with alternate name */
1415
1416    if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
1417      *(srvcmd + CKMAXPATH - 1) = NUL;
1418
1419    /* At this point, srvcmd[] contains the incoming filename or as-name */
1420
1421    if (fnrpath) {                      /* RECEIVE PATHNAMES OFF? */
1422        char *t;                        /* Yes. */
1423        zstrip((char *)srvcmd,&t);      /* Off with it. */
1424        debug(F110,"rcvfil zstrip",t,0);
1425        if (!t)                         /* Be sure we didn't strip too much */
1426          strcpy(ofn1,"UNKNOWN");
1427        else if (*t == '\0')
1428          strcpy(ofn1,"UNKNOWN");
1429        else
1430          strcpy(ofn1,t);
1431        strcpy((char *)srvcmd,ofn1);    /* Now copy it back. */
1432    }
1433
1434    /* Now srvcmd contains incoming filename with path possibly stripped */
1435
1436    if (fncnv)                          /* FILE NAMES CONVERTED? */
1437      zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
1438    else
1439      strcpy(ofn1,(char *)srvcmd);      /* No, copy literally. */
1440
1441    /* Now the incoming filename, possibly converted, is in ofn1[]. */
1442
1443#ifdef OS2
1444    /* Don't refuse the file just because the name is illegal. */
1445    if (!IsFileNameValid(ofn1)) {       /* Name is OK for OS/2? */
1446#ifdef __32BIT__
1447        char *zs = NULL;
1448        zstrip(ofn1, &zs);              /* Not valid, strip unconditionally */
1449        if (zs) {
1450            if (iattr.longname.len &&   /* Free previous longname, if any */
1451                iattr.longname.val)
1452              free(iattr.longname.val);
1453            iattr.longname.len = strlen(zs); /* Store in attribute structure */
1454            iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
1455            if (iattr.longname.val)     /* Remember this (illegal) name */
1456              strcpy(iattr.longname.val, zs);
1457        }
1458#endif /* __32BIT__ */
1459        debug(F110,"rcvfil: invalid file name",ofn1,0);
1460        ChangeNameForFAT(ofn1); /* Change to an acceptable name */
1461        debug(F110,"rcvfil: FAT file name",ofn1,0);
1462
1463    } else {                            /* Name is OK. */
1464
1465        debug(F110,"rcvfil: valid file name",ofn1,0);
1466#ifdef __32BIT__
1467        if (iattr.longname.len &&
1468             iattr.longname.val)        /* Free previous longname, if any */
1469          free(iattr.longname.val);
1470        iattr.longname.len = 0;
1471        iattr.longname.val = NULL;      /* This file doesn't need a longname */
1472#endif /* __32BIT__ */
1473    }
1474#endif /* OS2 */
1475    debug(F110,"rcvfil as",ofn1,0);
1476
1477/* Filename collision action section. */
1478
1479    dirflg =                            /* Is it a directory name? */
1480#ifdef CK_TMPDIR
1481        isdir(ofn1)
1482#else
1483        0
1484#endif /* CK_TMPDIR */
1485          ;
1486    debug(F101,"rcvfil dirflg","",dirflg);
1487    ofn1x = (zchki(ofn1) != -1);        /* File already exists? */
1488    debug(F101,"rcvfil ofn1x",ofn1,ofn1x);
1489
1490    if ( (
1491#ifdef UNIX
1492        strcmp(ofn1,"/dev/null") &&     /* It's not the null device? */
1493#else
1494#ifdef OSK
1495        strcmp(ofn1,"/nil") &&  /* It's not the null device? */
1496#endif /* OSK */
1497#endif /* UNIX */
1498        !stdouf ) &&                    /* Not copying to standard output? */
1499        ofn1x ||                        /* File of same name exists? */
1500        dirflg ) {                      /* Or file is a directory? */
1501        debug(F111,"rcvfil exists",ofn1,fncact);
1502        switch (fncact) {               /* Yes, do what user said. */
1503          case XYFX_A:                  /* Append */
1504            debug(F100,"rcvfil append","",0);
1505            if (dirflg) {
1506                rf_err = "Can't append to a directory";
1507                tlog(F100," error - can't append to directory","",0);
1508                discard = opnerr = 1;
1509                return(0);
1510            }
1511            tlog(F110," appending to",ofn1,0);
1512            break;
1513          case XYFX_Q:                  /* Query (Ask) */
1514            break;                      /* not implemented */
1515          case XYFX_B:                  /* Backup (rename old file) */
1516            if (dirflg) {
1517                rf_err = "Can't rename existing directory";
1518                tlog(F100," error - can't rename directory","",0);
1519                discard = opnerr = 1;
1520                return(0);
1521            }
1522            znewn(ofn1,&ofn2);          /* Get new unique name */
1523            tlog(F110," backup:",ofn2,0);
1524            debug(F110,"rcvfil backup ofn1",ofn1,0);
1525            debug(F110,"rcvfil backup ofn2",ofn2,0);
1526#ifdef OS2
1527#ifdef CK_LABELED
1528#ifdef __32BIT__
1529/*
1530  In case this is a FAT file system, we can't change only the FAT name, we
1531  also have to change the longname from the extended attributes block.
1532  Otherwise, we'll have many files with the same longname and if we copy them
1533  to an HPFS volume, only one will survive.
1534*/
1535            if (os2getlongname(ofn1, &longname) > -1) {
1536                if (strlen(longname)) {
1537                    char tmp[10];
1538                    extern int ck_znewn;
1539                    sprintf(tmp,".~%d~",ck_znewn);
1540                    newlongname =
1541                      (char *) malloc(strlen(longname) + strlen(tmp) + 1);
1542                    if (newlongname) {
1543                        strcpy(newlongname, longname);
1544                        strcat(newlongname, tmp);
1545                        os2setlongname(ofn1, newlongname);
1546                        free(newlongname);
1547                        newlongname = NULL;
1548                    }
1549                }
1550            } else debug(F100,"rcvfil os2getlongname failed","",0);
1551#endif /* __32BIT__ */
1552#endif /* CK_LABELED */
1553#endif /* OS2 */
1554
1555#ifdef COMMENT
1556            /* Do this later, in opena()... */
1557            if (zrename(ofn1,ofn2) < 0) {
1558                rf_err = "Can't transform filename";
1559                debug(F110,"rcvfil rename fails",ofn1,0);
1560                discard = opnerr = 1;
1561                return(0);
1562            }
1563#endif /* COMMENT */
1564            break;
1565
1566          case XYFX_D:                  /* Discard (refuse new file) */
1567            discard = 1;
1568            rejection = 1;              /* Horrible hack: reason = name */
1569            debug(F101,"rcvfil discard","",discard);
1570            tlog(F100," refused: name","",0);
1571            break;
1572
1573          case XYFX_R:                  /* Rename incoming file */
1574            znewn(ofn1,&ofn2);          /* Make new name for it */
1575#ifdef OS2
1576#ifdef __32BIT__
1577                if (iattr.longname.len) {
1578                    char tmp[10];
1579                    extern int ck_znewn;
1580                    sprintf(tmp,".~%d~",ck_znewn);
1581                    newlongname =
1582                      (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
1583                    if (newlongname) {
1584                        strcpy(newlongname, iattr.longname.val);
1585                        strcat(newlongname, tmp);
1586                        debug(F110,
1587                              "Rename Incoming: newlongname",newlongname,0);
1588
1589                        if (iattr.longname.len &&
1590                             iattr.longname.val)
1591                          free(iattr.longname.val);
1592                        iattr.longname.len = strlen(newlongname);
1593                        iattr.longname.val = newlongname;
1594                    }
1595                }
1596#endif /* __32BIT__ */
1597#endif /* OS2 */
1598            break;
1599          case XYFX_X:                  /* Replace old file */
1600            debug(F100,"rcvfil overwrite","",0);
1601            if (dirflg) {
1602                rf_err = "Can't overwrite existing directory";
1603                tlog(F100," error - can't overwrite directory","",0);
1604                discard = opnerr = 1;
1605#ifdef COMMENT
1606                return(0);
1607#else
1608                break;
1609#endif /* COMMENT */
1610            }
1611            tlog(F110,"overwriting",ofn1,0);
1612            break;
1613          case XYFX_U:                  /* Refuse if older */
1614            debug(F100,"rcvfil update","",0);
1615            if (dirflg) {
1616                rf_err = "File has same name as existing directory";
1617                tlog(F110," error - directory exists:",ofn1,0);
1618                discard = opnerr = 1;
1619#ifdef COMMENT
1620                /* Don't send an error packet, just refuse the file */
1621                return(0);
1622#endif /* COMMENT */
1623            }
1624            break;                      /* Not here, we don't have */
1625                                        /* the attribute packet yet. */
1626          default:
1627            debug(F101,"rcvfil bad collision action","",fncact);
1628            break;
1629        }
1630    }
1631    debug(F110,"rcvfil ofn1",ofn1,0);
1632    debug(F110,"rcvfil ofn2",ofn2,0);
1633    if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
1634        screen(SCR_AN,0,0l,ofn2);       /* Display renamed name */
1635        strcpy(n, ofn2);                /* Return it */
1636    } else {                            /* No */
1637        screen(SCR_AN,0,0l,ofn1);       /* Display regular name */
1638        strcpy(n, ofn1);                /* and return it. */
1639    }
1640
1641#ifdef CK_MKDIR
1642/*  Create directory(s) if necessary.  */
1643    if (!discard && !fnrpath) {         /* RECEIVE PATHAMES ON? */
1644        debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
1645        if (zmkdir(ofn1) < 0) {
1646            debug(F100,"zmkdir fails","",0);
1647            tlog(F110," error - directory creation failure:",ofn1,0);
1648            rf_err = "Directory creation failure.";
1649            discard = 1;
1650            return(0);
1651        }
1652    }
1653#else
1654    debug(F110,"sfile CK_MKDIR not defined",ofn1,0);
1655#endif /* CK_MKDIR */
1656
1657#ifndef NOICP
1658/* #ifndef MAC */
1659/* Why not Mac? */
1660    strcpy(fspec,ofn1);                 /* Here too for \v(filespec) */
1661/* #endif */
1662#endif /* NOICP */
1663    debug(F110,"rcvfil: n",n,0);
1664    ffc = 0L;                           /* Init per-file counters */
1665    cps = oldcps = 0L;
1666    rs_len = 0L;
1667    rejection = -1;
1668    fsecs = gtimer();                   /* Time this file started */
1669    filcnt++;
1670    intmsg(filcnt);
1671    return(1);                          /* Successful return */
1672}
1673
1674
1675/*  R E O F  --  Receive End Of File packet for incoming file */
1676
1677/*
1678  Closes the received file.
1679  Returns:
1680    0 on success.
1681   -1 if file could not be closed.
1682    2 if disposition was mail, mail was sent, but temp file not deleted.
1683    3 if disposition was print, file was printed, but not deleted.
1684   -2 if disposition was mail and mail could not be sent
1685   -3 if disposition was print and file could not be printed
1686*/
1687int
1688reof(f,yy) char *f; struct zattr *yy; {
1689    int x;
1690    char *p;
1691    char c;
1692
1693    debug(F111,"reof fncact",f,fncact);
1694    debug(F101,"reof discard","",discard);
1695    success = 1;                        /* Assume status is OK */
1696    lsstate = 0;                        /* Cancel locking-shift state */
1697    if (discard) {                      /* Handle attribute refusals, etc. */
1698        debug(F101,"reof discarding","",0);
1699        success = 0;                    /* Status = failed. */
1700        if (rejection == '#' ||         /* Unless rejection reason is */
1701            rejection ==  1  ||         /* date or name (SET FILE COLLISION */
1702            rejection == '?')           /* UPDATE or DISCARD) */
1703          success = 1;                     
1704        debug(F101,"reof success","",success);
1705        filrej++;                       /* Count this rejection. */
1706        discard = 0;                    /* We never opened the file, */
1707        return(0);                      /* so we don't close it. */
1708    }
1709#ifdef DEBUG
1710    if (deblog) {
1711        debug(F101,"reof cxseen","",cxseen);
1712        debug(F101,"reof czseen","",czseen);
1713        debug(F110,"reof rdatap",rdatap,0);
1714    }
1715#endif /* DEBUG */
1716    if (cxseen == 0) cxseen = (*rdatap == 'D'); /* Got cancel directive? */
1717    success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
1718    if (!success) filrej++;             /* "Uncount" this file */
1719    debug(F101,"reof success","",czseen);
1720    x = clsof(cxseen || czseen);        /* Close the file (resets cxseen) */
1721    if (x < 0) {                        /* If failure to close, FAIL */
1722        if (success) filrej++;
1723        success = 0;
1724    }
1725    if (success && atcapu) zstime(f,yy,0); /* Set file creation date */
1726#ifdef OS2
1727#ifdef __32BIT__
1728#ifdef CK_LABELED
1729    if (success && yy->longname.len)
1730      os2setlongname(f, yy->longname.val);
1731#endif /* CK_LABELED */
1732#endif /* __32BIT__ */
1733#endif /* OS2 */
1734    if (success == 0) xitsta |= W_RECV; /* And program return code */
1735
1736/* Handle dispositions from attribute packet... */
1737
1738#ifndef NOFRILLS
1739    if (yy->disp.len != 0) {
1740        p = yy->disp.val;
1741        c = *p++;
1742        if (c == 'M') {                 /* Mail to user. */
1743            x = zmail(p,filnam);        /* Do the system's mail command */
1744            if (x < 0) success = 0;     /* Remember status */
1745            tlog(F110,"mailed",filnam,0L);
1746            tlog(F110," to",p,0L);
1747            zdelet(filnam);             /* Delete the file */
1748        } else if (c == 'P') {          /* Print the file. */
1749            x = zprint(p,filnam);       /* Do the system's print command */
1750            if (x < 0) success = 0;     /* Remember status */
1751            tlog(F110,"printed",filnam,0L);
1752            tlog(F110," with options",p,0L);
1753#ifndef VMS
1754#ifndef STRATUS
1755            /* spooler will delete file after print complete in VOS & VMS */
1756            if (zdelet(filnam) && x == 0) x = 3; /* Delete the file */
1757#endif /* STRATUS */
1758#endif /* VMS */
1759        }
1760    }
1761#endif /* NOFRILLS */
1762    debug(F101,"reof returns","",x);
1763    *filnam = '\0';
1764    return(x);
1765}
1766
1767/*  R E O T  --  Receive End Of Transaction  */
1768
1769VOID
1770reot() {
1771    cxseen = czseen = discard = 0;      /* Reset interruption flags */
1772    tstats();
1773}
1774
1775/*  S F I L E -- Send File header or teXt header packet  */
1776
1777/*  Call with x nonzero for X packet, zero for F packet  */
1778/*  Returns 1 on success, 0 on failure                   */
1779
1780int
1781sfile(x) int x; {
1782#ifdef pdp11
1783#define PKTNL 64
1784#else
1785#define PKTNL 256
1786#endif /* pdp11 */
1787    char pktnam[PKTNL+1];               /* Local copy of name */
1788    char *s;
1789
1790    /* cmarg2 or filnam (with that precedence) have the file's name */
1791
1792    lsstate = 0;                        /* Cancel locking-shift state */
1793    if (nxtpkt() < 0) return(0);        /* Bump packet number, get buffer */
1794    if (x == 0) {                       /* F-Packet setup */
1795        if (cmarg2 && *cmarg2) {        /* If we have a send-as name, */
1796            debug(F111,"sfile cmarg2",cmarg2,cmarg2);
1797            strncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
1798            cmarg2 = "";                /* and blank it out for next time. */
1799        } else {                        /* Otherwise... */
1800            debug(F101,"sfile fnspath","",fnspath);
1801            if (fnspath) {              /* Stripping path names? */
1802                char *t;                /* Yes. */
1803                zstrip(filnam,&t);      /* Strip off the path. */
1804                debug(F110,"sfile zstrip",t,0);
1805                if (!t) t = "UNKNOWN";  /* Be cautious... */
1806                else if (*t == '\0')
1807                  t = "UNKNOWN";
1808                strncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
1809            } else {                    /* No stripping. */
1810                strcpy(pktnam,filnam);  /* Copy whole name. */
1811            }
1812            /* pktnam[] has the packet name, filnam[] has the original name. */
1813            /* But we still need to convert pktnam if FILE NAMES CONVERTED.  */
1814
1815            debug(F101,"SATURDAY fncnv","",fncnv);
1816            if (fncnv) {                /* If converting names, */
1817                zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
1818                strcpy(pktnam,(char *)srvcmd); /* with srvcmd as temp buffer */
1819                *srvcmd = NUL;
1820            }
1821        }
1822        debug(F110,"sfile",filnam,0);   /* Log debugging info */
1823        debug(F110," pktnam",pktnam,0);
1824        if (openi(filnam) == 0)         /* Try to open the input file */
1825          return(0);           
1826#ifdef CK_RESEND
1827        if (sendmode == SM_PSEND)       /* PSENDing? */
1828          if (sendstart > 0L)           /* Starting position */
1829            if (zfseek(sendstart) < 0)  /* seek to it... */
1830              return(0);
1831#endif /* CK_RESEND */
1832        s = pktnam;                     /* Name for packet data field */
1833#ifdef OS2
1834        /* Never send a disk letter. */
1835        if (isalpha(*s) && (*(s+1) == ':'))
1836          s += 2;
1837#endif /* OS2 */
1838
1839    } else {                            /* X-packet setup, not F-packet. */
1840
1841        debug(F110,"sxpack",cmdstr,0);  /* Log debugging info */
1842        s = cmdstr;                     /* Name for data field */
1843    }
1844
1845    /* Now s points to the string that goes in the packet data field. */
1846
1847    encstr((CHAR *)s);                  /* Encode the name. */
1848                                        /* Send the F or X packet */
1849    /* If the encoded string did not fit into the packet, it was truncated. */
1850   
1851#ifdef COMMENT
1852    spack((char) (x ? 'X' : 'F'), pktnum, size, encbuf+7);
1853#else
1854    spack((char) (x ? 'X' : 'F'), pktnum, size, data);
1855#endif /* COMMENT */
1856
1857    if (x == 0) {                       /* Display for F packet */
1858        if (displa) {                   /* Screen */
1859            screen(SCR_FN,'F',(long)pktnum,filnam);
1860            screen(SCR_AN,0,0l,pktnam);
1861            screen(SCR_FS,0,fsize,"");
1862        }
1863#ifdef pdp11
1864        tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
1865#else
1866#ifndef ZFNQFP
1867        tlog(F110,"Sending",filnam,0L);
1868#else
1869        {                               /* Log fully qualified filename */
1870            char *p = NULL, *q = filnam;
1871            if ((p = malloc(CKMAXPATH+1)))
1872              if (zfnqfp(filnam, CKMAXPATH, p))
1873                q = p;
1874            tlog(F110,"Sending",q,0L);
1875            if (p) free(p);
1876        }
1877#endif /* ZFNQFP */
1878#endif /* pdp11 */
1879        tlog(F110," as",pktnam,0L);
1880        if (binary) {                   /* Log file mode in transaction log */
1881            tlog(F101," mode: binary","",(long) binary);
1882        } else {                        /* If text mode, check character set */
1883            tlog(F100," mode: text","",0L);
1884#ifndef NOCSETS
1885            tlog(F110," file character set",fcsinfo[fcharset].name,0L);
1886            if (tcharset == TC_TRANSP)
1887              tlog(F110," xfer character set","transparent",0L);
1888            else
1889              tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
1890#endif /* NOCSETS */
1891        }
1892    } else {                            /* Display for X-packet */
1893
1894        screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
1895        tlog(F110,"Sending from:",cmdstr,0L);   /* Transaction log */
1896    }
1897    intmsg(++filcnt);                   /* Count file, give interrupt msg */
1898    first = 1;                          /* Init file character lookahead. */
1899    ffc = 0L;                           /* Init file character counter. */
1900    cps = oldcps = 0L;                  /* Init cps statistics */
1901    rejection = -1;
1902    fsecs = gtimer();                   /* Time this file started */
1903    debug(F101,"SFILE fsecs","",fsecs);
1904    return(1);
1905}
1906
1907/*  S D A T A -- Send a data packet */
1908
1909/*
1910  Returns -1 if no data to send (end of file), -2 if connection is broken.
1911  If there is data, a data packet is sent, and sdata() returns 1.
1912
1913  For window size greater than 1, we keep sending data packets until window
1914  is full or characters start to appear from the other Kermit, whichever
1915  happens first.
1916
1917  In the windowing case, when there is no more data left to send (or when
1918  sending has been interrupted), sdata() does nothing and returns 0 each time
1919  it is called until the current packet number catches up to the last data
1920  packet that was sent.
1921*/
1922
1923int
1924sdata() {
1925    int i, x, len;
1926   
1927    debug(F101,"sdata entry, first","",first);
1928    debug(F101," drain","",drain);
1929
1930/* The "drain" flag is used with window size > 1.  It means we have sent  */
1931/* our last data packet.  If called and drain is not zero, then we return */
1932/* 0 as if we had sent an empty data packet, until all data packets have  */
1933/* been ACK'd, then then we can finally return -1 indicating EOF, so that */
1934/* the protocol can switch to seof state.  This is a kludge, but at least */
1935/* it's localized...  */
1936
1937    if (first == 1) drain = 0;          /* Start of file, init drain flag. */
1938
1939    if (drain) {                        /* If draining... */
1940        debug(F101,"sdata draining, winlo","",winlo);
1941        if (winlo == pktnum)            /* If all data packets are ACK'd */
1942          return(-1);                   /* return EOF indication */
1943        else                            /* otherwise */
1944          return(0);                    /* pretend we sent a data packet. */
1945    }
1946    debug(F101,"sdata sbufnum","",sbufnum);
1947    for (i = sbufnum; i > 0; i--) {
1948        debug(F101,"sdata countdown","",i);
1949        x = nxtpkt();                   /* Get next pkt number and buffer */
1950        debug(F101,"sdata packet","",pktnum);
1951        if (x < 0) return(0);
1952        if (cxseen || czseen) {         /* If interrupted, done. */
1953            if (wslots > 1) {
1954                drain = 1;
1955                debug(F101,"sdata cx/zseen, drain","",cxseen);
1956                return(0);
1957            } else {
1958                return(-1);
1959            }
1960        }
1961        debug(F101,"sdata spsiz","",spsiz);
1962        len = getpkt(spsiz,1);
1963        if (len == 0) {                 /* Done if no data. */
1964            if (pktnum == winlo) return(-1);
1965            drain = 1;                  /* But can't return -1 until all */
1966            debug(F101,"sdata eof, drain","",drain);
1967            return(0);                  /* ACKs are drained. */
1968        }
1969        spack('D',pktnum,len,data);     /* Send the data packet. */
1970/*
1971  We should also want to call chkint() here to catch keyboard interruptions.
1972  But its return codes don't tell us whether we should return from here or
1973  keep going.
1974*/
1975        x = ttchk();                    /* Peek at input buffer. */
1976        debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe?  */
1977        if (x < 0)                      /* Or connection broken? */
1978          return(-2);
1979/*
1980  Here we check to see if any ACKs or NAKs have arrived, in which case we
1981  break out of the D-packet-sending loop and return to the state switcher
1982  to process them.  This is what makes our windows slide instead of lurch.
1983*/
1984        if (
1985#ifdef GEMDOS
1986/*
1987  In the Atari ST version, ttchk() can only return 0 or 1.  But note: x will
1988  probably always be > 0, since the as-yet-unread packet terminator from the
1989  last packet is probably still in the buffer, so sliding windows will
1990  probably never happen when the Atari ST is the file sender.  The alternative
1991  is to say "if (0)", in which case the ST will always send a window full of
1992  packets before reading any ACKs or NAKs.
1993*/
1994            x > 0
1995 
1996#else /* !GEMDOS */
1997/*
1998  In most other versions, ttchk() returns the actual count.
1999  It can't be a Kermit packet if it's less than five bytes long.
2000*/
2001            x > 4 + bctu
2002 
2003#endif /* GEMDOS */
2004            )
2005          return(1);                    /* Yes, stop sending data packets */
2006    }                                   /* and go try to read the ACKs. */
2007    return(1);
2008}
2009
2010
2011/*  S E O F -- Send an End-Of-File packet */
2012
2013/*  Call with a string pointer to character to put in the data field, */
2014/*  or else a null pointer or "" for no data.  */
2015
2016/*
2017  There are two "send-eof" functions.  seof() is used to send the normal eof
2018  packet at the end of a file's data (even if the file has no data), or when
2019  a file transfer is interrupted.  sxeof() is used to send an EOF packet that
2020  occurs because of attribute refusal.  The difference is purely a matter of
2021  buffer allocation and packet sequence number management.  Both functions
2022  act as "front ends" to the common send-eof function, szeof().
2023*/
2024
2025/* Code common to both seof() and sxeof() */
2026
2027int
2028szeof(s) CHAR *s; {
2029    lsstate = 0;                        /* Cancel locking-shift state */
2030    if ((s != NULL) && (*s != '\0')) {
2031        spack('Z',pktnum,1,s);
2032        xitsta |= W_SEND;
2033        tlog(F100," *** interrupted, sending discard request","",0L);
2034        filrej++;
2035    } else {
2036        spack('Z',pktnum,0,(CHAR *)"");
2037    }
2038    discard = 0;                        /* Turn off per-file discard flag */
2039    return(0);
2040}
2041
2042int
2043seof(s) CHAR *s; {
2044
2045/*
2046  ckcpro.w, before calling seof(), sets window size back to 1 and then calls
2047  window(), which clears out the old buffers.  This is OK because the final
2048  data packet for the file has been ACK'd.  However, sdata() has already
2049  called nxtpkt(), which set the new value of pktnum which seof() will use.
2050  So all we need to do here is is allocate a new send-buffer.
2051*/
2052    if (getsbuf(pktnum) < 0) {  /* Get a buffer for packet n */
2053        debug(F101,"seof can't get s-buffer","",pktnum);
2054        return(-1);
2055    }
2056    return(szeof(s));
2057}
2058
2059/*
2060  Version of seof() to be called when sdata() has not been called before.  The
2061  difference is that this version calls nxtpkt() to allocate a send-buffer and
2062  get the next packet number.
2063*/
2064int
2065sxeof(s) CHAR *s; {
2066    int x;
2067    x = nxtpkt();                       /* Get next pkt number and buffer */
2068    if (x < 0)
2069      debug(F101,"sxeof nxtpkt fails","",pktnum);
2070    else
2071      debug(F101,"sxeof packet","",pktnum);
2072    return(szeof(s));
2073}
2074
2075/*  S E O T -- Send an End-Of-Transaction packet */
2076
2077int
2078seot() {
2079    if (nxtpkt() < 0) return(-1);       /* Bump packet number, get buffer */
2080    spack('B',pktnum,0,(CHAR *)"");     /* Send the EOT packet */
2081    cxseen = czseen = discard = 0;      /* Reset interruption flags */
2082    tstats();                           /* Log timing info */
2083    return(0);
2084}
2085
2086
2087/*   R P A R -- Fill the data array with my send-init parameters  */
2088
2089CHAR dada[32];                          /* Use this instead of data[]. */
2090                                        /* To avoid some kind of wierd */
2091                                        /* addressing foulup in spack()... */
2092                                        /* (which might be fixed now...) */
2093
2094CHAR *
2095rpar() {
2096    char *p;
2097    int i, x;
2098    extern int xfermode;
2099    if (rpsiz > MAXPACK)                /* Biggest normal packet I want. */
2100      dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */
2101    else                                /* extended packet length below... */
2102      dada[0] = (char) tochar(rpsiz);   /* else use what the user said. */
2103    dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
2104    dada[2] = (char) tochar(mypadn);    /* How much padding I need (none) */
2105    dada[3] = (char) ctl(mypadc);       /* Padding character I want */
2106    dada[4] = (char) tochar(eol);       /* End-Of-Line character I want */
2107    dada[5] = myctlq;                   /* Control-Quote character I send */
2108
2109    switch (rqf) {                      /* 8th-bit prefix (single-shift) */
2110      case -1:                          /* I'm opening the bids */
2111      case  1:                          /* Other Kermit already bid 'Y' */
2112        if (parity) ebq = sq = MYEBQ;   /* So I reply with '&' if parity */
2113        break;                          /*  otherwise with 'Y'. */
2114      case  0:                          /* Other Kermit bid nothing */
2115      case  2:                          /* Other Kermit sent a valid prefix */
2116        break;                          /* So I reply with 'Y'. */
2117    }
2118    debug(F000,"rpar 8bq sq","",sq);
2119    debug(F000,"rpar 8bq ebq","",ebq);
2120    if (lscapu == 2)                    /* LOCKING-SHIFT FORCED */
2121      dada[6] = 'N';                    /* requires no single-shift */
2122    else                                /* otherwise send prefix or 'Y' */
2123      dada[6] = (char) sq;
2124    ebqsent = dada[6];                  /* And remember what I really sent */
2125
2126    dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
2127    if (rptena) {
2128        if (rptflg)                     /* Run length encoding */
2129          dada[8] = (char) rptq;        /* If receiving, agree */
2130        else                            /* by replying with same character. */
2131          dada[8] = (char) (rptq = myrptq); /* When sending use this. */
2132    } else dada[8] = SP;                /* Not enabled, put a space here. */
2133
2134    /* CAPAS mask */
2135
2136    dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
2137                     (atcapr ? atcapb : 0) | /* Attribute packets */
2138                     (lpcapr ? lpcapb : 0) | /* Long packets */
2139                     (swcapr ? swcapb : 0) | /* Sliding windows */
2140                     (rscapr ? rscapb : 0)); /* RESEND */
2141    dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
2142    if (urpsiz > 94)
2143      rpsiz = urpsiz - 1;               /* Long packets ... */
2144    dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
2145    dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
2146    dada[13] = '0';                     /* CAPAS+4 = WONT CHKPNT */
2147    dada[14] = '_';                     /* CAPAS+5 = CHKINT (reserved) */
2148    dada[15] = '_';                     /* CAPAS+6 = CHKINT (reserved) */
2149    dada[16] = '_';                     /* CAPAS+7 = CHKINT (reserved) */
2150#ifndef WHATAMI
2151    dada[17] = ' ';
2152#else
2153    dada[17] = (char) tochar( WM_FLAG | /* CAPAS+8 = WHATAMI... */
2154      (server ? WM_SERVE : 0)    |      /* I am (not) a server */
2155        (binary ? WM_FMODE : 0)  |      /*  My file transfer mode is ... */
2156          (fncnv ? WM_FNAME : 0));      /*    My filename conversion is ... */
2157#endif /* WHATAMI */
2158    i = 18;                             /* Position of next field */
2159    if (xfermode == XMODE_A) {          /* If TRANSFER MODE AUTOMATIC */
2160        p = cksysid;                    /* WHOAMI (my system ID) */
2161        x = strlen(p);
2162        if (x > 0) {
2163            dada[i++] = (char) tochar(x);
2164            while (*p)
2165              dada[i++] = *p++;
2166        }
2167    } else {                            /* TRANSFER MODE MANUAL */
2168        dada[i++] = (char) tochar(1);   /* Length */
2169        dada[i++] = '0';                /* "0" means anonymous - don't do it */
2170    }
2171    dada[i] = '\0';                     /* Terminate the init string */
2172
2173#ifdef DEBUG
2174    if (deblog) {
2175        debug(F110,"rpar",dada,0);
2176        rdebu(dada,(int)strlen((char *)dada));
2177    }
2178#endif /* DEBUG */
2179    strcpy((char *)myinit,(char *)dada);
2180    return(dada);                       /* Return pointer to string. */
2181}
2182
2183int
2184spar(s) CHAR *s; {                      /* Set parameters */
2185    int x, y, lpsiz;
2186
2187    debug(F110,"entering spar",s,0);
2188
2189    s--;                                /* Line up with field numbers. */
2190
2191/* Limit on size of outbound packets */
2192    x = (rln >= 1) ? xunchar(s[1]) : 80;
2193    lpsiz = spsizr;                     /* Remember what they SET. */
2194    if (spsizf) {                       /* SET-command override? */
2195        if (x < spsizr) spsiz = x;      /* Ignore LEN unless smaller */
2196    } else {                            /* otherwise */
2197        spsiz = (x < 10) ? 80 : x;      /* believe them if reasonable */
2198    }
2199    spmax = spsiz;                      /* Remember maximum size */
2200
2201/* Timeout on inbound packets */
2202    if (timef) {
2203        timint = rtimo;                 /* SET SEND TIMEOUT value overrides */
2204    } else {                            /* Otherwise use requested value, */
2205        x = (rln >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
2206        timint = (x < 0) ? rtimo : x;
2207    }
2208    timint = chktimo(timint,timef);     /* Adjust if necessary */
2209
2210/* Outbound Padding */
2211    npad = 0; padch = '\0';
2212    if (rln >= 3) {
2213        npad = xunchar(s[3]);
2214        if (rln >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
2215    }
2216    if (npad) {
2217        int i;
2218        for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
2219    }
2220
2221/* Outbound Packet Terminator */
2222    seol = (CHAR) (rln >= 5) ? xunchar(s[5]) : CR;
2223    if ((seol < 1) || (seol > 31)) seol = CR;
2224
2225/* Control prefix that the other Kermit is sending */
2226    x = (rln >= 6) ? s[6] : '#';
2227    ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
2228
2229/* 8th-bit prefix */
2230/*
2231  NOTE: Maybe this could be simplified using rcvtyp.
2232  If rcvtyp == 'Y' then we're reading the ACK,
2233  otherwise we're reading the other Kermit's initial bid.
2234  But his horrendous code works, so leave it alone for now.
2235*/
2236    rq = (rln >= 7) ? s[7] : 0;
2237    if (rq == 'Y') rqf = 1;
2238      else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
2239        else rqf = 0;
2240    debug(F000,"spar 8bq rq","",rq);
2241    debug(F000,"spar 8bq sq","",sq);
2242    debug(F000,"spar 8bq ebq","",ebq);
2243    debug(F101,"spar 8bq rqf","",rqf);
2244    switch (rqf) {
2245      case 0:                           /* Field is missing from packet. */
2246        ebqflg = 0;                     /* So no 8th-bit prefixing. */
2247        break;
2248      case 1:                           /* Other Kermit sent 'Y' = Will Do. */
2249        /*
2250          When I am the file receiver, ebqsent is 0 because I didn't send a
2251          negotiation yet.  If my parity is set to anything other than NONE,
2252          either because my user SET PARITY or because I detected parity bits
2253          on this packet, I reply with '&', otherwise 'Y'.
2254
2255          When I am the file sender, ebqsent is what I just sent in rpar(),
2256          which can be 'Y', 'N', or '&'.  If I sent '&', then this 'Y' means
2257          the other Kermit agrees to do 8th-bit prefixing.
2258
2259          If I sent 'Y' or 'N', but then detected parity on the ACK packet
2260          that came back, then it's too late: there is no longer any way for
2261          me to tell the other Kermit that I want to do 8th-bit prefixing, so
2262          I must not do it, and in that case, if there is any 8-bit data in
2263          the file to be transferred, the transfer will fail because of block
2264          check errors.
2265
2266          The following clause covers all of these situations:
2267        */
2268        if (parity && (ebqsent == 0 || ebqsent == '&')) {
2269            ebqflg = 1;
2270            ebq = MYEBQ;
2271        }
2272        break;
2273      case 2:                           /* Other Kermit send a valid prefix */
2274        if (ebqflg = (ebq == sq || sq == 'Y'))
2275          ebq = rq;
2276    }
2277    if (lscapu == 2) {     /* But no single-shifts if LOCKING-SHIFT FORCED */
2278        ebqflg = 0;
2279        ebq = 'N';
2280    }
2281
2282/* Block check */
2283    x = 1;
2284    if (rln >= 8) {
2285        if (s[8] == 'B') x = 4;
2286        else x = s[8] - '0';
2287        if ((x < 1) || (x > 4)) x = 1;
2288    }
2289    bctr = x;
2290
2291/* Repeat prefix */
2292
2293    rptflg = 0;                         /* Assume no repeat-counts */
2294    if (rln >= 9) {                     /* Is there a repeat-count field? */
2295        char t;                         /* Yes. */
2296        t = s[9];                       /* Get its contents. */
2297/*
2298  If I'm sending files, then I'm reading these parameters from an ACK, and so
2299  this character must agree with what I sent.
2300*/
2301        if (rptena) {                   /* If enabled ... */
2302            if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */
2303                if (t == myrptq) rptflg = 1;
2304            } else {                    /* I'm receiving files */
2305                if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
2306                    rptflg = 1;
2307                    rptq = t;
2308                }
2309            }
2310        } else rptflg = 0;
2311    }
2312
2313/* Capabilities */
2314
2315    atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
2316    if (lscapu != 2) lscapu = 0;        /* Assume no LS unless forced. */
2317    y = 11;                             /* Position of next field, if any */
2318    if (rln >= 10) {
2319        x = xunchar(s[10]);
2320        debug(F101,"spar capas","",x);
2321        atcapu = (x & atcapb) && atcapr; /* Attributes */
2322        lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
2323        swcapu = (x & swcapb) && swcapr; /* Sliding windows */
2324        rscapu = (x & rscapb) && rscapr; /* RESEND */
2325        debug(F101,"spar lscapu","",lscapu);
2326        debug(F101,"spar lscapr","",lscapr);
2327        debug(F101,"spar ebqflg","",ebqflg);
2328        if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
2329        debug(F101,"spar swcapr","",swcapr);
2330        debug(F101,"spar swcapu","",swcapu);
2331        debug(F101,"spar lscapu","",lscapu);
2332        for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++);
2333        debug(F101,"spar y","",y);
2334    }
2335
2336/* Long Packets */
2337    debug(F101,"spar lpcapu","",lpcapu);
2338    if (lpcapu) {
2339        if (rln > y+1) {
2340            x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
2341            debug(F101,"spar lp len","",x);
2342            if (spsizf) {               /* If overriding negotiations */
2343                spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
2344            } else {                             /* otherwise */
2345                spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
2346            }
2347            if (spsiz < 10) spsiz = 80; /* Be defensive... */
2348        }
2349    }
2350    /* (PWP) save current send packet size for optimal packet size calcs */
2351    spmax = spsiz;                      /* Maximum negotiated length */
2352    if (slostart && spsiz > 499) spsiz = 244; /* Slow start length */
2353    debug(F101,"spar slow-start spsiz","",spsiz);
2354    debug(F101,"spar lp spmax","",spmax);
2355    timint = chktimo(timint,timef);     /* Recalculate the packet timeout */
2356   
2357/* Sliding Windows... */
2358
2359    if (swcapr) {                       /* Only if requested... */
2360        if (rln > y) {                  /* See what other Kermit says */
2361            x = xunchar(s[y+1]);
2362            debug(F101,"spar window","",x);
2363            wslotn = (x > MAXWS) ? MAXWS : x;
2364/*
2365  wslotn = negotiated size (from other Kermit's S or I packet).
2366  wslotr = requested window size (from this Kermit's SET WINDOW command).
2367*/
2368            if (wslotn > wslotr)        /* Use the smaller of the two */
2369              wslotn = wslotr;
2370            if (wslotn < 1)             /* Watch out for bad negotiation */
2371              wslotn = 1;
2372            if (wslotn > 1) {
2373                swcapu = 1;             /* We do windows... */
2374                if (wslotn > maxtry)    /* Retry limit must be greater */
2375                  maxtry = wslotn + 1;  /* than window size. */
2376            }
2377            debug(F101,"spar window after adjustment","",x);
2378        } else {                        /* No window size specified. */
2379            wslotn = 1;                 /* We don't do windows... */
2380            debug(F101,"spar window","",x);
2381            swcapu = 0;
2382            debug(F101,"spar no windows","",wslotn);
2383        }
2384    }
2385
2386/* Now recalculate packet length based on number of windows.   */
2387/* The nogotiated number of window slots will be allocated,    */
2388/* and the maximum packet length will be reduced if necessary, */
2389/* so that a windowful of packets can fit in the big buffer.   */
2390
2391    if (wslotn > 1) {                   /* Shrink to fit... */
2392        x = adjpkl(spmax,wslotn,bigsbsiz);
2393        if (x < spmax) {
2394            spmax = x;
2395            if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
2396            debug(F101,"spar sending, redefine spmax","",spmax);
2397        }
2398    }
2399#ifdef WHATAMI
2400    if (rln > y+7)                      /* Get WHATAMI info if any */
2401      whatru = xunchar(s[y+8]);
2402#endif /* WHATAMI */
2403
2404    if (rln > y+8) {                    /* Get WHOAREYOU info if any */
2405        int x;
2406        x = xunchar(s[y+9]);            /* Length of it */
2407        if (x > 0 && x < 16 && rln >= y + 9 + x) {
2408            strncpy(whoareu,(char *)s+y+10,x); /* Other Kermit's system ID */
2409            if (whoareu[0]) {           /* Got one? */
2410                char *p;
2411#ifdef COMMENT
2412                char buf[64];
2413#endif /* COMMENT */
2414                extern int sysindex;
2415                extern struct sysdata sysidlist[];
2416
2417                sysindex = getsysix((char *)whoareu);
2418                if (sysindex > -1) {
2419                    p = sysidlist[sysindex].sid_name;
2420#ifdef COMMENT
2421                    sprintf(buf,"Remote system type is %s", p);
2422                    screen(SCR_ST,ST_MSG,0L,buf);
2423#endif /* COMMENT */
2424                    tlog(F110,"Remote system type: ",p,0L);
2425                    if (sysindex > 0)   /* Skip this for "anonymous" */
2426                      whoarewe();
2427                }
2428            }
2429        }
2430    }
2431/* Record parameters in debug log */
2432#ifdef DEBUG
2433    if (deblog) sdebu(rln);
2434#endif /* DEBUG */
2435    numerrs = 0;                        /* Start counting errors here. */
2436    return(0);
2437}
2438
2439/*  G N F I L E  --  Get name of next file to send  */
2440/*
2441  Expects global sndsrc to be:
2442   -1: next filename to be obtained by calling znext().
2443    0: no next file name
2444    1: (or greater) next filename to be obtained from **cmlist,
2445       or if addlist != 0, from the "filehead" linked list.
2446  Returns:
2447    1, with name of next file in filnam.
2448    0, no more files, with filnam set to empty string.
2449   -1, file not found
2450   -2, file is not readable
2451   -3, read access denied
2452   -4, cancelled
2453   -5, too many files match wildcard
2454*/
2455
2456int
2457gnfile() {
2458    int i, x; long y;
2459    int retcode = 0;
2460    char fullname[CKMAXPATH+1];
2461
2462    debug(F101,"gnfile sndsrc","",sndsrc);
2463    fsize = -1L;                        /* Initialize file size */
2464    if (sndsrc == 0) {                  /* It's not really a file */
2465        if (nfils > 0) {                /* It's a pipe, or stdin */
2466            strcpy(filnam, *cmlist);    /* Copy its "name" */
2467            nfils = 0;                  /* There is no next file */
2468            return(1);                  /* OK this time */
2469        } else return(0);               /* but not next time */
2470    }
2471
2472/* If file group interruption (C-Z) occurred, fail.  */
2473
2474    if (czseen) {
2475        tlog(F100,"Transaction cancelled","",0L);
2476        debug(F100,"gnfile czseen","",0);
2477        return(-4);
2478    }
2479
2480/* Loop through file list till we find a readable, sendable file */
2481
2482    y = -1L;                            /* Loop exit (file size) variable */
2483    while (y < 0L) {                    /* Keep trying till we get one... */
2484        if (sndsrc > 0) {               /* File list in cmlist */
2485            debug(F101,"gnfile nfils","",nfils);
2486            if (nfils-- > 0) {          /* Still some left? */
2487#ifndef NOMSEND
2488                if (addlist) {
2489                    if (filenext && filenext->fl_name) {
2490                        strncpy(filnam,filenext->fl_name,CKMAXPATH);
2491                        cmarg2 =
2492                          filenext->fl_alias ?
2493                            filenext->fl_alias :
2494                              "";
2495                        binary = filenext->fl_mode; /* plug and pray... */
2496                    } else {
2497                        printf("?Internal error expanding ADD list\n");
2498                        return(-5);
2499                    }
2500                    filenext = filenext->fl_next;
2501                    debug(F111,"gnfile addlist filnam",filnam,nfils);
2502                } else {
2503#endif /* NOMSEND */
2504                    strncpy(filnam,*cmlist++,CKMAXPATH);
2505                    debug(F111,"gnfile cmlist filnam",filnam,nfils);
2506#ifndef NOMSEND
2507                }
2508#endif /* NOMSEND */
2509                i = 0;
2510#ifndef NOSERVER
2511                debug(F101,"gnfile ngetpath","",ngetpath);
2512#endif /* NOSERVER */
2513nextinpath:
2514#ifndef NOSERVER
2515                if (server && !isabsolute(filnam) && (ngetpath > i)) {
2516                    strncpy(fullname,getpath[i],CKMAXPATH);
2517                    strncat(fullname,filnam,CKMAXPATH);
2518                    debug(F111,"gnfile getpath",fullname,i);
2519                    i++;
2520                } else {
2521                    i = ngetpath + 1;
2522#else
2523                    i = 1;              /* ? */
2524#endif /* NOSERVER */
2525                    strncpy(fullname,filnam,CKMAXPATH);
2526                    debug(F110,"gnfile absolute",fullname,0);
2527#ifndef NOSERVER
2528                }
2529#endif /* NOSERVER */
2530                if (iswild(fullname)) { /* It looks wild... */
2531                    /* First check if a file with this name exists */
2532                    debug(F110,"gnfile wild",fullname,0);
2533                    if (zchki(fullname) > -1) {
2534                        /*
2535                           Here we have a file whose name actually
2536                           contains wildcard characters.
2537                        */
2538                        goto gotnam;
2539                    }
2540                    x = zxpand(fullname); /* Now try to expand wildcards */
2541                    debug(F101,"gnfile zxpand","",x);
2542                    if (x == 1) {
2543                        znext(fullname);
2544                        debug(F110,"gnfile znext",fullname,0);
2545                        goto gotnam;
2546                    }
2547                    if (x == 0) {       /* None match */
2548#ifndef NOSERVER
2549                        if (server && ngetpath > i)
2550                          goto nextinpath;
2551#endif /* NOSERVER */
2552                        retcode = -1;
2553                        continue;
2554                    }
2555                    if (x < 0)          /* Too many to expand */
2556                      return(-5);
2557                    sndsrc = -1;        /* Change send-source to znext() */
2558                }
2559            } else {                    /* We're out of files. */
2560                debug(F101,"gnfile done","",nfils);
2561                *filnam = '\0';
2562                return(retcode);
2563            }
2564        }
2565
2566/* Otherwise, step to next element of internal wildcard expansion list. */
2567
2568        if (sndsrc < 0) {
2569            x = znext(filnam);
2570            debug(F111,"gnfile znext",filnam,x);
2571            if (x == 0) {               /* If no more, */
2572                sndsrc = 1;             /* go back to list */
2573                continue;
2574            } else strncpy(fullname,filnam,CKMAXPATH);
2575        }
2576
2577/* Get here with a filename. */
2578
2579gotnam:
2580        if (sndsrc) {
2581            y = zchki(fullname);        /* Check if file readable */
2582            retcode = (int) y;          /* Possible return code */
2583            if (y == -1L) {             /* If not found */
2584#ifndef NOSERVER
2585                if (server && ngetpath > i)
2586                  goto nextinpath;
2587#endif /* NOSERVER */
2588                debug(F110,"gnfile skipping:",fullname,0);
2589                tlog(F111,fullname,"not sent, reason",(long)y);
2590                screen(SCR_ST,ST_SKIP,0l,fullname);
2591                continue;
2592            } else if (y < 0) {
2593                if (y == -3) {          /* Exists but not readable */
2594                    filrej++;           /* Count this one as not sent */
2595                    tlog(F110,"Read access denied",fullname,0); /* Log this */
2596                    screen(SCR_ST,ST_SKIP,0l,fullname); /* Display message */
2597                }
2598                continue;
2599            } else {
2600                fsize = y;
2601                strncpy(filnam,fullname,CKMAXPATH);
2602                return(1);
2603            }
2604        } else {                        /* sndsrc is 0... */
2605            strncpy(filnam,fullname,CKMAXPATH);
2606            return(1);
2607        }
2608    }
2609    *filnam = '\0';                     /* Should never get here */
2610    return(0);
2611}
2612
2613/*  S N D H L P  --  Routine to send builtin help  */
2614
2615int
2616sndhlp(p) char *p; {
2617#ifndef NOSERVER
2618    nfils = 0;                          /* No files, no lists. */
2619    xflg = 1;                           /* Flag we must send X packet. */
2620    strcpy(cmdstr,versio);              /* Data for X packet. */
2621    first = 1;                          /* Init getchx lookahead */
2622    memstr = 1;                         /* Just set the flag. */
2623    memptr = p;                         /* And the pointer. */
2624    binary = XYFT_T;                    /* Text mode for this. */
2625    return(sinit());
2626#else
2627    return(0);
2628#endif /* NOSERVER */
2629}
2630
2631/*
2632  The following bunch of routines feed internally generated data to the server
2633  to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
2634  and so on.  Note that in writing this data to buffers, we do not use "\n".
2635  Instead we use "\15\12", i.e. LITERAL carriage return and linefeed, because
2636  that it was is required by the Kermit protocol in text mode.
2637*/
2638static
2639char funcbuf[512];
2640static int
2641  funcnxt = 0,
2642  funclen = 0,
2643  nxpnd = - 1;
2644static long
2645  ndirs =   0,
2646  nfiles =  0,
2647  nbytes =  0;
2648
2649/*  N X T T Y P -- provide data to type file to remote client */
2650/*
2651   Returns the next available character,
2652  -1 if no more data.
2653*/
2654int
2655nxttype() {
2656    int c;
2657
2658    if (zchin(ZIFILE,&c) < 0) {
2659        zclose(ZIFILE);
2660        return(-1);
2661    } else
2662      return((unsigned)c);
2663}
2664
2665/*  S N D T Y P -- TYPE a file to remote client */
2666
2667int
2668#ifdef CK_ANSI
2669sndtype(char * file)
2670#else
2671sndtype(file) char * file;
2672#endif /* CK_ANSI */
2673/* sndtype */ {
2674
2675#ifndef NOSERVER
2676    char * p = NULL, name[CKMAXPATH+1];
2677
2678#ifdef OS2
2679    if (*file) {
2680        strcpy(name, file);
2681        /* change / to \. */
2682        p = name;
2683        while (*p) {                    /* Change them back to \ */
2684            if (*p == '/') *p = '\\';
2685            p++;
2686        }
2687    } else
2688      return(0);
2689#else
2690    strcpy(name, file);
2691#endif /* OS2 */
2692
2693    funcnxt = 0;
2694    funclen = strlen(funcbuf);
2695    if (zchki(name) == -2) {
2696        /* Found a directory */
2697        return(0);
2698    }
2699    if (!zopeni(ZIFILE,name))
2700      return(0);
2701
2702    nfils = 0;                          /* No files, no lists. */
2703    xflg = 1;                           /* Flag we must send X packet. */
2704    strcpy(cmdstr,"type");              /* Data for X packet. */
2705    first = 1;                          /* Init getchx lookahead */
2706    funcstr = 1;                        /* Just set the flag. */
2707    funcptr = nxttype;                  /* And the pointer. */
2708    binary = XYFT_T;                    /* Text mode for this */
2709    return(sinit());
2710#else
2711    return(0);
2712#endif /* NOSERVER */
2713}
2714
2715/*
2716   N X T D I R  --  Provide data for senddir()
2717
2718   Returns the next available character or -1 if no more data.
2719*/
2720static int
2721nxtdir() {
2722    char name[257], *p = NULL;
2723    char * dstr = NULL;
2724    long len = 0;
2725    short month = 0, date = 0, year = 0, hour = 0, minute = 0, seconds = 0;
2726
2727    debug(F111,"nxtdir","funcnxt",funcnxt);
2728    debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
2729    if (funcnxt < funclen)
2730      return (funcbuf[funcnxt++]);
2731
2732    if (nxpnd > 0) {
2733        nxpnd--;
2734        if (!znext(name)) {
2735            nxpnd = 0;
2736            return(nxtdir());
2737        }
2738        dstr = zfcdat(name);
2739        if (!dstr) dstr = "";
2740        if (*dstr) {
2741            month = (dstr[4]-48)*10 + (dstr[5]-48);
2742#ifdef COMMENT
2743            switch(month) {             /* For anglophones only... */
2744              case 1:  mstr = "Jan"; break;
2745              case 2:  mstr = "Feb"; break;
2746              case 3:  mstr = "Mar"; break;
2747              case 4:  mstr = "Apr"; break;
2748              case 5:  mstr = "May"; break;
2749              case 6:  mstr = "Jun"; break;
2750              case 7:  mstr = "Jul"; break;
2751              case 8:  mstr = "Aug"; break;
2752              case 9:  mstr = "Sep"; break;
2753              case 10: mstr = "Oct"; break;
2754              case 11: mstr = "Nov"; break;
2755              case 12: mstr = "Dec"; break;
2756              default: mstr = "   ";
2757            }
2758#endif /* COMMENT */
2759            date = (dstr[6]-48)*10 + (dstr[7]-48);
2760            year = (((dstr[0]-48)*10 + (dstr[1]-48))*10
2761                    + (dstr[2]-48))*10 + (dstr[3]-48);
2762            hour = (dstr[9]-48)*10 + (dstr[10]-48);
2763            minute = (dstr[12]-48)*10 + (dstr[13]-48);
2764            seconds = (dstr[15]-48)*10 + (dstr[16]-48);
2765        } else {
2766            month = 0;
2767            date = 0;
2768            year = 0;
2769            hour = 0;
2770            minute = 0;
2771            seconds = 0;
2772        }
2773        len = zchki(name);
2774        /* Find just the name of the file */
2775#ifdef VMS
2776        p = name + ckindex("]",name,0,0,1);
2777#else
2778        for (p = name + (int) strlen(name);
2779             p != name && *p != '/'
2780#ifdef OS2
2781             && *p != '\\' && *p != ':'
2782#endif /* OS2 */             
2783              ; p--
2784             );
2785        if (*p == '/'
2786#ifdef OS2
2787             || *p == '\\' || *p == ':'
2788#endif /* OS2 */
2789            )
2790          p++;
2791#endif /* VMS */
2792        if (len > -1L) {
2793            nfiles++;
2794            nbytes += len;
2795            sprintf(funcbuf," %04d-%02d-%02d %02d:%02d %11ld %s\15\12",
2796                    year, month, date, hour, minute, len, p);
2797        } else {
2798            ndirs++;
2799            sprintf(funcbuf,
2800                    " %04d-%02d-%02d %02d:%02d %11s %s\15\12",
2801                    year, month, date, hour, minute, "(directory)", p);
2802        }
2803        funcnxt = 0;
2804        funclen = strlen(funcbuf);
2805    } else if (nxpnd == 0) {            /* Done, send summary */
2806        char *blankline = "";           /* At beginning of summary */
2807        char *endline = "\15\12";       /* At end of summary */
2808/*
2809  The idea is to prevent (a) unnecessary multiple blanklines, and (b)
2810  prompt-stomping.  Preventing (b) is practically impossible, because it
2811  depends on the client so for now always include that final CRLF.
2812*/
2813        if (!ndirs || !nbytes || !nfiles)
2814          blankline = "\15\12";
2815        sprintf(funcbuf,
2816                "%sSummary: %ld director%s, %ld file%s, %ld byte%s%s",
2817                blankline,
2818                ndirs,
2819                (ndirs == 1) ? "y" : "ies",
2820                nfiles,
2821                (nfiles == 1) ? "" : "s",
2822                nbytes,
2823                (nbytes == 1) ? "" : "s",
2824                endline
2825                );
2826        nxpnd--;
2827        funcnxt = 0;
2828        funclen = strlen(funcbuf);
2829    } else {
2830        funcbuf[0] = '\0';
2831        funcnxt = 0;
2832        funclen = 0;
2833    }
2834    /* If we have data to send... */
2835
2836    if (funcnxt < funclen)
2837      return(funcbuf[funcnxt++]);       /* Return a character */
2838    else
2839      return(-1);                       /* Nothing left, done. */
2840}
2841
2842/*  S N D D I R -- send directory listing  */
2843
2844int
2845#ifdef CK_ANSI
2846snddir(char * spec)
2847#else
2848snddir(spec) char * spec;
2849#endif /* CK_ANSI */
2850/* snddir */ {
2851#ifndef NOSERVER
2852    char * p = NULL, name[257]; 
2853    int rc = 0;
2854
2855    if (!spec) spec = "";
2856    debug(F110,"snddir",spec,0);
2857    if (*spec) {
2858        strcpy(name, spec);
2859#ifdef OS2
2860        /* change / to \. */
2861        p = name;
2862        while (*p) {                    /* Change them back to \ */
2863            if (*p == '/') *p = '\\';
2864            p++;
2865        }
2866#endif /* OS2 */
2867    } else {
2868#ifdef OS2
2869        strcpy(name, ".");
2870#else
2871#ifdef UNIX
2872        strcpy(name, "./*");
2873#else
2874#ifdef VMS
2875        strcpy(name, "*.*");
2876#else
2877#ifdef datageneral
2878        strcpy(name, "+");
2879#else
2880        return(0);
2881#endif /* datageneral */
2882#endif /* VMS */
2883#endif /* UNIX */
2884#endif /* OS2 */
2885        p = name + strlen(name);        /* Move it to end of list */
2886    }
2887    ndirs = 0L;
2888    nfiles = 0L;
2889    nbytes = 0L;
2890    sprintf(funcbuf,"Listing files: \"%s\"\15\12\15\12",name);
2891    funcnxt = 0;
2892    funclen = strlen(funcbuf);
2893
2894#ifdef OS2
2895    debug(F110,"snddir about to zchki",name,0);
2896    if (zchki(name) == -2) {            /* Found a directory */
2897        p--;
2898        if (*p == '\\' || *p == '/')
2899          strcat(name, "*");
2900        else if (*p == ':')
2901          strcat(name, ".");
2902        else
2903          strcat(name, "\\*");
2904    }
2905#endif /* OS2 */
2906
2907    nxpnd = zxpand(name);
2908    debug(F111,"snddir zxpand","nxpnd",nxpnd);
2909
2910    nfils = 0;                          /* No files, no lists. */
2911    xflg = 1;                           /* Flag we must send X packet. */
2912    strcpy(cmdstr,"REMOTE DIRECTORY");  /* Data for X packet. */
2913    first = 1;                          /* Init getchx lookahead */
2914    funcstr = 1;                        /* Just set the flag. */
2915    funcptr = nxtdir;                   /* And the pointer. */
2916    binary = XYFT_T;                    /* Text mode for this, */
2917    rc = sinit();
2918    debug(F111,"snddir","sinit()",rc);
2919    return(rc);
2920#else
2921    return(0);
2922#endif /* NOSERVER */
2923}
2924
2925/*  N X T D E L -- provide data for delete   */
2926
2927/*  Returns the next available character or -1 if no more data  */
2928
2929static int
2930nxtdel() {
2931    char name[257], *p = NULL;
2932    char * dstr = NULL;
2933    int len = 0;
2934    short month = 0, date = 0, year = 0, hour = 0, minute = 0, seconds = 0;
2935
2936    if (funcnxt < funclen)
2937      return (funcbuf[funcnxt++]);
2938
2939    if (nxpnd > 0) {
2940        nxpnd--;
2941        if (!znext(name)) {
2942            nxpnd = 0;
2943            return(nxtdel());
2944        }
2945
2946        len = zchki(name);
2947
2948        /* Find just the name of the file */
2949
2950        for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
2951        if (*p == '/') p++;
2952
2953        if (len > -1L) {
2954            nfiles++;
2955            nbytes += len;
2956            sprintf(funcbuf,
2957                    " %10s: %s\15\12",
2958                    zdelet(name) ? "skipping" : "deleted",
2959                    p
2960                    );
2961        } else
2962          sprintf(funcbuf," directory: %s\15\12", p);
2963        funcnxt = 0;
2964        funclen = strlen(funcbuf);
2965    } else
2966   
2967    /* If done processing the expanded entries send a summary statement */
2968
2969      if (nxpnd == 0) {
2970          sprintf(funcbuf,
2971                  "\15\12%ld file%s deleted, %ld byte%s freed\15\12",
2972                  nfiles,
2973                  (nfiles == 1) ? "" : "s",
2974                  nbytes,
2975                  (nbytes == 1) ? "" : "s"
2976                  );
2977          nxpnd--;
2978          funcnxt = 0;
2979          funclen = strlen(funcbuf);
2980      } else {
2981          funcbuf[0] = '\0';
2982          funcnxt = 0;
2983          funclen = 0;
2984      }
2985
2986    /* If we have data to send */
2987
2988    if (funcnxt < funclen)
2989      return (funcbuf[funcnxt++]);      /* Return a character */
2990    else
2991      return(-1);                       /* No more input */
2992}
2993
2994/*  S N D D E L  --  Send delete message  */
2995
2996int
2997#ifdef CK_ANSI
2998snddel(char * spec)
2999#else
3000snddel(spec) char * spec;
3001#endif /* CK_ANSI */
3002/* snddel */ {
3003#ifndef NOSERVER
3004    char * p=NULL, name[257];
3005
3006    if (!*spec)
3007      return(0);
3008
3009    strcpy(name, spec);
3010
3011#ifdef OS2
3012    /* change / to \. */
3013    p = name;
3014    while (*p) {                        /* Change them back to \ */
3015        if (*p == '/') *p = '\\';
3016        p++;
3017    }
3018#endif /* OS2 */
3019
3020    nfiles = nbytes = 0L;
3021    sprintf(funcbuf,"Deleting \"%s\"\15\12",name);
3022    funcnxt = 0;
3023    funclen = strlen(funcbuf);
3024
3025    nxpnd = zxpand(name);
3026    nfils = 0;                          /* No files, no lists. */
3027    xflg = 1;                           /* Flag we must send X packet. */
3028    strcpy(cmdstr,"REMOTE DELETE");     /* Data for X packet. */
3029    first = 1;                          /* Init getchx lookahead */
3030    funcstr = 1;                        /* Just set the flag. */
3031    funcptr = nxtdel;                   /* And the pointer. */
3032    binary = XYFT_T;                    /* Use text mode for this, */
3033    return(sinit());
3034#else
3035    return(0);
3036#endif /* NOSERVER */
3037}
3038
3039#ifdef OS2
3040/*  S N D S P A C E -- send disk space message  */
3041int
3042sndspace(int drive) {
3043#ifndef NOSERVER
3044    static char spctext[64];
3045    if (drive)
3046      sprintf(spctext,
3047              " Drive %c: %ldK free\15\12", drive,
3048              zdskspace(drive - 'A' + 1) / 1024L);
3049    else
3050      sprintf(spctext, " Free space: %ldK\15\12", zdskspace(0) / 1024L);
3051    nfils = 0;                          /* No files, no lists. */
3052    xflg = 1;                           /* Flag we must send X packet. */
3053    strcpy(cmdstr,"free space");        /* Data for X packet. */
3054    first = 1;                          /* Init getchx lookahead */
3055    memstr = 1;                         /* Just set the flag. */
3056    memptr = spctext;                   /* And the pointer. */
3057    binary = XYFT_T;                    /* Text mode for this. */
3058    return(sinit());
3059#else
3060    return(0);
3061#endif /* NOSERVER */
3062}
3063
3064/*  S N D W H O -- send who message  */
3065int
3066sndwho(char * who) {
3067#ifndef NOSERVER
3068    nfils = 0;                          /* No files, no lists. */
3069    xflg = 1;                           /* Flag we must send X packet. */
3070    strcpy(cmdstr,"who");               /* Data for X packet. */
3071    first = 1;                          /* Init getchx lookahead */
3072    memstr = 1;                         /* Just set the flag. */
3073#ifdef NT
3074    memptr = "\15\12K95 SERVER\15\12";  /* And the pointer. */
3075#else
3076    memptr = "\15\12K/2 SERVER\15\12";
3077#endif /* NT */
3078    binary = XYFT_T;                    /* Use text mode */
3079    return(sinit());
3080#else
3081    return(0);
3082#endif /* NOSERVER */
3083}
3084#endif /* OS2 */
3085
3086/*  C W D  --  Change current working directory  */
3087
3088/*
3089 String passed has first byte as length of directory name, rest of string
3090 is name.  Fails if can't connect, else ACKs (with name) and succeeds.
3091*/
3092
3093int
3094cwd(vdir) char *vdir; {
3095    char *cdd, *zgtdir(), *dirp;
3096
3097    vdir[xunchar(*vdir) + 1] = '\0';    /* Terminate string with a null */
3098    dirp = vdir+1;
3099    tlog(F110,"Directory requested: ",dirp,0L);
3100    if (zchdir(dirp)) {                 /* Try to change */
3101        cdd = zgtdir();                 /* Get new working directory. */
3102        debug(F110,"cwd",cdd,0);
3103        encstr((CHAR *)cdd);
3104#ifdef COMMENT
3105        ack1((CHAR *)(encbuf+7));
3106#else
3107        ack1(data);
3108#endif /* COMMENT */
3109        screen(SCR_CD,0,0l,cdd);
3110        tlog(F110,"Changed directory to",cdd,0L);
3111        return(1);
3112    } else {
3113        debug(F110,"cwd failed",dirp,0);
3114        tlog(F110,"Failed to change directory to",dirp,0L);
3115        return(0);
3116    }
3117}
3118
3119
3120/*  S Y S C M D  --  Do a system command  */
3121
3122/*  Command string is formed by concatenating the two arguments.  */
3123
3124int
3125syscmd(prefix,suffix) char *prefix, *suffix; {
3126    char *cp;
3127
3128    if (!prefix)
3129      return(0);
3130    if (!*prefix)
3131      return(0);
3132    for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++);
3133    while (*cp++ = *suffix++)
3134#ifdef OS2
3135        /* This takes away more than we gain in convenience
3136        if (*(cp-1) == '/') *(cp-1) = '\\' */
3137#endif /* OS2 */
3138      ;                                 /* Copy suffix */
3139
3140    debug(F110,"syscmd",cmdstr,0);
3141
3142    if (zxcmd(ZIFILE,cmdstr) > 0) {
3143        debug(F110,"syscmd zxcmd ok",cmdstr,0);
3144            nfils = sndsrc = 0;         /* Flag that input is from stdin */
3145        xflg = hcflg = 1;               /* And special flags for pipe */
3146        binary = XYFT_T;                /* Go to text mode */
3147        return (sinit());               /* Send S packet */
3148    } else {
3149        debug(F100,"syscmd zxcmd failed",cmdstr,0);
3150        return(0);
3151    }
3152}
3153
3154/*  R E M S E T  --  Remote Set  */
3155/*  Called by server to set variables as commanded in REMOTE SET packets.  */
3156/*  Returns 1 on success, 0 on failure.  */
3157
3158int
3159remset(s) char *s; {
3160    int len, i, x, y;
3161    char *p;
3162
3163    len = xunchar(*s++);                /* Length of first field */
3164    p = s + len;                        /* Pointer to second length field */
3165    *p++ = '\0';                        /* Zero out second length field */
3166    x = atoi(s);                        /* Value of first field */
3167    debug(F111,"remset",s,x);
3168    debug(F110,"remset",p,0);
3169    switch (x) {                        /* Do the right thing */
3170      case 132:                         /* Attributes (all, in) */
3171        atcapr = atoi(p);
3172        return(1);
3173      case 133:                         /* File length attributes */
3174      case 233:                         /* IN/OUT combined */
3175      case 148:                         /* Both kinds of lengths */
3176      case 248:
3177        atleni = atleno = atoi(p);
3178        return(1);
3179      case 134:                         /* File Type (text/binary) */
3180      case 234:
3181        attypi = attypo = atoi(p);
3182        return(1);
3183      case 135:                         /* File creation date */
3184      case 235:
3185        atdati = atdato = atoi(p);
3186        return(1);
3187      case 139:                         /* File Blocksize */
3188      case 239:
3189        atblki = atblko = atoi(p);
3190        return(1);
3191      case 141:                         /* Encoding / Character Set */
3192      case 241:
3193        atenci = atenco = atoi(p);
3194        return(1);
3195      case 142:                         /* Disposition */
3196      case 242:
3197        atdisi = atdiso = atoi(p);
3198        return(1);
3199      case 145:                         /* System ID */
3200      case 245:
3201        atsidi = atsido = atoi(p);
3202        return(1);
3203      case 147:                         /* System-Dependent Info */
3204      case 247:
3205        atsysi = atsyso = atoi(p);
3206        return(1);
3207      case 232:                         /* Attributes (all, out) */
3208        atcapr = atoi(p);
3209        return(1);
3210      case 300:                         /* File type (text, binary) */
3211        binary = atoi(p);
3212        return(1);
3213      case 301:                         /* File name conversion */
3214        fncnv = 1 - atoi(p);            /* (oops) */
3215        return(1);
3216      case 302:                         /* File name collision */
3217        x = atoi(p);
3218        if (x == XYFX_R) warn = 1;      /* Rename */
3219        if (x == XYFX_X) warn = 0;      /* Replace */
3220        fncact = x;
3221        return(1);
3222      case 310:                         /* Incomplete File Disposition */
3223        keep = atoi(p);                 /* Keep, Discard */
3224        return(1);
3225      case 311:                         /* Blocksize */
3226        fblksiz = atoi(p);
3227        return(1);
3228      case 312:                         /* Record Length */
3229        frecl = atoi(p);
3230        return(1);
3231      case 313:                         /* Record format */
3232        frecfm = atoi(p);
3233        return(1);
3234      case 314:                         /* File organization */
3235        forg = atoi(p);
3236        return(1);
3237      case 315:                         /* File carriage control */
3238        fcctrl = atoi(p);
3239        return(1);
3240      case 400:                         /* Block check */
3241        y = atoi(p);
3242        if (y < 5 && y > 0) {
3243            bctr = y;
3244            return(1);
3245        } else if (*p == 'B') {
3246            bctr = 4;
3247            return(1);
3248        }
3249        return(0);
3250      case 401:                         /* Receive packet-length */
3251        rpsiz = urpsiz = atoi(p);
3252        if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
3253        if (rpsiz > 94) rpsiz = 94;         /* Max short-packet length */
3254        urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
3255        return(1);
3256      case 402:                         /* Receive timeout */
3257        y = atoi(p);                    /* Client is telling us */
3258        if (y > -1 && y < 999) {        /* the timeout that it wants */
3259            pkttim = chktimo(y,timef);  /* us to tell it to use. */
3260            return(1);
3261        } else return(0);
3262      case 403:                         /* Retry limit */
3263        y = atoi(p);
3264        if (y > -1 && y < 95) {
3265            maxtry = y;
3266            return(1);
3267        } else return(0);
3268      case 404:                         /* Server timeout */
3269        y = atoi(p);
3270        if (y < 0) return(0);
3271        srvtim = y;
3272        return(1);
3273
3274#ifndef NOCSETS
3275      case 405:                         /* Transfer character set */
3276        for (i = 0; i < ntcsets; i++) {
3277            if (!strcmp(tcsinfo[i].designator,p)) break;
3278        }
3279        debug(F101,"remset xfer charset lookup","",i);
3280        if (i == ntcsets) return(0);
3281        tcharset = tcsinfo[i].code;     /* if known, use it */
3282        if (tcharset == TC_TRANSP)
3283          rx = NULL;
3284        else
3285          rx = xlr[tcharset][fcharset]; /* translation function */
3286        return(1);
3287#endif /* NOCSETS */
3288
3289      case 406:                         /* Window slots */
3290        y = atoi(p);
3291        if (y == 0) y = 1;
3292        if (y < 1 && y > MAXWS) return(0);
3293        wslotr = y;
3294        swcapr = 1;
3295        urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
3296        return(1);
3297      default:                          /* Anything else... */
3298        return(0);
3299    }
3300}
3301
3302/* Adjust packet length based on number of window slots and buffer size */
3303
3304int
3305adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
3306    if (protocol != PROTO_K) return(pktlen);
3307    debug(F101,"adjpkl len","",pktlen);
3308    debug(F101,"adjpkl slots","",slots);
3309    debug(F101,"adjpkl bufsiz","",bufsiz);
3310    if (((pktlen + 6) * slots) > bufsiz)
3311      pktlen = (bufsiz / slots) - 6;
3312    debug(F101,"adjpkl new len","",pktlen);
3313    return(pktlen);
3314}
3315
3316/* Set transfer mode and file naming based on comparison of system types */
3317
3318VOID
3319whoarewe() {
3320    extern int xfermode;
3321    extern char whoareu[];
3322    int flag = 0;
3323    debug(F101,"whoarewe xfermode","",xfermode);
3324    if (xfermode == XMODE_A) {          /* If TRANSFER MODE AUTOMATIC */
3325        if (whoareu[0]) {               /* and we know partner's system type */
3326            char * p = (char *)whoareu;
3327            debug(F110,"whoarewe remote sysid",whoareu,0);
3328            if (!strcmp(p,cksysid))     /* Other system same as us */
3329              flag = 1;
3330#ifdef UNIX
3331            if (!strcmp(p,"L3"))        /* UNIX is sort of like AmigaDOS */
3332              flag = 1;                 /* (same directory separator) */
3333            else if (!strcmp(p,"N3"))   /* UNIX like Aegis */
3334              flag = 1;
3335#else
3336#ifdef AMIGA
3337/* Like UNIX, but case distinctions are ignored and can begin with device:. */
3338            else if (!strcmp(p,"U1"))   /* Amiga is sort of like UNIX */
3339              flag = 1;
3340            else if (!strcmp(p,"N3"))   /* Amiga is sort of like Aegis */
3341              flag = 1;
3342#else
3343#ifdef OS2                              /* (Includes Windows 95/NT) */
3344
3345            /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
3346            /* All "the same" for FAT partitions but all bets off otherwise */
3347            /* so this part needs some refinement ...  */
3348
3349            else if (!strcmp(p,"U8"))   /* MS-DOS */
3350              flag = 1;
3351            else if (!strcmp(p,"UO"))   /* OS/2 */
3352              flag = 1;
3353            else if (!strcmp(p,"UN"))   /* Windows NT or 95 */
3354              flag = 1;
3355            else if (!strcmp(p,"K2"))   /* GEMDOS */
3356              flag = 1;
3357#else
3358#ifdef GEMDOS
3359            else if (!strcmp(p,"U8"))
3360              flag = 1;
3361            else if (!strcmp(p,"UO"))
3362              flag = 1;
3363            else if (!strcmp(p,"UN"))
3364              flag = 1;
3365            else if (!strcmp(p,"K2"))
3366              flag = 1;
3367#endif /* GEMDOS */
3368#endif /* OS2 */
3369#endif /* AMIGA */
3370#endif /* UNIX */
3371
3372            debug(F101,"whoarewe flag","",flag);
3373            if (flag) {                 /* We have a match */
3374                fncnv = XYFN_L;         /* so literal filenames */
3375#ifdef VMS
3376                binary = XYFT_L;        /* For VMS-to-VMS, use labeled */
3377#else
3378#ifdef OS2
3379                if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
3380                  binary = XYFT_L;      /* For OS/2-to-OS/2, use labeled */
3381#else
3382                binary = XYFT_B;        /* For all others use binary */
3383#endif /* OS2 */
3384#endif /* VMS */
3385            }
3386        }
3387    }
3388}
Note: See TracBrowser for help on using the repository browser.