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