|
|
1.1 root 1: /* @(#)conn.c 1.16
2: */
3: #include "uucp.h"
4: VERSION(@(#)conn.c 1.16);
5:
6: static char _ProtoStr[20] = ""; /* protocol string from Systems file entry */
7: extern jmp_buf Sjbuf;
8:
9: int alarmtr();
10: static void getProto();
11: /* static getto(), finds(); PUT this back after altconn is included */
12: extern getto();
13: static finds();
14:
15: static notin(), ifdate(), classmatch();
16:
17: extern struct caller caller[];
18:
19: /* Needed for cu for force which line will be used */
20: #ifdef STANDALONE
21: extern char *Myline;
22: #endif STANDALONE
23:
24: /*
25: * conn - place a telephone call to system and login, etc.
26: *
27: * return codes:
28: * FAIL - connection failed
29: * >0 - file no. - connect ok
30: * When a failure occurs, Uerror is set.
31: */
32:
33: conn(system)
34: char *system;
35: {
36: int nf, fn = FAIL;
37: char *flds[F_MAX+1];
38: FILE *fsys;
39: int (*oalrm)();
40: #ifdef MANYSYS
41: #define SYSCLOSE pclose
42: FILE *sysopen();
43: #else
44: #define SYSCLOSE fclose
45: #endif
46:
47: CDEBUG(4, "conn(%s)\n", system);
48: #ifndef MANYSYS
49: fsys = fopen(SYSFILE, "r");
50: #else
51: fsys = sysopen(system);
52: #endif
53: ASSERT(fsys != NULL, Ct_OPEN, SYSFILE, errno);
54: Uerror = 0;
55: while ((nf = finds(fsys, system, flds, F_MAX)) > 0) {
56: fn = getto(flds);
57: CDEBUG(4, "getto ret %d\n", fn);
58: if (fn < 0)
59: continue;
60: #ifdef STANDALONE
61: SYSCLOSE(fsys);
62: return(fn);
63: #else
64: if (chat(nf - F_LOGIN, flds + F_LOGIN, fn,"","") == SUCCESS) {
65: SYSCLOSE(fsys);
66: return(fn); /* successful return */
67: }
68:
69: /* login failed */
70: DEBUG(6, "close caller (%d)\n", fn);
71: if (setjmp(Sjbuf) == 0) {
72: oalrm = signal(SIGALRM, alarmtr);
73: alarm(30);
74: close(fn);
75: }
76: alarm(0);
77: signal(SIGALRM, oalrm);
78: if (Dc[0] != NULLCHAR) {
79: DEBUG(6, "delock(%s)\n", Dc);
80: delock(Dc);
81: }
82: #endif
83: }
84:
85: /* finds or getto failed */
86: SYSCLOSE(fsys);
87: CDEBUG(1, "Call Failed: %s\n", UERRORTEXT);
88: return(FAIL);
89: }
90:
91: /*
92: * getto - connect to remote machine
93: *
94: * return codes:
95: * >0 - file number - ok
96: * FAIL - failed
97: */
98:
99: getto(flds)
100: char *flds[];
101: {
102: FILE *dfp;
103: char *dev[D_MAX+2], devbuf[BUFSIZ];
104: register int status;
105: register int dcf = -1;
106: int reread = 0;
107: int tries = 0; /* count of call attempts - for limit purposes */
108:
109: CDEBUG(1, "Device Type %s wanted\n", flds[F_TYPE]);
110: dfp = fopen(DEVFILE, "r");
111: ASSERT(dfp != NULL, Ct_OPEN, DEVFILE, errno);
112: Uerror = 0;
113: while (tries < TRYCALLS) {
114: if ((status=rddev(dfp, flds[F_TYPE], dev, devbuf, D_MAX)) == FAIL) {
115: if (tries == 0 || ++reread >= TRYCALLS)
116: break;
117: rewind(dfp);
118: continue;
119: }
120: /* check class, check (and possibly set) speed */
121: if (classmatch(flds, dev) != SUCCESS)
122: continue;
123: if ((dcf = processdev(flds, dev)) >= 0)
124: break;
125:
126: switch(Uerror) {
127: case SS_CANT_ACCESS_DEVICE:
128: case SS_DEVICE_FAILED:
129: case SS_LOCKED_DEVICE:
130: break;
131: default:
132: tries++;
133: break;
134: }
135: }
136: (void) fclose(dfp);
137: if (status == FAIL && !Uerror) {
138: CDEBUG(1, "Requested Device Type Not Found\n", 0);
139: Uerror = SS_NO_DEVICE;
140: }
141: return(dcf);
142: }
143:
144: /*
145: * classmatch - process 'Any' in Devices and Systems and
146: * determine the correct speed, or match for ==
147: */
148:
149: static int
150: classmatch(flds, dev)
151: char *flds[], *dev[];
152: {
153: /* check class, check (and possibly set) speed */
154: if (EQUALS(flds[F_CLASS], "Any")
155: && EQUALS(dev[D_CLASS], "Any")) {
156: dev[D_CLASS] = flds[F_CLASS] = DEFAULT_BAUDRATE;
157: return(SUCCESS);
158: } else if (EQUALS(dev[F_CLASS], "Any")) {
159: dev[D_CLASS] = flds[F_CLASS];
160: return(SUCCESS);
161: } else if (EQUALS(flds[F_CLASS], "Any")) {
162: flds[D_CLASS] = dev[F_CLASS];
163: return(SUCCESS);
164: } else if (EQUALS(flds[F_CLASS], dev[D_CLASS]))
165: return(SUCCESS);
166: else
167: return(FAIL);
168: }
169:
170:
171: /***
172: * rddev - find and unpack a line from device file for this caller type
173: * lines starting with whitespace of '#' are comments
174: *
175: * return codes:
176: * >0 - number of arguments in vector - succeeded
177: * FAIL - EOF
178: ***/
179:
180: rddev(fp, type, dev, buf, devcount)
181: FILE *fp;
182: char *type;
183: char *dev[];
184: char *buf;
185: {
186: int na;
187:
188: while (fgets(buf, BUFSIZ, fp) != NULL) {
189: if (buf[0] == ' ' || buf[0] == '\t'
190: || buf[0] == '\n' || buf[0] == '\0' || buf[0] == '#')
191: continue;
192: na = getargs(buf, dev, devcount);
193: ASSERT(na >= D_CALLER, "BAD LINE", buf, na);
194:
195: /* For cu -- to force the requested line to be used */
196: #ifdef STANDALONE
197: if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE])) )
198: continue;
199: #endif STANDALONE
200:
201: bsfix(dev); /* replace \X fields */
202: if (EQUALS(dev[D_TYPE], type))
203: return(na);
204: }
205: return(FAIL);
206: }
207:
208:
209: /*
210: * finds - set system attribute vector
211: *
212: * input:
213: * fsys - open Systems file descriptor
214: * sysnam - system name to find
215: * output:
216: * flds - attibute vector from Systems file
217: * fldcount - number of fields in flds
218: * return codes:
219: * >0 - number of arguments in vector - succeeded
220: * FAIL - failed
221: * Uerror set:
222: * 0 - found a line in Systems file
223: * SS_BADSYSTEM - no line found in Systems file
224: * SS_TIME_WRONG - wrong time to call
225: */
226:
227: static
228: finds(fsys, sysnam, flds, fldcount)
229: char *sysnam, *flds[];
230: FILE *fsys;
231: {
232: static char info[BUFSIZ];
233: int na;
234:
235: /* format of fields
236: * 0 name;
237: * 1 time
238: * 2 acu/hardwired
239: * 3 speed
240: * etc
241: */
242: while (fgets(info, BUFSIZ, fsys) != NULL) {
243: if (info[0] == '#')
244: continue;
245: na = getargs(info, flds, fldcount);
246: bsfix(flds); /* replace \X fields */
247: if ( !EQUALSN(sysnam, flds[F_NAME], SYSNSIZE))
248: continue;
249: #ifndef STANDALONE
250: if (ifdate(flds[F_TIME])) {
251: /* found a good entry */
252: getProto(flds[F_TYPE]);
253: Uerror = 0;
254: return(na); /* FOUND OK LINE */
255: }
256: CDEBUG(1, "Wrong Time To Call: %s\n", flds[F_TIME]);
257: Uerror = SS_TIME_WRONG;
258: #else
259: Uerror = 0;
260: return(na); /* FOUND OK LINE */
261: #endif
262: }
263: if (!Uerror)
264: Uerror = SS_BADSYSTEM;
265: return(FAIL);
266: }
267:
268: /*
269: * getProto - get the protocol letters from the input string.
270: * input:
271: * str - string from Systems file (flds[F_TYPE])--the ,
272: * delimits the protocol string
273: * e.g. ACU,g or DK,d
274: * output:
275: * str - the , (if present) will be replaced with NULLCHAR
276: * global ProtoStr will be modified
277: * return: none
278: */
279:
280: static
281: void
282: getProto(str)
283: char *str;
284: {
285: register char *p;
286: if ( (p=strchr(str, ',')) != NULL) {
287: *p = NULLCHAR;
288: (void) strcpy(_ProtoStr, p+1);
289: DEBUG(7, "ProtoStr = %s\n", _ProtoStr);
290: }
291: else
292: *_ProtoStr = NULLCHAR;
293: }
294:
295: /*
296: * check for a specified protocol selection string
297: * return:
298: * protocol string pointer
299: * NULL if none specified for LOGNAME
300: */
301: char *
302: protoString()
303: {
304: return(_ProtoStr[0] == NULLCHAR ? NULL : _ProtoStr);
305: }
306:
307: static int _Echoflag;
308: static int _Slowflag;
309: /*
310: * chat - do conversation
311: * input:
312: * flds - fields from Systems file
313: * nf - number of fields in flds array
314: * dcr - write file number
315: * phstr1 - phone number to replace \D
316: * phstr2 - phone number to replace \T
317: *
318: * return codes: 0 | FAIL
319: */
320:
321: chat(nf, flds, fn, phstr1, phstr2)
322: char *flds[], *phstr1, *phstr2;
323: int nf, fn;
324: {
325: char *want, *altern;
326: extern char *strchr();
327: int k, ok;
328:
329: _Echoflag = 0;
330: _Slowflag = 0;
331: for (k = 0; k < nf; k += 2) {
332: want = flds[k];
333: ok = FAIL;
334: while (ok != 0) {
335: altern = strchr(want, '-');
336: if (altern != NULL)
337: *altern++ = NULLCHAR;
338: ok = expect(want, fn);
339: if (ok == 0)
340: break;
341: if (altern == NULL) {
342: Uerror = SS_LOGIN_FAILED;
343: logent(UERRORTEXT, "FAILED");
344: return(FAIL);
345: }
346: want = strchr(altern, '-');
347: if (want != NULL)
348: *want++ = NULLCHAR;
349: sendthem(altern, fn, phstr1, phstr2);
350: }
351: sleep(2);
352: if (flds[k+1])
353: sendthem(flds[k+1], fn, phstr1, phstr2);
354: }
355: return(0);
356: }
357:
358: /***
359: * expect(str, fn) look for expected string
360: * char *str;
361: *
362: * return codes:
363: * 0 - found
364: * FAIL - lost line or too many characters read
365: * some character - timed out
366: *
367: * There are many delicacies here.
368: * -- keep the system calls in the inner loop to a minimum;
369: * else a garrulous system might time out while we're reading
370: * its chatter.
371: * -- because systems may be garrulous but correct, the alarm
372: * must be reset whenever a character arrives; time out only
373: * if nothing has come for a while. But putting the alarm inside
374: * the inner loop slows it down too much; so put it outside,
375: * and don't time out if anything arrives. But that might let
376: * the far side time out in some pathological cases, so wait
377: * a shorter time if some character have already arrived.
378: * -- reading several characters at a time might be a mistake;
379: * we might consume something beyond the string we expect,
380: * discard it here, but need it later. Too bad for now.
381: */
382:
383: #define MR 2000 /* max chars before we give up */
384: #define NNEXT 4 /* chars to read at a time */
385:
386: expect(str, fn)
387: char *str;
388: int fn;
389: {
390: static char rdvec[MR];
391: register char *rp = rdvec;
392: register int kr, c;
393: char nextch[NNEXT];
394: char dbuf[NNEXT*2 + 1];
395: register char *dp, *cp;
396: int nread;
397: extern errno;
398:
399: CDEBUG(4, "expect: (", 0);
400: for (c=0; kr=str[c]; c++)
401: if (kr < 040) {
402: CDEBUG(4, "^%c", kr | 0100);
403: } else {
404: CDEBUG(4, "%c", kr);
405: }
406: CDEBUG(4, ")\n", 0);
407:
408: if (EQUALS(str, "\"\"")) {
409: CDEBUG(4, "got it\n", 0);
410: return(0);
411: }
412: nread = 0;
413: if (setjmp(Sjbuf) && nread == 0) {
414: return(FAIL);
415: }
416: (void) signal(SIGALRM, alarmtr);
417: if (nread)
418: alarm(MAXEXPECTTIME/2); /* cheap hack */
419: else
420: alarm(MAXEXPECTTIME);
421: nread = 0;
422: do {
423: errno = 0;
424: kr = read(fn, nextch, NNEXT);
425: if (kr <= 0) {
426: alarm(0);
427: CDEBUG(4, "lost line errno - %d\n", errno);
428: logent("LOGIN", "LOST LINE");
429: return(FAIL);
430: }
431: if (rp + kr >= rdvec + MR) {
432: CDEBUG(4, "\ntoo much junk\n", 0);
433: alarm(0);
434: return(FAIL);
435: }
436: nread += kr;
437: for (dp = dbuf, cp = nextch; --kr >= 0; ) {
438: if ((c = *cp++ & 0177) == 0)
439: continue;
440: *rp++ = c;
441: if (c >= 040)
442: *dp++ = c;
443: else {
444: *dp++ = '^';
445: *dp++ = c+0100;
446: }
447: }
448: *dp = 0;
449: CDEBUG(4, "%s", dbuf);
450: *rp = NULLCHAR;
451: } while (notin(str, rdvec));
452: alarm(0);
453: CDEBUG(4, "got it\n", 0);
454: return(0);
455: }
456:
457:
458: /***
459: * alarmtr() - catch alarm routine for "expect".
460: */
461:
462: alarmtr()
463: {
464: CDEBUG(6, "timed out\n", 0);
465: longjmp(Sjbuf, 1);
466: }
467:
468:
469: /***
470: * sendthem(str, fn, phstr1, phstr2) send line of chat sequence
471: * char *str, *phstr;
472: *
473: * return codes: none
474: */
475:
476: sendthem(str, fn, phstr1, phstr2)
477: char *str, *phstr1, *phstr2;
478: int fn;
479: {
480: int sendcr = 1;
481: register char *sptr, *pptr;
482:
483: if (PREFIX("BREAK", str)) {
484: /* send break */
485: CDEBUG(5, "BREAK\n", 0);
486: genbrk(fn);
487: return;
488: }
489:
490: if (EQUALS(str, "EOT")) {
491: CDEBUG(5, "EOT\n", 0);
492: (void) write(fn, EOTMSG, strlen(EOTMSG));
493: return;
494: }
495:
496: if (EQUALS(str, "\"\"")) {
497: CDEBUG(5, "\"\"\n", 0);
498: str += 2;
499: }
500:
501: CDEBUG(5, "sendthem (", "");
502: if (setjmp(Sjbuf)) /* Timer so echo check doesn't last forever */
503: goto err;
504: (void) signal(SIGALRM, alarmtr);
505: alarm(MAXEXPECTTIME);
506: for (sptr = str; *sptr; sptr++) {
507: if (*sptr == '\\')
508: switch(*++sptr) {
509: case 'D':
510: for (pptr=phstr1; *pptr; pptr++)
511: if (wrchar(fn, pptr))
512: goto err;
513: continue;
514: case 'T':
515: for (pptr=phstr2; *pptr; pptr++)
516: if (wrchar(fn, pptr))
517: goto err;
518: continue;
519: case 'N':
520: *sptr = 0;
521: break;
522: case 'd':
523: CDEBUG(5, "DELAY\n", 0);
524: sleep(2);
525: continue;
526: case 'c':
527: if (*(sptr+1) == NULLCHAR) {
528: CDEBUG(5, "<NO CR>", 0);
529: sendcr = 0;
530: continue;
531: }
532: CDEBUG(5, "<NO CR - MIDDLE IGNORED>\n", 0);
533: continue;
534: case 's':
535: *sptr = ' ';
536: break;
537: case 'p':
538: CDEBUG(5, "PAUSE\n", 0);
539: nap(HZ/4); /* approximately 1/4 second */
540: continue;
541: case 'E':
542: CDEBUG(5, "ECHO CHECK ON\n", 0);
543: _Echoflag = 1;
544: continue;
545: case 'e':
546: CDEBUG(5, "ECHO CHECK OFF\n", 0);
547: _Echoflag = 0;
548: continue;
549: case 'K':
550: CDEBUG(5, "BREAK\n", 0);
551: genbrk(fn);
552: continue;
553: case 'W':
554: _Slowflag = 1;
555: continue;
556: case 'w':
557: _Slowflag = 0;
558: continue;
559: case '\\':
560: /* backslash escapes itself */
561: break;
562: default:
563: /* send the backslash */
564: --sptr;
565: break;
566: }
567: if (wrchar(fn, sptr))
568: goto err;
569: }
570:
571: if (sendcr) {
572: CDEBUG(5, "^M", 0);
573: (void) write(fn, "\r", 1);
574: }
575: err:
576: alarm(0);
577: CDEBUG(5, ")\n", 0);
578: return;
579: }
580:
581: wrchar(fn, sptr)
582: register int fn;
583: register char *sptr;
584: {
585: if (GRPCHK(getgid())) /* protect Systems file */
586: {
587: CDEBUG(5, "%s", *sptr < 040 ? "^" : "");
588: CDEBUG(5, "%c", *sptr < 040 ? *sptr | 0100 : *sptr);
589: }
590: if ((write(fn, sptr, 1)) != 1)
591: return(FAIL);
592: if (_Echoflag) {
593: char chr;
594: while(1) { /* Should set a timer here */
595: if (read(fn, &chr, 1) != 1)
596: return(FAIL);
597: chr &= 0177;
598: CDEBUG(4, "%s", chr < 040 ? "^" : "");
599: CDEBUG(4, "%c", chr < 040 ? chr | 0100 : chr);
600: if (chr == ((*sptr) & 0177))
601: break;
602: }
603:
604: }
605: if (_Slowflag)
606: sleep(1);
607: return(SUCCESS);
608: }
609:
610:
611: /***
612: * notin(sh, lg) check for occurrence of substring "sh"
613: * char *sh, *lg;
614: *
615: * return codes:
616: * 0 - found the string
617: * 1 - not in the string
618: */
619:
620: static
621: notin(sh, lg)
622: register char *sh, *lg;
623: {
624: while (*lg != NULLCHAR) {
625: if (PREFIX(sh, lg))
626: return(0);
627: else
628: lg++;
629: }
630: return(1);
631: }
632:
633:
634: /*******
635: * ifdate(s)
636: * char *s;
637: *
638: * ifdate - this routine will check a string (s)
639: * like "MoTu0800-1730" to see if the present
640: * time is within the given limits.
641: * SIDE EFFECT - Retrytime is set to number following ";"
642: *
643: * String alternatives:
644: * Wk - Mo thru Fr
645: * zero or one time means all day
646: * Any - any day
647: *
648: * return codes:
649: * 0 - not within limits
650: * 1 - within limits
651: */
652:
653: static
654: ifdate(s)
655: char *s;
656: {
657: static char *days[] = {
658: "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
659: };
660: time_t clock;
661: int t__now;
662: char *p, *strrchr(), *strchr();
663: struct tm *tp;
664:
665: time(&clock);
666: tp = localtime(&clock);
667: t__now = tp->tm_hour * 100 + tp->tm_min; /* "navy" time */
668:
669: /*
670: * pick up retry time for failures
671: * global variable Retrytime is set here
672: */
673: if ((p = strrchr(s, ';')) != NULL)
674: if (isdigit(p[1])) {
675: if (sscanf(p+1, "%d", &Retrytime) < 1)
676: Retrytime = 5; /* 5 minutes is error default */
677: Retrytime *= 60;
678: *p = NULLCHAR;
679: }
680:
681: while (*s) {
682: int i, dayok;
683:
684: for (dayok = 0; (!dayok) && isalpha(*s); s++) {
685: if (PREFIX("Any", s))
686: dayok = 1;
687: else if (PREFIX("Wk", s)) {
688: if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
689: dayok = 1;
690: } else
691: for (i = 0; days[i]; i++)
692: if (PREFIX(days[i], s))
693: if (tp->tm_wday == i)
694: dayok = 1;
695: }
696:
697: if (dayok) {
698: int t__low, t__high;
699:
700: while (isalpha(*s)) /* flush remaining day stuff */
701: s++;
702:
703: if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2)
704: || (t__low == t__high))
705: return(1);
706:
707: /* 0000 crossover? */
708: if (t__low < t__high) {
709: if (t__low <= t__now && t__now <= t__high)
710: return(1);
711: } else if (t__low <= t__now || t__now <= t__high)
712: return(1);
713:
714: /* aim at next time slot */
715: if ((s = strchr(s, ',')) == NULL)
716: break;
717: }
718: s++;
719: }
720: return(0);
721: }
722:
723: /***
724: * char *
725: * fdig(cp) find first digit in string
726: *
727: * return - pointer to first digit in string or end of string
728: */
729:
730: char *
731: fdig(cp)
732: char *cp;
733: {
734: char *c;
735:
736: for (c = cp; *c; c++)
737: if (*c >= '0' && *c <= '9')
738: break;
739: return(c);
740: }
741:
742:
743: #ifdef FASTTIMER
744: /* Sleep in increments of 60ths of second. */
745: nap (time)
746: register int time;
747: {
748: static int fd;
749:
750: if (fd == 0)
751: fd = open (FASTTIMER, 0);
752:
753: read (fd, 0, time);
754: }
755:
756: #endif FASTTIMER
757:
758: #ifdef BSD4_2
759:
760: /* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */
761: /* This version, by Mark Horton, uses the select system call */
762:
763:
764: nap(n)
765: unsigned n;
766: {
767: struct timeval tv;
768: int rc;
769:
770: if (n==0)
771: return;
772: tv.tv_sec = n/60;
773: tv.tv_usec = ((n%60)*1000000L)/60;
774: rc = select(32, 0, 0, 0, &tv);
775: }
776:
777: #endif
778:
779: #ifdef NONAP
780:
781: /* nap(n) where n is ticks
782: *
783: * loop using n/HZ part of a second
784: * if n represents more than 1 second, then
785: * use sleep(time) where time is the equivalent
786: * seconds rounded off to full seconds
787: * NOTE - this is a rough approximation and chews up
788: * processor resource!
789: */
790:
791: nap(n)
792: unsigned n;
793: {
794: struct tms tbuf;
795: long endtime;
796: int i;
797:
798: if (n > HZ) {
799: /* > second, use sleep, rounding time */
800: sleep( (int) (((n)+HZ/2)/HZ) );
801: return;
802: }
803:
804: /* use timing loop for < 1 second */
805: endtime = times(&tbuf) + 3*n/4; /* use 3/4 because of scheduler! */
806: while (times(&tbuf) < endtime) {
807: for (i=0; i<1000; i++, i*i)
808: ;
809: }
810: return;
811: }
812:
813:
814: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.