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
doexit(x)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
sysinit()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
tmsg(s)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
tmsgl(s)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
logerr(s)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__
dopar(char ch)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
ttopen(ttname)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
ttpkt(parity)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
ttres()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
ttchk()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
ttflui()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
timerh(dummy)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__
ttinl(char * dest,int max,int timo,char eol,char soh,int turn)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
ttol(s,len)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
zchki(fn)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
zchko(fn)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
zopeni(name)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
zopeno(name)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 */
zltor(lclnam,pktnam,maxlen)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
zbackup(fn)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 */
zrtol(pktnam,lclnam,warn,maxlen)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
zclosi()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
zcloso(cx)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
zfillbuf(text)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