Bell 32V development
[unix-history] / usr / src / cmd / uucp / conn.c
CommitLineData
1d38f7f7
TL
1#define CONN
2#include "uucp.h"
3#include <signal.h>
4#include <sgtty.h>
5#include <setjmp.h>
6#include <ctype.h>
7#include <sys/types.h>
8#include <time.h>
9
10
11#define F_NAME 0
12#define F_TIME 1
13#define F_LINE 2
14#define F_SPEED 3
15#define F_PHONE 4
16#define F_LOGIN 5
17
18jmp_buf Sjbuf;
19#define INVOKE(a, r) ret = a; if (ret<0) return(r);
20/*******
21 * conn(system)
22 * char *system;
23 *
24 * conn - place a telephone call to system and
25 * login, etc.
26 *
27 * return codes:
28 * CF_SYSTEM: don't know system
29 * CF_TIME: wrong time to call
30 * CF_DIAL: call failed
31 * CF_LOGIN: login/password dialog failed
32 *
33 * >0 - file no. - connect ok
34 *
35 */
36
37conn(system)
38char *system;
39{
40 int ret, nf;
41 int fn;
42 char *flds[50];
43 DEBUG(4, "gdial %s\n", "called");
44 INVOKE(gdial(), CF_DIAL)
45 DEBUG(4, "finds %s\n", "called");
46 INVOKE(nf = finds(system, flds), nf)
47 DEBUG(4, "getto %s\n", "called");
48 INVOKE(fn = getto(flds), CF_DIAL)
49 DEBUG(4, "login %s\n", "called");
50 INVOKE(login(nf, flds, fn), CF_LOGIN)
51 return(fn);
52}
53
54/***
55 * char *
56 * lastc(s) return pointer to last character
57 * char *s;
58 *
59 */
60
61char *
62lastc(s)
63char *s;
64{
65 while (*s != '\0') s++;
66 return(s);
67}
68
69#define MAXDEV 10
70#define MAXDCH MAXDEV*20
71#define MAXCODE 30
72#define MAXCCH MAXCODE*20
73 /* This array tells us about possible acu's, etc. */
74struct Devices {
75 char *D_line;
76 char *D_acu;
77 int D_speed;
78 } Devs [MAXDEV];
79
80char Devbuff[MAXDCH];
81
82struct Codes {
83 char *C_locs;
84 char *C_prefix;
85 } Dialcodes [MAXCODE];
86
87char Codebuff[MAXCCH];
88int Dcfull = 0;
89
90
91/***
92 * gdial() get device and dial info
93 *
94 * return codes: 0 | FAIL
95 */
96
97gdial()
98{
99 char *flds[10], *lt;
100 char *lb = Devbuff;
101 char *lc = Codebuff;
102 FILE *fn;
103 int nr;
104 struct Devices *pd;
105 struct Codes *pc;
106 if (Dcfull) return(0);
107
108 fn = fopen(Devfile, "r");
109 ASSERT(fn != NULL, "CAN'T OPEN %s", Devfile);
110 for (pd = Devs; fgets(lb, 200, fn); pd++) {
111 lt = lastc(lb);
112 nr = getargs(lb, flds);
113 ASSERT(nr == 3, "BAD LINE %s", lb);
114 pd->D_line = flds[0];
115 pd->D_acu = flds[1];
116 pd->D_speed = atoi(flds[2]);
117 lb = lt;
118 ASSERT(lb < Devbuff + MAXDCH, "TOO LONG %s", Devbuff);
119 ASSERT(pd < Devs + MAXDEV, "TOO MANY DEVICES %d", MAXCODE);
120 }
121 pd->D_line = NULL;
122 fclose(fn);
123 ASSERT(pd > Devs, "BAD FILE %s", Devfile);
124 /* Now dialcodes, same way */
125 fn = fopen(Dialfile, "r");
126 ASSERT(fn != NULL, "CAN'T OPEN %s", Dialfile);
127 for (pc = Dialcodes; fgets(lc, 200, fn); pc++) {
128 lt = lastc(lc);
129 nr = getargs(lc, flds);
130 if (nr == 1) flds[nr++] = "";
131 ASSERT(nr == 2, "BAD LINE %s", lc);
132 pc->C_locs = flds[0];
133 pc->C_prefix = flds[1];
134 lc = lt;
135 ASSERT(lc < Codebuff + MAXCCH, "TOO LONG %s", Codebuff);
136 ASSERT(pc < Dialcodes + MAXCODE, "MANY DEVICES %d", MAXCODE);
137 }
138 pc->C_locs = 0;
139 fclose(fn);
140 return(0);
141}
142
143
144/***
145 * ckdev(type, speed, ndev)
146 * char *type, *speed;
147 * int ndev;
148 *
149 * ckdev - return the device number in table Devs for
150 * a device with proper attributes.
151 *
152 * return codes: >= 0 (ok) | FAIL
153 */
154
155ckdev(type, speed, ndev)
156char *type, *speed;
157int ndev;
158{
159 int sp, acu;
160 struct Devices *pd;
161
162 sp = atoi(speed);
163 acu =(strcmp(type, "ACU") == SAME);
164 for (pd = &Devs[ndev]; pd->D_line != NULL; pd++) {
165 if (sp != pd->D_speed)
166 continue;
167 if (acu && (strcmp(pd->D_acu, "0") != SAME)
168 && !mlock(pd->D_line))
169 return(ndev = pd - Devs);
170 if (!acu && (strcmp(pd->D_line, type) == SAME)
171 && !mlock(type))
172 return(ndev = pd - Devs);
173 }
174 return(FAIL);
175}
176
177
178/***
179 * getto(flds) connect to remote machine
180 * char *flds[];
181 *
182 * return codes:
183 * >0 - file number - ok
184 * FAIL - failed
185 */
186
187getto(flds)
188char *flds[];
189{
190 DEBUG(F_PHONE, "call: no. %s ", flds[4]);
191 DEBUG(4, "for sys %s ", flds[F_NAME]);
192
193 if (strcmp(flds[F_LINE], "ACU") == SAME)
194 return(call(flds));
195 else
196 return(direct(flds));
197}
198
199/***
200 * call(flds) call remote machine
201 * char *flds[];
202 *
203 * "flds" contains the call information (name, date, type, speed,
204 * phone no. ...
205 * Ndev has the device no.
206 *
207 * return codes:
208 * >0 - file number - ok
209 * FAIL - failed
210 */
211
212call(flds)
213char *flds[];
214{
215 char *pno, pref[20], phone[20];
216 char *s1, *s2;
217 int dcr;
218 struct Codes *pc;
219
220 pno = flds[F_PHONE];
221 s1 = pref; s2 = pno;
222 while (isalpha(*s2))
223 *s1++ = *s2++;
224 *s1 = '\0';
225 for (pc = Dialcodes; pc->C_locs; pc++)
226 if (strcmp(pc->C_locs, pref) == SAME) {
227 s1 = pc->C_prefix;
228 break;
229 }
230 sprintf(phone, "%s%s", s1, s2);
231 DEBUG(4, "Dial %s\n", phone);
232 dcr = dialup(phone, flds);
233 DEBUG(4, "dcr returned as %d\n", dcr);
234 if (dcr == FAIL)
235 return(FAIL);
236 return(dcr);
237
238}
239
240 /* file descriptor for call unit */
241int Dnf = 0;
242
243/***
244 * dialup(ph, flds) dial remote machine
245 * char *ph;
246 * char *flds[];
247 *
248 * return codes:
249 * file descriptor - succeeded
250 * FAIL - failed
251 */
252
253dialup(ph, flds)
254char *ph;
255char *flds[];
256{
257 char dcname[20], dnname[20], phone[20];
258 struct Devices *pd;
259 int nw, lt, pid, dcf, ndev;
260 extern int Error;
261 extern alarmtr();
262
263 for (ndev = 0;;ndev++) {
264 ndev = ckdev(flds[F_LINE], flds[F_SPEED], ndev);
265 if (ndev < 0) {
266 logent("AVAILABLE DEVICE", "NO");
267 return(FAIL);
268 }
269 pd = &Devs[ndev];
270 sprintf(dnname, "/dev/%s", pd->D_acu);
271 /* open call unit */
272 Dnf = open(dnname, 1);
273 if (Dnf >= 0)
274 break;
275 delock(pd->D_line);
276 }
277 sprintf(dcname, "/dev/%s", pd->D_line);
278 sprintf(phone, "%s%s", ph, ACULAST);
279 DEBUG(4, "dc - %s, ", dcname);
280 DEBUG(4, "acu - %s\n", dnname);
281 if (setjmp(Sjbuf)) {
282 DEBUG(1, "DN write %s\n", "timeout");
283 logent("DIALUP DN write", "TIMEOUT");
284 kill(pid, 9);
285 close(Dnf);
286 return(FAIL);
287 }
288 signal(SIGALRM, alarmtr);
289 alarm(30);
290 if ((pid = fork()) == 0) {
291 sleep(2);
292 fclose(stdin);
293 fclose(stdout);
294 nw = write(Dnf, phone, lt = strlen(phone));
295 if (nw != lt) {
296 DEBUG(1, "ACU write %s\n", "error");
297 logent("DIALUP ACU write", "FAILED");
298 exit(1);
299 }
300 DEBUG(4, "ACU write ok%s\n", "");
301 exit(0);
302 }
303 /* open line - will return on carrier */
304 dcf = open(dcname, 2);
305 DEBUG(4, "dcf is %d\n", dcf);
306 if (dcf < 0) {
307 DEBUG(1, "Line open %s\n", "failed");
308 logent("DIALUP LINE open", "FAILED");
309 alarm(0);
310 return(FAIL);
311 }
312 ioctl(dcf, TIOCHPCL, 0);
313 nw = wait(&lt);
314 alarm(0);
315 fflush(stdout);
316 fixline(dcf, pd->D_speed);
317 DEBUG(4, "Forked %d ", pid);
318 DEBUG(4, "Wait got %d ", nw);
319 DEBUG(4, "Status %o\n", lt);
320 if (lt != 0) {
321 close(dcf);
322 return(FAIL);
323 }
324 return(dcf);
325}
326
327
328/***
329 * clsacu() close call unit
330 *
331 * return codes: none
332 */
333
334clsacu()
335{
336 if (Dnf > 0) {
337 close(Dnf);
338 Dnf = 0;
339 }
340 return;
341}
342
343
344/***
345 * direct(flds) connect to hardware line
346 * char *flds[];
347 *
348 * return codes:
349 * >0 - file number - ok
350 * FAIL - failed
351 */
352
353direct(flds)
354char *flds[];
355{
356 int dcr, ndev;
357 char dcname[20];
358
359 ndev = 0;
360 if ((ndev = ckdev(flds[F_LINE], flds[F_SPEED], ndev)) < 0) {
361 logent("DEVICE", "NOT AVAILABLE");
362 return(FAIL);
363 }
364 sprintf(dcname, "/dev/%s", Devs[ndev].D_line);
365 signal(SIGALRM, alarmtr);
366 alarm(10);
367 if (setjmp(Sjbuf))
368 return(FAIL);
369 dcr = open(dcname, 2); /* read/write */
370 alarm(0);
371 if (dcr < 0)
372 return(FAIL);
373 fflush(stdout);
374 fixline(dcr, Devs[ndev].D_speed);
375 return(dcr);
376}
377
378
379
380#define MAXC 300
381
382/***
383 * finds(sysnam, flds) set system attribute vector
384 * char *sysnam, *flds[];
385 *
386 * return codes:
387 * >0 - number of arguments in vector - succeeded
388 * CF_SYSTEM - system name not found
389 * CF_TIME - wrong time to call
390 */
391
392finds(sysnam, flds)
393char *sysnam, *flds[];
394{
395 FILE *fsys;
396 static char info[MAXC];
397 char **fnp;
398 int na;
399 int fnd = 0;
400
401 for (fnp = Sysfiles; *fnp != NULL && !fnd; fnp++) {
402 fsys = fopen(*fnp, "r");
403 if (fsys == NULL)
404 continue;
405 while (!fnd && (fgets(info, MAXC, fsys) != NULL)) {
406 na = getargs(info, flds);
407 if (prefix(sysnam, flds[F_NAME]))
408 fnd = 1;
409 }
410 fclose(fsys);
411 }
412 if (fnd == 0)
413 return(CF_SYSTEM);
414 /* format of fields
415 * 0 name;
416 * 1 time
417 * 2 acu/hardwired
418 * 3 speed
419 * etc
420 */
421 if (ifdate(flds[F_TIME]) == 0) {
422 DEBUG(1, "Wrong time to call %s\n", sysnam);
423 logent(sysnam, "WRONG TIME TO CALL");
424 return(CF_TIME);
425 }
426 return(na);
427}
428
429
430/***
431 * login(nf, flds, dcr) do log conversation
432 * char *flds[];
433 * int nf;
434 *
435 * return codes: 0 | FAIL
436 */
437
438login(nf, flds, fn)
439char *flds[];
440int nf, fn;
441{
442 char *want, *altern;
443 extern char *index();
444 int k, ok;
445
446 ASSERT(nf > 4, "TOO FEW LOG FIELDS %d", nf);
447 for (k = F_LOGIN; k < nf; k += 2) {
448 want = flds[k];
449 ok = FAIL;
450 while (ok != 0) {
451 altern = index(want, '-');
452 if (altern != NULL)
453 *altern++ = '\0';
454 DEBUG(4, "wanted %s ", want);
455 ok = expect(want, fn);
456 DEBUG(4, "got %s\n", ok ? "?" : "that");
457 if (ok == 0)
458 break;
459 if (altern == NULL) {
460 logent("LOGIN", "FAILED");
461 return(FAIL);
462 }
463 want = index(altern, '-');
464 if (want != NULL)
465 *want++ = '\0';
466 sendthem(altern, fn);
467 }
468 sleep(2);
469 sendthem(flds[k+1], fn);
470 }
471 return(0);
472}
473
474
475struct sg_spds {int sp_val, sp_name;} spds[] = {
476 { 300, B300},
477 {1200, B1200},
478 {9600, B9600},
479 {0, 0} };
480
481/***
482 * fixline(tty, spwant) set speed/echo/mode...
483 * int tty, spwant;
484 *
485 * return codes: none
486 */
487
488fixline(tty, spwant)
489int tty, spwant;
490{
491 struct sgttyb ttbuf;
492 struct sg_spds *ps;
493 int speed = -1;
494 int ret;
495
496 for (ps = spds; ps->sp_val; ps++)
497 if (ps->sp_val == spwant)
498 speed = ps->sp_name;
499 ASSERT(speed >= 0, "BAD SPEED %d", speed);
500 ioctl(tty, TIOCGETP, &ttbuf);
501 ttbuf.sg_flags |=(ANYP|RAW);
502 ttbuf.sg_flags &= ~(ECHO|ALLDELAY);
503 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
504 DEBUG(4, "Speed: want %d ", spwant);
505 DEBUG(4, "use %o ", speed);
506 DEBUG(4, "ps %d\n", ps-spds);
507 ret = ioctl(tty, TIOCSETP, &ttbuf);
508 ASSERT(ret >= 0, "RETURN FROM STTY %d", ret);
509 ioctl(tty, TIOCHPCL, 0);
510 ioctl(tty, TIOCEXCL, 0);
511 return;
512}
513
514
515#define MR 300
516
517int Error = 0;
518
519/***
520 * expect(str, fn) look for expected string
521 * char *str;
522 *
523 * return codes:
524 * 0 - found
525 * FAIL - lost line or too many characters read
526 * some character - timed out
527 */
528
529expect(str, fn)
530char *str;
531int fn;
532{
533 static char rdvec[MR];
534 extern alarmtr();
535 char *rp = rdvec;
536 int nextch = 0, kr;
537
538 if (strcmp(str, "\"\"") == SAME)
539 return(0);
540 *rp = 0;
541 if (setjmp(Sjbuf)) {
542 return(FAIL);
543 }
544 signal(SIGALRM, alarmtr);
545 while (notin(str, rdvec)) {
546 alarm(MAXCHARTIME);
547 kr = read(fn, &nextch, 1);
548 if (kr <= 0) {
549 DEBUG(4, "kr - %d\n", kr);
550 alarm(0);
551 DEBUG(4, "lost line kr - %d, ", kr);
552 DEBUG(4, "fn - %d\n", fn);
553 logent("LOGIN", "LOST LINE");
554 return(FAIL);
555 }
556 {
557 int c;
558 c = nextch & 0177;
559 DEBUG(4, "%c", c > 040 ? c : '_');
560 }
561 if ((*rp = nextch & 0177) != '\0')
562 rp++;
563 *rp = '\0';
564 if (rp >= rdvec + MR)
565 return(FAIL);
566 }
567 alarm(0);
568 return(0);
569}
570
571
572/***
573 * alarmtr() - catch alarm routine for "expect".
574 */
575
576alarmtr()
577{
578 longjmp(Sjbuf, 1);
579}
580
581
582/***
583 * sendthem(str, fn) send line of login sequence
584 * char *str;
585 *
586 * return codes: none
587 */
588
589sendthem(str, fn)
590char *str;
591int fn;
592{
593 int nw, ns;
594 int nulls;
595
596 if (prefix("BREAK", str)) {
597 sscanf(&str[5], "%1d", &nulls);
598 if (nulls <= 0 || nulls > 10)
599 nulls = 3;
600 /* send break */
601 DEBUG(5, "%s,", str);
602 DEBUG(5, "%d\n", nulls);
603 genbrk(fn, Bspeed, nulls);
604 return;
605 }
606
607 if (strcmp(str, "EOT") == SAME) {
608 write(fn, EOTMSG, strlen(EOTMSG));
609 return;
610 }
611 if (strcmp(str, "") != SAME) {
612 nw = write(fn, str, ns = strlen(str));
613 ASSERT(nw == ns, "BAD WRITE $s", str);
614 }
615 write(fn, "\n", 1);
616 return;
617}
618
619
620/***
621 * genbrk(fn) send equivalent to break
622 *
623 * return codes; none
624 */
625
626genbrk(fn, bspeed, bnulls)
627int fn, bspeed, bnulls;
628{
629 struct sgttyb ttbuf;
630 int ret, sospeed;
631
632 ret = ioctl(fn, TIOCGETP, &ttbuf);
633 DEBUG(5, "ioctl ret %d\n", ret);
634 sospeed = ttbuf.sg_ospeed;
635 ttbuf.sg_ospeed = bspeed;
636 ret = ioctl(fn, TIOCSETP, &ttbuf);
637 DEBUG(5, "ioctl ret %d\n", ret);
638 ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
639 ASSERT(ret > 0, "BAD WRITE genbrk %d", ret);
640 ttbuf.sg_ospeed = sospeed;
641 ret = ioctl(fn, TIOCSETP, &ttbuf);
642 ret = write(fn, "@", 1);
643 ASSERT(ret > 0, "BAD WRITE genbrk %d", ret);
644 DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
645 return;
646}
647
648
649/***
650 * notin(sh, lg) check for occurrence of substring "sh"
651 * char *sh, *lg;
652 *
653 * return codes:
654 * 0 - found the string
655 * 1 - not in the string
656 */
657
658notin(sh, lg)
659char *sh, *lg;
660{
661 while (*lg != '\0') {
662 if (prefix(sh, lg))
663 return(0);
664 else
665 lg++;
666 }
667 return(1);
668}
669
670
671/*******
672 * ifdate(s)
673 * char *s;
674 *
675 * ifdate - this routine will check a string (s)
676 * like "MoTu0800-1730" to see if the present
677 * time is within the given limits.
678 *
679 * String alternatives:
680 * Wk - Mo thru Fr
681 * zero or one time means all day
682 * Any - any day
683 *
684 * return codes:
685 * 0 - not within limits
686 * 1 - within limits
687 */
688
689ifdate(s)
690char *s;
691{
692 static char *days[]={
693 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
694 };
695 long clock;
696 int i, tl, th, tn, dayok=0;
697 struct tm *localtime();
698 struct tm *tp;
699
700 time(&clock);
701 tp = localtime(&clock);
702 while (isalpha(*s)) {
703 for (i = 0; days[i]; i++) {
704 if (prefix(days[i], s))
705 if (tp->tm_wday == i)
706 dayok = 1;
707 }
708
709 if (prefix("Wk", s))
710 if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
711 dayok = 1;
712 if (prefix("Any", s))
713 dayok = 1;
714 s++;
715 }
716
717 if (dayok == 0)
718 return(0);
719 i = sscanf(s, "%d-%d", &tl, &th);
720 tn = tp->tm_hour * 100 + tp->tm_min;
721 if (i < 2)
722 return(1);
723 if (tn >= tl && tn <= th)
724 return(1);
725 return(0);
726}