ckcfns.c
资源名称:cku197.tar.Z [点击查看]
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:187k
源码类别:
通讯/手机编程
开发平台:
Windows_Unix
- char *fnsv = "C-Kermit functions, 7.0.187, 20 Dec 1999";
- char *nm[] = { "Disabled", "Local only", "Remote only", "Enabled" };
- /* C K C F N S -- System-independent Kermit protocol support functions. */
- /* ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */
- /*
- Author: Frank da Cruz <fdc@columbia.edu>,
- Columbia University Academic Information Systems, New York City.
- Copyright (C) 1985, 2000,
- Trustees of Columbia University in the City of New York.
- All rights reserved. See the C-Kermit COPYING.TXT file or the
- copyright text in the ckcmai.c module for disclaimer and permissions.
- */
- /*
- System-dependent primitives defined in:
- ck?tio.c -- terminal (communications) i/o
- cx?fio.c -- file i/o, directory structure
- */
- #include "ckcsym.h" /* Needed for Stratus VOS */
- #include "ckcasc.h" /* ASCII symbols */
- #include "ckcdeb.h" /* Debug formats, typedefs, etc. */
- #include "ckcker.h" /* Symbol definitions for Kermit */
- #include "ckcxla.h" /* Character set symbols */
- #include "ckcnet.h" /* VMS definition of TCPSOCKET */
- int docrc = 0; /* Accumulate CRC for v(crc16) */
- long crc16 = 0L; /* File CRC = v(crc16) */
- extern CHAR feol;
- extern int byteorder, xflg, remfile, what, fmask, cxseen, czseen;
- extern long ffc;
- #ifndef NOXFER
- /* (move these prototypes to the appropriate .h files...) */
- #ifdef COMMENT
- /* Not used */
- #ifdef VMS
- _PROTOTYP( int getvnum, (char *) );
- #endif /* VMS */
- #endif /* COMMENT */
- _PROTOTYP( static int bgetpkt, (int) );
- #ifndef NOCSETS
- _PROTOTYP( int lookup, (struct keytab[], char *, int, int *) );
- #endif /* NOCSETS */
- #ifndef NOSPL
- _PROTOTYP( int zzstring, (char *, char **, int *) );
- #endif /* NOSPL */
- #ifdef OS2ORUNIX
- _PROTOTYP( long zfsize, (char *) );
- #endif /* OS2ORUNIX */
- #ifdef OS2
- #include <io.h>
- #endif /* OS2 */
- #ifdef VMS
- #include <errno.h>
- #endif /* VMS */
- /* Externals from ckcmai.c */
- extern int srvcdmsg, srvidl, idletmo, bigendian;
- extern char * cdmsgfile[];
- extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
- rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
- extern int pktnum, bctr, bctu, bctl, clfils, sbufnum, protocol,
- size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success;
- extern int parity, turn, network, whatru, fsecs, justone, slostart,
- ckdelay, displa, mypadn, moving, recursive, nettype;
- extern long filcnt, flci, flco, tlci, tlco, tfc, fsize, sendstart, rs_len;
- extern long filrej, oldcps, cps, peakcps, ccu, ccp, calibrate, filestatus;
- extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup;
- extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
- extern int hcflg, binary, fncnv, b_save, f_save, server;
- extern int nakstate, discard, rejection, local, xfermode, interrupted;
- extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
- extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike;
- extern int atcapr, atcapb, atcapu;
- extern int lpcapr, lpcapb, lpcapu;
- extern int swcapr, swcapb, swcapu;
- extern int lscapr, lscapb, lscapu;
- extern int rscapr, rscapb, rscapu;
- extern int rptena, rptmin;
- extern int sseqtbl[];
- extern int numerrs, nzxopts;
- extern long rptn;
- extern int maxtry;
- extern int stdouf;
- extern int sendmode;
- extern int carrier, ttprty;
- #ifdef TCPSOCKET
- extern int ttnproto;
- #endif /* TCPSOCKET */
- #ifndef NOSPL
- extern int sndxin, sndxhi, sndxlo;
- #endif /* NOSPL */
- extern int g_binary, g_fncnv;
- #ifdef GFTIMER
- extern CKFLOAT fpfsecs;
- #endif /* GFTIMER */
- #ifdef OS2
- extern struct zattr iattr;
- #endif /* OS2 */
- #ifdef PIPESEND
- extern int pipesend, usepipes;
- #endif /* PIPESEND */
- /* Per-file text/binary-mode recognition */
- #ifdef PATTERNS
- extern int patterns;
- extern char *txtpatterns[];
- extern char *binpatterns[];
- #endif /* PATTERNS */
- #ifdef STREAMING
- extern int streamrq, streaming, streamed, streamok;
- #endif /* STREAMING */
- extern int reliable, clearrq, cleared, urclear;
- extern int
- atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
- attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
- extern int bigsbsiz, bigrbsiz;
- extern char *versio;
- extern char *filefile;
- extern char whoareu[], * cksysid;
- #ifndef NOSERVER
- extern int ngetpath;
- extern char * getpath[];
- extern int fromgetpath;
- #endif /* NOSERVER */
- extern int inserver;
- #ifdef CK_LOGIN
- extern int isguest;
- #endif /* CK_LOGIN */
- extern CHAR *srvcmd, * epktmsg;
- extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq;
- extern CHAR *data, padbuf[], stchr, mystch;
- extern CHAR *srvptr;
- extern CHAR *rdatap;
- extern char *cmarg, *cmarg2, **cmlist, filnam[];
- extern char fspec[], *sfspec, *rfspec;
- extern int fspeclen;
- #ifndef NOMSEND
- extern struct filelist * filehead, * filenext;
- extern int addlist;
- #endif /* NOMSEND */
- _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
- _PROTOTYP( int szeof, (CHAR *s) );
- _PROTOTYP( VOID fnlist, (void) );
- #endif /* NOXFER */
- /* Character set Translation */
- #ifndef NOCSETS
- extern int tcharset, fcharset;
- extern int ntcsets, xlatype, cseqtab[];
- extern struct csinfo tcsinfo[], fcsinfo[];
- _PROTOTYP( CHAR ident, (CHAR) ); /* Identity translation function */
- /* Arrays of and pointers to character translation functions */
- #ifdef CK_ANSIC
- extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */
- extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */
- extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Send */
- extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Recv */
- #ifdef UNICODE
- extern int (*xut)(USHORT); /* Translation function UCS to TCS */
- extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
- extern USHORT (*xtu)(CHAR); /* Translation function TCS to UCS */
- extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
- #endif /* UNICODE */
- #else /* The same declarations again for non-ANSI comilers... */
- extern CHAR (*rx)();
- extern CHAR (*sx)();
- extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
- extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();
- #ifdef UNICODE
- extern int (*xut)();
- extern int (*xuf)();
- extern USHORT (*xtu)();
- extern USHORT (*xfu)();
- #endif /* UNICODE */
- #endif /* CK_ANSIC */
- #endif /* NOCSETS */
- /* (PWP) external def. of things used in buffered file input and output */
- #ifdef DYNAMIC
- extern char *zinbuffer, *zoutbuffer;
- #else
- extern char zinbuffer[], zoutbuffer[];
- #endif /* DYNAMIC */
- extern char *zinptr, *zoutptr;
- extern int zincnt, zoutcnt, zobufsize;
- extern long crcta[], crctb[]; /* CRC-16 generation tables */
- extern int rseqtbl[]; /* Rec'd-packet sequence # table */
- #ifndef NOXFER
- /* Variables defined in this module but shared by other modules. */
- int xfrbel = 1;
- char * ofperms = ""; /* Output file permissions */
- int autopath = 0; /* SET RECEIVE PATHNAMES AUTO flag */
- #ifdef CALIBRATE
- #define CAL_O 3
- #define CAL_M 253
- int cal_j = 0;
- CHAR
- cal_a[] = {
- 16, 45, 98, 3, 52, 41, 14, 7, 76,165,122, 11,104, 77,166, 15,
- 160, 93, 18, 19,112, 85, 54, 23,232,213, 90, 27, 12, 81,126, 31,
- 4,205, 34, 35,144, 73,110, 39, 28,133,218, 43,156, 65,102, 47,
- 84, 61, 50, 51,208,117, 86, 55, 8,245, 74, 59, 44,125,222, 63,
- 80, 1,162, 67,116,105,206, 71,120, 9,250, 75, 88, 97, 6, 79,
- 100,221, 82, 83, 36, 89, 94, 87, 40, 21,106, 91,236,145,150, 95,
- 228, 33,130, 99,148,137,198,103,108,169, 42,107,184,129, 78,111,
- 0, 49,114,115, 32,121,254,119,172, 57,138,123,152,177, 22,127,
- 240,193, 2,131,176, 5, 38,135,204,229, 10,139,200,161,174,143,
- 128, 17,146,147, 68,153, 30,151, 72,217,170,155, 24,209, 62,159,
- 64,225,194,163,244,201, 70,167,216,197,234,171,188,109,230,175,
- 212,113,178,179,132,185,190,183,136,249,202,187, 92,241,118,191,
- 48,237, 66,195, 96,233,142,199,248, 37, 58,203, 60, 13,134,207,
- 20, 29,210,211,164,149,182,215,220, 25, 26,219,124,157,246,223,
- 180,141,226,227,192,101,238,231, 56, 69,154,235,252,173, 46,239,
- 224,253,242,243,196, 53,214,247,168,181,186,251,140,189,158,255
- };
- #endif /* CALIBRATE */
- char * rf_err = "Error receiving file"; /* rcvfil() error message */
- #ifdef CK_SPEED
- short ctlp[256] = { /* Control-Prefix table */
- 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 */
- 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 */
- 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,
- 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 */
- 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 */
- 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 */
- 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,
- 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 */
- };
- #endif /* CK_SPEED */
- int sndsrc; /* Flag for where to get names of files to send: */
- /* -1: znext() function */
- /* 0: stdin */
- /* >0: list in cmlist or other list */
- /* -9: calibrate */
- int memstr; /* Flag for input from memory string */
- int funcstr; /* Flag for input from function */
- int bestlen = 0;
- int maxsend = 0;
- int gnf_binary = 0; /* Prevailing xfer mode for gnfile */
- #ifdef pdp11
- #define MYINITLEN 32
- #else
- #define MYINITLEN 100
- #endif /* pdp11 */
- CHAR myinit[MYINITLEN]; /* Copy of my Send-Init data */
- /* Variables local to this module */
- #ifdef TLOG
- #ifndef XYZ_INTERNAL
- static
- #endif /* XYZ_INTERNAL */
- char *fncnam[] = {
- "rename", "replace", "backup", "append", "discard", "ask", "update", ""
- };
- #endif /* TLOG */
- static char *memptr; /* Pointer for memory strings */
- #ifdef VMS
- extern int batch;
- #else
- extern int backgrd;
- #endif /* VMS */
- #ifdef CK_CTRLZ
- static int lastchar = 0;
- #endif /* CK_CTRLZ */
- #ifdef CK_ANSIC
- static int (*funcptr)(void); /* Pointer for function strings */
- #else
- static int (*funcptr)();
- #endif /* CK_ANSIC */
- #ifdef pdp11
- #define CMDSTRL 50
- static char cmdstr[50]; /* System command string. */
- #else
- #ifdef BIGBUFOK
- #define CMDSTRL 1024
- #else
- #define CMDSTRL 256
- #endif /* BIGBUFOK */
- static char cmdstr[CMDSTRL+1];
- #endif /* pdp11 */
- static int drain; /* For draining stacked-up ACKs. */
- static int first; /* Flag for first char from input */
- static CHAR t; /* Current character */
- #ifdef COMMENT
- static CHAR next; /* Next character */
- #endif /* COMMENT */
- static int ebqsent = 0; /* 8th-bit prefix bid that I sent */
- static int lsstate = 0; /* Locking shift state */
- static int lsquote = 0; /* Locking shift quote */
- #ifdef datageneral
- extern int quiet;
- #endif /* datageneral */
- /* E N C S T R -- Encode a string from memory. */
- /*
- Call this instead of getpkt() if source is a string, rather than a file.
- Note: Character set translation is never done in this case.
- */
- #ifdef COMMENT
- #define ENCBUFL 200
- #ifndef pdp11
- CHAR encbuf[ENCBUFL];
- #else
- /* This is gross, but the pdp11 root segment is out of space */
- /* Will allocate it in ckuusr.c. */
- extern CHAR encbuf[];
- #endif /* pdp11 */
- #endif /* COMMENT */
- /*
- Encode packet data from a string in memory rather than from a file.
- Returns the length of the encoded string on success, -1 if the string
- could not be completely encoded into the currently negotiated data
- field length.
- */
- int
- #ifdef CK_ANSIC
- encstr(CHAR *s)
- #else /* CK_ANSIC */
- encstr(s) CHAR* s;
- #endif /* CK_ANSIC */
- {
- /*
- Recoded 30 Jul 94 to use the regular data buffer and the negotiated
- maximum packet size. Previously we were limited to the length of encbuf[].
- Also, to return a failure code if the entire encoded string would not fit.
- Modified 14 Jul 98 to return length of encoded string.
- */
- int m, rc, slen; char *p;
- if (!data) { /* Watch out for null pointers. */
- debug(F100,"SERIOUS ERROR: encstr data == NULL","",0);
- return(-1);
- }
- if (!s) s = (CHAR *)""; /* Ditto. */
- slen = strlen((char *)s); /* Length of source string. */
- debug(F111,"encstr",s,slen);
- rc = 0; /* Return code. */
- m = memstr; p = memptr; /* Save these. */
- memptr = (char *)s; /* Point to the string. */
- debug(F101,"encstr memptr 1","",memptr);
- memstr = 1; /* Flag memory string as source. */
- first = 1; /* Initialize character lookahead. */
- *data = NUL; /* In case s is empty */
- debug(F101,"encstr spsiz","",spsiz);
- rc = getpkt(spsiz,0); /* Fill a packet from the string. */
- debug(F101,"encstr getpkt rc","",rc);
- if (rc > -1 && memptr < (char *)(s + slen)) { /* Means we didn't encode */
- rc = -1; /* the whole string. */
- debug(F101,"encstr string too big","",size);
- }
- debug(F101,"encstr getpkt rc","",rc);
- memstr = m; /* Restore memory string flag */
- memptr = p; /* and pointer */
- first = 1; /* Put this back as we found it. */
- return(rc);
- }
- /* Output functions passed to 'decode': */
- int /* Put character in server command buffer */
- #ifdef CK_ANSIC
- putsrv(char c)
- #else
- putsrv(c) register char c;
- #endif /* CK_ANSIC */
- /* putsrv */ {
- *srvptr++ = c;
- *srvptr = ' '; /* Make sure buffer is null-terminated */
- return(0);
- }
- int /* Output character to console. */
- #ifdef CK_ANSIC
- puttrm(char c)
- #else
- puttrm(c) register char c;
- #endif /* CK_ANSIC */
- /* puttrm */ {
- #ifndef NOSPL
- extern int cmdsrc();
- extern char * qbufp; /* If REMOTE QUERY active, */
- extern int query, qbufn; /* also store response in */
- if (query && qbufn++ < 1024) { /* query buffer. */
- *qbufp++ = c;
- *qbufp = NUL;
- }
- if (!query || !cmdsrc())
- #endif /* NOSPL */
- conoc(c);
- return(0);
- }
- #endif /* NOXFER */
- int /* Output char to file. */
- #ifdef CK_ANSIC
- putmfil(char c) /* Just like putfil but to ZMFILE */
- #else /* rather than ZOFILE... */
- putmfil(c) register char c;
- #endif /* CK_ANSIC */
- /* putmfil */ {
- debug(F000,"putfil","",c);
- if (zchout(ZMFILE, (char) (c & fmask)) < 0) {
- czseen = 1;
- debug(F101,"putfil zchout write error, setting czseen","",1);
- return(-1);
- }
- return(0);
- }
- int /* Output char to file. */
- #ifdef CK_ANSIC
- putfil(char c)
- #else
- putfil(c) register char c;
- #endif /* CK_ANSIC */
- /* putfil */ {
- debug(F000,"putfil","",c);
- if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
- czseen = 1; /* If write error... */
- debug(F101,"putfil zchout write error, setting czseen","",1);
- return(-1);
- }
- return(0);
- }
- /*
- The following function is a wrapper for putfil(). The only reason for its
- existence is to be passed as a function pointer to decode(), which treats
- putfil() itself specially -- bypassing it and using an internal macro
- instead to speed things up. Use zputfil() instead of putfil() in cases where
- we do not want this to happen, e.g. when we need to send output to the file
- with a mixture of zchout() and zsout()/zsoutl() calls (as is the case with
- incoming short-form REMOTE command replies redirected to a file), which would
- otherwise result in data written to the file out of order.
- */
- int
- #ifdef CK_ANSIC
- zputfil(char c)
- #else
- zputfil(c) register char c;
- #endif /* CK_ANSIC */
- /* zputfil */ {
- return(putfil(c));
- }
- #ifndef NOXFER
- /* D E C O D E -- Kermit packet decoding procedure */
- /*
- Call with string to be decoded and an output function.
- Returns 0 on success, -1 on failure (e.g. disk full).
- This is the "inner loop" when receiving files, and must be coded as
- efficiently as possible. Note some potential problems: if a packet
- is badly formed, having a prefixed sequence ending prematurely, this
- function, as coded, could read past the end of the packet. This has
- never happened, thus the additional (time-consuming) tests have not
- been added.
- */
- static CHAR *xdbuf; /* Global version of decode()'s buffer pointer */
- /* for use by translation functions. */
- /* Function for pushing a character onto decode()'s input stream. */
- VOID
- #ifdef CK_ANSIC
- zdstuff(CHAR c)
- #else
- zdstuff(c) CHAR c;
- #endif /* CK_ANSIC */
- /* zdstuff */ {
- xdbuf--; /* Back up the pointer. */
- *xdbuf = c; /* Stuff the character. */
- }
- #ifdef CKTUNING
- /*
- Trimmed-down packet decoder for binary-mode no-parity transfers.
- decode() is the full version.
- */
- int
- #ifdef CK_ANSIC
- bdecode(CHAR *buf, int (*fn)(char))
- #else
- bdecode(buf,fn) register CHAR *buf; register int (*fn)();
- #endif /* CK_ANSIC */
- /* bdecode */ {
- register unsigned int a, a7; /* Various copies of current char */
- int ccpflg; /* For Ctrl-unprefixing stats */
- int t; /* Int version of character */
- int len;
- long z; /* For CRC calculation */
- CHAR c; /* Current character */
- if (!binary || parity || fn != putfil) /* JUST IN CASE */
- return(decode(buf,fn,1));
- debug(F100,"BDECODE","",0);
- xdbuf = buf; /* Global copy of source pointer. */
- len = rln; /* Number of bytes in data field */
- while (len > 0) {
- a = *xdbuf++ & 0xff; /* Get next character */
- len--;
- rpt = 0; /* Initialize repeat count. */
- if (a == rptq && rptflg) { /* Got a repeat prefix? */
- rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
- rptn += rpt;
- a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
- len -= 2;
- }
- ccpflg = 0; /* Control prefix flag. */
- if (a == ctlq) { /* If control prefix, */
- a = *xdbuf++ & 0xFF; /* get its operand */
- len--;
- a7 = a & 0x7F; /* and its low 7 bits. */
- if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
- a = ctl(a); /* if in control range. */
- a7 = a & 0x7F;
- ccpflg = 1; /* Note that we did this */
- ccp++; /* Count for stats */
- }
- } else a7 = a & 0x7f; /* Not control quote */
- if (a7 < 32 || a7 == 127) /* A bare control character? */
- if (!ccpflg) ccu++; /* Count it */
- if (!rpt) rpt = 1;
- for (; rpt > 0; rpt--) { /* Output the char RPT times */
- #ifdef CALIBRATE
- if (calibrate) {
- ffc++;
- continue;
- }
- #endif /* CALIBRATE */
- #ifdef OS2
- if (xflg && !remfile) { /* Write to virtual screen */
- char _a;
- _a = a & fmask;
- t = conoc(_a);
- if (t < 1)
- t = -1;
- } else
- #endif /* OS2 */
- t = zmchout(a & fmask); /* zmchout is a macro */
- if (t < 0) {
- debug(F101,"bdecode write error - errno","",errno);
- return(-1);
- }
- ffc++; /* Count the character */
- if (docrc && !remfile) { /* Update file CRC */
- c = a; /* Force conversion to unsigned char */
- z = crc16 ^ (long)c;
- crc16 = (crc16 >> 8) ^
- (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
- }
- }
- #ifdef CK_CTRLZ
- lastchar = a;
- #endif /* CK_CTRLZ */
- }
- return(0);
- }
- #endif /* CKTUNING */
- #endif /* NOXFER */
- /* P N B Y T E -- Output next byte to file or other destination */
- static long offc = 0L;
- static int
- #ifdef CK_ANSIC
- pnbyte(CHAR c, int (*fn)(char))
- #else
- pnbyte(c,fn) CHAR c; int (*fn)();
- #endif /* CK_ANSIC */
- /* pnbyte */ {
- int rc;
- long z;
- #ifdef OS2
- if (xflg && !remfile) { /* Write to virtual screen */
- char _a;
- _a = c & fmask;
- rc = conoc(_a);
- if (rc < 1)
- return(-1);
- } else {
- #endif /* OS2 */
- if (fn == putfil) /* Execute output function */
- rc = zmchout(c); /* to-file macro (fast) */
- else if (!fn)
- rc = putchar(c); /* to-screen macro (fast) */
- else
- rc = (*fn)(c); /* function call (not as fast) */
- if (rc < 0)
- return(rc);
- #ifdef OS2
- }
- #endif /* OS2 */
- /*
- Both xgnbyte() and xpnbyte() increment ffc (the file byte counter).
- During file transfer, only one of these functions is called. However,
- the TRANSLATE command is likely to call them both. offc, therefore,
- contains the output byte count, necessary for handling the UCS-2 BOM.
- */
- offc++; /* Count the byte */
- ffc++; /* Count the byte */
- #ifndef NOXFER
- if (docrc && !xflg && !remfile) { /* Update file CRC */
- z = crc16 ^ (long)c;
- crc16 = (crc16 >> 8) ^
- (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
- }
- #endif /* NOXFER */
- return(1);
- }
- /*
- X P N B Y T E -- Translate and put next byte to file.
- Only for Unicode. Call with next untranslated byte from incoming
- byte stream, which can be in any Transfer Character Set: UCS-2, UTF-8,
- Latin-1, Latin-Hebrew, etc. Translates to the file character set and
- writes bytes to the output file. Call with character as int to translate
- as an int, plus the transfer character set (to translate from) and the
- file character set (to translate to), or -1,0,0 to reset the UCS-2 byte
- number (which should be done at the beginning of a file). Returns:
- -1: On error
- 0: Nothing to write (mid-sequence)
- >0: Number of bytes written.
- */
- #ifdef KANJI
- static int jstate = 0, jx = 0; /* For outputting JIS-7 */
- static char jbuf[16] = { NUL, NUL };
- #endif /* KANJI */
- int
- #ifdef CK_ANSIC
- xpnbyte(int a, int tcs, int fcs, int (*fn)(char))
- #else
- xpnbyte(a,tcs,fcs,fn) int a, tcs, fcs; int (*fn)();
- #endif /* CK_ANSIC */
- /* xpnbyte */ {
- #ifdef UNICODE
- extern int ucsorder, ucsbom; /* Byte order */
- #endif /* UNICODE */
- CHAR c; /* Unsigned char worker */
- static union ck_short uc, eu, sj; /* UCS-2, EUC, and Shift-JIS workers */
- USHORT ch; /* ditto... */
- USHORT * us = NULL; /* ditto... */
- int c7, rc, haveuc = 0; /* Return code and UCS-2 flag */
- int utferror = 0; /* UTF-8 error */
- static int bn = 0; /* UCS-2 byte number */
- int swapping = 0; /* Swapping UCS bytes to output? */
- /* swapping must be 0 or 1 */
- if (a == -1 && (tcs | fcs) == 0) { /* Reset in case previous run */
- bn = 0; /* left bn at 1... */
- offc = 0L;
- debug(F101,"xpnbyte RESET","",bn);
- return(0);
- }
- debug(F001,"xpnbyte a","",a);
- #ifdef UNICODE
- if (ucsorder != 1 && ucsorder != 0) /* Also just in case... */
- ucsorder = 0;
- if ((byteorder && !ucsorder) || (!byteorder && ucsorder))
- swapping = 1; /* Swapping bytes to output */
- if (tcs == TC_UTF8) { /* 'a' is from a UTF-8 stream */
- ch = a;
- if (fcs == TC_UTF8) /* Output is UTF-8 too */
- return(pnbyte(ch,fn)); /* so just copy. */
- rc = utf8_to_ucs2(ch,&us); /* Otherwise convert to UCS-2 */
- if (rc == 0) { /* Done with this sequence */
- uc.x_short = *us; /* We have a Unicode */
- haveuc = 1;
- } else if (rc < 0) { /* Error */
- debug(F101,"xpnbyte UTF-8 conversion error","",rc);
- haveuc = 1; /* Replace by U+FFFD */
- uc.x_short = *us;
- utferror = 1;
- } else /* Sequence incomplete */
- return(0);
- } else if (tcs == TC_UCS2) { /* 'a' is UCS-2 */
- /* Here we have incoming UCS-2 in guaranteed Big Endian order */
- /* so we must exchange bytes if local machine is Little Endian. */
- switch (bn) { /* Which byte? */
- case 0: /* High... */
- uc.x_char[byteorder] = (unsigned)a & 0xff;
- bn++;
- return(0); /* Wait for next */
- case 1: /* Low... */
- uc.x_char[1-byteorder] = (unsigned)a & 0xff;
- bn = 0; /* Done with sequence */
- haveuc = 1; /* Have a Unicode */
- }
- } else
- #endif /* UNICODE */
- #ifdef KANJI /* Whether UNICODE is defined or not */
- if (tcs == TC_JEUC) { /* Incoming Japanese EUC */
- int bad = 0;
- static int kanji = 0; /* Flags set in case 0 for case 1 */
- static int kana = 0;
- switch (bn) { /* Byte number */
- case 0: /* Byte 0 */
- eu.x_short = 0;
- if ((a & 0x80) == 0) {
- sj.x_short = (unsigned)a & 0xff; /* Single byte */
- kanji = kana = 0;
- } else { /* Double byte */
- c7 = a & 0x7f;
- if (c7 > 0x20 && c7 < 0x7f) { /* Kanji */
- eu.x_char[byteorder] = (CHAR) a; /* Store first byte */
- bn++; /* Set up for second byte */
- kanji = 1;
- kana = 0;
- return(0);
- } else if (a == 0x8e) { /* SS2 -- Katakana prefix */
- eu.x_char[byteorder] = (CHAR) a; /* Save it */
- bn++;
- kana = 1;
- kanji = 0;
- return(0);
- } else {
- bad++;
- }
- }
- break;
- case 1: /* Byte 1 */
- bn = 0;
- if (kanji) {
- eu.x_char[1-byteorder] = (CHAR) a;
- sj.x_short = eu_to_sj(eu.x_short);
- break;
- } else if (kana) {
- sj.x_short = (CHAR) (a | 0x80);
- break;
- } else { /* (shouldn't happen) */
- bad++;
- }
- }
- /* Come here with one Shift-JIS character */
- #ifdef UNICODE
- if (bad) {
- uc.x_short = 0xfffd;
- } else {
- uc.x_short = sj_to_un(sj.x_short); /* Convert to Unicode */
- }
- haveuc = 1;
- #endif /* UNICODE */
- } else
- #endif /* KANJI */
- #ifdef UNICODE
- uc.x_short = (unsigned)a & 0xff; /* Latin-1 or whatever... */
- /* Come here with uc = the character to be translated. */
- /* If (haveuc) it's UCS-2 in native order, otherwise it's a byte. */
- debug(F101,"xpnbyte haveuc","",haveuc);
- if (haveuc) { /* If we have a Unicode... */
- debug(F101,"xpnbyte uc.x_short A","",uc.x_short);
- debug(F101,"xpnbyte feol","",feol);
- if (feol && uc.x_short == CR) {
- return(0);
- } else if (feol && uc.x_short == LF) {
- uc.x_short = feol;
- }
- debug(F101,"xpnbyte uc.x_short B","",uc.x_short);
- if (fcs == FC_UCS2) { /* And FCS is UCS-2 */
- /* Write out the bytes in the appropriate byte order */
- int count = 0;
- if (offc == 0L && ucsbom) { /* Beginning of file? */
- if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) /* BOM */
- return(rc);
- if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
- return(rc);
- count += 2;
- }
- if (utferror) {
- if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
- return(rc);
- if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
- return(rc);
- count += 2;
- }
- if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
- return(rc);
- if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
- return(rc);
- count += 2;
- return(count);
- } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */
- CHAR * buf = NULL;
- int i, count;
- if (utferror) {
- if ((rc = pnbyte((ucsorder ? 0xbd : 0xff),fn)) < 0)
- return(rc);
- if ((rc = pnbyte((ucsorder ? 0xff : 0xbd),fn)) < 0)
- return(rc);
- }
- if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
- return(-1);
- debug(F011,"xpnbyte buf",buf,count);
- for (i = 0; i < count; i++)
- if ((rc = pnbyte(buf[i],fn)) < 0)
- return(rc);
- if (utferror)
- count += 2;
- return(count);
- } else { /* Translate UCS-2 to byte */
- if (uc.x_short == 0x2028 || uc.x_short == 0x2029) {
- if (utferror)
- pnbyte(UNK,fn);
- if (feol)
- return(pnbyte((CHAR)feol,fn));
- if ((rc = pnbyte((CHAR)CR,fn)) < 0)
- return(rc);
- if ((rc = pnbyte((CHAR)LF,fn)) < 0)
- return(rc);
- else
- return(utferror ? 3 : 2);
- } else if (xuf) { /* UCS-to-FCS function */
- int x = 0;
- if (utferror)
- pnbyte(UNK,fn);
- if ((rc = (*xuf)(uc.x_short)) < 0) /* These can fail... */
- ch = UNK;
- else
- ch = (unsigned)((unsigned)rc & 0xffff);
- x = pnbyte(ch,fn);
- if (x < 0)
- return(x);
- else if (utferror)
- x++;
- return(x);
- #ifdef KANJI
- /* Also see the non-Unicode Kanji section further down in this function. */
- } else if (fcsinfo[fcs].alphabet == AL_JAPAN) {
- /* Translate UCS-2 to Japanese set */
- debug(F001,"xpnbyte uc","",uc.x_short);
- sj.x_short = un_to_sj(uc.x_short); /* First to Shift-JIS */
- debug(F001,"xpnbyte sj","",sj.x_short);
- switch (fcs) { /* File character set */
- case FC_SHJIS: /* Shift-JIS -- just output it */
- if (sj.x_char[byteorder]) /* But not high byte if zero */
- if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
- return(rc);
- if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
- return(rc);
- return(2);
- case FC_JEUC: /* EUC-JP */
- eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
- debug(F001,"xpnbyte eu","",eu.x_short);
- if (eu.x_short == 0xffff) { /* Bad */
- if ((rc = pnbyte(UNK,fn)) < 0)
- return(rc);
- return(1);
- } else { /* Good */
- int count = 0; /* Write high byte if not zero */
- if (eu.x_char[byteorder]) {
- if ((rc=pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
- return(rc);
- count++;
- }
- /* Always write low byte */
- if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
- return(rc);
- count++;
- return(count);
- }
- break;
- case FC_JIS7: /* JIS-7 */
- case FC_JDEC: /* DEC Kanji */
- eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
- if (eu.x_short == 0xffff) { /* Bad */
- debug(F001,"xpnbyte bad eu","",eu.x_short);
- if ((rc = pnbyte(UNK,fn)) < 0)
- return(rc);
- return(1);
- } else { /* Good */
- int i;
- /* ^^^ Use another name - 'a' hides parameter */
- /* It's OK as is but causes compiler warnings */
- char a = eu.x_char[1-byteorder]; /* Low byte */
- debug(F001,"xpnbyte eu","",eu.x_short);
- if (eu.x_char[byteorder] == 0) { /* Roman */
- switch (jstate) {
- case 1: /* Current state is Katakana */
- jbuf[0] = 0x0f; /* SI */
- jbuf[1] = a;
- jx = 2;
- break;
- case 2: /* Current state is Kanji */
- jbuf[0] = 0x1b; /* ESC */
- jbuf[1] = 0x28; /* ( */
- jbuf[2] = 0x4a; /* J */
- jbuf[3] = a;
- jx = 4;
- break;
- default: /* Current state is Roman */
- jbuf[0] = a;
- jx = 1;
- break;
- }
- jstate = 0; /* New state is Roman */
- } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
- jx = 0;
- switch (jstate) {
- case 2: /* from Kanji */
- jbuf[jx++] = 0x1b; /* ESC */
- jbuf[jx++] = 0x28; /* ( */
- jbuf[jx++] = 0x4a; /* J */
- case 0: /* from Roman */
- jbuf[jx++] = 0x0e; /* SO */
- default: /* State is already Kana*/
- jbuf[jx++] = (a & 0x7f); /* and the char */
- break;
- }
- jstate = 1; /* New state is Katakana */
- } else { /* Kanji */
- jx = 0;
- switch (jstate) {
- case 1: /* Current state is Katakana */
- jbuf[jx++] = 0x0f; /* SI */
- case 0: /* Current state is Roman */
- jbuf[jx++] = 0x1b; /* ESC */
- jbuf[jx++] = 0x24; /* $ */
- jbuf[jx++] = 0x42; /* B */
- default: /* Current state is already Kanji */
- jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
- jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
- break;
- }
- jstate = 2; /* Set state to Kanji */
- }
- for (i = 0; i < jx; i++) /* Output the result */
- if ((rc = pnbyte(jbuf[i],fn)) < 0)
- return(rc);
- return(jx); /* Return its length */
- }
- }
- #endif /* KANJI */
- } else { /* No translation function */
- int count = 0;
- if (utferror) {
- if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
- return(rc);
- if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
- return(rc);
- count += 2;
- }
- if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
- return(rc);
- if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
- return(rc);
- count += 2;
- return(count);
- }
- }
- } else { /* Byte to Unicode */
- if (xtu) { /* TCS-to-UCS function */
- if (((tcsinfo[tcs].size > 128) && (uc.x_short & 0x80)) ||
- tcsinfo[tcs].size <= 128)
- uc.x_short = (*xtu)(uc.x_short);
- }
- if (fcs == FC_UCS2) { /* And FCS is UCS-2 */
- /* Write out the bytes in the appropriate byte order */
- if (offc == 0 && ucsbom) { /* Beginning of file? */
- if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) /* BOM */
- return(rc);
- if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
- return(rc);
- }
- if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
- return(rc);
- if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
- return(rc);
- return(2);
- } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */
- CHAR * buf = NULL;
- int i, count;
- if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
- return(-1);
- for (i = 0; i < count; i++)
- if ((rc = pnbyte(buf[i],fn)) < 0)
- return(rc);
- return(count);
- } else {
- debug(F100,"xpnbyte impossible combination","",0);
- return(-1);
- }
- }
- #else
- #ifdef KANJI
- /*
- This almost, but not quite, duplicates the Kanji section above.
- There is no doubt a way to combine the sections more elegantly,
- but probably only at the expense of additional execution overhead.
- As matters stand, be careful to reflect any changes in this section
- to the other Kanji section above.
- */
- if (tcs == TC_JEUC) { /* Incoming Japanese EUC */
- int count = 0;
- switch (fcs) { /* File character set */
- case FC_SHJIS: /* Shift-JIS -- just output it */
- if (sj.x_char[byteorder]) /* But not high byte if zero */
- if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
- return(rc);
- count++;
- if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
- return(rc);
- count++;
- return(count);
- case FC_JEUC: /* EUC-JP */
- eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
- debug(F001,"xpnbyte FC_JEUC eu","",eu.x_short);
- if (eu.x_short == 0xffff) { /* Bad */
- if ((rc = pnbyte(UNK,fn)) < 0)
- return(rc);
- return(1);
- } else { /* Good */
- int count = 0; /* Write high byte if not zero */
- if (eu.x_char[byteorder]) {
- if ((rc = pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
- return(rc);
- count++;
- }
- /* Always write low byte */
- if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
- return(rc);
- count++;
- return(count);
- }
- break;
- case FC_JIS7: /* JIS-7 */
- case FC_JDEC: /* DEC Kanji */
- eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
- if (eu.x_short == 0xffff) { /* Bad */
- debug(F001,"xpnbyte FC_JIS7 bad eu","",eu.x_short);
- if ((rc = pnbyte(UNK,fn)) < 0)
- return(rc);
- return(1);
- } else { /* Good */
- int i;
- char a = eu.x_char[1-byteorder]; /* Low byte */
- debug(F001,"xpnbyte FC_JIS7 eu","",eu.x_short);
- if (eu.x_char[byteorder] == 0) { /* Roman */
- switch (jstate) {
- case 1: /* Current state is Katakana */
- jbuf[0] = 0x0f; /* SI */
- jbuf[1] = a;
- jx = 2;
- break;
- case 2: /* Current state is Kanji */
- jbuf[0] = 0x1b; /* ESC */
- jbuf[1] = 0x28; /* ( */
- jbuf[2] = 0x4a; /* J */
- jbuf[3] = a;
- jx = 4;
- break;
- default: /* Current state is Roman */
- jbuf[0] = a;
- jx = 1;
- break;
- }
- jstate = 0; /* New state is Roman */
- } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
- jx = 0;
- switch (jstate) {
- case 2: /* from Kanji */
- jbuf[jx++] = 0x1b; /* ESC */
- jbuf[jx++] = 0x28; /* ( */
- jbuf[jx++] = 0x4a; /* J */
- case 0: /* from Roman */
- jbuf[jx++] = 0x0e; /* SO */
- default: /* State is already Kana*/
- jbuf[jx++] = (a & 0x7f); /* and the char */
- break;
- }
- jstate = 1; /* New state is Katakana */
- } else { /* Kanji */
- jx = 0;
- switch (jstate) {
- case 1: /* Current state is Katakana */
- jbuf[jx++] = 0x0f; /* SI */
- case 0: /* Current state is Roman */
- jbuf[jx++] = 0x1b; /* ESC */
- jbuf[jx++] = 0x24; /* $ */
- jbuf[jx++] = 0x42; /* B */
- default: /* Current state is already Kanji */
- jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
- jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
- break;
- }
- jstate = 2; /* Set state to Kanji */
- }
- for (i = 0; i < jx; i++) /* Output the result */
- if ((rc = pnbyte(jbuf[i],fn)) < 0)
- return(rc);
- return(jx); /* Return its length */
- }
- default:
- if (sj.x_short < 0x80)
- return(sj.x_short);
- else
- return('?');
- }
- }
- #endif /* KANJI */
- #endif /* UNICODE */
- debug(F100,"xpnbyte BAD FALLTHRU","",0);
- return(-1);
- }
- #ifndef NOXFER
- /* D E C O D E -- Kermit Data-packet decoder */
- int
- #ifdef CK_ANSIC
- decode(CHAR *buf, int (*fn)(char), int xlate)
- #else
- decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
- #endif /* CK_ANSIC */
- /* decode */ {
- register unsigned int a, a7, a8, b8; /* Various copies of current char */
- int t; /* Int version of character */
- int ssflg; /* Character was single-shifted */
- int ccpflg; /* For Ctrl-unprefixing stats */
- int len;
- long z;
- CHAR c;
- /*
- Catch the case in which we are asked to decode into a file that is not open,
- for example, if the user interrupted the transfer, but the other Kermit
- keeps sending.
- */
- if ((cxseen || czseen || discard) && (fn == putfil))
- return(0);
- #ifdef COMMENT
- #ifdef CKTUNING
- if (binary && !parity)
- return(bdecode(buf,fn));
- #endif /* CKTUNING */
- #endif /* COMMENT */
- debug(F100,"DECODE","",0);
- xdbuf = buf; /* Make global copy of pointer. */
- rpt = 0; /* Initialize repeat count. */
- len = rln; /* Number of bytes in data field */
- while (len > 0) { /* Loop for each byte */
- a = *xdbuf++ & 0xff; /* Get next character */
- len--;
- if (a == rptq && rptflg) { /* Got a repeat prefix? */
- rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
- rptn += rpt;
- a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
- len -= 2;
- }
- b8 = lsstate ? 0200 : 0; /* 8th-bit value from SHIFT-STATE */
- if (ebqflg && a == ebq) { /* Have 8th-bit prefix? */
- b8 ^= 0200; /* Yes, invert the 8th bit's value, */
- ssflg = 1; /* remember we did this, */
- a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
- len--;
- } else ssflg = 0;
- ccpflg = 0;
- if (a == ctlq) { /* If control prefix, */
- a = *xdbuf++ & 0xFF; /* get its operand */
- len--;
- a7 = a & 0x7F; /* and its low 7 bits. */
- if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
- a = ctl(a); /* if in control range. */
- a7 = a & 0x7F;
- ccpflg = 1; /* Note that we did this */
- ccp++; /* Count for stats */
- }
- } else a7 = a & 0x7f; /* Not control quote */
- if (a7 < 32 || a7 == 127) { /* Control character? */
- if (!ccpflg) ccu++; /* A bare one, count it */
- if (lscapu) { /* If doing locking shifts... */
- if (lsstate) /* If SHIFTED */
- a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
- else /* otherwise */
- a8 = a | b8; /* OR in 8th bit */
- /* If we're not in a quoted sequence */
- if (!lsquote && (!lsstate || !ssflg)) {
- if (a8 == DLE) { /* Check for DLE quote */
- lsquote = 1; /* prefixed by single shift! */
- continue;
- } else if (a8 == SO) { /* Check for Shift-Out */
- lsstate = 1; /* SHIFT-STATE = SHIFTED */
- continue;
- } else if (a8 == SI) { /* or Shift-In */
- lsstate = 0; /* SHIFT-STATE = UNSHIFTED */
- continue;
- }
- } else lsquote = 0;
- }
- }
- a |= b8; /* OR in the 8th bit */
- if (rpt == 0) rpt = 1; /* If no repeats, then one */
- #ifndef NOCSETS
- if (!binary) { /* If in text mode, */
- if (tcharset != TC_UCS2) {
- if (feol && a == CR) /* Convert CRLF to newline char */
- continue;
- if (feol && a == LF)
- a = feol;
- }
- if (xlatype == XLA_BYTE) /* Byte-for-byte - do it now */
- if (xlate && rx) a = (*rx)((CHAR) a);
- }
- #endif /* NOCSETS */
- /* (PWP) Decoding speedup via buffered output and a macro... */
- if (fn == putfil) {
- for (; rpt > 0; rpt--) { /* Output the char RPT times */
- #ifdef CALIBRATE
- if (calibrate) {
- ffc++;
- continue;
- }
- #endif /* CALIBRATE */
- /* Note: The Unicode and Kanji sections can probably be combined now; */
- /* the Unicode method (xpnbyte()) covers Kanji too. */
- #ifdef UNICODE
- if (!binary && xlatype == XLA_UNICODE)
- t = xpnbyte((unsigned)((unsigned)a & 0xff),
- tcharset,
- fcharset,
- fn
- );
- else
- #endif /* UNICODE */
- #ifdef KANJI
- if (!binary && tcharset == TC_JEUC &&
- fcharset != FC_JEUC) { /* Translating from J-EUC */
- if (ffc == 0L) xkanjf();
- if (xkanji(a,fn) < 0) /* to something else? */
- return(-1);
- else t = 1;
- } else
- #endif /* KANJI */
- {
- #ifdef OS2
- if (xflg && !remfile) { /* Write to virtual screen */
- char _a;
- _a = a & fmask;
- t = conoc(_a);
- if (t < 1)
- t = -1;
- } else
- #endif /* OS2 */
- t = zmchout(a & fmask); /* zmchout is a macro */
- }
- if (t < 0) {
- debug(F101,"decode write errno","",errno);
- return(-1);
- }
- #ifdef UNICODE
- if (xlatype != XLA_UNICODE || binary) {
- ffc++; /* Count the character */
- if (docrc && !xflg && !remfile) { /* Update file CRC */
- c = a; /* Force conversion to unsigned char */
- z = crc16 ^ (long)c;
- crc16 = (crc16 >> 8) ^
- (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
- }
- }
- #endif /* UNICODE */
- }
- } else { /* Output to something else. */
- a &= fmask; /* Apply file mask */
- for (; rpt > 0; rpt--) { /* Output the char RPT times */
- #ifdef CALIBRATE
- if (calibrate) {
- ffc++;
- continue;
- }
- #endif /* CALIBRATE */
- if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
- }
- }
- #ifdef CK_CTRLZ
- lastchar = a;
- #endif /* CK_CTRLZ */
- }
- return(0);
- }
- /* G E T P K T -- Fill a packet data field */
- /*
- Gets characters from the current source -- file or memory string.
- Encodes the data into the packet, filling the packet optimally.
- Set first = 1 when calling for the first time on a given input stream
- (string or file).
- Call with:
- bufmax -- current send-packet size
- xlate -- flag: 0 to skip character-set translation, 1 to translate
- Uses global variables:
- t -- current character.
- first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
- next -- next character (not used any more).
- data -- pointer to the packet data buffer.
- size -- number of characters in the data buffer.
- memstr - flag that input is coming from a memory string instead of a file.
- memptr - pointer to string in memory.
- (*sx)() character set translation function
- Returns:
- The size as value of the function, and also sets global "size",
- and fills (and null-terminates) the global data array.
- Returns:
- 0 on EOF.
- -1 on fatal (internal) error.
- -3 on timeout (e.g. when reading data from a pipe).
- Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
- Incorporates old getchx() and encode() inline to reduce function calls,
- uses buffered input for much-improved efficiency, and clears up some
- confusion with line termination (CRLF vs LF vs CR).
- Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
- May 1991. And again in 1998 for efficiency, etc, with a separate
- bgetpkt() split out for binary-mode no-parity transfers.
- */
- /*
- Note: Separate Kanji support dates from circa 1991 and now (1999) can most
- likely be combined with the the Unicode support: the xgnbyte()/xpnbyte()
- mechanism works for both Unicode and Kanji.
- */
- #ifdef KANJI
- int
- kgetf(
- #ifdef CK_ANSIC
- VOID
- #endif /* CK_ANSIC */
- ) {
- if (funcstr)
- return((*funcptr)());
- else
- return(zminchar());
- }
- int
- kgetm(
- #ifdef CK_ANSIC
- VOID
- #endif /* CK_ANSIC */
- ) {
- int x;
- if (x = *memptr++) return(x);
- else return(-1);
- }
- #endif /* KANJI */
- /*
- Lookahead function to decide whether locking shift is worth it. Looks at
- the next four input characters to see if all of their 8th bits match the
- argument. Call with 0 or 0200. Returns 1 on match, 0 if they don't match.
- If we don't happen to have at least 4 more characters waiting in the input
- buffer, returns 1. Note that zinptr points two characters ahead of the
- current character because of repeat-count lookahead.
- */
- int
- lslook(b) unsigned int b; { /* Locking Shift Lookahead */
- int i;
- if (zincnt < 3) /* If not enough chars in buffer, */
- return(1); /* force shift-state switch. */
- b &= 0200; /* Force argument to proper form. */
- for (i = -1; i < 3; i++) /* Look at next 5 characters to */
- if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match. */
- return(0); /* They don't. */
- return(1); /* They do. */
- }
- /* Routine to compute maximum data length for packet to be filled */
- int
- maxdata() { /* Get maximum data length */
- int n, len;
- debug(F101,"maxdata spsiz 1","",spsiz);
- if (spsiz < 0) /* How could this happen? */
- spsiz = DSPSIZ;
- debug(F101,"maxdata spsiz 2","",spsiz);
- n = spsiz - 5; /* Space for Data and Checksum */
- if (n > 92 && n < 96) n = 92; /* "Short" Long packets don't pay */
- if (n > 92 && lpcapu == 0) /* If long packets needed, */
- n = 92; /* make sure they've been negotiated */
- len = n - bctl; /* Space for data */
- if (n > 92) len -= 3; /* Long packet needs header chksum */
- debug(F101,"maxdata len 1","",len);
- if (len < 0) len = 10;
- debug(F101,"maxdata len 2","",len);
- return(len);
- }
- static CHAR leftover[9] = { ' ',' ',' ',' ',' ',' ',' ',' ',' ' };
- static int nleft = 0;
- #ifdef CKTUNING
- /*
- When CKTUNING is defined we use this special trimmed-down version of getpkt
- to speed up binary-mode no-parity transfers. When CKTUNING is not defined,
- or for text-mode or parity transfers, we use the regular getpkt() function.
- Call just like getpkt() but test first for transfer mode and parity. NOTE:
- This routine is only to be called when sending a real file -- not for
- filenames, server responses, etc, because it only reads from the input file.
- See getpkt() for more detailed commentary.
- */
- static int
- bgetpkt(bufmax) int bufmax; {
- register CHAR rt = t, rnext;
- register CHAR *dp, *odp, *p1, *p2;
- register int x = 0, a7;
- CHAR xxrc, xxcq; /* Pieces of prefixed sequence */
- long z; /* A long worker (for CRC) */
- if (!binary || parity || memstr) /* JUST IN CASE caller didn't test */
- return(getpkt(bufmax,!binary));
- if (!data) {
- debug(F100,"SERIOUS ERROR: bgetpkt data == NULL","",0);
- return(-1);
- }
- dp = data; /* Point to packet data buffer */
- size = 0; /* And initialize its size */
- bufmax = maxdata(); /* Get maximum data length */
- #ifdef DEBUG
- if (deblog)
- debug(F101,"bgetpkt bufmax","",bufmax);
- #endif /* DEBUG */
- if (first == 1) { /* If first character of this file.. */
- ffc = 0L; /* reset file character counter */
- #ifdef COMMENT
- /* Moved to below */
- first = 0; /* Next character won't be first */
- #endif /* COMMENT */
- *leftover = ' '; /* Discard any interrupted leftovers */
- nleft = 0;
- /* Get first character of file into rt, watching out for null file */
- #ifdef CALIBRATE
- if (calibrate) {
- #ifdef NORANDOM
- rt = 17;
- #else
- rt = cal_a[rand() & 0xff];
- #endif /* NORANDOM */
- first = 0;
- } else
- #endif /* CALIBRATE */
- if ((x = zminchar()) < 0) { /* EOF or error */
- if (x == -3) { /* Timeout. */
- size = (dp - data);
- debug(F101,"bgetpkt timeout size","",size);
- return((size == 0) ? x : size);
- }
- first = -1;
- size = 0;
- if (x == -2) { /* Error */
- debug(F100,"bgetpkt: input error","",0);
- cxseen = 1; /* Interrupt the file transfer */
- } else {
- debug(F100,"bgetpkt empty file","",0);
- }
- return(0);
- }
- first = 0; /* Next char will not be the first */
- ffc++; /* Count a file character */
- rt = (CHAR) x; /* Convert int to char */
- if (docrc && what == W_SEND) { /* Accumulate file crc */
- z = crc16 ^ (long)rt;
- crc16 = (crc16 >> 8) ^
- (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
- }
- rt &= fmask; /* Apply SET FILE BYTESIZE mask */
- } else if (first == -1 && nleft == 0) { /* EOF from last time */
- return(size = 0);
- }
- /*
- Here we handle characters that were encoded for the last packet but
- did not fit, and so were saved in the "leftover" array.
- */
- if (nleft) {
- for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
- *dp++ = *p1++;
- *leftover = ' '; /* Delete leftovers */
- nleft = 0;
- }
- if (first == -1) /* Handle EOF */
- return(size = (dp - data));
- /* Now fill up the rest of the packet. */
- rpt = 0; /* Initialize character repeat count */
- while (first > -1) { /* Until EOF... */
- #ifdef CALIBRATE
- if (calibrate) { /* We generate our own "file" */
- if (ffc >= calibrate) { /* EOF */
- first = -1;
- ffc--;
- } else { /* Generate next character */
- if (cal_j > CAL_M * ffc)
- cal_j = cal_a[ffc & 0xff];
- x = (unsigned)cal_a[(cal_j & 0xff)];
- if (x == rt) x ^= 2;
- }
- ffc++;
- cal_j += (unsigned int)(ffc + CAL_O);
- } else
- #endif /* CALIBRATE */
- if ((x = zminchar()) < 0) { /* Check for EOF */
- if (x == -3) { /* Timeout. */
- t = rt;
- size = (dp-data);
- debug(F101,"bgetpkt timeout size","",size);
- return((size == 0) ? x : size);
- }
- first = -1; /* Flag eof for next time. */
- if (x == -2) cxseen = 1; /* If error, cancel this file. */
- } else {
- ffc++; /* Count the character */
- if (docrc && what == W_SEND) { /* Accumulate file crc */
- z = crc16 ^ (long)((CHAR)x & 0xff);
- crc16 = (crc16 >> 8) ^
- (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
- }
- }
- rnext = (CHAR) (x & fmask); /* Apply file mask */
- /*
- At this point, the character we just read is in rnext,
- and the character we are about to encode into the packet is in rt.
- */
- odp = dp; /* Remember where we started. */
- xxrc = xxcq = NUL; /* Clear these. */
- /*
- Now encode the character according to the options that are in effect:
- ctlp[]: whether this control character needs prefixing.
- rptflg: repeat counts enabled.
- Other options don't apply in this routine.
- */
- if (rptflg && rt == rnext && first == 0) { /* Got a run... */
- if (++rpt < 94) { /* Below max, just count */
- continue; /* go back and get another */
- } else if (rpt == 94) { /* Reached max, must dump */
- xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
- rptn += rpt; /* Accumulate it for statistics */
- rpt = 0; /* And reset it */
- }
- } else if (rpt > 0) { /* End of run */
- xxrc = (CHAR)tochar(++rpt); /* The count */
- rptn += rpt; /* For stats */
- rpt = 0; /* Reset repeat count */
- }
- a7 = rt & 0177; /* Get low 7 bits of character */
- if (
- #ifdef CK_SPEED
- ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
- #else
- (a7 < SP) || (a7 == DEL)
- #endif /* CK_SPEED */
- ) { /* Do control prefixing if necessary */
- xxcq = myctlq; /* The prefix */
- ccp++; /* Count it */
- rt = (CHAR) ctl(rt); /* Uncontrollify the character */
- }
- #ifdef CK_SPEED
- else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
- ccu++;
- #endif /* CK_SPEED */
- if (a7 == myctlq) /* Always prefix the control prefix */
- xxcq = myctlq;
- if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
- xxcq = myctlq; /* prefix it if doing repeat counts */
- /* Now construct the prefixed sequence */
- if (xxrc) { /* Repeat count */
- if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
- *dp++ = rt; /* So just do this */
- } else { /* More than two or prefixed */
- *dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */
- }
- }
- if (xxcq) { *dp++ = myctlq; } /* Control prefix */
- *dp++ = rt; /* Finally, the character itself */
- rt = rnext; /* Next character is now current. */
- /* Done encoding the character. Now take care of packet buffer overflow. */
- size = dp - data; /* How many bytes we put in buffer. */
- if (size >= bufmax) { /* If too big, save some for next. */
- *dp = ' '; /* Mark the end. */
- if (size > bufmax) { /* if packet is overfull */
- /* Copy the part that doesn't fit into the leftover buffer, */
- /* taking care not to split a prefixed sequence. */
- int i;
- nleft = dp - odp;
- p1 = leftover;
- p2 = odp;
- for (i = 0; i < nleft; i++)
- *p1++ = *p2++;
- size = odp - data; /* Return truncated packet. */
- *odp = ' '; /* Mark the new end */
- }
- t = rt; /* Save for next time */
- return(size);
- }
- } /* Otherwise, keep filling. */
- size = dp - data; /* End of file */
- *dp = ' '; /* Mark the end of the data. */
- return(size); /* Return partially filled last packet. */
- }
- #endif /* CKTUNING */
- VOID
- dofilcrc(c) int c; { /* Accumulate file crc */
- long z;
- z = crc16 ^ (long)c;
- crc16 = (crc16 >> 8) ^
- (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
- }
- /* For SENDing from an array... */
- int
- agnbyte() { /* Get next byte from array */
- #ifndef NOSPL
- char c;
- static int save = 0; /* For CRLF */
- static char ** ap = NULL; /* Array pointer */
- static char * p = NULL; /* Character pointer */
- static int i = 0, n = 0; /* Array index and limit */
- extern int a_dim[]; /* Array dimension */
- int x = 1;
- if (!ap) { /* First time thru */
- ap = sndarray; /* Set up array pointers */
- if (!ap || (i = sndxlo) > a_dim[sndxin]) {
- sndarray = NULL;
- ap = NULL;
- return(-1);
- }
- p = ap[i]; /* Point to first element in range */
- n = sndxhi; /* Index of last element in range */
- if (sndxhi > a_dim[sndxin]) /* Adjust if necessary */
- n = a_dim[sndxin];
- }
- if (save) { /* If anything saved */
- c = save; /* unsave it */
- save = 0; /* and return it */
- return(c & 0xff);
- }
- if (i > n) { /* No more elements */
- sndarray = NULL;
- ap = NULL;
- return(-1);
- }
- if (!p) /* Source pointer is NULL */
- c = NUL; /* this means an empty line */
- else /* Source pointer not NULL */
- c = *p++; /* Next char */
- if (!c) { /* Char is empty? */
- if (!binary) { /* Text: end of line. */
- if (feol) { /* Supply NL */
- c = feol;
- } else { /* or CRLF */
- save = LF;
- c = CR;
- }
- p = ap[++i];
- return(c & 0xff);
- }
- while (i++ < n) { /* Binary - get next element */
- p = ap[i];
- if (!p) /* Empty line? */
- continue; /* Ignore it and get another */
- c = *p++; /* Get next char */
- if (!c) /* Emtpy char? */
- continue; /* Ignore it and get another */
- return(c & 0xff); /* Not empty - return it */
- }
- sndarray = NULL;
- ap = NULL;
- return(-1); /* Done */
- }
- return(c & 0xff); /* Char is not empty */
- #else
- sndarray = NULL;
- return(-1);
- #endif /* NOSPL */
- }
- #endif /* NOXFER */
- #ifndef NOCSETS
- static CHAR xlabuf[32] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- static int xlacount = 0;
- static int xlaptr = 0;
- static USHORT lastucs2 = 0;
- /*
- X G N B Y T E -- Get next translated byte from the input file.
- Returns the next byte that is to be put into the packet, already translated.
- This isolates getpkt() from having to know anything about translation,
- single- vs multibyte character sets, one-to-many vs many-to-one, etc, but it
- has rather high overhead, so don't call it unless you know translation is
- needed to or from Unicode, Japanese, or other multibyte character set.
- Call with:
- fcs: File character set (source, file we are reading from)
- tcs: Target character set (use an FC_xxx code, not a TC_xxx code)
- Returns:
- >= 0: A translated byte suitable for writing.
- < 0: Fatal error (such as EOF on input source).
- */
- int
- xgnbyte(tcs,fcs) int tcs, fcs; {
- _PROTOTYP( int (*xx), (USHORT) ) = NULL;
- #ifdef UNICODE
- extern int ucsorder; /* SET FILE UCS BYTE-ORDER */
- #endif /* UNICODE */
- int haveuc = 0; /* Flag for have Unicode character */
- #ifdef KANJI
- int havesj = 0; /* Have Shift-JIS character */
- int haveeu = 0; /* Have EUC-JP character */
- #endif /* KANJI */
- int rc = -1, x = 0, flag = 0;
- int utferror = 0;
- int eolflag = 0;
- unsigned int xc, thischar;
- static int swapping = 0;
- CHAR rt;
- USHORT ch;
- #ifdef UNICODE
- union ck_short uc;
- #endif /* UNICODE */
- #ifdef KANJI
- union ck_short sj, eu; /* Shift-JIS character */
- #endif /* KANJI */
- #ifdef KANJI
- sj.x_short = 0;
- #endif /* KANJI */
- if (xlacount-- > 0) { /* We already have some */
- x = xlabuf[xlaptr++];
- debug(F001,"xgnbyte SEND from buf","",x);
- return(x);
- }
- if (xlatype != XLA_NONE) { /* Not not translating... */
- haveuc = 0;
- #ifdef UNICODE
- if (fcs == FC_UCS2) { /* UCS-2: Read two bytes */
- if (ffc == 0) { /* Beginning of file? */
- swapping = 0; /* Reset byte-swapping flag */
- }
- uc.x_short = 0;
- bomskip:
- x = zminchar(); /* Get first byte */
- flag = 1; /* Remember we called zminchar() */
- if (x > -1) { /* Didn't fail */
- ffc++; /* Count a file byte */
- uc.x_char[swapping] = x & 0xff;
- #ifndef NOXFER
- if (docrc && what == W_SEND)
- dofilcrc(x);
- #endif /* NOXFER */
- if ((x = zminchar()) > -1) { /* If didn't fail */
- ffc++; /* count another file byte */
- uc.x_char[1-swapping] = x & 0xff;
- haveuc = 1; /* And remember we have Unicode */
- #ifndef NOXFER
- if (docrc && what == W_SEND)
- dofilcrc(x);
- #endif /* NOXFER */
- if (ffc == 2) { /* Second char of file */
- debug(F001,"xgnbyte 1st UCS2","",uc.x_short);
- if (uc.x_short == (USHORT)0xfeff) {
- swapping = 0;
- debug(F101,
- "xgnbyte UCS2 goodbom swap","",swapping);
- goto bomskip;
- } else if (uc.x_short == (USHORT)0xfffe) {
- swapping = 1;
- debug(F101,
- "xgnbyte UCS2 badbom swap","",swapping);
- goto bomskip;
- } else if ((byteorder && !ucsorder) ||
- (!byteorder && ucsorder)) {
- CHAR c;
- c = uc.x_char[0];
- uc.x_char[0] = uc.x_char[1];
- uc.x_char[1] = c;
- swapping = 1;
- debug(F101,
- "xgnbyte UCS2 no BOM X swap","",swapping);
- } else {
- swapping = 0;
- debug(F101,
- "xgnbyte UCS2 no BOM Y swap","",swapping);
- }
- }
- } else
- return(x);
- } else
- return(x);
- debug(F001,"xgnbyte UCS2","",uc.x_short);
- } else if (fcs == FC_UTF8) { /* File is UTF-8 */
- CHAR ch = 0; /* Data types needed for API... */
- USHORT * us = NULL;
- uc.x_short = 0;
- flag = 1; /* We (will) have called zminchar() */
- while ((x = zminchar()) > -1) { /* Read source bytes */
- ffc++; /* Got a byte - count it */
- #ifndef NOXFER
- if (docrc && what == W_SEND)
- dofilcrc(x);
- #endif /* NOXFER */
- ch = x;
- rc = utf8_to_ucs2(ch,&us); /* Convert to UCS-2 */
- if (rc == 0) { /* Done */
- uc.x_short = *us;
- haveuc = 1;
- break;
- } else if (rc < 0) { /* Error */
- utferror = 1;
- debug(F101,"xgnbyte UTF-8 input error","",rc);
- haveuc = 1;
- uc.x_short = *us;
- break;
- }
- }
- if (x < 0)
- return(x);
- debug(F001,"xgnbyte UTF8->UTF2","",uc.x_short);
- }
- #endif /* UNICODE */
- #ifdef KANJI
- #ifdef UNICODE
- else
- #endif /* UNICODE */
- if (fcsinfo[fcs].alphabet == AL_JAPAN) { /* Japanese source file */
- int c7, x, y, done = 0;
- if (fcs == FC_JIS7) { /* If file charset is JIS-7 */
- if (ffc == 0L) /* If first byte of file */
- j7init(); /* Initialize JIS-7 parser */
- x = getj7(); /* Get a JIS-7 byte */
- } else /* Otherwise */
- x = zminchar(); /* Just get byte */
- if (x < 0) { /* Propogate EOF or error */
- debug(F100,"XGNBYTE EOF","",0);
- return(x);
- }
- debug(F001,"XGNBYTE x","",x);
- ffc++; /* Count */
- #ifndef NOXFER
- if (docrc && what == W_SEND) dofilcrc(x); /* Do CRC */
- #endif /* NOXFER */
- switch (fcs) { /* What next depends on charset */
- case FC_SHJIS: /* Shift-JIS */
- if ((x <= 0x80) || /* Any 7-bit char... */
- (x >= 0xa0 && x <= 0xdf)) { /* or halfwidth Katakana */
- sj.x_short = (USHORT) x; /* we read one byte. */
- } else { /* Anything else */
- if ((y = zminchar()) < 0) /* get another */
- return(y);
- #ifndef NOXFER
- if (docrc && what == W_SEND) dofilcrc(y);
- #endif /* NOXFER */
- ffc++;
- sj.x_char[byteorder] = (CHAR) x;
- sj.x_char[1-byteorder] = (CHAR) y;
- }
- break;
- case FC_JIS7: /* JIS-7 */
- case FC_JDEC: /* DEC Kanji */
- case FC_JEUC: /* EUC-JP */
- if ((x & 0x80) == 0) { /* Convert to Shift-JIS */
- sj.x_short = (USHORT) x; /* C0 or G0: one byte */
- eu.x_short = (USHORT) x;
- haveeu = 1;
- } else {
- c7 = x & 0x7f;
- if (c7 > 0x20 && c7 < 0x7f) { /* Kanji: two bytes */
- if ((y = (fcs == FC_JEUC) ? zminchar() : getj7()) < 0)
- return(y);
- ffc++;
- #ifndef NOXFER
- if (docrc && what == W_SEND) dofilcrc(y);
- #endif /* NOXFER */
- eu.x_char[byteorder] = (CHAR) x;
- eu.x_char[1-byteorder] = (CHAR) y;
- sj.x_short = eu_to_sj(eu.x_short);
- haveeu = 1;
- } else if (x == 0x8e) { /* SS2 Katakana prefix: 2 bytes */
- if ((y = (fcs == FC_JIS7) ? getj7() : zminchar()) < 0)
- return(y);
- ffc++;
- #ifndef NOXFER
- if (docrc && what == W_SEND) dofilcrc(y);
- #endif /* NOXFER */
- sj.x_short = y | 0x80;
- debug(F001,"XGNBYTE KANA SJ","",sj.x_short);
- } else {
- /* Something that translates to U+FFFD */
- sj.x_short = UNKSJIS;
- }
- }
- break;
- }
- havesj = 1; /* Have Shift-JIS */
- #ifdef UNICODE
- uc.x_short = sj_to_un(sj.x_short); /* Translate to UCS-2 */
- haveuc = 1; /* Have Unicode */
- #endif /* UNICODE */
- flag = 1; /* Have a char */
- }
- #endif /* KANJI */
- }
- if (!flag) { /* If no character was read yet... */
- if ((x = zminchar()) > -1) /* read one now */
- ffc++;
- debug(F101,"xgnbyte zminchar 1","",x);
- if (x < 0)
- return(x);
- haveuc = 0;
- }
- #ifdef UNICODE
- if (haveuc) {
- thischar = uc.x_short;
- lastucs2 = uc.x_short;
- } else
- #endif /* UNICODE */
- thischar = x;
- debug(F001,"xgnbyte thischar",haveuc ? "[UNICODE]" : "[other]",thischar);
- #ifdef CK_CTRLZ /* SET EOF CTRLZ */
- if (eofmethod == XYEOF_Z && !binary && thischar == 26) {
- debug(F100,"xgnbyte EOF on Ctrl-Z 1","",0);
- return(-1);
- }
- #endif /* CK_CTRLZ */
- #ifdef UNICODE
- if (!haveuc) /* If not Unicode... */
- #endif /* UNICODE */
- x &= fmask; /* Apply SET FILE BYTESIZE mask */
- switch (xlatype) { /* Translation type... */
- #ifdef UNICODE
- case XLA_UNICODE: { /* Unicode is involved */
- xc = 0;
- /*
- Here we must choose the appropriate translation function. If we are being
- called by getpkt() (i.e. when transferring a file), we are translating from
- Unicode to the Transfer Character Set and therefore must use the function
- pointed to by xut. Otherwise, e.g. during TRANSLATE, CONNECT, TRANSMIT, etc,
- we are translating from Unicode to the File Character Set and so must call
- the function pointed to by xuf. There might be a cleaner way to set this
- up but I don't think so. For example, setxlatype() might have been called
- too soon and so might not have known whether it was a file transfer or a
- local operation.
- */
- xx = (what == W_SEND) ? xut : xuf;
- eolflag = 0;
- if (haveuc) { /* File is Unicode */
- /* See Unicode TR13, "Converting to Other Character Sets" */
- if (uc.x_short == 0x2028 || /* Line Separator? */
- uc.x_short == 0x2029 || /* Paragraph Separator */
- (feol && (uc.x_short == (USHORT)feol))
- ) {
- debug(F001,"xgnbyte uc eol","",uc.x_short);
- rc = 0;
- eolflag = 1; /* Don't translate and handle later */
- }
- if (xx && !eolflag) { /* UCS-to-TCS function (UCS->byte) */
- rc = (*xx)(uc.x_short); /* These can fail... */
- debug(F101,"xgnbyte xx rc","",rc);
- if (rc < 0) /* If it can't be translated */
- uc.x_short = UNK; /* Put unknown-character symbol */
- else
- uc.x_short = (unsigned)((unsigned)rc & 0xffff);
- debug(F101,"xgnbyte xx uc","",uc.x_short);
- }
- #ifdef KANJI
- if (tcs == FC_JEUC) { /* Translating to EUC-JP */
- USHORT sj;
- union ck_short eu;
- debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short);
- if (!havesj) /* If we don't already have it */
- sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */
- eu.x_short = sj_to_eu(sj);
- debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short);
- xlaptr = 0;
- xlacount = 0;
- if (eolflag) {
- if (what == W_SEND) {
- xlabuf[xlacount++] = LF;
- return(CR);
- } else {
- return(feol);
- }
- }
- if (eu.x_char[byteorder]) { /* Two bytes */
- rc = eu.x_char[byteorder];
- xlabuf[xlacount++] = eu.x_char[1-byteorder];
- debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]);
- } else { /* One byte */
- rc = eu.x_char[1-byteorder];
- }
- debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount);
- debug(F001,"xgnbyte UCS->EUC rc","",rc);
- return(rc);
- } else
- #endif /* KANJI */
- if (tcs != FC_UCS2 && tcs != FC_UTF8) {
- if (uc.x_short & 0xff00) { /* Decoding error */
- debug(F001,"xgnbyte decoding error","",uc.x_short);
- return(-2);
- } else
- return((unsigned int)(uc.x_short & 0xff));
- }
- xc = uc.x_short;
- } else { /* File is not Unicode */
- USHORT ch;
- /* Translate from single FCS byte to UCS-2 */
- /*
- This is a bit nonobvious... The blah_u() (Blah-to-Unicode) routines are
- called only with pieces of character sets, in the ISO 2022 sense. So,
- for example, if ch is a Latin-1 character, we call the translation
- routine only if it is in the right half; if it's in the left half, it
- isn't translated, and in fact will give the wrong result if sent to the
- translation function. That's because those functions were designed for
- use with the ISO 2022 G0..G3 sets, not for file transfer. On the other
- hand, if it's a 7-bit character set, we *do* call the translation
- function. (To put it another way, the left half of any 8-bit character
- set is ASCII and therefore doesn't need to be translated but 7-bit sets
- such as ISO 646 German do need translation).
- */
- ch = (unsigned)(thischar & 0xff);
- if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) ||
- fcsinfo[fcs].size <= 128) {
- if (xfu) { /* FCS-to-UCS function */
- ch = (*xfu)(ch);
- }
- }
- xc = ch;
- }
- /* At this point we have a UCS-2 character in native format */
- /* (Big Endian or Little Endian) in xc, which is an unsigned int. */
- debug(F001,"xgnbyte xc","",xc);
- if (tcs == FC_UTF8) { /* Now convert to UTF-8 */
- USHORT c; /* NOTE: this is FC_UTF8 on purpose! */
- CHAR * buf = NULL;
- int i, k = 0, x;
- xlaptr = 0;
- if (utferror) {
- xlabuf[k++] = 0xff;
- xlabuf[k++] = 0xbd;
- }
- if (eolflag) { /* We detected EOL in source file */
- if (what == W_SEND) { /* Convert to CRLF */
- xlabuf[k++] = LF;
- xlacount = k;
- return((unsigned int)CR);
- } else { /* Or to local line-end */
- xlacount = k;
- return((unsigned int)feol);
- }
- }
- c = xc;
- if ((x = ucs2_to_utf8(c,&buf)) < 1) {
- debug(F101,"xgnbyte ucs2_to_utf8 error","",c);
- return(-2);
- }
- debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]);
- for (i = 1; i < x; i++) {
- xlabuf[k+i-1] = buf[i];
- debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]);
- }
- xlaptr = 0;
- xlacount = x - 1;
- debug(F101,"xgnbyte UTF8 xlacount","",xlacount);
- return((unsigned int)buf[0]);
- } else { /* Or keep it as UCS-2 */
- int k = 0;
- CHAR c;
- xlaptr = 0;
- if (utferror) {
- xlabuf[k++] = 0xff;
- xlabuf[k++] = 0xfd;
- debug(F101,"xgnbyte error","",k);
- }
- if (eolflag) { /* We detected EOL in source file */
- if (what == W_SEND) { /* Convert to CRLF */
- xlabuf[k++] = CR;
- xlabuf[k++] = NUL;
- xlabuf[k++] = LF;
- xlacount = k;
- debug(F101,"xgnbyte send CRLF","",k);
- return(0); /* Return NUL */
- } else { /* Or to local line-end */
- xlabuf[k++] = (CHAR)feol;
- xlacount = k;
- debug(F101,"xgnbyte send feol","",k);
- return(0); /* Return NUL */
- }
- }
- if (what == W_SEND || !ucsorder) {
- xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */
- xlabuf[k++] = xc & 0xff;
- debug(F110,"xgnbyte to UCS2 BE",ckitoa(xlabuf[0]),0);
- } else { /* Little Endian */
- xlabuf[k++] = xc & 0xff;
- xlabuf[k++] = (xc >> 8) & 0xff;
- debug(F110,"xgnbyte to UCS2 LE",ckitoa(xlabuf[0]),0);
- }
- c = xlabuf[0];
- xlaptr = 1;
- xlacount = k-1;
- debug(F101,"xgnbyte c","",c);
- debug(F101,"xgnbyte xlaptr","",xlaptr);
- debug(F101,"xgnbyte xlacount","",xlacount);
- return((unsigned int)c);
- }
- }
- #endif /* UNICODE */
- case XLA_NONE:
- return(zminchar());
- case XLA_BYTE: /* Byte-for-Byte translation */
- rt = x;
- if (sx)
- rt = (*sx)(rt);
- #ifdef UNICODE
- if (utferror) {
- xlaptr = 0;
- xlacount = 1;
- xlabuf[0] = rt;
- return(UNK);
- } else
- #endif /* UNICODE */
- return((unsigned int)rt);
- #ifdef KANJI
- case XLA_JAPAN: /* Come here with Shift-JIS */
- if (tcs == FC_JEUC) { /* It better be... */
- xlaptr = 0;
- xlacount = 0;
- if (!havesj) {
- printf("BAD BADn");
- return(-2);
- }
- if (!haveeu) /* We might already have EUC too */
- eu.x_short = sj_to_eu(sj.x_short);
- if (eu.x_char[byteorder]) {
- xlabuf[xlacount++] = eu.x_char[1-byteorder];
- return(eu.x_char[byteorder]);
- } else {
- return(eu.x_char[1-byteorder]);
- }
- break;
- }
- #endif /* KANJI */
- default:
- debug(F101,"xgnbyte bad xlatype","",xlatype);
- return(-2);
- }
- /* NOTREACHED */
- /* Some compilers complain if this is not here, others if it is. */
- debug(F100,"xgnbyte switch failure","",0);
- return(-2);
- }
- #endif /* NOCSETS */
- #ifndef NOXFER
- /* G E T P K T -- Fill a packet data field from the indicated source. */
- /*
- Parameters:
- bufmax: Maximum length of entire packet.
- xlate: Flag for whether to translate charsets when in text mode.
- Returns: Number of characters written to packet data field, 0 or more,
- Or -1 on failure (internal error),
- or -3 on timeout (e.g. when reading from a pipe).
- This is the full version allowing for parity and text-mode conversions;
- i.e. it works in all cases. Also see bgetpkt(), a special lean/mean/fast
- packet encoder that works only for binary-mode no-parity transfers.
- */
- static int uflag = 0;
- int
- getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
- register CHAR rt = t, rnext = NUL; /* Register shadows of the globals */
- register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
- register int x; /* Loop index. */
- register int a7; /* Low 7 bits of character */
- int thischar = 0; /* Might be byte or wide */
- CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */
- if (binary) xlate = 0; /* We don't translate if binary */
- if (!data) {
- debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0);
- return(-1);
- }
- dp = data; /* Point to packet data buffer */
- size = 0; /* And initialize its size */
- /*
- Assume bufmax is the receiver's total receive-packet buffer length.
- Our whole packet has to fit into it, so we adjust the data field length.
- We also decide optimally whether it is better to use a short-format or
- long-format packet when we're near the borderline.
- */
- bufmax = maxdata(); /* Get maximum data length */
- if (first == 1) { /* If first character of this file.. */
- #ifdef UNICODE
- /* Special end-of-line handling for Unicode */
- if (tcharset == TC_UCS2 || tcharset == TC_UTF8)
- uflag = 1;
- #endif /* UNICODE */
- debug(F101,"getpkt first uflag","",uflag);
- debug(F101,"getpkt first rt","",rt);
- if (!memstr && !funcstr) /* and real file... */
- ffc = 0L; /* reset file character counter */
- #ifdef COMMENT
- /* Moved to below... */
- first = 0; /* Next character won't be first */
- #endif /* COMMENT */
- *leftover = ' '; /* Discard any interrupted leftovers */
- nleft = 0;
- #ifndef NOCSETS
- setxlatype(tcharset,fcharset); /* Set up charset translations */
- #endif /* NOCSETS */
- /* Get first character of file into rt, watching out for null file */
- #ifdef CALIBRATE
- if (calibrate && !memstr) {
- #ifdef NORANDOM
- x = rt = 53;
- #else
- x = rt = cal_a[rand() & 0xff];
- #endif /* NORANDOM */
- first = 0;
- ffc++;
- } else
- #endif /* CALIBRATE */
- #ifdef KANJI
- if (xlate && tcharset == TC_JEUC) { /* Kanji text */
- x = zkanjf();
- if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
- first = -1;
- size = 0;
- if (x == -2) {
- debug(F100,"getpkt zkanji: input error","",0);
- cxseen = 1;
- } else debug(F100,"getpkt zkanji: empty string/file","",0);
- return(0);
- }
- rt = x;
- first = 0;
- if (!memstr) {
- ffc++;
- if (docrc && what == W_SEND) /* Accumulate file crc */
- dofilcrc((int)rt);
- }
- } else { /* Not Kanji text */
- #endif /* KANJI */
- if (memstr) { /* Reading data from memory string */
- /* This will not be Unicode */
- if ((rt = *memptr++) == ' ') { /* end of string ==> EOF */
- first = -1;
- size = 0;
- debug(F100,"getpkt: empty string","",0);
- return(0);
- }
- first = 0;
- } else if (funcstr) { /* Reading data from a function */
- /* This will not be Unicode */
- if ((x = (*funcptr)()) < 0) { /* End of input */
- first = -1;
- size = 0; /* Empty */
- return(0);
- }
- ffc++; /* Count a file character */
- rt = (CHAR) x; /* Convert int to char */
- first = 0;
- debug(F000,"getpkt funcstr","",rt);
- } else { /* Reading data from a file */
- #ifndef NOCSETS
- if (xlate && !binary) { /* Could be Unicode */
- if (xlatype == XLA_UNICODE) {
- /* Get next translated byte */
- x = xgnbyte(cseqtab[tcharset],fcharset);
- debug(F101,"getpkt xgnbyte","",x);
- } else { /* Not Unicode */
- x = zminchar(); /* Get next byte, translate below */
- debug(F101,"getpkt zminchar A","",x);
- }
- } else { /* Just get next byte */
- #endif /* NOCSETS */
- x = zminchar();
- debug(F101,"getpkt zminchar B","",x);
- #ifndef NOCSETS
- }
- #endif /* NOCSETS */
- if (x < 0) { /* End of file or input error */
- if (x == -3) { /* Timeout. */
- size = (dp-data);
- debug(F101,"getpkt timeout size","",size);
- return((size == 0) ? x : size);
- }
- first = -1;
- size = 0;
- if (x == -2) { /* Error */
- debug(F100,"getpkt: input error","",0);
- cxseen = 1; /* Interrupt the file transfer */
- } else {
- debug(F100,"getpkt empty file","",0);
- }
- return(0);
- }
- first = 0; /* Next character won't be first */
- rt = (CHAR) x; /* Convert int to char */
- #ifndef NOCSETS
- if (xlatype != XLA_UNICODE || binary) {
- ffc++;
- if (sx)
- rt = (*sx)(rt);
- if (docrc && what == W_SEND)
- dofilcrc(x);
- }
- #endif /* NOCSETS */
- #ifdef DEBUG
- if (deblog)
- debug(F101,"getpkt 1st char","",rt);
- #endif /* DEBUG */
- if (/* !haveuc && */ docrc && what == W_SEND) /* File CRC */
- dofilcrc(x);
- }
- #ifdef KANJI
- }
- #endif /* KANJI */
- /* PWP: handling of feol is done later (in the while loop)... */
- } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */
- #ifdef DEBUG
- if (deblog) {
- debug(F101,"getpkt eof crc16","",crc16);
- debug(F101,"getpkt eof ffc","",ffc);
- }
- #endif /* DEBUG */
- return(size = 0);
- }
- /*
- Here we handle characters that were encoded for the last packet but
- did not fit, and so were saved in the "leftover" array.
- */
- debug(F101,"getpkt nleft","",nleft);
- if (nleft) {
- for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
- *dp++ = *p1++;
- *leftover = ' '; /* Delete leftovers */
- nleft = 0;
- }
- if (first == -1) /* Handle EOF */
- return(size = (dp - data));
- /* Now fill up the rest of the packet. */
- rpt = 0; /* Initialize character repeat count */
- while (first > -1) { /* Until EOF... */
- #ifdef CALIBRATE
- if (calibrate && !memstr) { /* We generate our own "file" */
- if (ffc >= calibrate) { /* EOF */
- first = -1;
- ffc--;
- } else { /* Generate next character */
- if (cal_j > CAL_M * ffc)
- cal_j = cal_a[ffc & 0xff];
- x = (unsigned)cal_a[(cal_j & 0xff)];
- if (x == rt) x ^= 2;
- }
- cal_j += (unsigned int)(ffc + CAL_O);
- ffc++;
- } else
- #endif /* CALIBRATE */
- #ifdef KANJI
- if (xlate && tcharset == TC_JEUC) {
- if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
- first = -1;
- if (x == -2) cxseen = 1;
- } else if (!memstr) ffc++;
- rnext = (CHAR) (x & fmask);
- } else {
- #endif /* KANJI */
- if (memstr) { /* Get next char from memory string */
- if ((x = *memptr++) == ' ') /* End of string means EOF */
- first = -1; /* Flag EOF for next time. */
- rnext = (CHAR) (x & fmask); /* Apply file mask */
- } else if (funcstr) { /* Get next char from function */
- if ((x = (*funcptr)()) < 0) /* End of string means EOF */
- first = -1; /* Flag EOF for next time. */
- rnext = (CHAR) (x & fmask); /* Apply file mask */
- } else { /* From file... */
- #ifndef NOCSETS
- if (xlate && !binary) { /* Could be Unicode */
- if (xlatype == XLA_UNICODE) {
- /* Get next translated byte */
- x = xgnbyte(cseqtab[tcharset],fcharset);
- } else { /* Not Unicode */
- x = zminchar(); /* Get next byte, translate below */
- debug(F101,"xgnbyte B zminchar","",x);
- }
- } else { /* Just get next byte */
- #endif /* NOCSETS */
- x = zminchar();
- debug(F101,"xgnbyte C zminchar","",x);
- #ifndef NOCSETS
- }
- #endif /* NOCSETS */
- if (x < 0) { /* Check for EOF */
- if (x == -3) { /* Timeout reading from pipe */
- t = rt;
- size = (dp-data);
- debug(F101,"getpkt timeout size","",size);
- return((size == 0) ? x : size);
- }
- first = -1; /* Flag eof for next time. */
- if (x == -2) cxseen = 1; /* If error, cancel this file. */
- }
- rnext = (CHAR) (x & fmask); /* Apply file mask */
- #ifndef NOCSETS
- if (xlatype != XLA_UNICODE) {
- #endif /* NOCSETS */
- ffc++;
- #ifndef NOCSETS
- if (sx)
- rt = (*sx)(rt);
- #endif /* NOCSETS */
- if (docrc && what == W_SEND)
- dofilcrc(x);
- #ifndef NOCSETS
- }
- #endif /* NOCSETS */
- }
- #ifdef KANJI
- }
- #endif /* KANJI */
- /*
- At this point, the character we just read is in rnext,
- and the character we are about to encode into the packet is in rt.
- */
- odp = dp; /* Remember where we started. */
- xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
- /*
- Now encode the character according to the options that are in effect:
- ctlp[]: whether this control character needs prefixing.
- binary: text or binary mode.
- rptflg: repeat counts enabled.
- ebqflg: 8th-bit prefixing enabled.
- lscapu: locking shifts enabled.
- */
- if (rptflg) { /* Repeat processing is on? */
- if (!uflag &&
- /*
- * If the next char is really CRLF, then we cannot
- * be doing a repeat (unless CR,CR,LF which becomes
- * "~ <n-1> CR CR LF", which is OK but not most efficient).
- * I just plain don't worry about this case. The actual
- * conversion from NL to CRLF is done after the rptflg if...
- */
- (!feol || binary || (feol && (rnext != feol))) &&
- (rt == rnext) && (first == 0)) { /* Got a run... */
- if (++rpt < 94) { /* Below max, just count */
- continue; /* go back and get another */
- } else if (rpt == 94) { /* Reached max, must dump */
- xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
- rptn += rpt; /* Accumulate it for statistics */
- rpt = 0; /* And reset it */
- }
- } else if (rpt > 1) { /* More than two */
- xxrc = (CHAR) tochar(++rpt); /* and count. */
- rptn += rpt;
- rpt = 0; /* Reset repeat counter. */
- }
- /*
- If (rpt == 1) we must encode exactly two characters.
- This is done later, after the first character is encoded.
- */
- }
- /* If it's the newline character... */
- if (!uflag && !binary && feol && (rt == feol)) {
- if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */
- if (ebqflg) { /* If single shifts enabled, */
- *dp++ = (CHAR) ebq; /* insert a single shift. */
- } else { /* Otherwise must shift in. */
- *dp++ = myctlq; /* Insert shift-out code */
- *dp++ = 'O';
- lsstate = 0; /* Change shift state */
- }
- }
- #ifdef CK_SPEED
- if (ctlp[CR]) {
- *dp++ = myctlq; /* Insert carriage return directly */
- *dp++ = 'M';
- ccp++;
- } else {
- *dp++ = CR; /* Perhaps literally */
- ccu++;
- }
- #else /* !CK_SPEED */
- *dp++ = myctlq; /* Insert carriage return directly */
- *dp++ = 'M';
- ccp++;
- #endif /* CK_SPEED */
- rt = LF; /* Now make next char be linefeed. */
- }
- /*
- Now handle the 8th bit of the file character. If we have an 8-bit
- connection, we preserve the 8th bit. If we have a 7-bit connection,
- we employ either single or locking shifts (if they are enabled).
- */
- a7 = rt & 0177; /* Get low 7 bits of character */
- if (rt & 0200) { /* 8-bit character? */
- if (lscapu) { /* Locking shifts enabled? */
- if (!lsstate) { /* Not currently shifted? */
- x = lslook(0200); /* Look ahead */
- if (x != 0 || ebqflg == 0) { /* Locking shift decision */
- xxls = 'N'; /* Need locking shift-out */
- lsstate = 1; /* and change to shifted state */
- } else if (ebqflg) { /* Not worth it */
- xxss = (CHAR) ebq; /* Use single shift */
- }
- }
- rt = (CHAR) a7; /* Replace character by 7-bit value */
- } else if (ebqflg) { /* 8th bit prefixing is on? */
- xxss = (CHAR) ebq; /* Insert single shift */
- rt = (CHAR) a7; /* Replace character by 7-bit value */
- }
- /*
- In case we have a 7-bit connection and this is an 8-bit character, AND
- neither locking shifts nor single shifts are enabled, then the character's
- 8th bit will be destroyed in transmission, and a block check error will
- occur.
- */
- } else if (lscapu) { /* 7-bit character */
- if (lsstate) { /* Comes while shifted out? */
- x = lslook(0); /* Yes, look ahead */
- if (x || ebqflg == 0) { /* Time to shift in. */
- xxls = 'O'; /* Set shift-in code */
- lsstate = 0; /* Exit shifted state */
- } else if (ebqflg) { /* Not worth it, stay shifted out */
- xxss = (CHAR) ebq; /* Insert single shift */
- }
- }
- }
- /* If data character is significant to locking shift protocol... */
- if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
- xxdl = 'P'; /* Insert datalink escape */
- if (
- #ifdef CK_SPEED
- /*
- Thwart YET ANOTHER unwanted, unneeded, and unloved sign
- extension. This one was particularly nasty because it prevented
- 255 (Telnet IAC) from being prefixed on some platforms -- e.g.
- VMS with VAX C -- but not others, thus causing file transfers to
- fail on Telnet connections by sending bare IACs. Not to mention
- the stray memory reference. Signed chars are a BAD idea.
- */
- ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
- #else
- (a7 < SP) || (a7 == DEL)
- #endif /* CK_SPEED */
- ) { /* Do control prefixing if necessary */
- xxcq = myctlq; /* The prefix */
- ccp++; /* Count it */
- rt = (CHAR) ctl(rt); /* Uncontrollify the character */
- }
- #ifdef CK_SPEED
- else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
- ccu++;
- #endif /* CK_SPEED */
- if (a7 == myctlq) /* Always prefix the control prefix */
- xxcq = myctlq;
- if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
- xxcq = myctlq; /* prefix it if doing repeat counts */
- if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */
- xxcq = myctlq; /* if doing 8th-bit prefixes */
- /* Now construct the entire sequence */
- if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
- odp2 = dp; /* (Save this place) */
- if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
- if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
- if (xxss) { *dp++ = (CHAR) ebq; } /* Single shift */
- if (xxcq) { *dp++ = myctlq; } /* Control prefix */
- *dp++ = rt; /* Finally, the character itself */
- if (rpt == 1) { /* Exactly two copies? */
- rpt = 0;
- p2 = dp; /* Save place temporarily */
- for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
- *dp++ = *p1;
- if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
- if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */
- }
- rt = rnext; /* Next character is now current. */
- /* Done encoding the character. Now take care of packet buffer overflow. */
- if ((dp-data) >= bufmax) { /* If too big, save some for next. */
- debug(F000,"getpkt EOP","",rt);
- size = (dp-data); /* Calculate the size. */
- *dp = ' '; /* Mark the end. */
- if (memstr) { /* No leftovers for memory strings */
- if (rt) /* Char we didn't encode yet */
- memptr--; /* (for encstr()) */
- return(size);
- }
- if ((dp-data) > bufmax) { /* if packet is overfull */
- /* copy the part that doesn't fit into the leftover buffer, */
- /* taking care not to split a prefixed sequence. */
- int i;
- nleft = dp - odp;
- for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) {
- *p1++ = *p2++;
- if (memstr) memptr--; /* (for encstr) */
- }
- debug(F111,"getpkt leftover",leftover,size);
- debug(F101,"getpkt osize","",(odp-data));
- size = (odp-data); /* Return truncated packet. */
- *odp = ' '; /* Mark the new end */
- }
- t = rt; /* Save for next time */
- return(size);
- }
- } /* Otherwise, keep filling. */
- size = (dp-data); /* End of file */
- *dp = ' '; /* Mark the end of the data. */
- debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
- return(size); /* return partially filled last packet. */
- }
- /* T I N I T -- Initialize a transaction */
- int epktrcvd = 0, epktsent = 0;
- /*
- Call with 1 to reset everything before S/I/Y negotiation, or 0 to
- reset only the things that are not set in the S/I/Y negotiation.
- Returns -1 on failure (e.g. to create packet buffers), 0 on success.
- */
- int
- tinit(flag) int flag; {
- int x;
- #ifdef CK_TIMERS
- extern int rttflg;
- #else
- extern int rcvtimo;
- #endif /* CK_TIMERS */
- extern int fatalio;
- debug(F101,"tinit flag","",flag);
- *epktmsg = NUL;
- epktrcvd = 0;
- epktsent = 0;
- ofperms = "";
- diractive = 0; /* DIR / REMOTE DIR not active */
- interrupted = 0; /* Not interrupted */
- fatalio = 0; /* No fatal i/o error */
- if (server) {
- moving = 0;
- #ifdef PIPESEND
- pipesend = 0; /* This takes care of multiple GETs sent to a server. */
- #endif /* PIPESEND */
- }
- bestlen = 0; /* For packet length optimization */
- maxsend = 0; /* Biggest data field we can send */
- #ifdef STREAMING
- streamok = 0; /* Streaming negotiated */
- streaming = 0; /* Streaming being done now */
- #endif /* STREAMING */
- binary = b_save; /* ... */
- gnf_binary = binary; /* Per-file transfer mode */
- retrans = 0; /* Packet retransmission count */
- sndtyp = 0; /* No previous packet */
- xflg = 0; /* Reset x-packet flag */
- memstr = 0; /* Reset memory-string flag */
- memptr = NULL; /* and buffer pointer */
- funcstr = 0; /* Reset "read from function" flag */
- funcptr = NULL; /* and function pointer */
- autopar = 0; /* Automatic parity detection flag */
- /* This stuff is only for BEFORE S/I/Y negotiation, not after */
- if (flag) {
- bctu = bctl = 1; /* Reset block check type to 1 */
- myinit[0] = ' '; /* Haven't sent init string yet */
- rqf = -1; /* Reset 8th-bit-quote request flag */
- ebq = MYEBQ; /* Reset 8th-bit quoting stuff */
- ebqflg = 0; /* 8th bit quoting not enabled */
- ebqsent = 0; /* No 8th-bit prefix bid sent yet */
- sq = 'Y'; /* 8th-bit prefix bid I usually send */
- spsiz = spsizr; /* Initial send-packet size */
- debug(F101,"tinit spsiz","",spsiz);
- wslots = 1; /* One window slot */
- wslotn = 1; /* No window negotiated yet */
- justone = 0; /* (should this be zero'd here?) */
- what = W_INIT; /* Doing nothing so far... */
- }
- fncnv = f_save; /* Back to what user last said */
- pktnum = 0; /* Initial packet number to send */
- cxseen = czseen = discard = 0; /* Reset interrupt flags */
- *filnam = ' '; /* Clear file name */
- spktl = 0; /* And its length */
- nakstate = 0; /* Assume we're not in a NAK state */
- numerrs = 0; /* Transmission error counter */
- idletmo = 0; /* No idle timeout yet */
- if (server) { /* If acting as server, */
- if (srvidl > 0) /* If an idle timeout is given */
- timint = srvidl;
- else
- timint = srvtim; /* use server timeout interval. */
- } else { /* Otherwise */
- timint = chktimo(rtimo,timef); /* and use local timeout value */
- }
- debug(F101,"tinit timint","",timint);
- #ifdef CK_TIMERS
- if (rttflg && timint > 0) /* Using round-trip timers? */
- rttinit();
- #else
- rcvtimo = timint;
- #endif /* CK_TIMERS */
- winlo = 0; /* Packet 0 is at window-low */
- debug(F101,"tinit winlo","",winlo);
- x = mksbuf(1); /* Make a 1-slot send-packet buffer */
- if (x < 0) return(x);
- x = getsbuf(0); /* Allocate first send-buffer. */
- debug(F101,"tinit getsbuf","",x);
- if (x < 0) return(x);
- dumpsbuf();
- x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */
- if (x < 0) return(x);
- lsstate = 0; /* Initialize locking shift state */
- if (autopath) { /* SET RECEIVE PATHNAMES AUTO fixup */
- fnrpath = PATH_AUTO;
- autopath = 0;
- }
- return(0);
- }
- VOID
- pktinit() { /* Initialize packet sequence */
- pktnum = 0; /* number & window low. */
- winlo = 0;
- debug(F101,"pktinit winlo","",winlo);
- }
- /* R I N I T -- Respond to S or I packet */
- VOID
- rinit(d) CHAR *d; {
- char *tp;
- ztime(&tp);
- tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
- tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
- tlog(F110,"Collision action:", fncnam[fncact],0);
- tlog(F100,"","",0);
- debug(F101,"rinit fncact","",fncact);
- filcnt = filrej = 0; /* Init file counters */
- spar(d);
- ack1(rpar());
- #ifdef datageneral
- if ((local) && (!quiet)) /* Only do this if local & not quiet */
- consta_mt(); /* Start the asynch read task */
- #endif /* datageneral */
- }
- /* R E S E T C -- Reset per-transaction character counters */
- VOID
- resetc() {
- rptn = 0; /* Repeat counts */
- fsecs = flci = flco = 0L; /* File chars in and out */
- #ifdef GFTIMER
- fpfsecs = 0.0;
- #endif /* GFTIMER */
- tfc = tlci = tlco = 0L; /* Total file, line chars in & out */
- ccu = ccp = 0L; /* Control-char statistics */
- #ifdef COMMENT
- fsize = -1L; /* File size */
- #else
- if (what != W_SEND)
- fsize = -1L;
- debug(F101,"resetc fsize","",fsize);
- #endif /* COMMENT */
- timeouts = retrans = 0; /* Timeouts, retransmissions */
- spackets = rpackets = 0; /* Packet counts out & in */
- crunched = 0; /* Crunched packets */
- wcur = 0; /* Current window size */
- wmax = 0; /* Maximum window size used */
- peakcps = 0; /* Peak chars per second */
- }
- /* S I N I T -- Get & verify first file name, then send Send-Init packet */
- /*
- Returns:
- 1 if send operation begins successfully
- 0 if send operation fails
- */
- #ifdef DYNAMIC
- char *cmargbuf = NULL;
- #else
- char cmargbuf[CKMAXPATH+1];
- #endif /* DYNAMIC */
- char *cmargp[2];
- VOID
- fnlist() {
- if (!calibrate)
- sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */
- #ifdef DYNAMIC
- if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1)))
- fatal("fnlist: no memory for cmargbuf");
- #endif /* DYNAMIC */
- cmargbuf[0] = NUL; /* Initialize name buffer */
- debug(F101,"fnlist nfils","",nfils);
- debug(F110,"fnlist cmarg",cmarg,0);
- debug(F110,"fnlist cmarg2",cmarg2,0);
- if (!cmarg2) cmarg2 = "";
- if (nfils == 0) { /* Sending from stdin or memory. */
- if ((cmarg2 != NULL) && (*cmarg2)) {
- cmarg = cmarg2; /* If F packet, "as-name" is used */
- cmarg2 = ""; /* if provided */
- } else
- cmarg = "stdin"; /* otherwise just use "stdin" */
- ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1);
- cmargp[0] = cmargbuf;
- cmargp[1] = "";
- cmlist = cmargp;
- nfils = 1;
- }
- }
- int
- sinit() {
- int x; /* Worker int */
- char *tp, *xp, *m; /* Worker string pointers */
- filcnt = filrej = 0; /* Initialize file counters */
- fnlist();
- xp = "";
- if (nfils < 0) {
- #ifdef PIPESEND
- if (usepipes && protocol == PROTO_K && *cmarg == '!') {
- pipesend = 1;
- cmarg++;
- }
- #endif /* PIPESEND */
- xp = cmarg;
- } else {
- #ifndef NOMSEND
- if (addlist)
- xp = filehead->fl_name;
- else
- #endif /* NOMSEND */
- if (filefile)
- xp = filefile;
- else if (calibrate)
- xp = "Calibration";
- else
- xp = *cmlist;
- }
- debug(F110,"sinit xp",xp,0);
- x = gnfile(); /* Get first filename. */
- m = NULL; /* Error message pointer */
- debug(F101,"sinit gnfil","",x);
- switch (x) {
- case -5: m = "Too many files match wildcard"; break;
- case -4: m = "Cancelled"; break;
- case -3: m = "Read access denied"; break;
- case -2: m = "File is not readable"; break;
- #ifdef COMMENT
- case -1: m = iswild(filnam) ? "No files match" : "File not found";
- break;
- case 0: m = "No filespec given!"; break;
- #else
- case 0:
- case -1: m = iswild(filnam) ? "No files match" : "File not found";
- break;
- #endif /* COMMENT */
- default:
- break;
- }
- debug(F101,"sinit nfils","",nfils);
- debug(F110,"sinit filnam",filnam,0);
- if (x < 1) { /* Didn't get a file. */
- if (server) /* Doing GET command */
- errpkt((CHAR *)m); /* so send Error packet. */
- else /* Doing SEND command */
- xxscreen(SCR_EM,0,0l,m); /* so print message. */
- tlog(F110,xp,m,0L); /* Make transaction log entry. */
- freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
- return(0); /* Return failure code */
- }
- if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */
- sleep(ckdelay); /* Delay if requested */
- #ifdef datageneral
- if ((local) && (!quiet)) /* Only do this if local & not quiet */
- consta_mt(); /* Start the asynch read task */
- #endif /* datageneral */
- freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
- sipkt('S'); /* Send the Send-Init packet. */
- ztime(&tp); /* Get current date/time */
- tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
- tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
- tlog(F100,"","",0);
- debug(F111,"sinit ok",filnam,0);
- return(1);
- }
- int
- #ifdef CK_ANSIC
- sipkt(char c) /* Send S or I packet. */
- #else
- sipkt(c) char c;
- #endif
- /* sipkt */ {
- CHAR *rp; int k, x;
- debug(F101,"sipkt pktnum","",pktnum);
- k = sseqtbl[pktnum]; /* Find slot for this packet */
- debug(F101,"sipkt k","",k);
- if (k < 0) { /* No slot? */
- k = getsbuf(winlo = pktnum); /* Make one. */
- debug(F101,"sipkt getsbuf","",k);
- }
- ttflui(); /* Flush pending input. */
- rp = rpar(); /* Get protocol parameters. */
- x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */
- return(x);
- }
- /* X S I N I T -- Retransmit S-packet */
- /*
- For use in the GET-SEND sequence, when we start to send, but receive another
- copy of the GET command because the receiver didn't get our S packet.
- This retransmits the S packet and frees the receive buffer for the ACK.
- This special case is necessary because packet number zero is being re-used.
- */
- VOID
- xsinit() {
- int k;
- k = rseqtbl[0];
- debug(F101,"xsinit k","",k);
- if (k > -1)
- freerbuf(k);
- resend(0);
- }
- /* R C V F I L -- Receive a file */
- /*
- Incoming filename is in data field of F packet.
- This function decodes it into the srvcmd buffer, substituting an
- alternate "as-name", if one was given.
- Then it does any requested transformations (like converting to
- lowercase), and finally if a file of the same name already exists,
- takes the desired collision action.
- Returns:
- 1 on success.
- 0 on failure.
- */
- char ofn1[CKMAXPATH+4]; /* Buffer for output file name */
- char * ofn2; /* Pointer to backup file name */
- int ofn1x; /* Flag output file already exists */
- int opnerr; /* Flag for open error */
- int /* Returns success ? 1 : 0 */
- rcvfil(n) char *n; {
- extern int en_cwd;
- extern char * rcvexcept[];
- int i, skipthis;
- char * n2;
- #ifdef OS2ONLY
- char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
- #endif /* OS2ONLY */
- #ifdef DTILDE
- char *dirp;
- #endif /* DTILDE */
- int dirflg, x, y;
- #ifdef PIPESEND
- extern char * rcvfilter;
- #endif /* PIPESEND */
- extern char * rrfspec;
- #ifdef CALIBRATE
- extern int dest;
- int csave;
- csave = calibrate; /* So we can decode filename */
- calibrate = 0;
- #endif /* CALIBRATE */
- ofperms = ""; /* Reset old-file permissions */
- opnerr = 0; /* No open error (yet) */
- ofn2 = NULL; /* No new name (yet) */
- lsstate = 0; /* Cancel locking-shift state */
- srvptr = srvcmd; /* Decode file name from packet. */
- #ifdef UNICODE
- xpnbyte(-1,0,0,NULL); /* Reset UCS-2 byte counter. */
- #endif /* UNICODE */
- debug(F110,"rcvfil rdatap",rdatap,0);
- decode(rdatap,putsrv,0); /* Don't xlate charsets. */
- #ifdef CALIBRATE
- calibrate = csave;
- if (dest == DEST_N) {
- calibrate = 1;
- cmarg2 = "CALIBRATE";
- }
- #endif /* CALIBRATE */
- if (*srvcmd == ' ') /* Watch out for null F packet. */
- strcpy((char *)srvcmd,"NONAME");
- makestr(&rrfspec,(char *)srvcmd);
- #ifdef DTILDE
- if (*srvcmd == '~') {
- dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
- if (*dirp != ' ') strcpy((char *)srvcmd,dirp);
- }
- #else
- #ifdef OS2
- if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == ' ')
- strcat((char *)srvcmd,"NONAME");
- #endif /* OS2 */
- #endif /* DTILDE */
- if (!ENABLED(en_cwd)) { /* CD is disabled */
- zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
- if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
- rf_err = "Access denied";
- return(0);
- }
- }
- #ifdef COMMENT
- /* Wrong place for this -- handle cmarg2 first -- see below... */
- if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
- debug(F110,"rcvfil access denied",srvcmd,0);
- rf_err = "Write access denied";
- discard = opnerr = 1;
- return(0);
- }
- xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
- debug(F110,"rcvfil srvcmd 1",srvcmd,0);
- tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
- #endif /* COMMENT */
- skipthis = 0; /* This file in our exception list? */
- for (i = 0; i < 8; i++) {
- if (!rcvexcept[i]) {
- break;
- }
- if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) {
- skipthis = 1;
- break;
- }
- }
- #ifdef DEBUG
- if (deblog && skipthis) {
- debug(F111,"rcvfil rcvexcept",rcvexcept[i],i);
- debug(F110,"rcvfil skipping",srvcmd,0);
- }
- #endif /* DEBUG */
- if (skipthis) { /* Skipping this file */
- discard = 1;
- rejection = 1;
- rf_err = "Exception list";
- debug(F101,"rcvfil discard","",discard);
- tlog(F100," refused: exception list","",0);
- return(1);
- }
- /* File is not in exception list */
- if (!cmarg2) /* No core dumps please */
- cmarg2 = "";
- debug(F110,"rcvfil cmarg2",cmarg2,0);
- if (*cmarg2) { /* Check for alternate name */
- #ifndef NOSPL
- int y; char *s; /* Pass it thru the evaluator */
- extern int cmd_quoting;
- if (cmd_quoting) {
- y = MAXRP;
- ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for v(filename) */
- s = (char *)srvcmd;
- zzstring(cmarg2,&s,&y);
- } else
- *srvcmd = NUL;
- if (!*srvcmd) /* If we got something */
- #endif /* NOSPL */
- strcpy((char *)srvcmd,cmarg2);
- }
- debug(F110,"rcvfil srvcmd 2",srvcmd,0);
- #ifdef PIPESEND
- /* If it starts with "bang", it's a pipe, not a file. */
- if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) {
- CHAR *s;
- s = srvcmd+1; /* srvcmd[] is not a pointer. */
- while (*s) { /* So we have to slide the contents */
- *(s-1) = *s; /* over 1 space to the left. */
- s++;
- }
- *(s-1) = NUL;
- pipesend = 1;
- }
- #endif /* PIPESEND */
- #ifdef COMMENT
- /*
- This is commented out because we need to know whether the name we are
- using was specified by the local user as an override, or came from the
- incoming packet. In the former case, we don't do stuff to it (like
- strip the pathname) that we might do to it in the latter.
- */
- cmarg2 = ""; /* Done with alternate name */
- #endif /* COMMENT */
- if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
- *(srvcmd + CKMAXPATH - 1) = NUL;
- /* At this point, srvcmd[] contains the incoming filename or as-name. */
- /* So NOW we check for write access. */
- if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
- debug(F110,"rcvfil access denied",srvcmd,0);
- rf_err = "Write access denied";
- discard = opnerr = 1;
- return(0);
- }
- xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
- debug(F110,"rcvfil srvcmd 1",srvcmd,0);
- tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
- #ifdef CK_LABELED
- #ifdef VMS
- /*
- If we have an as-name, this overrides the internal name if we are doing
- a labeled-mode transfer.
- */
- if (*cmarg2) {
- extern int lf_opts;
- lf_opts &= ~LBL_NAM;