1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32
33
34 #include "uucp.h"
35
36 GLOBAL char _Protocol[40] = ""; /* working protocol string */
37 static char _ProtoSys[40] = ""; /* protocol string from Systems file entry */
38 static char _ProtoDev[40] = ""; /* protocol string from Devices file entry */
39 EXTERN char _ProtoCfg[]; /* protocol string from Config file entry */
40
41 EXTERN jmp_buf Sjbuf;
42 EXTERN unsigned expecttime;
43
44 GLOBAL int Modemctrl;
45
46 /* Parity control during login procedure */
47 #define P_ZERO 0
48 #define P_ONE 1
49 #define P_EVEN 2
50 #define P_ODD 3
51
52 static char par_tab[128];
53
54 EXTERN void alarmtr();
55 static void addProto(), mergeProto(), removeProto();
56 static void bld_partab();
57 static char *nextProto();
58 EXTERN char *findProto();
59 static void getProto();
60 EXTERN int getto(); /* make this static when ct uses altconn() */
61 EXTERN int chat(), rddev(), expect(), wrstr(), wrchr();
62 EXTERN int processdev(), getdevline(), getsysline(), sysaccess();
63 EXTERN int clear_hup();
64 EXTERN char *currsys(), *currdev();
65 static int finds();
66 static int wait_for_hangup(), expect_str();
67
68 EXTERN void sendthem(), nap();
69 static int notin(), ifdate(), checkdate(), checktime(), classmatch();
70
71 GLOBAL char *Myline = CNULL; /* to force which line will be used */
72 GLOBAL char *Mytype = CNULL; /* to force selection of specific device type */
73 GLOBAL int Dologin; /* to force login chat sequence */
74
75 /*
76 * conn - place a telephone call to system and login, etc.
77 *
78 * return codes:
79 * FAIL - connection failed
80 * >0 - file no. - connect ok
81 * When a failure occurs, Uerror is set.
82 */
83
84 GLOBAL int
conn(system)85 conn(system)
86 char *system;
87 {
88 int nf, fn;
89 char *flds[F_MAX+1];
90 EXTERN void sysreset();
91
92 CDEBUG(4, "conn(%s)\n", system);
93 Uerror = 0;
94 while ((nf = finds(system, flds, F_MAX)) > 0) {
95 fn = getto(flds);
96 CDEBUG(4, "getto ret %d\n", fn);
97 if (fn < 0)
98 continue;
99
100 #ifdef TIOCSPGRP
101 {
102 #ifdef ATTSV
103 int pgrp = getpgrp();
104 #else
105 int pgrp = getpgrp(0);
106 #endif
107 ioctl(fn, TIOCSPGRP, &pgrp);
108 }
109 #endif
110 if (Dologin || EQUALS(Progname, "uucico")) {
111 if (chat(nf - F_LOGIN, flds + F_LOGIN, fn,"","") == SUCCESS) {
112 sysreset();
113 return(fn); /* successful return */
114 }
115
116 /* login failed */
117 DEBUG(6, "close caller (%d)\n", fn);
118 fd_rmlock(fn);
119 close(fn);
120 if (Dc[0] != NULLCHAR) {
121 DEBUG(6, "delock line (%s)\n", Dc);
122 }
123 } else {
124 sysreset();
125 return(fn);
126 }
127 }
128
129 /* finds or getto failed */
130 sysreset();
131 CDEBUG(1, "Call Failed: %s\n", UERRORTEXT);
132 return(FAIL);
133 }
134
135 /*
136 * getto - connect to remote machine
137 *
138 * return codes:
139 * >0 - file number - ok
140 * FAIL - failed
141 */
142
143 GLOBAL int
getto(flds)144 getto(flds)
145 char *flds[];
146 {
147 char *dev[D_MAX+2], devbuf[BUFSIZ];
148 int status;
149 int dcf = -1;
150 int reread = 0;
151 int tries = 0; /* count of call attempts - for limit purposes */
152 EXTERN void devreset();
153
154 CDEBUG(1, "Device Type %s wanted\n", flds[F_TYPE]);
155 Uerror = 0;
156 while (tries < TRYCALLS) {
157 if ((status=rddev(flds[F_TYPE], dev, devbuf, D_MAX)) == FAIL) {
158 if (tries == 0 || ++reread >= TRYCALLS)
159 break;
160 devreset();
161 continue;
162 }
163 /* check class, check (and possibly set) speed */
164 if (classmatch(flds, dev) != SUCCESS) {
165 DEBUG(7, "Skipping entry in '%s'", currdev());
166 DEBUG(7, " - class (%s) not wanted.\n", dev[D_CLASS]);
167 continue;
168 }
169 DEBUG(5, "Trying device entry '%s' ", dev[D_LINE]);
170 DEBUG(5, "from '%s'.\n", currdev());
171 if ((dcf = processdev(flds, dev)) >= 0)
172 break;
173
174 switch(Uerror) {
175 case SS_CANT_ACCESS_DEVICE:
176 case SS_DEVICE_FAILED:
177 case SS_LOCKED_DEVICE:
178 case SS_CHAT_FAILED:
179 break;
180 default:
181 tries++;
182 break;
183 }
184 }
185 devreset(); /* reset devices file(s) */
186 if (status == FAIL && !Uerror) {
187 CDEBUG(1, "Requested Device Type Not Found\n%s", "");
188 Uerror = SS_NO_DEVICE;
189 }
190 return(dcf);
191 }
192
193 /*
194 * classmatch - process 'Any' in Devices and Systems and
195 * determine the correct speed, or match for ==
196 */
197
198 static int
classmatch(flds,dev)199 classmatch(flds, dev)
200 char *flds[], *dev[];
201 {
202 /* check class, check (and possibly set) speed */
203 if (EQUALS(flds[F_CLASS], "Any")
204 && EQUALS(dev[D_CLASS], "Any")) {
205 dev[D_CLASS] = DEFAULT_BAUDRATE;
206 return(SUCCESS);
207 } else if (EQUALS(dev[D_CLASS], "Any")) {
208 dev[D_CLASS] = flds[F_CLASS];
209 return(SUCCESS);
210 } else if (EQUALS(flds[F_CLASS], "Any") ||
211 EQUALS(flds[F_CLASS], dev[D_CLASS]))
212 return(SUCCESS);
213 else
214 return(FAIL);
215 }
216
217
218 /*
219 * rddev - find and unpack a line from device file for this caller type
220 * lines starting with whitespace of '#' are comments
221 *
222 * return codes:
223 * >0 - number of arguments in vector - succeeded
224 * FAIL - EOF
225 */
226
227 GLOBAL int
rddev(type,dev,buf,devcount)228 rddev(type, dev, buf, devcount)
229 char *type;
230 char *dev[];
231 char *buf;
232 {
233 char *commap, d_type[BUFSIZ];
234 int na;
235
236 while (getdevline(buf, BUFSIZ)) {
237 if (buf[0] == ' ' || buf[0] == '\t'
238 || buf[0] == '\n' || buf[0] == '\0' || buf[0] == '#')
239 continue;
240 na = getargs(buf, dev, devcount);
241 ASSERT(na >= D_CALLER, "BAD LINE", buf, na);
242
243 if ( strncmp(dev[D_LINE],"/dev/",5) == 0 ) {
244 /* since cu (altconn()) strips off leading */
245 /* "/dev/", do the same here. */
246 strcpy(dev[D_LINE], &(dev[D_LINE][5]) );
247 }
248
249 /* may have ",M" subfield in D_LINE */
250 Modemctrl = FALSE;
251 if ( (commap = strchr(dev[D_LINE], ',')) != (char *)NULL ) {
252 if ( strcmp( commap, ",M") == SAME )
253 Modemctrl = TRUE;
254 *commap = '\0';
255 }
256
257 /*
258 * D_TYPE field may have protocol subfield, which
259 * must be pulled off before comparing to desired type.
260 */
261 (void)strcpy(d_type, dev[D_TYPE]);
262 if ((commap = strchr(d_type, ',')) != (char *)NULL )
263 *commap = '\0';
264
265 /* to force the requested device type to be used. */
266 if ((Mytype != NULL) && (!EQUALS(Mytype, d_type)) )
267 continue;
268 /* to force the requested line to be used */
269 if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE])) )
270 continue;
271
272 bsfix(dev); /* replace \X fields */
273
274 if (EQUALS(d_type, type)) {
275 getProto( _ProtoDev, dev[D_TYPE] );
276 return(na);
277 }
278 }
279 return(FAIL);
280 }
281
282
283 /*
284 * finds - set system attribute vector
285 *
286 * input:
287 * fsys - open Systems file descriptor
288 * sysnam - system name to find
289 * output:
290 * flds - attibute vector from Systems file
291 * fldcount - number of fields in flds
292 * return codes:
293 * >0 - number of arguments in vector - succeeded
294 * FAIL - failed
295 * Uerror set:
296 * 0 - found a line in Systems file
297 * SS_BADSYSTEM - no line found in Systems file
298 * SS_TIME_WRONG - wrong time to call
299 */
300
301 static int
finds(sysnam,flds,fldcount)302 finds(sysnam, flds, fldcount)
303 char *sysnam, *flds[];
304 {
305 static char info[BUFSIZ];
306 int na;
307
308 /* format of fields
309 * 0 name;
310 * 1 time
311 * 2 acu/hardwired
312 * 3 speed
313 * etc
314 */
315 if (sysnam == 0 || *sysnam == 0 ) {
316 Uerror = SS_BADSYSTEM;
317 return(FAIL);
318 }
319
320 while (getsysline(info, sizeof(info))) {
321 na = getargs(info, flds, fldcount);
322 bsfix(flds); /* replace \X fields */
323 if ( !EQUALSN(sysnam, flds[F_NAME], MAXBASENAME))
324 continue;
325 /* check if requested Mytype device type */
326 if ((Mytype != CNULL) &&
327 (na <= F_TYPE ||
328 !EQUALSN(flds[F_TYPE], Mytype, strlen(Mytype)))) {
329 DEBUG(7, "Skipping entry in '%s'", currsys());
330 DEBUG(7, " - type (%s) not wanted.\n", na > F_TYPE ?
331 flds[F_TYPE] : "Missing type entry");
332 continue;
333 } else {
334 DEBUG(5, "Trying entry from '%s'", currsys());
335 DEBUG(5, " - device type %s.\n", na > F_TYPE ?
336 flds[F_TYPE] : "<Missing type entry>");
337 }
338 /* OK if not uucico (ie. ct or cu) or the time is right */
339 if (!EQUALS(Progname, "uucico") ||
340 (na > F_TIME && ifdate(flds[F_TIME]))) {
341 /* found a good entry */
342 if (na > F_TYPE) {
343 getProto(_ProtoSys, flds[F_TYPE]);
344 Uerror = 0;
345 return(na); /* FOUND OK LINE */
346 }
347 DEBUG(5, "Trying entry from '%s'", currsys());
348 DEBUG(5, " - Missing type entry for <%s>.\n",
349 flds[F_NAME]);
350 } else {
351 CDEBUG(1, "Wrong Time To Call: %s\n", na > F_TIME ?
352 flds[F_TIME] : "<Missing time entry>");
353 if (!Uerror)
354 Uerror = SS_TIME_WRONG;
355 }
356 }
357 if (!Uerror)
358 Uerror = SS_BADSYSTEM;
359 return(FAIL);
360 }
361
362 /*
363 * getProto - get the protocol letters from the input string.
364 * input:
365 * str - string from Systems/Devices/Config file,
366 * a ',' delimits the protocol string
367 * e.g. ACU,g or DK,d
368 * output:
369 * str - the , (if present) will be replaced with NULLCHAR
370 *
371 * return: none
372 */
373
374 static void
getProto(save,str)375 getProto(save, str)
376 char *save;
377 char *str;
378 {
379 char *p;
380
381 *save = NULLCHAR;
382 if ( (p=strchr(str, ',')) != NULL) {
383 *p = NULLCHAR;
384 (void) strcpy(save, p+1);
385 DEBUG(7, "Protocol = %s\n", save);
386 }
387 return;
388 }
389
390 /*
391 * check for a specified protocol selection string
392 * return:
393 * protocol string pointer
394 * NULL if none specified for LOGNAME
395 */
396 GLOBAL char *
protoString(valid)397 protoString(valid)
398 char *valid;
399 {
400 char *save;
401
402 save =strdup(valid);
403 _Protocol[0] = '\0';
404
405 if ( _ProtoSys[0] != '\0' )
406 addProto(_ProtoSys, valid);
407 if ( _ProtoDev[0] != '\0' )
408 addProto(_ProtoDev, valid);
409 if ( _ProtoCfg[0] != '\0' )
410 addProto(_ProtoCfg, valid);
411
412 if ( _Protocol[0] == '\0' ) {
413 (void) strcpy(valid, save);
414 (void) strcpy(_Protocol, save);
415 }
416
417 return(_Protocol[0] == NULLCHAR ? NULL : _Protocol);
418 }
419
420 /*
421 * addProto
422 *
423 * Verify that the desired protocols from the Systems and Devices file
424 * have been compiled into this application.
425 *
426 * desired - list of desired protocols
427 * valid - list of protocols that are compiled in.
428 */
429
430 static void
addProto(desired,valid)431 addProto (desired, valid)
432 char *desired;
433 char *valid;
434 {
435 char *protoPtr;
436 char *wantPtr;
437
438 if ( *desired == '\0' )
439 return;
440
441 if ( *(protoPtr = _Protocol) != NULLCHAR ) {
442 while ( *(protoPtr = nextProto(protoPtr)) != NULLCHAR ) {
443 if ( *(wantPtr = findProto(desired, *protoPtr)) == NULLCHAR ) {
444 removeProto(valid, *protoPtr);
445 removeProto(protoPtr, *protoPtr);
446 } else {
447 mergeProto(protoPtr, wantPtr);
448 protoPtr++;
449 }
450 }
451 } else {
452 wantPtr = desired;
453 while ( *(wantPtr = nextProto(wantPtr)) != NULLCHAR ) {
454 if ( *(findProto(valid, *wantPtr)) != NULLCHAR ) {
455 mergeProto(protoPtr, wantPtr);
456 }
457 wantPtr++;
458 }
459 }
460 if ( *(protoPtr = _Protocol) != NULLCHAR ) {
461 while ( *(protoPtr = nextProto(protoPtr)) != NULLCHAR )
462 *(valid++) = *(protoPtr++);
463 *valid = NULLCHAR;
464 }
465 return;
466 }
467
468 /*
469 * mergeProto
470 *
471 * input
472 * char *tostring, *fromstring;
473 */
474 static void
mergeProto(tostring,fromstring)475 mergeProto(tostring, fromstring)
476 char *tostring, *fromstring;
477 {
478 char buffer[BUFSIZ];
479 int length;
480
481 while ( *(tostring = nextProto(tostring)) != NULLCHAR ) {
482 if ( *tostring == *fromstring )
483 break;
484 else
485 tostring++;
486 }
487
488 if ( *tostring == NULLCHAR ) {
489 length = nextProto(fromstring + 1) - fromstring;
490 (void) strncpy(tostring, fromstring, length);
491 *(tostring + length) = NULLCHAR;
492 } else {
493 tostring++;
494 fromstring++;
495 if ( (*tostring != '(') && (*fromstring == '(') ) {
496 (void) strcpy(buffer, tostring);
497 length = nextProto(fromstring) - fromstring;
498 (void) strncpy(tostring, fromstring, length);
499 (void) strcpy(tostring+length, buffer);
500 }
501 }
502 return;
503 }
504
505 /*
506 * removeProto
507 *
508 * char *old
509 * char letter
510 *
511 * return
512 * none
513 */
514 static void
removeProto(string,letter)515 removeProto(string, letter)
516 char *string, letter;
517 {
518 while ( *(string = nextProto(string)) != NULLCHAR ) {
519 if ( *string == letter )
520 (void) strcpy(string, nextProto(string+1));
521 else
522 string++;
523 }
524 }
525
526 /*
527 * nextProto
528 * char *string;
529 * return
530 * char * to next non-parameter letter
531 */
532 static char *
nextProto(string)533 nextProto(string)
534 char *string;
535 {
536 if ( *string == '(' )
537 while ( *string != NULLCHAR )
538 if ( *(string++) == ')' )
539 break;
540 return(string);
541 }
542
543 /*
544 * findProto
545 * char *desired,
546 * char protoPtr;
547 * return
548 * char *pointer to found or string terminating NULLCHAR
549 */
550 GLOBAL char *
findProto(string,letter)551 findProto(string, letter)
552 char *string;
553 char letter;
554 {
555 while ( *(string = nextProto(string)) != NULLCHAR )
556 if ( *string == letter )
557 break;
558 else
559 string++;
560 return(string);
561 }
562
563 /*
564 * chat - do conversation
565 * input:
566 * nf - number of fields in flds array
567 * flds - fields from Systems file
568 * fn - write file number
569 * phstr1 - phone number to replace \D
570 * phstr2 - phone number to replace \T
571 *
572 * return codes: 0 | FAIL
573 */
574
575 GLOBAL int
chat(nf,flds,fn,phstr1,phstr2)576 chat(nf, flds, fn, phstr1, phstr2)
577 char *flds[], *phstr1, *phstr2;
578 int nf, fn;
579 {
580 char *want, *altern;
581 int k, ok;
582
583 for (k = 0; k < nf; k += 2) {
584 want = flds[k];
585 ok = FAIL;
586 while (ok != 0) {
587 altern = index(want, '-');
588 if (altern != NULL)
589 *altern++ = NULLCHAR;
590 ok = expect(want, fn);
591 if (ok == 0)
592 break;
593 if (altern == NULL) {
594 Uerror = SS_LOGIN_FAILED;
595 logent(UERRORTEXT, "FAILED");
596 return(FAIL);
597 }
598 want = index(altern, '-');
599 if (want != NULL)
600 *want++ = NULLCHAR;
601 sendthem(altern, fn, phstr1, phstr2);
602 }
603 sleep(2);
604 if (flds[k+1])
605 sendthem(flds[k+1], fn, phstr1, phstr2);
606 }
607 return(0);
608 }
609
610 #define MR 1000
611
612 /*
613 * expect(str, fn) look for expected string w/ possible special chars
614 *
615 * return codes:
616 * 0 - found
617 * FAIL - too many characters read
618 * some character - timed out
619 */
620
621 GLOBAL int
expect(str,fn)622 expect(str, fn)
623 char *str;
624 int fn;
625 {
626 char *bptr, *sptr;
627 char buf[BUFSIZ];
628
629 bptr = buf;
630
631 for (sptr = str; *sptr; sptr++) {
632 if (*sptr == '\\') {
633 switch (*++sptr) {
634 case 'H':
635 *bptr++ = '\0';
636 if (expect_str(buf, fn) == FAIL) {
637 return (FAIL);
638 }
639 if (wait_for_hangup(fn) == FAIL) {
640 return (FAIL);
641 }
642 bptr = buf;
643 continue;
644 case '\\':
645 *bptr++ = '\\';
646 continue;
647 default:
648 *bptr++ = '\\';
649 *bptr++ = *sptr;
650 continue;
651 }
652 } else
653 *bptr++ = *sptr;
654 }
655 *bptr = '\0';
656 if (expect_str(buf, fn) == FAIL) {
657 return (FAIL);
658 }
659 return (0);
660 }
661
662 /*
663 * expect_str(str, fn) look for expected string, w/ no special chars
664 *
665 * return codes:
666 * 0 - found
667 * FAIL - too many characters read
668 * some character - timed out
669 */
670
671 GLOBAL int
expect_str(str,fn)672 expect_str(str, fn)
673 char *str;
674 int fn;
675 {
676 static char rdvec[MR];
677 char *rp = rdvec;
678 int kr, c;
679 char nextch;
680
681 *rp = 0;
682
683 CDEBUG(4, "expect: (%s", "");
684 for (c=0; (kr=str[c]) != 0 ; c++)
685 if (kr < 040) {
686 CDEBUG(4, "^%c", kr | 0100);
687 } else
688 CDEBUG(4, "%c", kr);
689 CDEBUG(4, ")\n%s", "");
690
691 if (EQUALS(str, "\"\"")) {
692 CDEBUG(4, "got it\n%s", "");
693 return(0);
694 }
695 if (*str== '\0') {
696 return(0);
697 }
698 if (setjmp(Sjbuf)) {
699 return (FAIL);
700 }
701 (void) signal(SIGALRM, alarmtr);
702 alarm(expecttime);
703 while (notin(str, rdvec)) {
704 errno = 0;
705 kr = (*Read)(fn, &nextch, 1);
706 if (kr <= 0) {
707 alarm(0);
708 CDEBUG(4, "lost line errno - %d\n", errno);
709 logent("LOGIN", "LOST LINE");
710 return(FAIL);
711 }
712 c = nextch & 0177;
713 CDEBUG(4, "%s", c < 040 ? "^" : "");
714 CDEBUG(4, "%c", c < 040 ? c | 0100 : c);
715 if ((*rp = nextch & 0177) != NULLCHAR)
716 rp++;
717 if (rp >= rdvec + MR) {
718 CDEBUG(4, "enough already\n%s", "");
719 alarm(0);
720 return(FAIL);
721 }
722 *rp = NULLCHAR;
723 }
724 alarm(0);
725 CDEBUG(4, "got it\n%s", "");
726 return(0);
727 }
728 /*
729 * alarmtr() - catch alarm routine for "expect".
730 */
731 /*ARGSUSED*/
732 GLOBAL void
alarmtr(sig)733 alarmtr(sig)
734 int sig;
735 {
736 CDEBUG(6, "timed out\n%s", "");
737 longjmp(Sjbuf, 1);
738 }
739
740 /*
741 * wait_for_hangup() - wait for a hangup to occur on the given device
742 */
743 int
wait_for_hangup(dcf)744 wait_for_hangup(dcf)
745 int dcf;
746 {
747 int rval;
748 char buff[BUFSIZ];
749
750 CDEBUG(4, "Waiting for hangup\n%s", "");
751 while((rval = read(dcf, buff, BUFSIZ)) > 0);
752
753 if (rval < 0) {
754 return (FAIL);
755 }
756 CDEBUG(4, "Received hangup\n%s", "");
757
758 if (clear_hup(dcf) != SUCCESS) {
759 CDEBUG(4, "Unable to clear hup on device\n%s", "");
760 return (FAIL);
761 }
762 return (SUCCESS);
763 }
764
765 /*
766 * sendthem(str, fn, phstr1, phstr2) send line of chat sequence
767 * char *str, *phstr;
768 *
769 * return codes: none
770 */
771
772 #define FLUSH() {\
773 if ((bptr - buf) > 0)\
774 if (wrstr(fn, buf, bptr - buf, echocheck) != SUCCESS)\
775 goto err;\
776 bptr = buf;\
777 }
778
779 GLOBAL void
sendthem(str,fn,phstr1,phstr2)780 sendthem(str, fn, phstr1, phstr2)
781 char *str, *phstr1, *phstr2;
782 int fn;
783 {
784 int sendcr = 1, echocheck = 0;
785 char *sptr, *bptr;
786 char buf[BUFSIZ];
787 struct termio ttybuf;
788 static int p_init = 0;
789
790 if (!p_init) {
791 p_init++;
792 bld_partab(P_EVEN);
793 }
794
795 /* should be EQUALS, but previous versions had BREAK n for integer n */
796 if (PREFIX("BREAK", str)) {
797 /* send break */
798 CDEBUG(5, "BREAK\n%s", "");
799 (*genbrk)(fn);
800 return;
801 }
802
803 if (PREFIX("STTY=", str)) {
804 CDEBUG(5, "STTY %s\n", str+5);
805 setmode(str+5, fn);
806 return;
807 }
808
809 if (EQUALS(str, "EOT")) {
810 CDEBUG(5, "EOT\n%s", "");
811 bptr = buf;
812 for (sptr = EOTMSG; *sptr; sptr++)
813 *bptr++ = par_tab[*sptr&0177];
814 (void) (*Write)(fn, buf, bptr - buf);
815 return;
816 }
817
818 /* Set parity as needed */
819 if (EQUALS(str, "P_ZERO")) {
820 bld_partab(P_ZERO);
821 return;
822 }
823 if (EQUALS(str, "P_ONE")) {
824 bld_partab(P_ONE);
825 return;
826 }
827 if (EQUALS(str, "P_EVEN")) {
828 bld_partab(P_EVEN);
829 return;
830 }
831 if (EQUALS(str, "P_ODD")) {
832 bld_partab(P_ODD);
833 return;
834 }
835
836 if (EQUALS(str, "\"\"")) {
837 CDEBUG(5, "\"\"\n%s", "");
838 str += 2;
839 }
840
841 bptr = buf;
842 CDEBUG(5, "sendthem (%s", "");
843 for (sptr = str; *sptr; sptr++) {
844 if (*sptr == '\\') {
845 switch(*++sptr) {
846
847 /* adjust switches */
848 case 'c': /* no CR after string */
849 FLUSH();
850 if (sptr[1] == NULLCHAR) {
851 CDEBUG(5, "<NO CR>%s", "");
852 sendcr = 0;
853 } else
854 CDEBUG(5, "<NO CR IGNORED>\n%s", "");
855 continue;
856
857 /* stash in buf and continue */
858 case 'D': /* raw phnum */
859 strcpy(bptr, phstr1);
860 bptr += strlen(bptr);
861 continue;
862 case 'T': /* translated phnum */
863 strcpy(bptr, phstr2);
864 bptr += strlen(bptr);
865 continue;
866 case 'N': /* null */
867 *bptr++ = 0;
868 continue;
869 case 's': /* space */
870 *bptr++ = ' ';
871 continue;
872 case '\\': /* backslash escapes itself */
873 *bptr++ = *sptr;
874 continue;
875 default: /* send the backslash */
876 *bptr++ = '\\';
877 *bptr++ = *sptr;
878 continue;
879
880 /* flush buf, perform action, and continue */
881 case 'E': /* echo check on */
882 FLUSH();
883 CDEBUG(5, "ECHO CHECK ON\n%s", "");
884 echocheck = 1;
885 continue;
886 case 'e': /* echo check off */
887 FLUSH();
888 CDEBUG(5, "ECHO CHECK OFF\n%s", "");
889 echocheck = 0;
890 continue;
891 case 'd': /* sleep briefly */
892 FLUSH();
893 CDEBUG(5, "DELAY\n%s", "");
894 sleep(2);
895 continue;
896 case 'p': /* pause momentarily */
897 FLUSH();
898 CDEBUG(5, "PAUSE\n%s", "");
899 nap(HZ/4); /* approximately 1/4 second */
900 continue;
901 case 'K': /* inline break */
902 FLUSH();
903 CDEBUG(5, "BREAK\n%s", "");
904 (*genbrk)(fn);
905 continue;
906 case 'M': /* modem control - set CLOCAL */
907 case 'm': /* no modem control - clear CLOCAL */
908 FLUSH();
909 CDEBUG(5, ")\n%s CLOCAL ",
910 (*sptr == 'M' ? "set" : "clear"));
911 #ifdef ATTSVTTY
912 if ( (*Ioctl)(fn, TCGETA, &ttybuf) != 0 ) {
913 CDEBUG(5, "ignored. TCGETA failed, errno %d", errno);
914 } else {
915 if (*sptr == 'M')
916 ttybuf.c_cflag |= CLOCAL;
917 else
918 ttybuf.c_cflag &= ~CLOCAL;
919 if ( (*Ioctl)(fn, TCSETAW, &ttybuf) != 0 )
920 CDEBUG(5, "failed. TCSETAW failed, errno %d", errno);
921 }
922 #endif
923 CDEBUG(5, "\n%s", "");
924 continue;
925 }
926 } else
927 *bptr++ = *sptr;
928 }
929 if (sendcr)
930 *bptr++ = '\r';
931 if ( (bptr - buf) > 0 )
932 (void) wrstr(fn, buf, bptr - buf, echocheck);
933
934 err:
935 CDEBUG(5, ")\n%s", "");
936 return;
937 }
938
939 /*
940 * generate parity table for use by sendthem.
941 */
942 static void
bld_partab(type)943 bld_partab(type)
944 int type;
945 {
946 int i, j, n;
947
948 for (i = 0; i < 128; i++) {
949 n = 0;
950 for (j = i&0177; j; j = (j-1)&j)
951 n++;
952 par_tab[i] = i;
953 if (type == P_ONE
954 || (type == P_EVEN && (n&01) != 0)
955 || (type == P_ODD && (n&01) == 0))
956 par_tab[i] |= 0200;
957 }
958 }
959
960 #undef FLUSH
961
962 GLOBAL int
wrstr(fn,buf,len,echocheck)963 wrstr(fn, buf, len, echocheck)
964 char *buf;
965 {
966 int i;
967 char dbuf[BUFSIZ], *dbptr = dbuf;
968
969 if (echocheck)
970 return(wrchr(fn, buf, len));
971
972 if (Debug >= 5) {
973 if (sysaccess(ACCESS_SYSTEMS) == 0) { /* Systems file access ok */
974 for (i = 0; i < len; i++) {
975 *dbptr = buf[i];
976 if (*dbptr < 040) {
977 *dbptr++ = '^';
978 *dbptr = buf[i] | 0100;
979 }
980 dbptr++;
981 }
982 *dbptr = 0;
983 } else
984 strcpy(dbuf, "????????");
985 CDEBUG(5, "%s", dbuf);
986 }
987 dbptr = dbuf;
988 for (i = 0; i < len; i++)
989 *dbptr++ = par_tab[buf[i]&0177];
990 if ((*Write)(fn, dbuf, len) != len)
991 return(FAIL);
992 return(SUCCESS);
993 }
994
995 GLOBAL int
wrchr(fn,buf,len)996 wrchr(fn, buf, len)
997 int fn;
998 char *buf;
999 {
1000 int i, saccess;
1001 char cin, cout;
1002
1003 saccess = (sysaccess(ACCESS_SYSTEMS) == 0); /* protect Systems file */
1004 if (setjmp(Sjbuf))
1005 return(FAIL);
1006 (void) signal(SIGALRM, alarmtr);
1007
1008 for (i = 0; i < len; i++) {
1009 cout = buf[i]&0177;
1010 if (saccess) {
1011 CDEBUG(5, "%s", cout < 040 ? "^" : "");
1012 CDEBUG(5, "%c", cout < 040 ? cout | 0100 : cout);
1013 } else
1014 CDEBUG(5, "?%s", "");
1015 if (((*Write)(fn, &par_tab[cout], 1)) != 1)
1016 return(FAIL);
1017 do {
1018 (void) alarm(expecttime);
1019 if ((*Read)(fn, &cin, 1) != 1)
1020 return(FAIL);
1021 (void) alarm(0);
1022 cin &= 0177;
1023 if (saccess) {
1024 CDEBUG(5, "%s", cin < 040 ? "^" : "");
1025 CDEBUG(5, "%c", cin < 040 ? cin | 0100 : cin);
1026 } else
1027 CDEBUG(5, "?%s", "");
1028 } while (cout != cin);
1029 }
1030 return(SUCCESS);
1031 }
1032
1033
1034 /*
1035 * notin(sh, lg) check for occurrence of substring "sh"
1036 * char *sh, *lg;
1037 *
1038 * return codes:
1039 * 0 - found the string
1040 * 1 - not in the string
1041 */
1042
1043 static int
notin(sh,lg)1044 notin(sh, lg)
1045 char *sh, *lg;
1046 {
1047 while (*lg != NULLCHAR) {
1048 if (PREFIX(sh, lg))
1049 return(0);
1050 else
1051 lg++;
1052 }
1053 return(1);
1054 }
1055
1056
1057 /*
1058 * ifdate(s)
1059 * char *s;
1060 *
1061 * ifdate - this routine will check a string (s)
1062 * like "MoTu0800-1730" to see if the present
1063 * time is within the given limits.
1064 *
1065 * SIDE EFFECT - Retrytime is set to number following ";"
1066 * SIDE EFFECT - MaxGrade is set to character following "/"
1067 *
1068 * if a grade is specified, iswrk() is consulted, so that we don't
1069 * place calls when there's only low priority work. this will appear
1070 * as a "wrong time to call" in the status file. sorry.
1071 *
1072 * String alternatives:
1073 * Wk - Mo thru Fr
1074 * zero or one time means all day
1075 * Any - any day
1076 *
1077 * return codes:
1078 * 0 - not within limits, or grade too low
1079 * 1 - within limits
1080 */
1081
1082 static int
ifdate(s)1083 ifdate(s)
1084 char *s;
1085 {
1086 char *r;
1087 #ifdef MAXGRADE
1088 char *m, grade;
1089 #endif
1090 struct tm *tp;
1091 time_t clock;
1092 int t__now;
1093
1094 time(&clock);
1095 tp = localtime(&clock);
1096 t__now = tp->tm_hour * 100 + tp->tm_min; /* "navy" time */
1097
1098 /*
1099 * pick up retry time for failures and max grade
1100 * global variables Retrytime and MaxGrade are set here
1101 */
1102 r = strrchr(s, ';');
1103
1104 /* set retry time */
1105 if (r != NULL) {
1106 if (isdigit(r[1])) {
1107 if (sscanf(r+1, "%ld", &Retrytime) < 1)
1108 Retrytime = 5; /* 5 minutes is error default */
1109 DEBUG(5, "Retry time set to %d minutes\n", Retrytime);
1110 Retrytime *= 60; /* convert to seconds */
1111 *r = NULLCHAR; /* blow away retry time field */
1112 }
1113 } else
1114 Retrytime = 0; /* use exponential backoff */
1115
1116 #ifdef MAXGRADE
1117 /* set grade */
1118 MaxGrade = NULLCHAR; /* default */
1119 m = strrchr(s, '/');
1120 if (m != NULL) {
1121 if (isalnum(m[1]))
1122 MaxGrade = m[1]; /* you asked for it! */
1123 *m = NULLCHAR; /* blow away max grade field */
1124 DEBUG(5, "Max Grade set to %c\n", MaxGrade);
1125 }
1126
1127 /* test grade */
1128 if (MaxGrade != NULLCHAR) {
1129 grade = iswrk(CNULL);
1130 if (grade == NULLCHAR || MaxGrade < grade) {
1131 DEBUG(4, "No work of grade %c -- no call\n", MaxGrade);
1132 return(0);
1133 }
1134 }
1135 #endif /* MAXGRADE */
1136
1137
1138 while (checkdate(s, tp, t__now) == 0) {
1139 s = strchr(s, ',');
1140 if (s == CNULL)
1141 return(0);
1142 s++;
1143 }
1144 return(1);
1145 }
1146
1147 /* worker function for ifdate() */
1148 static int
checkdate(s,tp,t__now)1149 checkdate(s, tp, t__now)
1150 char *s;
1151 struct tm *tp;
1152 int t__now;
1153 {
1154 static char *days[] = {
1155 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
1156 };
1157 int i;
1158
1159 /*
1160 * check day of week
1161 */
1162
1163 while (isalpha(*s)) {
1164 if (PREFIX("Any", s))
1165 return(checktime(s, t__now));
1166
1167 if (PREFIX("Wk", s) && tp->tm_wday >= 1 && tp->tm_wday <= 5)
1168 return(checktime(s, t__now));
1169
1170 for (i = 0; days[i]; i++)
1171 if (PREFIX(days[i], s) && tp->tm_wday == i)
1172 return(checktime(s, t__now));
1173 s++;
1174 }
1175
1176 return(0); /* day match failed */
1177 }
1178
1179 /* day match ok -- check time */
1180 static int
checktime(s,t__now)1181 checktime(s, t__now)
1182 char *s;
1183 int t__now;
1184 {
1185 int t__low, t__high;
1186
1187 while (isalpha(*s)) /* flush day stuff */
1188 s++;
1189
1190 if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2))
1191 return(1); /* time match ok (default) */
1192
1193 if (t__low == t__high)
1194 return(1);
1195
1196 /* 0000 crossover? */
1197 if (t__low < t__high) {
1198 if (t__low <= t__now && t__now <= t__high)
1199 return(1);
1200 } else {
1201 if (t__low <= t__now || t__now <= t__high)
1202 return(1);
1203 }
1204
1205 return(0);
1206 }
1207
1208 /*
1209 * char *
1210 * fdig(cp) find first digit in string
1211 *
1212 * return - pointer to first digit in string or end of string
1213 */
1214
1215 GLOBAL char *
fdig(cp)1216 fdig(cp)
1217 char *cp;
1218 {
1219 char *c;
1220
1221 for (c = cp; *c; c++)
1222 if (*c >= '0' && *c <= '9')
1223 break;
1224 return(c);
1225 }
1226
1227
1228 #ifdef FASTTIMER
1229 /* Sleep in increments of 60ths of second. */
1230 GLOBAL void
nap(time)1231 nap (time)
1232 int time;
1233 {
1234 static int fd;
1235
1236 if (fd == 0)
1237 fd = open (FASTTIMER, 0);
1238
1239 (void) (*Read)(fd, 0, time);
1240 return;
1241 }
1242
1243 #endif /* FASTTIMER */
1244
1245 #if defined(BSD4_2) || defined(ATTSVR4)
1246
1247 /* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */
1248 /* This version uses the select system call */
1249
1250
1251 GLOBAL void
nap(n)1252 nap(n)
1253 unsigned n;
1254 {
1255 struct timeval tv;
1256
1257 if (n==0)
1258 return;
1259 tv.tv_sec = n/60;
1260 tv.tv_usec = ((n%60)*1000000L)/60;
1261 (void) select(32, 0, 0, 0, &tv);
1262 return;
1263 }
1264
1265 #endif /* BSD4_2 || ATTSVR4 */
1266
1267 #ifdef NONAP
1268
1269 /* nap(n) where n is ticks
1270 *
1271 * loop using n/HZ part of a second
1272 * if n represents more than 1 second, then
1273 * use sleep(time) where time is the equivalent
1274 * seconds rounded off to full seconds
1275 * NOTE - this is a rough approximation and chews up
1276 * processor resource!
1277 */
1278
1279 GLOBAL void
nap(n)1280 nap(n)
1281 unsigned n;
1282 {
1283 struct tms tbuf;
1284 long endtime;
1285 int i;
1286
1287 if (n > HZ) {
1288 /* > second, use sleep, rounding time */
1289 sleep( (int) (((n)+HZ/2)/HZ) );
1290 return;
1291 }
1292
1293 /* use timing loop for < 1 second */
1294 endtime = times(&tbuf) + 3*n/4; /* use 3/4 because of scheduler! */
1295 while (times(&tbuf) < endtime) {
1296 for (i=0; i<1000; i++, (void) (i*i))
1297 ;
1298 }
1299 return;
1300 }
1301
1302 #endif /* NONAP */
1303
1304 /*
1305
1306 * altconn - place a telephone call to system
1307 * from cu when telephone number or direct line used
1308 *
1309 * return codes:
1310 * FAIL - connection failed
1311 * >0 - file no. - connect ok
1312 * When a failure occurs, Uerror is set.
1313 */
1314 GLOBAL int
altconn(call)1315 altconn(call)
1316 struct call *call;
1317 {
1318 int fn = FAIL;
1319 char *alt[7];
1320 EXTERN char *Myline;
1321
1322 alt[F_NAME] = "dummy"; /* to replace the Systems file fields */
1323 alt[F_TIME] = "Any"; /* needed for getto(); [F_TYPE] and */
1324 alt[F_TYPE] = ""; /* [F_PHONE] assignment below */
1325 alt[F_CLASS] = call->speed;
1326 alt[F_PHONE] = "";
1327 alt[F_LOGIN] = "";
1328 alt[6] = NULL;
1329
1330 CDEBUG(4,"altconn called\r\n%s", "");
1331
1332 /* cu -l dev ... */
1333 /* if is "/dev/device", strip off "/dev/" because must */
1334 /* exactly match entries in Devices file, which usually */
1335 /* omit the "/dev/". if doesn't begin with "/dev/", */
1336 /* either they've omitted the "/dev/" or it's a non- */
1337 /* standard path name. in either case, leave it as is */
1338
1339 if(call->line != NULL ) {
1340 if ( strncmp(call->line, "/dev/", 5) == 0 ) {
1341 Myline = (call->line + 5);
1342 } else {
1343 Myline = call->line;
1344 }
1345 }
1346
1347 /* cu ... telno */
1348 if(call->telno != NULL) {
1349 alt[F_PHONE] = call->telno;
1350 alt[F_TYPE] = "ACU";
1351 } else {
1352 /* cu direct line */
1353 alt[F_TYPE] = "Direct";
1354 }
1355 if (call->type != NULL)
1356 alt[F_TYPE] = call->type;
1357 fn = getto(alt);
1358 CDEBUG(4, "getto ret %d\n", fn);
1359
1360 return(fn);
1361
1362 }
1363