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