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

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