1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)conn.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include <signal.h>
13 #include "uucp.h"
14 #include <setjmp.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #ifdef USG
18 #include <termio.h>
19 #include <fcntl.h>
20 #endif
21 #ifndef USG
22 #include <sgtty.h>
23 #endif
24 #ifdef BSD4_2
25 #include <sys/time.h>
26 #else
27 #include <time.h>
28 #endif
29
30 #define MAXC 1000
31
32 extern jmp_buf Sjbuf;
33 jmp_buf Cjbuf;
34 extern int errno, onesys;
35 extern const char *const sys_errlist[];
36 extern char MaxGrade, DefMaxGrade;
37
38 /* Parity control during login procedure */
39 #define P_ZERO 0
40 #define P_ONE 1
41 #define P_EVEN 2
42 #define P_ODD 3
43
44 #define ABORT -2
45
46 char *AbortOn = NULL;
47 char par_tab[128]; /* must be power of two */
48 int linebaudrate; /* used for the sleep test in pk1.c */
49 int next_fd = -1; /* predicted fd to close interrupted opens */
50
51 char *PCP = "PCP"; /* PC Pursuit device type */
52 /*
53 * catch alarm routine for "expect".
54 */
55 void
alarmtr()56 alarmtr()
57 {
58 signal(SIGALRM, alarmtr);
59 if (next_fd >= 0) {
60 if (close(next_fd))
61 logent("FAIL", "ACU LINE CLOSE");
62 next_fd = -1;
63 }
64 longjmp(Sjbuf, 1);
65 }
66
67 /* This template is for seismo to call ihnp4
68 * the 3 lines marked ---> will be overwritten for the appropriate city
69 */
70 #define PCP_BAUD 3
71 #define PCP_PHONE 4
72 #define PCP_CITY 14
73 #define PCP_PASSWORD 16
74 #define PCP_RPHONE 20
75 #define NPCFIELDS 23
76
77 static char *PCFlds[] = {
78 "PC-PURSUIT",
79 "Any",
80 "ACU",
81 "1200",
82 CNULL,
83 CNULL,
84 "P_ZERO", /* Telenet insists on zero parity */
85 "ABORT",
86 "BUSY", /* Abort on Busy Signal */
87 CNULL,
88 "\\d\\d\\r\\d\\r", /* Get telenet's attention */
89 "TERMINAL=~3-\r-TERM~3-\r-TERM~5", /* Terminal type ? */
90 "\\r",
91 "@", /* telenet's prompt */
92 "D/DCWAS/21,telenetloginstring", /* overwritten later */
93 "PASSWORD",
94 CNULL, /* telenet password */
95 "CONNECTED", /* We're now talking to a Hayes in the remote city */
96 "ATZ", /* Reset it */
97 "OK",
98 "ATDT6907171", /* overwritten */
99 "CONNECT",
100 "\\d\\r", /* We're in !*/
101 CNULL,
102 };
103
104 static char PCP_brand[25];
105 int Dcf = -1;
106 char *Flds[MAXC/10];
107 char LineType[10];
108 extern int LocalOnly;
109
110 /*
111 * place a telephone call to system and login, etc.
112 *
113 * return codes:
114 * CF_SYSTEM: don't know system
115 * CF_TIME: wrong time to call
116 * CF_DIAL: call failed
117 * CF_NODEV: no devices available to place call
118 * CF_LOGIN: login/password dialog failed
119 *
120 * >0 - file no. - connect ok
121 */
conn(system)122 conn(system)
123 char *system;
124 {
125 int nf;
126 char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE];
127 register FILE *fsys;
128 int fcode = 0;
129
130 nf = 0;
131
132 fsys = fopen(SYSFILE, "r");
133 if (fsys == NULL) {
134 syslog(LOG_ERR, "fopen(%s) failed: %m", SYSFILE);
135 cleanup(FAIL);
136 }
137
138 DEBUG(4, "finds (%s) called\n", system);
139 keeplooking:
140 while((nf = finds(fsys, system, info, Flds)) > 0) {
141 strncpy(LineType, Flds[F_LINE], 10);
142 if (LocalOnly) {
143 if (strcmp("TCP", LineType)
144 && strcmp("DIR", LineType)
145 && strcmp("LOCAL", LineType) ) {
146 fcode = CF_TIME;
147 continue;
148 }
149 }
150 sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
151 if (!onesys && MaxGrade != DefMaxGrade &&
152 !iswrk(file, "chk", Spool, wkpre)) {
153 fcode = CF_TIME;
154 continue;
155 }
156 /* For GTE's PC Pursuit */
157 if (snccmp(LineType, PCP) == SAME) {
158 FILE *dfp;
159 int status;
160 static struct Devices dev;
161
162 dfp = fopen(DEVFILE, "r");
163 if (dfp == NULL) {
164 syslog(LOG_ERR, "fopen(%s) failed: %m",
165 DEVFILE);
166 cleanup(FAIL);
167 }
168 while ((status=rddev(dfp, &dev)) != FAIL
169 && strcmp(PCP, dev.D_type) != SAME)
170 ;
171 fclose(dfp);
172 if (status == FAIL)
173 continue;
174 if (mlock(PCP) == FAIL) {
175 fcode = CF_NODEV;
176 logent("DEVICE", "NO");
177 continue;
178 }
179 PCFlds[PCP_BAUD] = dev.D_class;
180 PCFlds[PCP_PHONE] = dev.D_calldev;
181 sprintf(PCFlds[PCP_CITY], "c d/%s%s,%s",
182 Flds[F_CLASS],
183 index(Flds[F_CLASS], '/') == NULL ? "/12" : "",
184 dev.D_arg[D_CHAT]);
185 PCFlds[PCP_PASSWORD] = dev.D_line;
186 strncpy(&PCFlds[PCP_RPHONE][4], Flds[F_PHONE], 7);
187 strncpy(PCP_brand, dev.D_brand, sizeof(PCP_brand));
188 if ((fcode = getto(PCFlds)) < 0) {
189 rmlock(PCP);
190 continue;
191 }
192 Dcf = fcode;
193 fcode = login(NPCFIELDS, PCFlds, Dcf);
194 if (fcode == SUCCESS)
195 break;
196 fcode = CF_DIAL;
197 rmlock(PCP);
198 /* end PC Pursuit */
199 } else if ((fcode = getto(Flds)) > 0) {
200 Dcf = fcode;
201 break;
202 }
203 }
204
205 if (nf <= 0) {
206 fclose(fsys);
207 return fcode ? fcode : nf;
208 }
209
210
211 if (fcode >= 0) {
212 DEBUG(4, "login %s\n", "called");
213 setproctitle("login");
214 fcode = login(nf, Flds, Dcf); }
215 if (fcode < 0) {
216 clsacu();
217 if (fcode == ABORT) {
218 fcode = CF_DIAL;
219 goto keeplooking;
220 } else {
221 fclose(fsys);
222 return CF_LOGIN;
223 }
224 }
225 fclose(fsys);
226 fioclex(Dcf);
227 return Dcf;
228 }
229
230 int nulldev();
231 int (*CU_end)() = nulldev;
232
233 /*
234 * connect to remote machine
235 *
236 * return codes:
237 * >0 - file number - ok
238 * FAIL - failed
239 */
getto(flds)240 getto(flds)
241 register char *flds[];
242 {
243 register struct condev *cd;
244 int diropn();
245 char *line;
246
247 DEBUG(4, "getto: call no. %s ", flds[F_PHONE]);
248 DEBUG(4, "for sys %s\n", flds[F_NAME]);
249
250 if (snccmp(flds[F_LINE], "LOCAL") == SAME)
251 line = "ACU";
252 else
253 line = flds[F_LINE];
254 #ifdef DIALINOUT
255 if (snccmp(line, "ACU") != SAME)
256 reenable();
257 #endif DIALINOUT
258 CU_end = nulldev;
259 if (snccmp(line, PCP) == SAME) {
260 for(cd = condevs; cd->CU_meth != NULL; cd++) {
261 if (snccmp(PCP_brand, cd->CU_brand) == SAME) {
262 CU_end = cd->CU_clos;
263 return diropn(flds);
264 }
265 }
266 logent(PCP_brand, "UNSUPPORTED ACU TYPE");
267 } else {
268 for (cd = condevs; cd->CU_meth != NULL; cd++) {
269 if (snccmp(cd->CU_meth, line) == SAME) {
270 DEBUG(4, "Using %s to call\n", cd->CU_meth);
271 return (*(cd->CU_gen))(flds);
272 }
273 }
274 DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]);
275 }
276 return diropn(flds); /* search failed, so use direct */
277 }
278
279 /*
280 * close call unit
281 *
282 * return codes: none
283 */
clsacu()284 clsacu()
285 {
286 /* make *sure* Dcf is no longer exclusive.
287 * Otherwise dual call-in/call-out modems could get stuck.
288 * Unfortunately, doing this here is not ideal, but it is the
289 * easiest place to put the call.
290 * Hopefully everyone honors the LCK protocol, of course
291 */
292 #ifdef TIOCNXCL
293 if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0)
294 DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]);
295 #endif
296 if (setjmp(Sjbuf))
297 logent(Rmtname, "CLOSE TIMEOUT");
298 else {
299 signal(SIGALRM, alarmtr);
300 alarm(20);
301 (*(CU_end))(Dcf);
302 alarm(0);
303 }
304 if (close(Dcf) == 0) {
305 DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
306 logent("clsacu", "NOT CLOSED by CU_clos");
307 }
308 Dcf = -1;
309 CU_end = nulldev;
310 }
311
312 /*
313 * expand phone number for given prefix and number
314 */
exphone(in,out)315 exphone(in, out)
316 register char *in, *out;
317 {
318 FILE *fn;
319 char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
320 char buf[BUFSIZ];
321 register char *s1;
322
323 if (!isascii(*in) || !isalpha(*in)) {
324 strcpy(out, in);
325 return;
326 }
327
328 s1=pre;
329 while (isascii(*in) && isalpha(*in))
330 *s1++ = *in++;
331 *s1 = '\0';
332 s1 = npart;
333 while (*in != '\0')
334 *s1++ = *in++;
335 *s1 = '\0';
336
337 tpre[0] = '\0';
338 if ((fn = fopen(DIALFILE, "r")) == NULL)
339 DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
340 else {
341 while (cfgets(buf, BUFSIZ, fn)) {
342 if (sscanf(buf, "%s%s", p, tpre) != 2)
343 continue;
344 if (strcmp(p, pre) == SAME)
345 goto found;
346 tpre[0] = '\0';
347 }
348 DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
349 found:;
350 fclose(fn);
351 }
352
353 strcpy(out, tpre);
354 strcat(out, npart);
355 }
356
357 /*
358 * read and decode a line from device file
359 *
360 * return code - FAIL at end-of file; 0 otherwise
361 */
rddev(fp,dev)362 rddev(fp, dev)
363 register struct Devices *dev;
364 FILE *fp;
365 {
366 register int na;
367
368 if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp))
369 return FAIL;
370 na = getargs(dev->D_argbfr, dev->D_arg, 20);
371 if (na < 4) {
372 syslog(LOG_ERR, "%s: invalid device entry", dev->D_argbfr);
373 cleanup(FAIL);
374 }
375 if (na == 4) {
376 dev->D_brand = "";
377 na++;
378 }
379 dev->D_speed = atoi(fdig(dev->D_class));
380 dev->D_numargs = na;
381 return 0;
382 }
383
384 /*
385 * set system attribute vector
386 *
387 * return codes:
388 * >0 - number of arguments in vector - succeeded
389 * CF_SYSTEM - system name not found
390 * CF_TIME - wrong time to call
391 */
finds(fsys,sysnam,info,flds)392 finds(fsys, sysnam, info, flds)
393 char *sysnam, info[], *flds[];
394 FILE *fsys;
395 {
396 int na;
397 int fcode = 0;
398
399 /* format of fields
400 * 0 name;
401 * 1 time
402 * 2 acu/hardwired
403 * 3 speed
404 * etc
405 */
406 while (cfgets(info, MAXC, fsys) != NULL) {
407 na = getargs(info, flds, MAXC/10);
408 if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME)
409 continue;
410 if (ifdate(flds[F_TIME]) != FAIL)
411 /* found a good entry */
412 return na;
413 DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
414 fcode = CF_TIME;
415 }
416 return fcode ? fcode : CF_SYSTEM;
417 }
418
419 /*
420 * do login conversation
421 *
422 * return codes: SUCCESS | FAIL
423 */
login(nf,flds,fn)424 login(nf, flds, fn)
425 register char *flds[];
426 int nf, fn;
427 {
428 register char *want, *altern;
429 int k, ok;
430
431 if (nf < 4) {
432 syslog(LOG_ERR, "Too few log fields: %d", nf);
433 cleanup(FAIL);
434 }
435 if (setjmp(Cjbuf))
436 return FAIL;
437 AbortOn = NULL;
438 for (k = F_LOGIN; k < nf; k += 2) {
439 want = flds[k];
440 if (want == NULL)
441 want = "";
442 ok = FAIL;
443 while (ok != SUCCESS) {
444 altern = index(want, '-');
445 if (altern != NULL)
446 *altern++ = '\0';
447 if (strcmp(want, "ABORT") == 0) {
448 AbortOn = flds[k+1];
449 DEBUG(4, "ABORT ON: %s\n", AbortOn);
450 goto nextfield;
451 }
452 DEBUG(4, "wanted \"%s\"\n", want);
453 ok = expect(want, fn);
454 DEBUG(4, "got: %s\n", ok ? "?" : "that");
455 if (ok == FAIL) {
456 if (altern == NULL) {
457 logent("LOGIN", _FAILED);
458 return FAIL;
459 }
460 want = index(altern, '-');
461 if (want != NULL)
462 *want++ = '\0';
463 sendthem(altern, fn);
464 } else
465 if (ok == ABORT) {
466 char sbuf[MAXFULLNAME];
467 sprintf(sbuf, "LOGIN ABORTED on \"%s\"", AbortOn);
468 logent(sbuf, _FAILED);
469 return ABORT;
470 }
471 }
472 sleep(1);
473 if (k+1 < nf)
474 sendthem(flds[k+1], fn);
475 nextfield: ;
476 }
477 return SUCCESS;
478 }
479
480
481 /* conditional table generation to support odd speeds */
482 struct sg_spds {int sp_val, sp_name;} spds[] = {
483 #ifdef B50
484 { 50, B50},
485 #endif
486 #ifdef B75
487 { 75, B75},
488 #endif
489 #ifdef B110
490 { 110, B110},
491 #endif
492 #ifdef B150
493 { 150, B150},
494 #endif
495 #ifdef B200
496 { 200, B200},
497 #endif
498 #ifdef B300
499 { 300, B300},
500 #endif
501 #ifdef B600
502 {600, B600},
503 #endif
504 #ifdef B1200
505 {1200, B1200},
506 #endif
507 #ifdef B1800
508 {1800, B1800},
509 #endif
510 #ifdef B2000
511 {2000, B2000},
512 #endif
513 #ifdef B2400
514 {2400, B2400},
515 #endif
516 #ifdef B3600
517 {3600, B3600},
518 #endif
519 #ifdef B4800
520 {4800, B4800},
521 #endif
522 #ifdef B7200
523 {7200, B7200},
524 #endif
525 #ifdef B9600
526 {9600, B9600},
527 #endif
528 #ifdef B19200
529 {19200, B19200},
530 #endif
531 #ifdef EXTA
532 {19200, EXTA},
533 #endif
534 {0, 0}
535 };
536
537 /*
538 * set speed/echo/mode...
539 *
540 * return codes: none
541 */
fixline(tty,spwant)542 fixline(tty, spwant)
543 int tty, spwant;
544 {
545 #ifdef USG
546 struct termio ttbuf;
547 #else !USG
548 struct sgttyb ttbuf;
549 #endif !USG
550 register struct sg_spds *ps;
551 int speed = -1;
552
553 for (ps = spds; ps->sp_val; ps++)
554 if (ps->sp_val == spwant)
555 speed = ps->sp_name;
556 if (speed < 0) {
557 syslog(LOG_ERR, "unrecognized speed: %d", speed);
558 cleanup(FAIL);
559 }
560 #ifdef USG
561 if (ioctl(tty, TCGETA, &ttbuf) < 0)
562 return FAIL;
563 /* ttbuf.sg_flags = (ANYP|RAW);
564 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
565 ttbuf.c_iflag = (ushort)0;
566 ttbuf.c_oflag = (ushort)0;
567 ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
568 ttbuf.c_lflag = (ushort)0;
569 ttbuf.c_cc[VMIN] = 6;
570 ttbuf.c_cc[VTIME] = 1;
571 if (ioctl(tty, TCSETA, &ttbuf) < 0)
572 return FAIL;
573 #else !USG
574 if (ioctl(tty, TIOCGETP, &ttbuf) < 0)
575 return FAIL;
576 ttbuf.sg_flags = (ANYP|RAW);
577 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
578 if (ioctl(tty, TIOCSETP, &ttbuf) < 0)
579 return FAIL;
580 #endif
581 #ifndef USG
582 if (ioctl(tty, TIOCHPCL, STBNULL) < 0)
583 return FAIL;
584 if (ioctl(tty, TIOCEXCL, STBNULL) < 0)
585 return FAIL;
586 #endif
587 linebaudrate = spwant;
588 return SUCCESS;
589 }
590
591 #define MR 100
592
593 /*
594 * look for expected string
595 *
596 * return codes:
597 * 0 - found
598 * FAIL - lost line or too many characters read
599 * some character - timed out
600 */
expect(str,fn)601 expect(str, fn)
602 register char *str;
603 int fn;
604 {
605 char rdvec[MR];
606 register char *rp = rdvec, *strptr;
607 int kr, cnt_char;
608 char nextch;
609 int timo = MAXMSGTIME;
610
611 if (*str == '\0' || strcmp(str, "\"\"") == SAME)
612 return SUCCESS;
613 /* Cleanup str, convert \0xx strings to one char */
614 for (strptr = str; *strptr; strptr++) {
615 if (*strptr == '\\')
616 switch(*++strptr) {
617 case 's':
618 DEBUG(5, "BLANK\n", CNULL);
619 strptr--;
620 *strptr = ' ';
621 strcpy(&strptr[1], &strptr[4]);
622 break;
623 default:
624 strptr--; /* back up to backslash */
625 sscanf(strptr + 1,"%o", &cnt_char);
626 DEBUG(6, "BACKSLASHED %02xH\n", cnt_char);
627 *strptr = (char) (cnt_char);
628 strcpy(&strptr[1], &strptr[4]);
629 }
630 }
631
632 strptr = index(str, '~');
633 if (strptr != NULL) {
634 *strptr++ = '\0';
635 timo = atoi(strptr);
636 if (timo <= 0)
637 timo = MAXMSGTIME;
638 }
639
640 if (setjmp(Sjbuf))
641 return FAIL;
642 signal(SIGALRM, alarmtr);
643 alarm(timo);
644 *rp = 0;
645 while (notin(str, rdvec)) {
646 int c;
647 if(AbortOn != NULL && !notin(AbortOn, rdvec)) {
648 DEBUG(1, "Call aborted on '%s'\n", AbortOn);
649 alarm(0);
650 return ABORT;
651 }
652 kr = read(fn, &nextch, 1);
653 if (kr <= 0) {
654 alarm(0);
655 DEBUG(4, "lost line kr - %d\n, ", kr);
656 logent("LOGIN", "LOST LINE");
657 return FAIL;
658 }
659 c = nextch & 0177;
660 if (c == '\0')
661 continue;
662 DEBUG(4, (isprint(c) || isspace(c)) ? "%c" : "\\%03o", c);
663 *rp++ = c;
664 if (rp >= rdvec + MR) {
665 register char *p;
666 for (p = rdvec+MR/2; p < rp; p++)
667 *(p-MR/2) = *p;
668 rp -= MR/2;
669 }
670 *rp = '\0';
671 }
672 alarm(0);
673 return SUCCESS;
674 }
675
676
677 /*
678 * Determine next file descriptor that would be allocated.
679 * This permits later closing of a file whose open was interrupted.
680 * It is a UNIX kernel problem, but it has to be handled.
681 * unc!smb (Steve Bellovin) probably first discovered it.
682 */
getnextfd()683 getnextfd()
684 {
685 close(next_fd = open("/", 0));
686 }
687
688 /*
689 * send line of login sequence
690 *
691 * return codes: none
692 */
sendthem(str,fn)693 sendthem(str, fn)
694 register char *str;
695 int fn;
696 {
697 register char *strptr;
698 int i, n, cr = 1;
699 register char c;
700 static int p_init = 0;
701
702 DEBUG(5, "send \"%s\"\n", str);
703
704 if (!p_init) {
705 p_init++;
706 bld_partab(P_ZERO);
707 }
708
709 if (prefix("BREAK", str)) {
710 sscanf(&str[5], "%1d", &i);
711 if (i <= 0 || i > 10)
712 i = 3;
713 /* send break */
714 genbrk(fn, i);
715 return;
716 }
717
718 if (prefix("PAUSE", str)) {
719 sscanf(&str[5], "%1d", &i);
720 if (i <= 0 || i > 10)
721 i = 3;
722 /* pause for a while */
723 sleep((unsigned)i);
724 return;
725 }
726
727 if (strcmp(str, "EOT") == SAME) {
728 p_chwrite(fn, '\04');
729 return;
730 }
731
732 /* Send a '\n' */
733 if (strcmp(str, "LF") == SAME) {
734 p_chwrite(fn, '\n');
735 return;
736 }
737
738 /* Send a '\r' */
739 if (strcmp(str, "CR") == SAME) {
740 p_chwrite(fn, '\r');
741 return;
742 }
743
744 /* Set parity as needed */
745 if (strcmp(str, "P_ZERO") == SAME) {
746 bld_partab(P_ZERO);
747 return;
748 }
749 if (strcmp(str, "P_ONE") == SAME) {
750 bld_partab(P_ONE);
751 return;
752 }
753 if (strcmp(str, "P_EVEN") == SAME) {
754 bld_partab(P_EVEN);
755 return;
756 }
757 if (strcmp(str, "P_ODD") == SAME) {
758 bld_partab(P_ODD);
759 return;
760 }
761
762 /* If "", just send '\r' */
763 if (strcmp(str, "\"\"") == SAME) {
764 p_chwrite(fn, '\r');
765 return;
766 }
767
768 strptr = str;
769 while ((c = *strptr++) != '\0') {
770 if (c == '\\') {
771 switch(*strptr++) {
772 case '\0':
773 DEBUG(5, "TRAILING BACKSLASH IGNORED\n", CNULL);
774 --strptr;
775 continue;
776 case 's':
777 DEBUG(5, "BLANK\n", CNULL);
778 c = ' ';
779 break;
780 case 'd':
781 DEBUG(5, "DELAY\n", CNULL);
782 sleep(1);
783 continue;
784 case 'n':
785 DEBUG(5, "NEW LINE\n", CNULL);
786 c = '\n';
787 break;
788 case 'r':
789 DEBUG(5, "RETURN\n", CNULL);
790 c = '\r';
791 break;
792 case 'b':
793 if (isdigit(*strptr)) {
794 i = (*strptr++ - '0');
795 if (i <= 0 || i > 10)
796 i = 3;
797 } else
798 i = 3;
799 /* send break */
800 genbrk(fn, i);
801 if (*strptr == '\0')
802 cr = 0;
803 continue;
804 case 'c':
805 if (*strptr == '\0') {
806 DEBUG(5, "NO CR\n", CNULL);
807 cr = 0;
808 } else
809 DEBUG(5, "NO CR - IGNORED NOT EOL\n", CNULL);
810 continue;
811 #define isoctal(x) ((x >= '0') && (x <= '7'))
812 default:
813 if (isoctal(strptr[-1])) {
814 i = 0;
815 n = 0;
816 --strptr;
817 while (isoctal(*strptr) && ++n <= 3)
818 i = i * 8 + (*strptr++ - '0');
819 DEBUG(5, "\\%o\n", i);
820 p_chwrite(fn, (char)i);
821 continue;
822 }
823 }
824 }
825 p_chwrite(fn, c);
826 }
827
828 if (cr)
829 p_chwrite(fn, '\r');
830 return;
831 }
832
p_chwrite(fd,c)833 p_chwrite(fd, c)
834 int fd;
835 char c;
836 {
837 c = par_tab[c&0177];
838 if (write(fd, &c, 1) != 1) {
839 logent(sys_errlist[errno], "BAD WRITE");
840 longjmp(Cjbuf, 2);
841 }
842 }
843
844 /*
845 * generate parity table for use by p_chwrite.
846 */
bld_partab(type)847 bld_partab(type)
848 int type;
849 {
850 register int i, j, n;
851
852 for (i = 0; i < sizeof(par_tab); i++) {
853 n = 0;
854 for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
855 n++;
856 par_tab[i] = i;
857 if (type == P_ONE
858 || (type == P_EVEN && (n&01) != 0)
859 || (type == P_ODD && (n&01) == 0))
860 par_tab[i] |= sizeof(par_tab);
861 }
862 }
863
864 /*
865 * check for occurrence of substring "sh"
866 *
867 * return codes:
868 * 0 - found the string
869 * 1 - not in the string
870 */
notin(sh,lg)871 notin(sh, lg)
872 register char *sh, *lg;
873 {
874 while (*lg != '\0') {
875 if (wprefix(sh, lg))
876 return 0;
877 else
878 lg++;
879 }
880 return 1;
881 }
882
883 /*
884 * Allow multiple date specifications separated by ','.
885 */
ifdate(p)886 ifdate(p)
887 register char *p;
888 {
889 register char *np;
890 register int ret, g;
891 int rtime, i;
892
893 /* pick up retry time for failures */
894 /* global variable Retrytime is set here */
895 if ((np = index(p, ';')) == NULL) {
896 Retrytime = RETRYTIME;
897 } else {
898 i = sscanf(np+1, "%d", &rtime);
899 if (i < 1 || rtime < 0)
900 rtime = 5;
901 Retrytime = rtime * 60;
902 }
903
904 ret = FAIL;
905 MaxGrade = '\0';
906 do {
907 np = strpbrk(p, ",|"); /* prefer , but allow | for compat */
908 if (np)
909 *np = '\0';
910 g = ifadate(p);
911 DEBUG(11,"ifadate returns %o\n", g);
912 if (g != FAIL) {
913 ret = SUCCESS;
914 if (g > MaxGrade)
915 MaxGrade = g;
916 }
917 if (np)
918 *np = ',';
919 p = np + 1;
920 } while (np);
921 if (MaxGrade == '\0')
922 MaxGrade = DefMaxGrade;
923 return ret;
924 }
925
926 /*
927 * this routine will check a string (string)
928 * like "MoTu0800-1730" to see if the present
929 * time is within the given limits.
930 * SIDE EFFECT - Retrytime is set
931 *
932 * return codes:
933 * 0 - not within limits
934 * 1 - within limits
935 */
936
ifadate(string)937 ifadate(string)
938 char *string;
939 {
940 static char *days[]={
941 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
942 };
943 time_t clock;
944 register char *s = string;
945 int i, tl, th, tn, dayok=0;
946 struct tm *localtime();
947 struct tm *tp;
948 char *p, MGrade;
949
950 if ((p = index(s, '/')) == NULL)
951 MGrade = DefMaxGrade;
952 else
953 MGrade = p[1];
954
955 time(&clock);
956 tp = localtime(&clock);
957 while (isascii(*s) && isalpha(*s)) {
958 for (i = 0; days[i]; i++) {
959 if (prefix(days[i], s))
960 if (tp->tm_wday == i)
961 dayok = 1;
962 }
963
964 if (prefix("Wk", s))
965 if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
966 dayok = 1;
967 if (prefix("Any", s))
968 dayok = 1;
969 if (prefix("Evening", s)) {
970 /* Sat or Sun */
971 if (tp->tm_wday == 6 || tp->tm_wday == 0
972 || tp->tm_hour >= 17 || tp->tm_hour < 8)
973 dayok = 1;
974 }
975 if (prefix("Night", s)) {
976 if (tp->tm_wday == 6 /* Sat */
977 || tp->tm_hour >= 23 || tp->tm_hour < 8
978 /* Sunday before 5pm */
979 || (tp->tm_wday == 0 && tp->tm_hour < 17))
980 dayok = 1;
981 }
982 if (prefix("NonPeak", s)) { /* For Tymnet and PC Pursuit */
983 /* Sat or Sun */
984 if (tp->tm_wday == 6 || tp->tm_wday == 0
985 || tp->tm_hour >= 18 || tp->tm_hour < 7)
986 dayok = 1;
987 }
988 s++;
989 }
990
991 if (dayok == 0 && s != string)
992 return FAIL;
993 i = sscanf(s, "%d-%d", &tl, &th);
994 if (i < 2)
995 return MGrade;
996 tn = tp->tm_hour * 100 + tp->tm_min;
997 if (th < tl) { /* crosses midnight */
998 if (tl <= tn || tn < th)
999 return MGrade;
1000 } else {
1001 if (tl <= tn && tn < th)
1002 return MGrade;
1003 }
1004 return FAIL;
1005 }
1006
1007 /*
1008 * find first digit in string
1009 *
1010 * return - pointer to first digit in string or end of string
1011 */
1012 char *
fdig(cp)1013 fdig(cp)
1014 register char *cp;
1015 {
1016 register char *c;
1017
1018 for (c = cp; *c; c++)
1019 if (*c >= '0' && *c <= '9')
1020 break;
1021 return c;
1022 }
1023
1024 /*
1025 * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0
1026 * Strings are compared as if they contain all capital letters.
1027 */
snccmp(s1,s2)1028 snccmp(s1, s2)
1029 register char *s1, *s2;
1030 {
1031 char c1, c2;
1032
1033 if (islower(*s1))
1034 c1 = toupper(*s1);
1035 else
1036 c1 = *s1;
1037 if (islower(*s2))
1038 c2 = toupper(*s2);
1039 else
1040 c2 = *s2;
1041
1042 while (c1 == c2) {
1043 if (*s1++ == '\0')
1044 return 0;
1045 s2++;
1046 if (islower(*s1))
1047 c1 = toupper(*s1);
1048 else
1049 c1 = *s1;
1050 if (islower(*s2))
1051 c2 = toupper(*s2);
1052 else
1053 c2 = *s2;
1054 }
1055 return c1 - c2;
1056 }
1057
1058 /*
1059 * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0
1060 * Strings are compared as if they contain all capital letters.
1061 */
sncncmp(s1,s2,n)1062 sncncmp(s1, s2, n)
1063 register char *s1, *s2;
1064 register int n;
1065 {
1066 char c1, c2;
1067
1068 if (islower(*s1))
1069 c1 = toupper(*s1);
1070 else
1071 c1 = *s1;
1072 if (islower(*s2))
1073 c2 = toupper(*s2);
1074 else
1075 c2 = *s2;
1076
1077 while ( --n >= 0 && c1 == c2) {
1078 if (*s1++ == '\0')
1079 return 0;
1080 s2++;
1081 if (islower(*s1))
1082 c1 = toupper(*s1);
1083 else
1084 c1 = *s1;
1085 if (islower(*s2))
1086 c2 = toupper(*s2);
1087 else
1088 c2 = *s2;
1089 }
1090 return n<0 ? 0 : (c1 - c2);
1091 }
1092 /*
1093 * do chat script
1094 * occurs after local port is opened,
1095 * before 'dialing' the other machine.
1096 */
dochat(dev,flds,fd)1097 dochat(dev, flds, fd)
1098 register struct Devices *dev;
1099 char *flds[];
1100 int fd;
1101 {
1102 register int i;
1103 register char *p;
1104 char bfr[sizeof(dev->D_argbfr)];
1105
1106 if (dev->D_numargs <= 5)
1107 return(0);
1108 DEBUG(4, "dochat called %d\n", dev->D_numargs);
1109 for (i = 0; i < dev->D_numargs-5; i++) {
1110 sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]);
1111 if (strcmp(bfr, dev->D_arg[D_CHAT+i])) {
1112 p = malloc((unsigned)strlen(bfr)+1);
1113 if (p != NULL) {
1114 strcpy(p, bfr);
1115 dev->D_arg[D_CHAT+i] = p;
1116 }
1117 }
1118 }
1119 /* following is a kludge because login() arglist is a kludge */
1120 i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd);
1121 /*
1122 * If login() last did a sendthem(), must pause so things can settle.
1123 * But don't bother if chat failed.
1124 */
1125 if (i == 0 && (dev->D_numargs&01))
1126 sleep(2);
1127 return(i);
1128 }
1129
1130 /*
1131 * fix kill/echo/raw on line
1132 *
1133 * return codes: none
1134 */
fixmode(tty)1135 fixmode(tty)
1136 register int tty;
1137 {
1138 #ifdef USG
1139 struct termio ttbuf;
1140 #else !USG
1141 struct sgttyb ttbuf;
1142 #endif !USG
1143 register struct sg_spds *ps;
1144 int speed;
1145
1146 if (IsTcpIp)
1147 return;
1148 #ifdef USG
1149 ioctl(tty, TCGETA, &ttbuf);
1150 ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0;
1151 speed = ttbuf.c_cflag &= (CBAUD);
1152 ttbuf.c_cflag |= (CS8|CREAD);
1153 ttbuf.c_cc[VMIN] = 6;
1154 ttbuf.c_cc[VTIME] = 1;
1155 ioctl(tty, TCSETA, &ttbuf);
1156 #else !USG
1157 ioctl(tty, TIOCGETP, &ttbuf);
1158 ttbuf.sg_flags = (ANYP | RAW);
1159 ioctl(tty, TIOCSETP, &ttbuf);
1160 speed = ttbuf.sg_ispeed;
1161 ioctl(tty, TIOCEXCL, STBNULL);
1162 #endif !USG
1163
1164 for (ps = spds; ps->sp_val; ps++)
1165 if (ps->sp_name == speed) {
1166 linebaudrate = ps->sp_val;
1167 DEBUG(9,"Incoming baudrate is %d\n", linebaudrate);
1168 return;
1169 }
1170 if (linebaudrate < 0) {
1171 syslog(LOG_ERR, "unrecognized speed: %d", linebaudrate);
1172 cleanup(FAIL);
1173 }
1174 }
1175