new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / uucp / uucico / conn.c
CommitLineData
d34dfbc0
KB
1/*-
2 * Copyright (c) 1985 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
a8e0ea6c 8#ifndef lint
d34dfbc0
KB
9static char sccsid[] = "@(#)conn.c 5.17 (Berkeley) %G%";
10#endif /* not lint */
55a580e3 11
55a580e3 12#include <signal.h>
941b257e 13#include "uucp.h"
55a580e3
SL
14#include <setjmp.h>
15#include <ctype.h>
55a580e3 16#include <errno.h>
46b15d8a 17#ifdef USG
55a580e3
SL
18#include <termio.h>
19#include <fcntl.h>
20#endif
46b15d8a 21#ifndef USG
55a580e3
SL
22#include <sgtty.h>
23#endif
46b15d8a
RC
24#ifdef BSD4_2
25#include <sys/time.h>
26#else
27#include <time.h>
28#endif
55a580e3
SL
29
30#define MAXC 1000
31
32extern jmp_buf Sjbuf;
46b15d8a 33jmp_buf Cjbuf;
1a85e9d2 34extern int errno, onesys;
46b15d8a 35extern char *sys_errlist[];
1a85e9d2 36extern char MaxGrade, DefMaxGrade;
55a580e3
SL
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
55a580e3 43
46b15d8a
RC
44#define ABORT -2
45
46char *AbortOn = NULL;
47char par_tab[128]; /* must be power of two */
48int linebaudrate; /* used for the sleep test in pk1.c */
55a580e3 49int next_fd = -1; /* predicted fd to close interrupted opens */
2af814a5
JB
50
51char *PCP = "PCP"; /* PC Pursuit device type */
01af9d69
JB
52/*
53 * catch alarm routine for "expect".
55a580e3 54 */
41654125 55void
55a580e3
SL
56alarmtr()
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
2af814a5
JB
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
f43a5ec5
RA
72#define PCP_CITY 14
73#define PCP_PASSWORD 16
74#define PCP_RPHONE 20
75#define NPCFIELDS 23
2af814a5
JB
76
77static char *PCFlds[] = {
78 "PC-PURSUIT",
79 "Any",
80 "ACU",
81 "1200",
f43a5ec5
RA
82 CNULL,
83 CNULL,
84 "P_ZERO", /* Telenet insists on zero parity */
2af814a5 85 "ABORT",
f43a5ec5
RA
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,
2af814a5
JB
102};
103
f43a5ec5 104static char PCP_brand[25];
ac09522b
RA
105int Dcf = -1;
106char *Flds[MAXC/10];
107char LineType[10];
108extern int LocalOnly;
2af814a5 109
1a85e9d2
RC
110/*
111 * place a telephone call to system and login, etc.
55a580e3
SL
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
55a580e3 121 */
55a580e3
SL
122conn(system)
123char *system;
124{
2af814a5 125 int nf;
1a85e9d2 126 char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE];
55a580e3
SL
127 register FILE *fsys;
128 int fcode = 0;
129
130 nf = 0;
55a580e3
SL
131
132 fsys = fopen(SYSFILE, "r");
7dd5932d
RA
133 if (fsys == NULL) {
134 syslog(LOG_ERR, "fopen(%s) failed: %m", SYSFILE);
135 cleanup(FAIL);
136 }
55a580e3 137
46b15d8a 138 DEBUG(4, "finds (%s) called\n", system);
01af9d69 139keeplooking:
46b15d8a 140 while((nf = finds(fsys, system, info, Flds)) > 0) {
9313cec6 141 strncpy(LineType, Flds[F_LINE], 10);
46b15d8a 142 if (LocalOnly) {
9313cec6
JB
143 if (strcmp("TCP", LineType)
144 && strcmp("DIR", LineType)
145 && strcmp("LOCAL", LineType) ) {
2af814a5
JB
146 fcode = CF_TIME;
147 continue;
148 }
46b15d8a 149 }
941b257e 150 sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
1a85e9d2 151 if (!onesys && MaxGrade != DefMaxGrade &&
2af814a5
JB
152 !iswrk(file, "chk", Spool, wkpre)) {
153 fcode = CF_TIME;
154 continue;
55a580e3 155 }
2af814a5 156 /* For GTE's PC Pursuit */
9313cec6 157 if (snccmp(LineType, PCP) == SAME) {
2af814a5
JB
158 FILE *dfp;
159 int status;
160 static struct Devices dev;
f43a5ec5 161
2af814a5 162 dfp = fopen(DEVFILE, "r");
7dd5932d
RA
163 if (dfp == NULL) {
164 syslog(LOG_ERR, "fopen(%s) failed: %m",
165 DEVFILE);
166 cleanup(FAIL);
167 }
2af814a5
JB
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;
f43a5ec5
RA
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);
2af814a5 187 strncpy(PCP_brand, dev.D_brand, sizeof(PCP_brand));
f43a5ec5
RA
188 if ((fcode = getto(PCFlds)) < 0) {
189 rmlock(PCP);
2af814a5 190 continue;
f43a5ec5 191 }
2af814a5
JB
192 Dcf = fcode;
193 fcode = login(NPCFIELDS, PCFlds, Dcf);
f43a5ec5
RA
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;
2af814a5 201 break;
f43a5ec5 202 }
55a580e3 203 }
55a580e3 204
01af9d69
JB
205 if (nf <= 0) {
206 fclose(fsys);
46b15d8a 207 return fcode ? fcode : nf;
01af9d69 208 }
55a580e3 209
2af814a5 210
2af814a5
JB
211 if (fcode >= 0) {
212 DEBUG(4, "login %s\n", "called");
ac09522b 213 setproctitle("login");
f43a5ec5 214 fcode = login(nf, Flds, Dcf); }
2af814a5 215 if (fcode < 0) {
55a580e3 216 clsacu();
2af814a5 217 if (fcode == ABORT) {
01af9d69
JB
218 fcode = CF_DIAL;
219 goto keeplooking;
220 } else {
221 fclose(fsys);
941b257e 222 return CF_LOGIN;
01af9d69 223 }
55a580e3 224 }
01af9d69 225 fclose(fsys);
2af814a5
JB
226 fioclex(Dcf);
227 return Dcf;
55a580e3
SL
228}
229
ac09522b
RA
230int nulldev();
231int (*CU_end)() = nulldev;
232
01af9d69
JB
233/*
234 * connect to remote machine
55a580e3
SL
235 *
236 * return codes:
237 * >0 - file number - ok
238 * FAIL - failed
239 */
55a580e3
SL
240getto(flds)
241register char *flds[];
242{
243 register struct condev *cd;
21038734 244 int diropn();
01af9d69 245 char *line;
55a580e3 246
46b15d8a 247 DEBUG(4, "getto: call no. %s ", flds[F_PHONE]);
55a580e3
SL
248 DEBUG(4, "for sys %s\n", flds[F_NAME]);
249
01af9d69
JB
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
55a580e3 258 CU_end = nulldev;
2af814a5
JB
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 }
55a580e3 265 }
2af814a5
JB
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]);
55a580e3 275 }
46b15d8a
RC
276 return diropn(flds); /* search failed, so use direct */
277}
55a580e3 278
01af9d69
JB
279/*
280 * close call unit
55a580e3
SL
281 *
282 * return codes: none
283 */
55a580e3
SL
284clsacu()
285{
46b15d8a
RC
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 */
2af814a5 292#ifdef TIOCNXCL
941b257e
JB
293 if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0)
294 DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]);
46b15d8a
RC
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 }
55a580e3
SL
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
01af9d69
JB
312/*
313 * expand phone number for given prefix and number
55a580e3 314 */
55a580e3
SL
315exphone(in, out)
316register 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
46b15d8a 323 if (!isascii(*in) || !isalpha(*in)) {
55a580e3
SL
324 strcpy(out, in);
325 return;
326 }
327
328 s1=pre;
46b15d8a 329 while (isascii(*in) && isalpha(*in))
55a580e3
SL
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)) {
46b15d8a
RC
342 if (sscanf(buf, "%s%s", p, tpre) != 2)
343 continue;
55a580e3
SL
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);
55a580e3
SL
355}
356
1a85e9d2
RC
357/*
358 * read and decode a line from device file
55a580e3
SL
359 *
360 * return code - FAIL at end-of file; 0 otherwise
361 */
55a580e3
SL
362rddev(fp, dev)
363register struct Devices *dev;
364FILE *fp;
365{
46b15d8a
RC
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);
7dd5932d
RA
371 if (na < 4) {
372 syslog(LOG_ERR, "%s: invalid device entry", dev->D_argbfr);
373 cleanup(FAIL);
374 }
46b15d8a
RC
375 if (na == 4) {
376 dev->D_brand = "";
377 na++;
378 }
55a580e3 379 dev->D_speed = atoi(fdig(dev->D_class));
46b15d8a
RC
380 dev->D_numargs = na;
381 return 0;
55a580e3
SL
382}
383
1a85e9d2
RC
384/*
385 * set system attribute vector
55a580e3
SL
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 */
55a580e3
SL
392finds(fsys, sysnam, info, flds)
393char *sysnam, info[], *flds[];
394FILE *fsys;
395{
55a580e3
SL
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) {
46b15d8a 407 na = getargs(info, flds, MAXC/10);
941b257e 408 if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME)
55a580e3 409 continue;
1a85e9d2 410 if (ifdate(flds[F_TIME]) != FAIL)
55a580e3 411 /* found a good entry */
46b15d8a 412 return na;
55a580e3
SL
413 DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
414 fcode = CF_TIME;
415 }
46b15d8a 416 return fcode ? fcode : CF_SYSTEM;
55a580e3
SL
417}
418
1a85e9d2
RC
419/*
420 * do login conversation
55a580e3 421 *
941b257e 422 * return codes: SUCCESS | FAIL
55a580e3 423 */
55a580e3
SL
424login(nf, flds, fn)
425register char *flds[];
426int nf, fn;
427{
428 register char *want, *altern;
55a580e3
SL
429 int k, ok;
430
7dd5932d
RA
431 if (nf < 4) {
432 syslog(LOG_ERR, "Too few log fields: %d", nf);
433 cleanup(FAIL);
434 }
46b15d8a
RC
435 if (setjmp(Cjbuf))
436 return FAIL;
437 AbortOn = NULL;
55a580e3
SL
438 for (k = F_LOGIN; k < nf; k += 2) {
439 want = flds[k];
f43a5ec5
RA
440 if (want == NULL)
441 want = "";
55a580e3 442 ok = FAIL;
46b15d8a 443 while (ok != SUCCESS) {
55a580e3
SL
444 altern = index(want, '-');
445 if (altern != NULL)
446 *altern++ = '\0';
46b15d8a
RC
447 if (strcmp(want, "ABORT") == 0) {
448 AbortOn = flds[k+1];
449 DEBUG(4, "ABORT ON: %s\n", AbortOn);
450 goto nextfield;
55a580e3 451 }
2af814a5 452 DEBUG(4, "wanted \"%s\"\n", want);
46b15d8a
RC
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) {
f43a5ec5
RA
466 char sbuf[MAXFULLNAME];
467 sprintf(sbuf, "LOGIN ABORTED on \"%s\"", AbortOn);
468 logent(sbuf, _FAILED);
941b257e 469 return ABORT;
46b15d8a 470 }
55a580e3 471 }
46b15d8a 472 sleep(1);
55a580e3
SL
473 if (k+1 < nf)
474 sendthem(flds[k+1], fn);
46b15d8a 475nextfield: ;
55a580e3 476 }
46b15d8a 477 return SUCCESS;
55a580e3
SL
478}
479
480
46b15d8a 481/* conditional table generation to support odd speeds */
55a580e3
SL
482struct 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
46b15d8a
RC
529 {19200, B19200},
530#endif
531#ifdef EXTA
532 {19200, EXTA},
55a580e3
SL
533#endif
534 {0, 0}
535};
536
1a85e9d2
RC
537/*
538 * set speed/echo/mode...
55a580e3
SL
539 *
540 * return codes: none
541 */
55a580e3
SL
542fixline(tty, spwant)
543int tty, spwant;
544{
46b15d8a 545#ifdef USG
55a580e3 546 struct termio ttbuf;
46b15d8a 547#else !USG
55a580e3 548 struct sgttyb ttbuf;
46b15d8a 549#endif !USG
55a580e3
SL
550 register struct sg_spds *ps;
551 int speed = -1;
55a580e3
SL
552
553 for (ps = spds; ps->sp_val; ps++)
554 if (ps->sp_val == spwant)
555 speed = ps->sp_name;
7dd5932d
RA
556 if (speed < 0) {
557 syslog(LOG_ERR, "unrecognized speed: %d", speed);
558 cleanup(FAIL);
559 }
46b15d8a 560#ifdef USG
941b257e
JB
561 if (ioctl(tty, TCGETA, &ttbuf) < 0)
562 return FAIL;
55a580e3
SL
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;
941b257e
JB
571 if (ioctl(tty, TCSETA, &ttbuf) < 0)
572 return FAIL;
46b15d8a 573#else !USG
941b257e
JB
574 if (ioctl(tty, TIOCGETP, &ttbuf) < 0)
575 return FAIL;
55a580e3
SL
576 ttbuf.sg_flags = (ANYP|RAW);
577 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
941b257e
JB
578 if (ioctl(tty, TIOCSETP, &ttbuf) < 0)
579 return FAIL;
55a580e3 580#endif
46b15d8a 581#ifndef USG
941b257e
JB
582 if (ioctl(tty, TIOCHPCL, STBNULL) < 0)
583 return FAIL;
584 if (ioctl(tty, TIOCEXCL, STBNULL) < 0)
585 return FAIL;
55a580e3 586#endif
46b15d8a 587 linebaudrate = spwant;
941b257e 588 return SUCCESS;
55a580e3
SL
589}
590
46b15d8a 591#define MR 100
55a580e3 592
1a85e9d2
RC
593/*
594 * look for expected string
55a580e3
SL
595 *
596 * return codes:
597 * 0 - found
598 * FAIL - lost line or too many characters read
599 * some character - timed out
600 */
55a580e3
SL
601expect(str, fn)
602register char *str;
603int fn;
604{
50cde384 605 char rdvec[MR];
46b15d8a
RC
606 register char *rp = rdvec, *strptr;
607 int kr, cnt_char;
55a580e3 608 char nextch;
01af9d69 609 int timo = MAXMSGTIME;
55a580e3 610
46b15d8a
RC
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);
ac09522b 619 strptr--;
46b15d8a 620 *strptr = ' ';
ac09522b 621 strcpy(&strptr[1], &strptr[4]);
46b15d8a
RC
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 }
55a580e3 630 }
46b15d8a 631
01af9d69
JB
632 strptr = index(str, '~');
633 if (strptr != NULL) {
634 *strptr++ = '\0';
635 timo = atoi(strptr);
636 if (timo <= 0)
637 timo = MAXMSGTIME;
638 }
639
46b15d8a
RC
640 if (setjmp(Sjbuf))
641 return FAIL;
55a580e3 642 signal(SIGALRM, alarmtr);
01af9d69
JB
643 alarm(timo);
644 *rp = 0;
55a580e3 645 while (notin(str, rdvec)) {
2af814a5 646 int c;
46b15d8a
RC
647 if(AbortOn != NULL && !notin(AbortOn, rdvec)) {
648 DEBUG(1, "Call aborted on '%s'\n", AbortOn);
649 alarm(0);
650 return ABORT;
651 }
55a580e3
SL
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");
46b15d8a 657 return FAIL;
55a580e3 658 }
55a580e3 659 c = nextch & 0177;
2af814a5
JB
660 if (c == '\0')
661 continue;
662 DEBUG(4, (isprint(c) || isspace(c)) ? "%c" : "\\%03o", c);
663 *rp++ = c;
55a580e3 664 if (rp >= rdvec + MR) {
46b15d8a
RC
665 register char *p;
666 for (p = rdvec+MR/2; p < rp; p++)
667 *(p-MR/2) = *p;
668 rp -= MR/2;
55a580e3
SL
669 }
670 *rp = '\0';
671 }
672 alarm(0);
46b15d8a 673 return SUCCESS;
55a580e3
SL
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 */
683getnextfd()
684{
685 close(next_fd = open("/", 0));
686}
687
46b15d8a
RC
688/*
689 * send line of login sequence
55a580e3
SL
690 *
691 * return codes: none
692 */
55a580e3
SL
693sendthem(str, fn)
694register char *str;
695int fn;
696{
697 register char *strptr;
698 int i, n, cr = 1;
46b15d8a 699 register char c;
55a580e3
SL
700 static int p_init = 0;
701
2af814a5 702 DEBUG(5, "send \"%s\"\n", str);
55a580e3
SL
703
704 if (!p_init) {
705 p_init++;
7dd5932d 706 bld_partab(P_ZERO);
55a580e3
SL
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
55a580e3 732 /* Send a '\n' */
2af814a5
JB
733 if (strcmp(str, "LF") == SAME) {
734 p_chwrite(fn, '\n');
735 return;
736 }
55a580e3
SL
737
738 /* Send a '\r' */
2af814a5
JB
739 if (strcmp(str, "CR") == SAME) {
740 p_chwrite(fn, '\r');
741 return;
742 }
55a580e3
SL
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' */
46b15d8a
RC
763 if (strcmp(str, "\"\"") == SAME) {
764 p_chwrite(fn, '\r');
765 return;
766 }
767
2af814a5
JB
768 strptr = str;
769 while ((c = *strptr++) != '\0') {
46b15d8a
RC
770 if (c == '\\') {
771 switch(*strptr++) {
2af814a5
JB
772 case '\0':
773 DEBUG(5, "TRAILING BACKSLASH IGNORED\n", CNULL);
774 --strptr;
775 continue;
46b15d8a
RC
776 case 's':
777 DEBUG(5, "BLANK\n", CNULL);
2af814a5 778 c = ' ';
46b15d8a
RC
779 break;
780 case 'd':
781 DEBUG(5, "DELAY\n", CNULL);
782 sleep(1);
783 continue;
2af814a5
JB
784 case 'n':
785 DEBUG(5, "NEW LINE\n", CNULL);
786 c = '\n';
787 break;
46b15d8a
RC
788 case 'r':
789 DEBUG(5, "RETURN\n", CNULL);
2af814a5 790 c = '\r';
46b15d8a
RC
791 break;
792 case 'b':
793 if (isdigit(*strptr)) {
794 i = (*strptr++ - '0');
795 if (i <= 0 || i > 10)
796 i = 3;
797 } else
55a580e3 798 i = 3;
46b15d8a
RC
799 /* send break */
800 genbrk(fn, i);
801 if (*strptr == '\0')
802 cr = 0;
55a580e3 803 continue;
46b15d8a
RC
804 case 'c':
805 if (*strptr == '\0') {
806 DEBUG(5, "NO CR\n", CNULL);
807 cr = 0;
2af814a5
JB
808 } else
809 DEBUG(5, "NO CR - IGNORED NOT EOL\n", CNULL);
55a580e3 810 continue;
2af814a5 811#define isoctal(x) ((x >= '0') && (x <= '7'))
46b15d8a 812 default:
2af814a5 813 if (isoctal(strptr[-1])) {
46b15d8a
RC
814 i = 0;
815 n = 0;
2af814a5
JB
816 --strptr;
817 while (isoctal(*strptr) && ++n <= 3)
818 i = i * 8 + (*strptr++ - '0');
819 DEBUG(5, "\\%o\n", i);
46b15d8a
RC
820 p_chwrite(fn, (char)i);
821 continue;
822 }
55a580e3 823 }
2af814a5
JB
824 }
825 p_chwrite(fn, c);
55a580e3
SL
826 }
827
55a580e3
SL
828 if (cr)
829 p_chwrite(fn, '\r');
830 return;
831}
832
833p_chwrite(fd, c)
834int fd;
46b15d8a 835char c;
55a580e3 836{
46b15d8a
RC
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 }
55a580e3
SL
842}
843
844/*
845 * generate parity table for use by p_chwrite.
846 */
847bld_partab(type)
848int 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
1a85e9d2
RC
864/*
865 * check for occurrence of substring "sh"
55a580e3
SL
866 *
867 * return codes:
868 * 0 - found the string
869 * 1 - not in the string
870 */
55a580e3
SL
871notin(sh, lg)
872register char *sh, *lg;
873{
874 while (*lg != '\0') {
55a580e3 875 if (wprefix(sh, lg))
1a85e9d2 876 return 0;
55a580e3
SL
877 else
878 lg++;
879 }
1a85e9d2 880 return 1;
55a580e3
SL
881}
882
1a85e9d2 883/*
941b257e 884 * Allow multiple date specifications separated by ','.
55a580e3 885 */
1a85e9d2
RC
886ifdate(p)
887register char *p;
55a580e3 888{
2af814a5 889 register char *np;
1a85e9d2 890 register int ret, g;
941b257e
JB
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 }
1a85e9d2
RC
903
904 ret = FAIL;
905 MaxGrade = '\0';
906 do {
941b257e
JB
907 np = strpbrk(p, ",|"); /* prefer , but allow | for compat */
908 if (np)
909 *np = '\0';
1a85e9d2
RC
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 }
941b257e
JB
917 if (np)
918 *np = ',';
919 p = np + 1;
920 } while (np);
921 if (MaxGrade == '\0')
922 MaxGrade = DefMaxGrade;
1a85e9d2 923 return ret;
55a580e3
SL
924}
925
1a85e9d2
RC
926/*
927 * this routine will check a string (string)
55a580e3
SL
928 * like "MoTu0800-1730" to see if the present
929 * time is within the given limits.
930 * SIDE EFFECT - Retrytime is set
931 *
55a580e3
SL
932 * return codes:
933 * 0 - not within limits
934 * 1 - within limits
935 */
936
1a85e9d2
RC
937ifadate(string)
938char *string;
55a580e3
SL
939{
940 static char *days[]={
941 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
942 };
943 time_t clock;
1a85e9d2 944 register char *s = string;
46b15d8a 945 int i, tl, th, tn, dayok=0;
55a580e3
SL
946 struct tm *localtime();
947 struct tm *tp;
1a85e9d2 948 char *p, MGrade;
55a580e3 949
941b257e 950 if ((p = index(s, '/')) == NULL)
1a85e9d2
RC
951 MGrade = DefMaxGrade;
952 else
953 MGrade = p[1];
954
55a580e3
SL
955 time(&clock);
956 tp = localtime(&clock);
46b15d8a 957 while (isascii(*s) && isalpha(*s)) {
55a580e3
SL
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;
46b15d8a
RC
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 */
1a85e9d2
RC
977 || tp->tm_hour >= 23 || tp->tm_hour < 8
978 /* Sunday before 5pm */
979 || (tp->tm_wday == 0 && tp->tm_hour < 17))
46b15d8a
RC
980 dayok = 1;
981 }
2af814a5
JB
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 }
55a580e3
SL
988 s++;
989 }
990
1a85e9d2
RC
991 if (dayok == 0 && s != string)
992 return FAIL;
55a580e3 993 i = sscanf(s, "%d-%d", &tl, &th);
1a85e9d2
RC
994 if (i < 2)
995 return MGrade;
46b15d8a 996 tn = tp->tm_hour * 100 + tp->tm_min;
1a85e9d2
RC
997 if (th < tl) { /* crosses midnight */
998 if (tl <= tn || tn < th)
999 return MGrade;
9313cec6 1000 } else {
46b15d8a 1001 if (tl <= tn && tn < th)
1a85e9d2 1002 return MGrade;
9313cec6 1003 }
1a85e9d2 1004 return FAIL;
55a580e3
SL
1005}
1006
1a85e9d2
RC
1007/*
1008 * find first digit in string
55a580e3
SL
1009 *
1010 * return - pointer to first digit in string or end of string
1011 */
55a580e3
SL
1012char *
1013fdig(cp)
1014register char *cp;
1015{
1016 register char *c;
1017
1018 for (c = cp; *c; c++)
1019 if (*c >= '0' && *c <= '9')
1020 break;
46b15d8a 1021 return c;
55a580e3
SL
1022}
1023
55a580e3
SL
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 */
55a580e3
SL
1028snccmp(s1, s2)
1029register char *s1, *s2;
1030{
1031 char c1, c2;
1032
01af9d69
JB
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;
55a580e3
SL
1041
1042 while (c1 == c2) {
01af9d69 1043 if (*s1++ == '\0')
46b15d8a 1044 return 0;
55a580e3 1045 s2++;
01af9d69
JB
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;
55a580e3 1054 }
46b15d8a
RC
1055 return c1 - c2;
1056}
01af9d69
JB
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 */
1062sncncmp(s1, s2, n)
1063register char *s1, *s2;
1064register 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}
46b15d8a
RC
1092/*
1093 * do chat script
1094 * occurs after local port is opened,
1095 * before 'dialing' the other machine.
1096 */
1097dochat(dev, flds, fd)
1098register struct Devices *dev;
1099char *flds[];
1100int 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);
55a580e3 1128}
2af814a5
JB
1129
1130/*
1131 * fix kill/echo/raw on line
1132 *
1133 * return codes: none
1134 */
1135fixmode(tty)
1136register 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 }
7dd5932d
RA
1170 if (linebaudrate < 0) {
1171 syslog(LOG_ERR, "unrecognized speed: %d", linebaudrate);
1172 cleanup(FAIL);
1173 }
2af814a5 1174}