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