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