Research V7 development
[unix-history] / usr / src / cmd / uucp / conn.c
CommitLineData
1bb4d653
N
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 DEBUG(4, "NO AVAILABLE DEVICE %s\n", "");
268 return(FAIL);
269 }
270 pd = &Devs[ndev];
271 sprintf(dnname, "/dev/%s", pd->D_acu);
272 /* open call unit */
273 Dnf = open(dnname, 1);
274 if (Dnf >= 0)
275 break;
276 delock(pd->D_line);
277 }
278 sprintf(dcname, "/dev/%s", pd->D_line);
279 sprintf(phone, "%s%s", ph, ACULAST);
280 DEBUG(4, "dc - %s, ", dcname);
281 DEBUG(4, "acu - %s\n", dnname);
282 if (setjmp(Sjbuf)) {
283 DEBUG(1, "DN write %s\n", "timeout");
284 logent("DIALUP DN write", "TIMEOUT");
285 kill(pid, 9);
286 close(Dnf);
287 return(FAIL);
288 }
289 signal(SIGALRM, alarmtr);
290 alarm(30);
291 if ((pid = fork()) == 0) {
292 sleep(2);
293 fclose(stdin);
294 fclose(stdout);
295 nw = write(Dnf, phone, lt = strlen(phone));
296 if (nw != lt) {
297 DEBUG(1, "ACU write %s\n", "error");
298 logent("DIALUP ACU write", "FAILED");
299 exit(1);
300 }
301 DEBUG(4, "ACU write ok%s\n", "");
302 exit(0);
303 }
304 /* open line - will return on carrier */
305 dcf = open(dcname, 2);
306 DEBUG(4, "dcf is %d\n", dcf);
307 if (dcf < 0) {
308 DEBUG(1, "Line open %s\n", "failed");
309 logent("DIALUP LINE open", "FAILED");
310 alarm(0);
311 return(FAIL);
312 }
313 ioctl(dcf, TIOCHPCL, 0);
314 nw = wait(&lt);
315 alarm(0);
316 fflush(stdout);
317 fixline(dcf, pd->D_speed);
318 DEBUG(4, "Forked %d ", pid);
319 DEBUG(4, "Wait got %d ", nw);
320 DEBUG(4, "Status %o\n", lt);
321 if (lt != 0) {
322 close(dcf);
323 return(FAIL);
324 }
325 return(dcf);
326}
327
328
329/***
330 * clsacu() close call unit
331 *
332 * return codes: none
333 */
334
335clsacu()
336{
337 if (Dnf > 0) {
338 close(Dnf);
339 Dnf = 0;
340 }
341 return;
342}
343
344
345/***
346 * direct(flds) connect to hardware line
347 * char *flds[];
348 *
349 * return codes:
350 * >0 - file number - ok
351 * FAIL - failed
352 */
353
354direct(flds)
355char *flds[];
356{
357 int dcr, ndev;
358 char dcname[20];
359
360 ndev = 0;
361 if ((ndev = ckdev(flds[F_LINE], flds[F_SPEED], ndev)) < 0) {
362 logent("DEVICE", "NOT AVAILABLE");
363 return(FAIL);
364 }
365 sprintf(dcname, "/dev/%s", Devs[ndev].D_line);
366 signal(SIGALRM, alarmtr);
367 alarm(10);
368 if (setjmp(Sjbuf))
369 return(FAIL);
370 dcr = open(dcname, 2); /* read/write */
371 alarm(0);
372 if (dcr < 0)
373 return(FAIL);
374 fflush(stdout);
375 fixline(dcr, Devs[ndev].D_speed);
376 return(dcr);
377}
378
379
380
381#define MAXC 300
382
383/***
384 * finds(sysnam, flds) set system attribute vector
385 * char *sysnam, *flds[];
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 */
392
393finds(sysnam, flds)
394char *sysnam, *flds[];
395{
396 FILE *fsys;
397 static char info[MAXC];
398 char **fnp;
399 int na;
400 int fnd = 0;
401
402 for (fnp = Sysfiles; *fnp != NULL && !fnd; fnp++) {
403 fsys = fopen(*fnp, "r");
404 if (fsys == NULL)
405 continue;
406 while (!fnd && (fgets(info, MAXC, fsys) != NULL)) {
407 na = getargs(info, flds);
408 if (prefix(sysnam, flds[F_NAME]))
409 fnd = 1;
410 }
411 fclose(fsys);
412 }
413 if (fnd == 0)
414 return(CF_SYSTEM);
415 /* format of fields
416 * 0 name;
417 * 1 time
418 * 2 acu/hardwired
419 * 3 speed
420 * etc
421 */
422 if (ifdate(flds[F_TIME]) == 0) {
423 DEBUG(1, "Wrong time to call %s\n", sysnam);
424 logent(sysnam, "WRONG TIME TO CALL");
425 return(CF_TIME);
426 }
427 return(na);
428}
429
430
431/***
432 * login(nf, flds, dcr) do log conversation
433 * char *flds[];
434 * int nf;
435 *
436 * return codes: 0 | FAIL
437 */
438
439login(nf, flds, fn)
440char *flds[];
441int nf, fn;
442{
443 char *want, *altern;
444 extern char *index();
445 int k, ok;
446
447 ASSERT(nf > 4, "TOO FEW LOG FIELDS %d", nf);
448 for (k = F_LOGIN; k < nf; k += 2) {
449 want = flds[k];
450 ok = FAIL;
451 while (ok != 0) {
452 altern = index(want, '-');
453 if (altern != NULL)
454 *altern++ = '\0';
455 DEBUG(4, "wanted %s ", want);
456 ok = expect(want, fn);
457 DEBUG(4, "got %s\n", ok ? "?" : "that");
458 if (ok == 0)
459 break;
460 if (altern == NULL) {
461 logent("LOGIN", "FAILED");
462 return(FAIL);
463 }
464 want = index(altern, '-');
465 if (want != NULL)
466 *want++ = '\0';
467 sendthem(altern, fn);
468 }
469 sleep(2);
470 sendthem(flds[k+1], fn);
471 }
472 return(0);
473}
474
475
476struct sg_spds {int sp_val, sp_name;} spds[] = {
477 { 300, B300},
478 {1200, B1200},
479 {4800, B4800},
480 {9600, B9600},
481 {0, 0} };
482
483/***
484 * fixline(tty, spwant) set speed/echo/mode...
485 * int tty, spwant;
486 *
487 * return codes: none
488 */
489
490fixline(tty, spwant)
491int tty, spwant;
492{
493 struct sgttyb ttbuf;
494 struct sg_spds *ps;
495 int speed = -1;
496 int ret;
497
498 for (ps = spds; ps->sp_val; ps++)
499 if (ps->sp_val == spwant)
500 speed = ps->sp_name;
501 ASSERT(speed >= 0, "BAD SPEED %d", speed);
502 ioctl(tty, TIOCGETP, &ttbuf);
503 ttbuf.sg_flags |=(ANYP|RAW);
504 ttbuf.sg_flags &= ~(ECHO|ALLDELAY);
505 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
506 DEBUG(4, "Speed: want %d ", spwant);
507 DEBUG(4, "use %o ", speed);
508 DEBUG(4, "ps %d\n", ps-spds);
509 ret = ioctl(tty, TIOCSETP, &ttbuf);
510 ASSERT(ret >= 0, "RETURN FROM STTY %d", ret);
511 ioctl(tty, TIOCHPCL, 0);
512 ioctl(tty, TIOCEXCL, 0);
513 return;
514}
515
516
517#define MR 300
518
519int Error = 0;
520
521/***
522 * expect(str, fn) look for expected string
523 * char *str;
524 *
525 * return codes:
526 * 0 - found
527 * FAIL - lost line or too many characters read
528 * some character - timed out
529 */
530
531expect(str, fn)
532char *str;
533int fn;
534{
535 static char rdvec[MR];
536 extern alarmtr();
537 char *rp = rdvec;
538 int nextch = 0, kr;
539
540 if (strcmp(str, "\"\"") == SAME)
541 return(0);
542 *rp = 0;
543 if (setjmp(Sjbuf)) {
544 return(FAIL);
545 }
546 signal(SIGALRM, alarmtr);
547 while (notin(str, rdvec)) {
548 alarm(MAXCHARTIME);
549 kr = read(fn, &nextch, 1);
550 if (kr <= 0) {
551 DEBUG(4, "kr - %d\n", kr);
552 alarm(0);
553 DEBUG(4, "lost line kr - %d, ", kr);
554 DEBUG(4, "fn - %d\n", fn);
555 logent("LOGIN", "LOST LINE");
556 return(FAIL);
557 }
558 {
559 int c;
560 c = nextch & 0177;
561 DEBUG(4, "%c", c > 040 ? c : '_');
562 }
563 if ((*rp = nextch & 0177) != '\0')
564 rp++;
565 *rp = '\0';
566 if (rp >= rdvec + MR)
567 return(FAIL);
568 }
569 alarm(0);
570 return(0);
571}
572
573
574/***
575 * alarmtr() - catch alarm routine for "expect".
576 */
577
578alarmtr()
579{
580 longjmp(Sjbuf, 1);
581}
582
583
584/***
585 * sendthem(str, fn) send line of login sequence
586 * char *str;
587 *
588 * return codes: none
589 */
590
591sendthem(str, fn)
592char *str;
593int fn;
594{
595 int nw, ns;
596 int nulls;
597
598 if (prefix("BREAK", str)) {
599 sscanf(&str[5], "%1d", &nulls);
600 if (nulls <= 0 || nulls > 10)
601 nulls = 3;
602 /* send break */
603 DEBUG(5, "%s,", str);
604 DEBUG(5, "%d\n", nulls);
605 genbrk(fn, Bspeed, nulls);
606 return;
607 }
608
609 if (strcmp(str, "EOT") == SAME) {
610 write(fn, EOTMSG, strlen(EOTMSG));
611 return;
612 }
613 if (strcmp(str, "") != SAME) {
614 nw = write(fn, str, ns = strlen(str));
615 ASSERT(nw == ns, "BAD WRITE $s", str);
616 }
617 write(fn, "\n", 1);
618 return;
619}
620
621
622/***
623 * genbrk(fn) send equivalent to break
624 *
625 * return codes; none
626 */
627
628genbrk(fn, bspeed, bnulls)
629int fn, bspeed, bnulls;
630{
631 struct sgttyb ttbuf;
632 int ret, sospeed;
633
634 ret = ioctl(fn, TIOCGETP, &ttbuf);
635 DEBUG(5, "ioctl ret %d\n", ret);
636 sospeed = ttbuf.sg_ospeed;
637 ttbuf.sg_ospeed = bspeed;
638 ret = ioctl(fn, TIOCSETP, &ttbuf);
639 DEBUG(5, "ioctl ret %d\n", ret);
640 ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
641 ASSERT(ret > 0, "BAD WRITE genbrk %d", ret);
642 ttbuf.sg_ospeed = sospeed;
643 ret = ioctl(fn, TIOCSETP, &ttbuf);
644 ret = write(fn, "@", 1);
645 ASSERT(ret > 0, "BAD WRITE genbrk %d", ret);
646 DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
647 return;
648}
649
650
651/***
652 * notin(sh, lg) check for occurrence of substring "sh"
653 * char *sh, *lg;
654 *
655 * return codes:
656 * 0 - found the string
657 * 1 - not in the string
658 */
659
660notin(sh, lg)
661char *sh, *lg;
662{
663 while (*lg != '\0') {
664 if (prefix(sh, lg))
665 return(0);
666 else
667 lg++;
668 }
669 return(1);
670}
671
672
673/*******
674 * ifdate(s)
675 * char *s;
676 *
677 * ifdate - this routine will check a string (s)
678 * like "MoTu0800-1730" to see if the present
679 * time is within the given limits.
680 *
681 * String alternatives:
682 * Wk - Mo thru Fr
683 * zero or one time means all day
684 * Any - any day
685 *
686 * return codes:
687 * 0 - not within limits
688 * 1 - within limits
689 */
690
691ifdate(s)
692char *s;
693{
694 static char *days[]={
695 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
696 };
697 long clock;
698 int i, tl, th, tn, dayok=0;
699 struct tm *localtime();
700 struct tm *tp;
701
702 time(&clock);
703 tp = localtime(&clock);
704 while (isalpha(*s)) {
705 for (i = 0; days[i]; i++) {
706 if (prefix(days[i], s))
707 if (tp->tm_wday == i)
708 dayok = 1;
709 }
710
711 if (prefix("Wk", s))
712 if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
713 dayok = 1;
714 if (prefix("Any", s))
715 dayok = 1;
716 s++;
717 }
718
719 if (dayok == 0)
720 return(0);
721 i = sscanf(s, "%d-%d", &tl, &th);
722 tn = tp->tm_hour * 100 + tp->tm_min;
723 if (i < 2)
724 return(1);
725 if (tn >= tl && tn <= th)
726 return(1);
727 return(0);
728}