home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / gunixio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  29KB  |  1,173 lines

  1. /* G U N I X I O  --  UNIX i/o module for gkermit */
  2.  
  3. /*
  4.   UNIX i/o functions for gkermit.
  5.  
  6.   Author:
  7.     Frank da Cruz
  8.     The Kermit Project
  9.     Columbia University
  10.     612 West 115th Street
  11.     New York NY 10025-7799  USA
  12.     http://www.columbia.edu/kermit/
  13.     kermit@columbia.edu
  14.  
  15.   Copyright (C) 1999,
  16.   The Trustees of Columbia University in the City of New York.
  17.  
  18.   This program is free software; you can redistribute it and/or modify
  19.   it under the terms of the GNU General Public License as published by
  20.   the Free Software Foundation; either version 2 of the License, or
  21.   (at your option) any later version.
  22.  
  23.   This program is distributed in the hope that it will be useful,
  24.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.   GNU General Public License for more details.
  27.  
  28.   You should have received a copy of the GNU General Public License
  29.   along with this program; if not, write to the Free Software
  30.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  31. */
  32.  
  33. /*
  34.  CONTENTS...
  35.  
  36.  Console Output:
  37.    tmsg   - Type a message
  38.    tmsgl  - Type a line
  39.  
  40.  Communication Device:
  41.    ttopen - Open
  42.    ttpkt  - Put in packet mode
  43.    ttres  - Restore normal mode
  44.    ttinl  - Input a raw packet
  45.    ttol   - Send a packet
  46.    ttchk  - Check if input ready
  47.    ttflui - Flush input buffer
  48.  
  49.  File:
  50.    zchki  - See if file can be opened for input
  51.    zopeni - Open input file
  52.    zopeno - Open output file
  53.    zclosi - Close input file
  54.    zcloso - Close output file
  55.    zrtol  - Remote-to-Local filename conversion
  56.    zltor  - Local-to-Remote filename conversion
  57.    zgetc  - Get character from input file
  58. */
  59.  
  60. #include <stdio.h>            /* Standard input/output */
  61.  
  62. #ifdef POSIX
  63. #include <termios.h>            /* Terminal modes */
  64. #else
  65. #ifdef SYSV
  66. #include <termio.h>
  67. #else
  68. #include <sgtty.h>
  69. #endif /* SYSV */
  70. #endif /* POSIX */
  71.  
  72. #include <ctype.h>            /* Character types */
  73. #include <sys/types.h>            /* Needed e.g. by <stat.h> */
  74. #include <signal.h>            /* Interrupts */
  75. #include <setjmp.h>            /* Longjumps */
  76. #include <sys/stat.h>            /* File exist, file size */
  77. #include <errno.h>            /* Error symbols */
  78. #include "gkermit.h"            /* gkermit definitions */
  79.  
  80. /* All versions of HP-UX need Xon/Xoff */
  81.  
  82. #ifdef hpux                /* HP-UX Pre-7.00 */
  83. #ifndef __hpux
  84. #define __hpux
  85. #endif /* __hpux */
  86. #endif /* hpux */
  87.  
  88. #ifdef __hpux                /* HP-UX 7.00 and later */
  89. #ifndef SETXONXOFF
  90. #define SETXONXOFF
  91. #endif /* SETXONXOFF */
  92. #endif /*  __hpux */
  93.  
  94. #ifdef NOXONXOFF            /* -DNOXONXOFF overrides */
  95. #ifdef SETXONXOFF
  96. #undef SETXONXOFF
  97. #endif /* SETXONXOFF */
  98. #endif /* NOXONXOFF */
  99.  
  100. #ifndef TINBUFSIZ            /* read() inpbut buffer */
  101. #ifdef USE_GETCHAR
  102. #define TINBUFSIZ 0            /* getchar() has its own */
  103. #else
  104. #ifdef SMALL
  105. #define TINBUFSIZ 240
  106. #else
  107. #define TINBUFSIZ 4080
  108. #endif /* SMALL */
  109. #endif /* USE_GETCHAR */
  110. #endif /* TINBUFSIZ */
  111.  
  112. #ifndef DUMBIO
  113. #ifndef USE_GETCHAR
  114. #ifndef NOFCNTL_H            /* For nonblocking buffered read() */
  115. #ifdef SYS_FCNTL_H
  116. #include <sys/fcntl.h>
  117. #else
  118. #include <fcntl.h>
  119. #ifndef O_NDELAY
  120. #ifdef O_NONBLOCK
  121. #define O_NDELAY O_NONBLOCK
  122. #endif /* O_NONBLOCK */
  123. #endif /* O_NDELAY */
  124. #endif /* SYS_FCNTL_H */
  125. #endif /* NOFCNTL_H */
  126. #endif /* USE_GETCHAR */
  127. #endif /* DUMBIO */
  128.  
  129. #ifdef O_NDELAY                /* For System V R3 and earlier */
  130. #ifndef EWOULDBLOCK
  131. #ifdef EAGAIN
  132. #define EWOULDBLOCK EAGAIN
  133. #endif /* EAGAIN */
  134. #endif /* EWOULDBLOCK */
  135. #endif /* O_NDELAY */
  136.  
  137. #ifndef DUMBIO                /* To force single-char read/write */
  138. #ifndef USE_GETCHAR
  139. #ifndef O_NDELAY
  140. #define DUMBIO
  141. #endif /* O_NDELAY */
  142. #endif /* USE_GETCHAR */
  143. #endif /* DUMBIO */
  144.  
  145. /* Header file deficiencies section... */
  146.  
  147. #ifndef R_OK
  148. #define R_OK 4
  149. #endif /* R_OK */
  150.  
  151. #ifndef W_OK
  152. #define W_OK 2
  153. #endif /* W_OK */
  154.  
  155. #ifndef _IFMT
  156. #ifdef S_IFMT
  157. #define _IFMT S_IFMT
  158. #else
  159. #define _IFMT 0170000
  160. #endif /* S_IFMT */
  161. #endif /* _IFMT */
  162.  
  163. #ifndef S_ISREG
  164. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  165. #endif /* S_ISREG */
  166.  
  167. /* External variables */
  168.  
  169. extern int literal;            /* Literal filenames */
  170. extern int quiet;            /* No messages */
  171. extern int keep;            /* Keep incomplete files */
  172. extern int streamok;            /* OK to offer streaming */
  173. extern int nomodes;            /* Don't get/set tty modes */
  174. extern int xonxoff;            /* Set Xon/Xoff */
  175. extern int noxonxoff;            /* Don't set Xon/Xoff */
  176. extern FILE * db;            /* Debug log file */
  177.  
  178. /* Exported variables */
  179.  
  180. FILE *ifp, *ofp;            /* Input and output file pointers */
  181. char zinbuf[MAXRECORD+1];        /* File input buffer */
  182. int zincnt = 0;                /* count */
  183. char * zinptr = NULL;            /* and pointer. */
  184.  
  185. /* Private global variables */
  186.  
  187. static int havemodes = 0;        /* Have obtained terminal modes */
  188. static int ttflags = -1;        /* Terminal flags */
  189. static int nonblock = 0;        /* Nonblocking i/o enabled */
  190. static char tinbuf[TINBUFSIZ+16];    /* Communications input buffer */
  191. static char * tinptr = NULL;        /* Pointer to current item */
  192. static int tincnt = 0;            /* Buffer count */
  193. static int tlast = 0;            /* Last item in buffer */
  194. static int xparity = 0;            /* Parity in use, 0 = none */
  195. static int raw = 0;            /* Terminal rawmode flag */
  196. static char work[MAXPATHLEN+1];        /* Filename conversion buffer */
  197.  
  198. /* Terminal mode structs */
  199.  
  200. #ifdef POSIX                /* POSIX */
  201. static struct termios ttold, ttraw;
  202. #else
  203. #ifdef SYSV                /* System V */
  204. static struct termio ttold = {0};
  205. static struct termio ttraw = {0};
  206. #else
  207. #ifdef BSD                /* 4.2 BSD or UNIX V7 */
  208. static struct sgttyb ttold, ttraw;
  209. #endif /* BSD */
  210. #endif /* SYSV */
  211. #endif /* POSIX */
  212.  
  213. static jmp_buf jbuf;            /* Longjump buffer for timeouts */
  214.  
  215. /* Functions... */
  216.  
  217. SIGTYP
  218. doexit(x) int x; {            /* Exit routine */
  219.     if (x)                /* If failure */
  220.       ttflui();                /* flush pending junk we won't read */
  221.     ttres();                /* Reset the communication device */
  222. #ifdef F_SETFL
  223.     if (ttflags > -1)            /* Restore its flags */
  224.       fcntl(0,F_SETFL,ttflags);
  225. #endif /* F_SETFL */
  226.     if (debug) {
  227.     fprintf(db,"exit %d\n",x);
  228.     fclose(db);
  229.     }
  230.     exit(x);
  231. }
  232.  
  233. VOID
  234. sysinit() {                /* To be run first thing */
  235. #ifdef F_SETFL
  236.     ttflags = fcntl(0,F_GETFL,0);    /* Get and save stdin flags */
  237. #endif /* F_SETFL */
  238. #ifdef SIGINT
  239.     signal(SIGINT,SIG_IGN);        /* Ignore interrupts */
  240. #endif /* SIGINT */
  241. #ifdef SIGTSTP
  242.     signal(SIGTSTP,SIG_IGN);
  243. #endif /* SIGTSTP */
  244. #ifdef SIGQUIT
  245.     signal(SIGQUIT,SIG_IGN);
  246. #endif /* SIGQUIT */
  247.     signal(SIGHUP,doexit);        /* Go here on hangup */
  248. }
  249.  
  250. /* Console Functions */
  251.  
  252. #ifdef COMMENT                /* (not used) */
  253. VOID
  254. tmsg(s) char *s; {            /* tmsg() */
  255.     if (!quiet)
  256.       fprintf(stderr,"%s",s);        /* Type message on the screen. */
  257. }
  258. #endif /* COMMENT */
  259.  
  260. VOID
  261. tmsgl(s) char *s; {            /* tmsgl() */
  262.     if (!quiet) {
  263.     if (raw)
  264.       fprintf(stderr,"%s\r\n",s);    /* Type message with CRLF */
  265.     else
  266.       fprintf(stderr,"%s\n",s);
  267.     }
  268. }
  269.  
  270. /* Debugging functions */
  271.  
  272. VOID
  273. logerr(s) char * s; {            /* Log text and errno */
  274.     if (!s) s = "";
  275.     if (!debug) return;
  276.     if (db) fprintf(db,"%s: errno = %d\n",s,errno);
  277. }
  278.  
  279. /* Parity function */
  280.  
  281. char
  282. #ifdef __STDC__
  283. dopar(char ch)
  284. #else
  285. dopar(ch) char ch;
  286. #endif /* __STDC__ */
  287. {                    /* Do parity */
  288.     unsigned int a;
  289.     if (!xparity) return(ch); else ch &= 0177;
  290.     switch (xparity) {
  291.       case 'm':  return(ch | 128);    /* Mark */
  292.       case 's':  return(ch & 127);    /* Space */
  293.       case 'o':                /* Odd (fall thru) */
  294.       case 'e':                /* Even */
  295.     a = (ch & 15) ^ ((ch >> 4) & 15);
  296.     a = (a & 3) ^ ((a >> 2) & 3);
  297.     a = (a & 1) ^ ((a >> 1) & 1);
  298.     if (xparity == 'o') a = 1 - a;    /* Switch sense for odd */
  299.     return(ch | (a << 7));
  300.       default: return(ch);
  301.     }
  302. }
  303.  
  304. /* Communication functions */
  305.  
  306. int
  307. ttopen(ttname) char *ttname; {        /* "Open" the communication device */
  308.     if (debug) {            /* Vital statistics for debug log */
  309. #ifdef __STDC__
  310.     fprintf(db,"ttopen __STDC__\n");
  311. #endif /* __STDC__ */
  312. #ifdef SIG_V
  313.     fprintf(db,"ttopen SIG_V\n");
  314. #else
  315. #ifdef SIG_I
  316.     fprintf(db,"ttopen SIG_I\n");
  317. #endif /* SIG_I */
  318. #endif /* SIG_V */
  319. #ifdef USE_GETCHAR
  320.     fprintf(db,"ttopen getchar/putchar\n");
  321. #ifdef BUFSIZ
  322.     fprintf(db,"ttopen BUFSIZ = %d\n", BUFSIZ);
  323. #endif /* BUFSIZ */
  324. #else
  325. #ifdef DUMBIO
  326.     fprintf(db,"ttopen single-byte read/write\n");
  327. #else
  328.     fprintf(db,"ttopen nonblocking read/write\n");
  329. #endif /* DUMBIO */
  330. #endif /* USE_GETCHAR */
  331.     fprintf(db,"ttopen TINBUFSIZ = %d\n", TINBUFSIZ);
  332. #ifdef __hpux
  333.     fprintf(db,"ttopen __hpux\n");
  334. #endif /* __hpux */
  335. #ifdef pdp11
  336.     fprintf(db,"ttopen pdp11\n");
  337. #endif /* pdp11 */
  338. #ifdef SETXONXOFF
  339.     fprintf(db,"ttopen SETXONXOFF\n");
  340. #endif /* SETXONXOFF */
  341.     fprintf(db,"ttopen xonxoff = %d\n",xonxoff);
  342.     fprintf(db,"ttopen noxonxoff = %d\n",noxonxoff);
  343.     fprintf(db,"ttopen ttflags %d\n",ttflags);
  344.     fprintf(db,"ttopen nomodes %d\n",nomodes);
  345.     }
  346.     if (nomodes) {            /* If external protocol */
  347. #ifdef SIGINT                /* exit on interrupts */
  348.     signal(SIGINT,doexit);
  349. #endif /* SIGINT */
  350. #ifdef SIGTSTP
  351.     signal(SIGTSTP,doexit);
  352. #endif /* SIGTSTP */
  353. #ifdef SIGQUIT
  354.     signal(SIGQUIT,doexit);
  355. #endif /* SIGQUIT */
  356.     return(0);
  357.     }
  358.  
  359. #ifndef DUMBIO
  360. #ifndef USE_GETCHAR
  361. #ifdef O_NDELAY
  362. #ifdef F_SETFL
  363.     if (ttflags != -1) {        /* Set nonbocking i/o on stdin */
  364.     errno = 0;
  365.     if (fcntl(0, F_SETFL,ttflags|O_NDELAY) == -1)
  366.       logerr("ttopen fcntl(0,F_SETFL,O_NDELAY)");
  367.     else
  368.       nonblock = 1;
  369.     }
  370. #endif /* F_SETFL */
  371. #endif /* O_NDELAY */
  372. #endif /* USE_GETCHAR */
  373. #endif /* DUMBIO */
  374.     if (!nonblock)            /* No streaming without */
  375.       streamok = -1;            /* nonblocking reads */
  376.  
  377.     if (debug)
  378.       fprintf(db,"ttopen nonblock = %d\n", nonblock);
  379. #ifdef POSIX
  380.     tcgetattr(0,&ttold);        /* Get stdin device attributes */
  381.     tcgetattr(0,&ttraw);
  382. #else
  383. #ifdef SYSV
  384.     ioctl(0,TCGETA,&ttold);
  385.     ioctl(0,TCGETA,&ttraw);
  386. #else
  387. #ifdef BSD
  388.     gtty(0,&ttold);
  389.     gtty(0,&ttraw);
  390. #endif /* BSD */
  391. #endif /* SYSV */
  392. #endif /* POSIX */
  393.     havemodes++;
  394.     return(0);
  395. }
  396.  
  397. int
  398. ttpkt(parity) int parity; {        /* Put comm device in packet mode */
  399. #ifdef BSD
  400.     int x;
  401. #endif /* BSD */
  402.     xparity = parity;            /* Make local copy of parity */
  403.     if (nomodes)
  404.       return(0);
  405.  
  406. #ifdef SVORPOSIX            /* System V or POSIX section... */
  407.     ttraw.c_iflag |= IGNPAR;
  408.     ttraw.c_lflag &= ~(ICANON|ECHO);
  409.     ttraw.c_lflag &= ~ISIG;
  410.     ttraw.c_lflag |= NOFLSH;
  411. #ifdef SETXONXOFF
  412.     if (!noxonxoff) {
  413.     ttraw.c_iflag |= (IXON|IXOFF);
  414.     if (debug) fprintf(db,"ttpkt SVORPOSIX Xon/Xoff\n");
  415.     }
  416. #else
  417.     if (xonxoff) {
  418.     if (debug) fprintf(db,"ttpkt SVORPOSIX Xon/Xoff\n");
  419.     ttraw.c_iflag |= (IXON|IXOFF);
  420.     }
  421. #endif /* SETXONXOFF */
  422. #ifdef IEXTEN
  423.     ttraw.c_lflag &= ~IEXTEN;
  424. #endif /* IEXTEN */
  425. #ifdef POSIX
  426.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
  427. #else
  428.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
  429. #endif /* POSIX */
  430.     ttraw.c_oflag &= ~OPOST;
  431.     ttraw.c_cflag &= ~(CSIZE);
  432.     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
  433.     ttraw.c_cflag &= ~(PARENB);
  434.  
  435. #ifndef VEOF
  436.     ttraw.c_cc[4] = 1;
  437. #else
  438. #ifdef VMIN
  439.     ttraw.c_cc[VMIN] = 1;
  440. #endif /* VMIN */
  441. #endif /* VEOF */
  442.  
  443. #ifndef VEOL
  444.     ttraw.c_cc[5] = 0;
  445. #else
  446. #ifdef VTIME
  447.     ttraw.c_cc[VTIME] = 0;
  448. #endif /* VTIME */
  449. #endif /* VEOL */
  450.  
  451. #ifdef VINTR
  452.     ttraw.c_cc[VINTR] = 0;
  453. #endif /* VINTR */
  454.  
  455. #ifdef POSIX
  456.     if (tcsetattr(0,TCSADRAIN,&ttraw) < 0)
  457.       return(-1);
  458. #else
  459.     if (ioctl(0,TCSETAW,&ttraw) < 0)
  460.       return(-1);
  461. #ifdef SYSV
  462. #endif /* SYSV */
  463. #endif /* POSIX */
  464.  
  465. #else  /* Not SVORPOSIX */
  466.  
  467. #ifdef BSD
  468.     ttraw.sg_flags |= RAW;        /* BSD/V7 raw (binary) mode */
  469. #ifdef SETXONXOFF
  470.     if (!noxonxoff) {
  471.     ttraw.sg_flags |= TANDEM;
  472.     if (debug) fprintf(db,"ttpkt BSD Xon/Xoff\n");
  473.     }
  474. #else
  475.     if (xonxoff) {
  476.     ttraw.sg_flags |= TANDEM;
  477.     if (debug) fprintf(db,"ttpkt BSD Xon/Xoff\n");
  478.     }
  479. #endif /* SETXONXOFF */
  480.     ttraw.sg_flags &= ~(ECHO|CRMOD);    /* No echo, etc */
  481.     if (stty(0,&ttraw) < 0) return(-1); /* Set modes */
  482. #else
  483.     system("stty raw -echo");
  484. #endif /* BSD */
  485. #endif /* SVORPOSIX */
  486.     raw = 1;                /* Flag we're now in raw mode */
  487.     return(0);
  488. }
  489.  
  490. int
  491. ttres() {                /* Reset terminal */
  492.     int x = 0;
  493.     if (havemodes) {            /* Restore old modes */
  494. #ifdef POSIX
  495.     x = tcsetattr(0,TCSADRAIN,&ttold);
  496. #else
  497. #ifdef SYSV
  498.     sleep(1);            /* Let output finish */
  499.     x = ioctl(0,TCSETAW,&ttold);
  500. #else
  501. #ifdef BSD
  502.     sleep(1);            /* Let output finish */
  503.     x = stty(0,&ttold);
  504. #else
  505.     x = system("stty -raw echo");
  506. #endif /* BSD */
  507. #endif /* SYSV */
  508. #endif /* POSIX */
  509.     }
  510.     write(1,"\015\012",2);
  511.     raw = 0;
  512.     return(x);
  513. }
  514.  
  515. int
  516. ttchk() {                /* Check if input ready */
  517.     int x = 0;
  518.     if (nonblock) {            /* Try to read */
  519.     errno = 0;
  520.     x = read(0,&tinbuf[tlast],TINBUFSIZ-tlast);
  521. #ifdef EXTRADEBUG
  522.     fprintf(db,"ttchk read %d errno = %d\n",x,errno);
  523. #endif /* EXTRADEBUG */
  524. #ifdef EWOULDBLOCK
  525.     if (x < 0 && errno == EWOULDBLOCK) /* Nothing to read */
  526.       x = 0;
  527. #endif /* EWOULDBLOCK */
  528.     if (x < 0)            /* Fatal i/o error */
  529.       return(-1);
  530.     }
  531.     tincnt += x;            /* Buffer bookkeeping */
  532.     tlast  += x;
  533.     return(x + tincnt);            /* How much is waiting to be read */
  534. }
  535.  
  536. int
  537. ttflui() {                /* Flush comm device input buffer */
  538. #ifdef BSD
  539.     long n = 1;                /* Specify read queue */
  540. #endif /* BSD */
  541.     int x;
  542.     tincnt = 0;                /* Our own buffer */
  543.     tlast = 0;
  544.     tinptr = tinbuf;
  545.     errno = 0;
  546. #ifdef POSIX
  547.     x = tcflush(0,TCIFLUSH);        /* kernel/driver buffers */
  548. #else
  549. #ifdef SYSV
  550.     x = ioctl(0,TCFLSH,0);
  551. #else
  552. #ifdef BSD
  553.     x = ioctl(0,TIOCFLUSH,&n);
  554. #endif /* BSD */
  555. #endif /* SYSV */
  556. #endif /* POSIX */
  557.     if (debug) fprintf(db,"ttflui = %d, errno = %d\n",x,errno);
  558.     return(x);
  559. }
  560.  
  561. SIGTYP
  562. timerh(dummy) int dummy; {        /* Timeout handler */
  563.     longjmp(jbuf,1);
  564.     SIGRETURN;
  565. }
  566.  
  567. /*
  568.  ttinl() - Read a raw packet.
  569.  
  570.  Call with:
  571.    dest - where to put it
  572.    max  - maximum length
  573.    timo - timeout (seconds, 0 = none)
  574.    eol  - packet terminator
  575.    turn - half-duplex line turnaround character to wait for, 0 = none
  576.  
  577.  Returns length obtained, or -1 if error or timeout, -2 on disconnection.
  578. */
  579. #ifndef DEBUGWRAP
  580. #define DEBUGWRAP 48
  581. #endif /* DEBUGWRAP */
  582.  
  583. int
  584. #ifdef __STDC__
  585. ttinl(char * dest, int max, int timo, char eol, char soh, int turn)
  586. #else
  587. ttinl(dest,max,timo,eol,soh,turn) int max, timo, turn; char eol, soh, *dest;
  588. #endif /* __STDC__ */
  589. {
  590.     int n = 0, x = 0, flag = 0, rc = 0, ccn = 0; /* Local variables */
  591.     char c = NUL;
  592.     int havelen = 0, pktlen = 0, lplen = 0;
  593.  
  594. #ifdef USE_GETCHAR
  595.     if (debug) fprintf(db,"ttinl getchar timo = %d\n",timo);
  596. #else
  597.     if (debug) fprintf(db,"ttinl read timo = %d\n",timo);
  598. #endif /* USE_GETCHAR */
  599.     *dest = NUL;            /* Clear destination buffer */
  600.     if (timo) {
  601.     signal(SIGALRM,timerh);        /* Enable timer interrupt */
  602.     alarm(timo);            /* Set it. */
  603.     }
  604.     if (setjmp(jbuf)) {            /* Timer went off? */
  605.     if (debug) fprintf(db,"ttinl timeout\n");
  606.         rc = -1;            /* Yes, set this return code. */
  607.     } else {                /* Otherwise... */
  608.     while (1) {            /* Read until we have a packet */
  609. #ifdef DUMBIO
  610.         x = read(0,&c,1);        /* Dumb blocking read byte loop */
  611.         if (x < 0) {
  612.         logerr("ttinl XX read 1");
  613.         rc = -2;
  614.         }
  615. #else
  616. #ifdef USE_GETCHAR
  617.         errno = 0;
  618.         x = getchar();        /* Buffered read with getchar() */
  619.         if (x == EOF) {
  620.         if (errno == EINTR)
  621.           continue;
  622.         logerr("ttinl getchar");
  623.         rc = -2;
  624.         }
  625.         c = x;
  626. #else  /* USE_GETCHAR */
  627. #ifdef O_NDELAY
  628.         if (nonblock) {        /* Buffered nonblocking read() */
  629.         int x;
  630.         if (tincnt < 1) {    /* Need to fill our buffer */
  631.             errno = 0;
  632.             tincnt = read(0,tinbuf,TINBUFSIZ);
  633.             if (tincnt > -1) tlast = tincnt;
  634.             if (debug)
  635.               fprintf(db,"ttinl nonblock tincnt=%d errno=%d\n",
  636.                   tincnt,errno);
  637.             if (tincnt == 0 || errno == EWOULDBLOCK) {
  638. #ifdef F_SETFL
  639.             /* Go back to blocking and wait for 1 char */
  640.             if (ttflags != -1) {
  641.                 errno = 0;
  642.                 x = fcntl(0, F_SETFL, ttflags  & ~O_NDELAY);
  643.                 if (x == -1 || errno)
  644.                   logerr("ttinl fcntl O_NDELAY off");
  645.                 errno = 0;
  646.                 tincnt = read(0,tinbuf,1);
  647.                 if (tincnt < 1 || errno)
  648.                   logerr("ttinl BL read");
  649.                 errno = 0;
  650.                 fcntl(0, F_SETFL, ttflags | O_NDELAY);
  651.                 if (x == -1 || errno)
  652.                   logerr("ttinl fcntl O_NDELAY on");
  653.             }
  654.             if (tincnt == 0) { /* Check results */
  655.                 continue;
  656.             }
  657.             if (tincnt < 0) { /* I/O error */
  658.                 rc = -2;
  659.                 goto xttinl;
  660.             }
  661.             if (debug)
  662.               fprintf(db,"ttinl blocking read %d\n",tincnt);
  663. #else
  664.             /* No other form of sleeping is portable */
  665.             sleep(1);
  666.             continue;
  667. #endif /* F_SETFL */
  668.             } else if (tincnt < 0) {
  669.             rc = -2;
  670.             goto xttinl;
  671.             }
  672.             tinptr = tinbuf;
  673.         }
  674.         c = *tinptr++;
  675.         tincnt--;
  676.         } else {
  677. #endif /* O_NDELAY */
  678.         x = read(0,&c,1);    /* Dumb read byte loop */
  679.         if (x < 0) {
  680.             logerr("ttinl XX read 1");
  681.             rc = -2;
  682.         }
  683. #ifdef O_NDELAY
  684.         }
  685. #endif /* O_NDELAY */
  686. #endif /* USE_GETCHAR */
  687. #endif /* DUMBIO */
  688.         if (rc < 0)
  689.           break;
  690.         if (xparity)        /* Strip parity */
  691.           c &= 0x7f;
  692. #ifdef COMMENT
  693.         /* Only uncomment in emergencies */
  694.         if (debug)
  695.           fprintf(db,"ttinl char=%c flag=%d tincnt=%d\n",c,flag,tincnt);
  696. #endif /* COMMENT */
  697.         if (c == '\03') {        /* Got ^C, count it. */
  698.             if (++ccn > 2) {    /* If more than 2, let them out */
  699.             fprintf(stderr,"^C...");
  700.             ttres();
  701.             if (debug) fprintf(db,"ttinl interrupted\n");
  702.             dest[n = 0] = NUL;
  703.             rc = -9;
  704.             goto xttinl;
  705.         }
  706.         } else            /* Not ^C so reset counter*/
  707.           ccn = 0;
  708.  
  709.         if (!flag && (c != soh))    /* Look for SOH */
  710.           continue;            /* Skip stuff between packets */
  711.         flag = 1;            /* Have SOH */
  712.  
  713.         if (n >= max) {
  714.         if (debug) fprintf(db,"ttinl overflow\n");
  715.         rc = -2;
  716.         goto xttinl;
  717.         }
  718.         dest[n++] = c;        /* Store the character */
  719. #ifdef USE_EOL
  720.         /* Use EOL to determine end of packet */
  721.         if (c == eol) {
  722.         dest[n] = NUL;
  723.         break;
  724.         }
  725. #else
  726.         /* Use length field for framing */
  727.         if (!havelen) {
  728.         if (n == 2) {
  729.             pktlen = xunchar(dest[1] & 0x7f);
  730.             if (pktlen > 1) {
  731.             if (debug) fprintf(db,"ttinl length = %d\n",pktlen);
  732.             havelen = 1;
  733.             }
  734.         } else if (n == 5 && pktlen == 0) {
  735.             lplen = xunchar(dest[4] & 0x7f);
  736.         } else if (n == 6 && pktlen == 0) {
  737.             pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
  738.             if (debug) fprintf(db,"ttinl length = %d\n",pktlen);
  739.             havelen = 1;
  740.         }
  741.         }
  742.         if (havelen && (n > pktlen+1)) {
  743.         if (turn && c != turn)    /* Wait for turnaround char */
  744.           continue;
  745.         dest[n] = NUL;        /* Null-terminate whatever we got */
  746.         break;
  747.         }
  748. #endif /* USE_EOL */
  749.     }
  750.     }
  751.   xttinl:                /* Common exit point */
  752.     if (timo) {
  753.     alarm(0);            /* Turn off the alarm */
  754.     signal(SIGALRM,SIG_IGN);    /* and associated interrupt */
  755.     }
  756.     if (debug && n > 0) {        /* Log packet */
  757. #ifndef FULLPACKETS
  758.     if (n > DEBUGWRAP) {        /* Truncate if it would wrap */
  759.         dest[n] = NUL;        /* in case of interruption */
  760.         c = dest[DEBUGWRAP];
  761.         dest[DEBUGWRAP] = NUL;
  762.         fprintf(db,"PKT<-[^A%s...](%d) rc=%d\n",&dest[1],n,rc);
  763.         dest[DEBUGWRAP] = c;
  764.  
  765.     } else
  766. #endif /* FULLPACKETS */
  767.         fprintf(db,"PKT<-[^A%s](%d) rc=%d\n",&dest[1],n,rc);
  768.     }
  769.     if (rc == -9)            /* Interrupted by user */
  770.       doexit(1);
  771.     else if (rc > -1)
  772.       rc = n;
  773.     return(rc);                /* Return length, or failure. */
  774. }
  775.  
  776. int
  777. ttol(s,len) int len; char *s; {        /* Output string s of given length  */
  778.     register int i = 0, n = 0, m = 0;
  779.     int partial = 0;
  780.  
  781.     n = len;
  782.     if (n < 0) {
  783.     if (debug) fprintf(db,"ttol len = %d\n",n);
  784.     return(-1);
  785.     }
  786.     if (xparity) {            /* Add parity if requested */
  787.     for (i = 0; i < n; i++)
  788.       s[i] = dopar(s[i]);
  789.     }
  790.     if (debug) {            /* Log the packet if requested */
  791.     char c;
  792. #ifndef FULLPACKETS
  793.     if (n > DEBUGWRAP) {
  794.         c = s[DEBUGWRAP];
  795.         s[DEBUGWRAP] = NUL;
  796.         fprintf(db,"PKT->[^A%s...](%d)\n",&s[1],n);
  797.         s[DEBUGWRAP] = c;
  798.     } else {
  799. #endif /* FULLPACKETS */
  800.         c = s[n-1];
  801.         s[n-1] = NUL;
  802.         fprintf(db,"PKT->[^A%s](%d)\n",&s[1],n);
  803.         s[n-1] = c;
  804. #ifndef FULLPACKETS
  805.     }
  806. #endif /* FULLPACKETS */
  807.     }
  808. #ifdef USE_GETCHAR
  809.     {                    /* Send the packet with putchar() */
  810.     register CHAR c; register int i;
  811.     for (i = 0; i < n; i++) {
  812.         c = *s++;
  813.         if (putchar(c) == EOF) {
  814.         logerr("ttol putchar");
  815.         return(-1);
  816.         }
  817.     }
  818.     }
  819.     fflush(stdout);            /* Push it out */
  820.     return(n);
  821. #else
  822.     while (n > 0) {            /* Send the packet with write() */
  823.     i = write(1,&s[m],n);        /* Allowing for partial results */
  824.     if (i < 0) {
  825.         if (errno == EWOULDBLOCK)    /* and even no results at all.. */
  826.           continue;
  827.         logerr("ttol write");
  828.         return(-1);
  829.     }
  830.     if (i == n)
  831.       break;
  832.     partial++;
  833.     m += i;
  834.     if (debug) fprintf(db,"ttol partial write %d (%d/%d)\n",i,m,len);
  835.     n -= i;
  836.     }
  837.     if (partial) {
  838.     m += i;
  839.     if (debug) fprintf(db,"ttol partial write %d (%d/%d)\n",i,m,len);
  840.     if (m != len) {
  841.         if (debug) fprintf(db,"ttol foulup %d != %d\n",m,len);
  842.         return(-1);
  843.     }
  844.     }
  845.     return(len);
  846. #endif /* USE_GETCHAR */
  847. }
  848.  
  849. /* File Functions */
  850.  
  851. char ofile[MAXPATHLEN];            /* Output filename */
  852. long filelength = -1L;
  853.  
  854. long
  855. zchki(fn) char * fn; {            /* Check if file is readable */
  856.     struct stat buf;
  857.     if (!fn) return(-1);
  858.     if (stat(fn,&buf) < 0)
  859.       return(-1);
  860.     errno = 0;
  861.     if (access(fn,R_OK) < 0) {
  862.     if (debug)
  863.       fprintf(db,"zchki access %s errno = %d\n",fn,errno);
  864.     return(-1);
  865.     }
  866.     if (!S_ISREG(buf.st_mode)) {
  867.     if (debug)
  868.       fprintf(db,"zchki %s is a directory",fn);
  869.     return(-2);
  870.     }
  871.     return(buf.st_size);
  872. }
  873.  
  874. int
  875. zchko(fn) char *fn; {            /* Check write access */
  876.     int i, x;
  877.     char * s;
  878.  
  879.     if (!fn)                /* Defend against empty name */
  880.       fn = "";
  881.     if (!*fn)
  882.       return(-1);
  883.     if (!strcmp(fn,"/dev/null"))    /* Null device is OK. */
  884.       return(0);
  885.     if ((x = zchki(fn)) == -2)        /* An existing directory? */
  886.       return(-1);
  887.     s = fn;
  888.     if (x < 0) {            /* If file does not exist */
  889.     strncpy(work,fn,MAXPATHLEN);
  890.     work[MAXPATHLEN] = NUL;
  891.     s = work;
  892.     for (i = (int)strlen(s); i > 0; i--) { /* Strip filename from right */
  893.         if (s[i-1] == '/') {    /* and check its directory */
  894.         s[i-1] = NUL;
  895.         break;
  896.         }
  897.     }
  898.     if (i == 0)
  899.       s = ".";
  900.     }
  901.     errno = 0;
  902.     x = access(s,W_OK);            /* Check access of path. */
  903.     if (debug) fprintf(db,"zchko(%s) x = %d errno = %d\n",s,x,errno);
  904.     return((x < 0) ? -1 : 0);           /* and return. */
  905. }
  906.  
  907. int
  908. zopeni(name) char *name; {        /* Open existing file for input */
  909.     ifp = fopen(name,"r");
  910.     if (debug) fprintf(db,"zopeni %s: %d\n",name, ifp ? 0 : errno);
  911.     filelength = zchki(name);
  912.     if (filelength < 0)
  913.       return((int)filelength);
  914.     zincnt = 0;
  915.     zinptr = zinbuf;
  916.     return((ifp == NULL) ? -1 : 0);
  917. }
  918.  
  919. int
  920. zopeno(name) char *name; {        /* Open new file for output */
  921.     errno = 0;
  922.     ofp = fopen(name,"w");
  923.     if (debug) fprintf(db,"zopeno %s: %d\n",name, ofp ? 0 : errno);
  924.     if (ofp) {
  925.     strncpy(ofile,name,MAXPATHLEN);
  926.     ofile[MAXPATHLEN-1] = NUL;
  927.     return(0);
  928.     } else
  929.       return(-1);
  930. }
  931.  
  932. VOID                    /* Local to remote file name */
  933. zltor(lclnam,pktnam,maxlen) char *lclnam, *pktnam; int maxlen; {
  934.     char *p, *np = NULL, *cp, *pp, c;
  935.     char *dotp = NULL;
  936.     char *dirp = NULL;
  937.     int n = 0;
  938.  
  939.     if (debug)
  940.       fprintf(db,"zltor %s: maxlen = %d, literal = %d\n",
  941.           lclnam,maxlen,literal);
  942.     if (literal) {
  943.     p = lclnam;
  944.     dirp = p;
  945.     while (*p) {
  946.         if (*p == '/') dirp = p+1;
  947.         p++;
  948.     }
  949.     strncpy(pktnam,dirp,maxlen);
  950.     } else {
  951.     for (p = lclnam; *p; p++) {    /* Point to name part */
  952.         if (*p == '/')
  953.           np = p;
  954.     }
  955.     if (np) {
  956.         np++;
  957.         if (!*np) np = lclnam;
  958.     } else
  959.       np = lclnam;
  960.  
  961.     if (debug)
  962.       fprintf(db,"zltor np %s\n",np);
  963.  
  964.     pp = work;            /* Output buffer */
  965.     for (cp = np, n = 0; *cp && n < maxlen; cp++,n++) {
  966.         c = *cp;
  967.         if (islower(c))        /* Uppercase letters */
  968.           *pp++ = toupper(c);    /* Change tilde to hyphen */
  969.         else if (c == '~')
  970.           *pp++ = '-';
  971.         else if (c == '#')        /* Change number sign to 'X' */
  972.           *pp++ = 'X';
  973.         else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */
  974.           *pp++ = 'X';
  975.         else if (c == ' ')        /* Change space to underscore */
  976.           *pp++ = '_';
  977.         else if (c < ' ')        /* Change space and controls to 'X' */
  978.           *pp++ = 'X';
  979.         else if (c == '.') {    /* Change dot to underscore */
  980.         dotp = pp;        /* Remember where we last did this */
  981.         *pp++ = '_';
  982.         } else {
  983.         if (c == '/')
  984.           dirp = pp;
  985.         *pp++ = c;
  986.         }
  987.     }
  988.     *pp = NUL;            /* Tie it off. */
  989.     if (dotp > dirp) *dotp = '.';    /* Restore last dot in file name */
  990.     cp = pktnam;            /* If nothing before dot, */
  991.     if (*work == '.') *cp++ = 'X';    /* insert 'X' */
  992.     strncpy(cp,work,maxlen);
  993.     cp[maxlen-1] = NUL;
  994.     }
  995.     if (debug)
  996.       fprintf(db,"zltor result: %s\n",pktnam);
  997. }
  998.  
  999. int
  1000. zbackup(fn) char * fn; {        /* Back up existing file */
  1001.     struct stat buf;
  1002.     int i, j, k, x, state, flag;
  1003.     char *p, newname[MAXPATHLEN+12];
  1004.  
  1005.     if (!fn)                /* Watch out for null pointers. */
  1006.       return(-1);
  1007.     if (!*fn)                /* And empty names. */
  1008.       return(-1);
  1009.     if (stat(fn,&buf) < 0)        /* If file doesn't exist */
  1010.       return(0);            /* no need to back it up. */
  1011.  
  1012.     i = strlen(fn);            /* Get length */
  1013.     if (i > MAXPATHLEN)            /* Guard buffer */
  1014.       i = MAXPATHLEN;
  1015.     if (debug)
  1016.       fprintf(db,"zbackup A %s: %d\n", fn, i);
  1017.  
  1018.     strncpy(work,fn,MAXPATHLEN);    /* Make pokeable copy of name */
  1019.     work[MAXPATHLEN] = NUL;
  1020.     p = work;                /* Strip any backup prefix */
  1021.  
  1022.     i--;
  1023.     for (flag = state = 0; (!flag && (i > 0)); i--) {
  1024.     switch (state) {
  1025.       case 0:            /* State 0 - final char */
  1026.         if (p[i] == '~')        /* Is tilde */
  1027.           state = 1;        /* Switch to next state */
  1028.         else            /* Otherwise */
  1029.           flag = 1;            /* Quit - no backup suffix. */
  1030.         break;
  1031.       case 1:            /* State 1 - digits */
  1032.         if (p[i] == '~'  && p[i-1] == '.') { /* Have suffix */
  1033.         p[i-1] = NUL;        /* Trim it */
  1034.         flag = 1;        /* done */
  1035.         } else if (p[i] >= '0' && p[i] <= '9') { /* In number part */
  1036.         continue;        /* Keep going */
  1037.         } else {            /* Something else */
  1038.         flag = 1;        /* Not a backup suffix - quit. */
  1039.         }
  1040.         break;
  1041.     }
  1042.     }
  1043.     if (debug)
  1044.       fprintf(db,"zbackup B %s\n", p);
  1045.     if (!p[0])
  1046.       p = fn;
  1047.     j = strlen(p);
  1048.     strncpy(newname,p,MAXPATHLEN);
  1049.     for (i = 1; i < 1000; i++) {    /* Search from 1 to 999 */
  1050.     if (i < 10)            /* Length of numeric part of suffix */
  1051.       k = 1;
  1052.     else if (i < 100)
  1053.       k = 2;
  1054.     else
  1055.       k = 3;
  1056.     x = j;                /* Where to write suffix */
  1057.     if ((x + k + 3) > MAXPATHLEN)
  1058.       x = MAXPATHLEN - k - 3;
  1059.     sprintf(&newname[x],".~%d~",i); /* Make a backup name */
  1060.     if (stat(newname,&buf) < 0) {    /* If it doesn't exist */
  1061.         errno = 0;
  1062.         if (link(fn,newname) <  0) { /* Rename old file to backup name */
  1063.         if (debug)
  1064.           fprintf(db,"zbackup failed: link(%s): %d\n",newname,errno);
  1065.         return(-1);
  1066.         } else if (unlink(fn) < 0) {
  1067.         if (debug)
  1068.           fprintf(db,"zbackup failed: unlink(%s): %d\n",fn,errno);
  1069.         return(-1);
  1070.         } else {
  1071.         if (debug)
  1072.           fprintf(db,"zbackup %s: OK\n",newname);
  1073.         return(0);
  1074.         }
  1075.     }
  1076.     }
  1077.     if (debug)
  1078.       fprintf(db,"zbackup failed: all numbers used\n");
  1079.     return(-1);
  1080. }
  1081.  
  1082. int                    /* Remote to local filename */
  1083. zrtol(pktnam,lclnam,warn,maxlen) char *pktnam, *lclnam; int warn, maxlen; {
  1084.     int acase = 0, flag = 0, n = 0;
  1085.     char * p;
  1086.  
  1087.     if (literal) {
  1088.     strncpy(lclnam,pktnam,maxlen);
  1089.     } else {
  1090.     for (p = lclnam; *pktnam != '\0' && n < maxlen; pktnam++) {
  1091.         if (*pktnam > SP) flag = 1;    /* Strip leading blanks and controls */
  1092.         if (flag == 0 && *pktnam < '!')
  1093.           continue;
  1094.         if (isupper(*pktnam))    /* Check for mixed case */
  1095.           acase |= 1;
  1096.         else if (islower(*pktnam))
  1097.           acase |= 2;
  1098.         *p++ = *pktnam;
  1099.         n++;
  1100.     }
  1101.     *p-- = NUL;            /* Terminate */
  1102.     while (*p < '!' && p > lclnam)    /* Strip trailing blanks & controls */
  1103.       *p-- = '\0';
  1104.  
  1105.     if (!*lclnam) {            /* Nothing left? */
  1106.         strncpy(lclnam,"NONAME",maxlen); /* do this... */
  1107.     } else if (acase == 1) {    /* All uppercase? */
  1108.         p = lclnam;            /* So convert all letters to lower */
  1109.         while (*p) {
  1110.         if (isupper(*p))
  1111.           *p = tolower(*p);
  1112.         p++;
  1113.         }
  1114.     }
  1115.     }
  1116.     if (warn) {
  1117.     if (zbackup(lclnam) < 0)
  1118.       return(-1);
  1119.     }
  1120.     return(0);
  1121. }
  1122.  
  1123. int
  1124. zclosi() {                /* Close input file */
  1125.     int rc;
  1126.     rc = (fclose(ifp) == EOF) ? -1 : 0;
  1127.     ifp = NULL;
  1128.     return(rc);
  1129. }
  1130.  
  1131. int
  1132. zcloso(cx) int cx; {            /* Close output file */
  1133.     int rc;
  1134.     rc = (fclose(ofp) == EOF) ? -1 : 0;
  1135.     if (debug) fprintf(db,"zcloso(%s) cx = %d keep = %d\n", ofile, cx, keep);
  1136.     if (cx && !keep ) unlink(ofile);    /* Delete if incomplete */
  1137.     ofp = NULL;
  1138.     return(rc);
  1139. }
  1140.  
  1141. int
  1142. zfillbuf(text) int text; {        /* Refill input file buffer */
  1143.     if (zincnt < 1) {            /* Nothing in buffer - must refill */
  1144.     if (text) {            /* Text mode needs LF/CRLF handling */
  1145.         int c;            /* Current character */
  1146.         for (zincnt = 0;        /* Read a line */
  1147.          zincnt < MAXRECORD - 1 && (c = getc(ifp)) != EOF && c != '\n';
  1148.          zincnt++
  1149.          ) {
  1150.         zinbuf[zincnt] = c;
  1151.         }
  1152.         if (c == '\n') {        /* Have newline. */
  1153.         zinbuf[zincnt++] = '\r'; /* Substitute CRLF */
  1154.         zinbuf[zincnt++] = c;
  1155.         }
  1156.     } else {            /* Binary - just read raw buffers */
  1157.         zincnt = fread(zinbuf, sizeof(char), MAXRECORD, ifp);
  1158.     }
  1159.     zinbuf[zincnt] = NUL;        /* Terminate. */
  1160.     if (zincnt == 0)        /* Check for EOF */
  1161.       return(-1);
  1162.     zinptr = zinbuf;        /* Not EOF - reset pointer */
  1163.     }
  1164. #ifdef EXTRADEBUG                /* Voluminous debugging */
  1165.     if (debug) fprintf(db,"zfillbuf (%s) zincnt = %d\n",
  1166.                text ? "text" : "binary",
  1167.                zincnt
  1168.                );
  1169. #endif /* EXTRADEBUG */
  1170.     zincnt--;                /* Return first byte. */
  1171.     return(*zinptr++ & 0xff);
  1172. }
  1173.