3124 Remove any existing references to utmp, use utmpx instead
[unleashed.git] / usr / src / cmd / bnu / conn.c
blobd2b7fcd8a4397508ed7e32aaeab1667c7f251394
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include "uucp.h"
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 */
41 EXTERN jmp_buf Sjbuf;
42 EXTERN unsigned expecttime;
44 GLOBAL int Modemctrl;
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
52 static char par_tab[128];
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();
68 EXTERN void sendthem(), nap();
69 static int notin(), ifdate(), checkdate(), checktime(), classmatch();
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 */
76 * conn - place a telephone call to system and login, etc.
78 * return codes:
79 * FAIL - connection failed
80 * >0 - file no. - connect ok
81 * When a failure occurs, Uerror is set.
84 GLOBAL int
85 conn(system)
86 char *system;
88 int nf, fn;
89 char *flds[F_MAX+1];
90 EXTERN void sysreset();
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;
100 #ifdef TIOCSPGRP
102 #ifdef ATTSV
103 int pgrp = getpgrp();
104 #else
105 int pgrp = getpgrp(0);
106 #endif
107 ioctl(fn, TIOCSPGRP, &pgrp);
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 */
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);
123 } else {
124 sysreset();
125 return(fn);
129 /* finds or getto failed */
130 sysreset();
131 CDEBUG(1, "Call Failed: %s\n", UERRORTEXT);
132 return(FAIL);
136 * getto - connect to remote machine
138 * return codes:
139 * >0 - file number - ok
140 * FAIL - failed
143 GLOBAL int
144 getto(flds)
145 char *flds[];
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();
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;
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;
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;
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;
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;
190 return(dcf);
194 * classmatch - process 'Any' in Devices and Systems and
195 * determine the correct speed, or match for ==
198 static int
199 classmatch(flds, dev)
200 char *flds[], *dev[];
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);
219 * rddev - find and unpack a line from device file for this caller type
220 * lines starting with whitespace of '#' are comments
222 * return codes:
223 * >0 - number of arguments in vector - succeeded
224 * FAIL - EOF
227 GLOBAL int
228 rddev(type, dev, buf, devcount)
229 char *type;
230 char *dev[];
231 char *buf;
233 char *commap, d_type[BUFSIZ];
234 int na;
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);
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]) );
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';
258 * D_TYPE field may have protocol subfield, which
259 * must be pulled off before comparing to desired type.
261 (void)strcpy(d_type, dev[D_TYPE]);
262 if ((commap = strchr(d_type, ',')) != (char *)NULL )
263 *commap = '\0';
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;
272 bsfix(dev); /* replace \X fields */
274 if (EQUALS(d_type, type)) {
275 getProto( _ProtoDev, dev[D_TYPE] );
276 return(na);
279 return(FAIL);
284 * finds - set system attribute vector
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
301 static int
302 finds(sysnam, flds, fldcount)
303 char *sysnam, *flds[];
305 static char info[BUFSIZ];
306 int na;
308 /* format of fields
309 * 0 name;
310 * 1 time
311 * 2 acu/hardwired
312 * 3 speed
313 * etc
315 if (sysnam == 0 || *sysnam == 0 ) {
316 Uerror = SS_BADSYSTEM;
317 return(FAIL);
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>");
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 */
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;
357 if (!Uerror)
358 Uerror = SS_BADSYSTEM;
359 return(FAIL);
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
371 * return: none
374 static void
375 getProto(save, str)
376 char *save;
377 char *str;
379 char *p;
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);
387 return;
391 * check for a specified protocol selection string
392 * return:
393 * protocol string pointer
394 * NULL if none specified for LOGNAME
396 GLOBAL char *
397 protoString(valid)
398 char *valid;
400 char *save;
402 save =strdup(valid);
403 _Protocol[0] = '\0';
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);
412 if ( _Protocol[0] == '\0' ) {
413 (void) strcpy(valid, save);
414 (void) strcpy(_Protocol, save);
417 return(_Protocol[0] == NULLCHAR ? NULL : _Protocol);
421 * addProto
423 * Verify that the desired protocols from the Systems and Devices file
424 * have been compiled into this application.
426 * desired - list of desired protocols
427 * valid - list of protocols that are compiled in.
430 static void
431 addProto (desired, valid)
432 char *desired;
433 char *valid;
435 char *protoPtr;
436 char *wantPtr;
438 if ( *desired == '\0' )
439 return;
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++;
451 } else {
452 wantPtr = desired;
453 while ( *(wantPtr = nextProto(wantPtr)) != NULLCHAR ) {
454 if ( *(findProto(valid, *wantPtr)) != NULLCHAR ) {
455 mergeProto(protoPtr, wantPtr);
457 wantPtr++;
460 if ( *(protoPtr = _Protocol) != NULLCHAR ) {
461 while ( *(protoPtr = nextProto(protoPtr)) != NULLCHAR )
462 *(valid++) = *(protoPtr++);
463 *valid = NULLCHAR;
465 return;
469 * mergeProto
471 * input
472 * char *tostring, *fromstring;
474 static void
475 mergeProto(tostring, fromstring)
476 char *tostring, *fromstring;
478 char buffer[BUFSIZ];
479 int length;
481 while ( *(tostring = nextProto(tostring)) != NULLCHAR ) {
482 if ( *tostring == *fromstring )
483 break;
484 else
485 tostring++;
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);
502 return;
506 * removeProto
508 * char *old
509 * char letter
511 * return
512 * none
514 static void
515 removeProto(string, letter)
516 char *string, letter;
518 while ( *(string = nextProto(string)) != NULLCHAR ) {
519 if ( *string == letter )
520 (void) strcpy(string, nextProto(string+1));
521 else
522 string++;
527 * nextProto
528 * char *string;
529 * return
530 * char * to next non-parameter letter
532 static char *
533 nextProto(string)
534 char *string;
536 if ( *string == '(' )
537 while ( *string != NULLCHAR )
538 if ( *(string++) == ')' )
539 break;
540 return(string);
544 * findProto
545 * char *desired,
546 * char protoPtr;
547 * return
548 * char *pointer to found or string terminating NULLCHAR
550 GLOBAL char *
551 findProto(string, letter)
552 char *string;
553 char letter;
555 while ( *(string = nextProto(string)) != NULLCHAR )
556 if ( *string == letter )
557 break;
558 else
559 string++;
560 return(string);
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
572 * return codes: 0 | FAIL
575 GLOBAL int
576 chat(nf, flds, fn, phstr1, phstr2)
577 char *flds[], *phstr1, *phstr2;
578 int nf, fn;
580 char *want, *altern;
581 int k, ok;
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);
598 want = index(altern, '-');
599 if (want != NULL)
600 *want++ = NULLCHAR;
601 sendthem(altern, fn, phstr1, phstr2);
603 sleep(2);
604 if (flds[k+1])
605 sendthem(flds[k+1], fn, phstr1, phstr2);
607 return(0);
610 #define MR 1000
613 * expect(str, fn) look for expected string w/ possible special chars
615 * return codes:
616 * 0 - found
617 * FAIL - too many characters read
618 * some character - timed out
621 GLOBAL int
622 expect(str, fn)
623 char *str;
624 int fn;
626 char *bptr, *sptr;
627 char buf[BUFSIZ];
629 bptr = buf;
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);
639 if (wait_for_hangup(fn) == FAIL) {
640 return (FAIL);
642 bptr = buf;
643 continue;
644 case '\\':
645 *bptr++ = '\\';
646 continue;
647 default:
648 *bptr++ = '\\';
649 *bptr++ = *sptr;
650 continue;
652 } else
653 *bptr++ = *sptr;
655 *bptr = '\0';
656 if (expect_str(buf, fn) == FAIL) {
657 return (FAIL);
659 return (0);
663 * expect_str(str, fn) look for expected string, w/ no special chars
665 * return codes:
666 * 0 - found
667 * FAIL - too many characters read
668 * some character - timed out
671 GLOBAL int
672 expect_str(str, fn)
673 char *str;
674 int fn;
676 static char rdvec[MR];
677 char *rp = rdvec;
678 int kr, c;
679 char nextch;
681 *rp = 0;
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", "");
691 if (EQUALS(str, "\"\"")) {
692 CDEBUG(4, "got it\n%s", "");
693 return(0);
695 if (*str== '\0') {
696 return(0);
698 if (setjmp(Sjbuf)) {
699 return (FAIL);
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);
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);
722 *rp = NULLCHAR;
724 alarm(0);
725 CDEBUG(4, "got it\n%s", "");
726 return(0);
729 * alarmtr() - catch alarm routine for "expect".
731 /*ARGSUSED*/
732 GLOBAL void
733 alarmtr(sig)
734 int sig;
736 CDEBUG(6, "timed out\n%s", "");
737 longjmp(Sjbuf, 1);
741 * wait_for_hangup() - wait for a hangup to occur on the given device
744 wait_for_hangup(dcf)
745 int dcf;
747 int rval;
748 char buff[BUFSIZ];
750 CDEBUG(4, "Waiting for hangup\n%s", "");
751 while((rval = read(dcf, buff, BUFSIZ)) > 0);
753 if (rval < 0) {
754 return (FAIL);
756 CDEBUG(4, "Received hangup\n%s", "");
758 if (clear_hup(dcf) != SUCCESS) {
759 CDEBUG(4, "Unable to clear hup on device\n%s", "");
760 return (FAIL);
762 return (SUCCESS);
766 * sendthem(str, fn, phstr1, phstr2) send line of chat sequence
767 * char *str, *phstr;
769 * return codes: none
772 #define FLUSH() {\
773 if ((bptr - buf) > 0)\
774 if (wrstr(fn, buf, bptr - buf, echocheck) != SUCCESS)\
775 goto err;\
776 bptr = buf;\
779 GLOBAL void
780 sendthem(str, fn, phstr1, phstr2)
781 char *str, *phstr1, *phstr2;
782 int fn;
784 int sendcr = 1, echocheck = 0;
785 char *sptr, *bptr;
786 char buf[BUFSIZ];
787 struct termio ttybuf;
788 static int p_init = 0;
790 if (!p_init) {
791 p_init++;
792 bld_partab(P_EVEN);
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;
803 if (PREFIX("STTY=", str)) {
804 CDEBUG(5, "STTY %s\n", str+5);
805 setmode(str+5, fn);
806 return;
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;
818 /* Set parity as needed */
819 if (EQUALS(str, "P_ZERO")) {
820 bld_partab(P_ZERO);
821 return;
823 if (EQUALS(str, "P_ONE")) {
824 bld_partab(P_ONE);
825 return;
827 if (EQUALS(str, "P_EVEN")) {
828 bld_partab(P_EVEN);
829 return;
831 if (EQUALS(str, "P_ODD")) {
832 bld_partab(P_ODD);
833 return;
836 if (EQUALS(str, "\"\"")) {
837 CDEBUG(5, "\"\"\n%s", "");
838 str += 2;
841 bptr = buf;
842 CDEBUG(5, "sendthem (%s", "");
843 for (sptr = str; *sptr; sptr++) {
844 if (*sptr == '\\') {
845 switch(*++sptr) {
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;
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;
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);
922 #endif
923 CDEBUG(5, "\n%s", "");
924 continue;
926 } else
927 *bptr++ = *sptr;
929 if (sendcr)
930 *bptr++ = '\r';
931 if ( (bptr - buf) > 0 )
932 (void) wrstr(fn, buf, bptr - buf, echocheck);
934 err:
935 CDEBUG(5, ")\n%s", "");
936 return;
940 * generate parity table for use by sendthem.
942 static void
943 bld_partab(type)
944 int type;
946 int i, j, n;
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;
960 #undef FLUSH
962 GLOBAL int
963 wrstr(fn, buf, len, echocheck)
964 char *buf;
966 int i;
967 char dbuf[BUFSIZ], *dbptr = dbuf;
969 if (echocheck)
970 return(wrchr(fn, buf, len));
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;
980 dbptr++;
982 *dbptr = 0;
983 } else
984 strcpy(dbuf, "????????");
985 CDEBUG(5, "%s", dbuf);
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);
995 GLOBAL int
996 wrchr(fn, buf, len)
997 int fn;
998 char *buf;
1000 int i, saccess;
1001 char cin, cout;
1003 saccess = (sysaccess(ACCESS_SYSTEMS) == 0); /* protect Systems file */
1004 if (setjmp(Sjbuf))
1005 return(FAIL);
1006 (void) signal(SIGALRM, alarmtr);
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);
1030 return(SUCCESS);
1035 * notin(sh, lg) check for occurrence of substring "sh"
1036 * char *sh, *lg;
1038 * return codes:
1039 * 0 - found the string
1040 * 1 - not in the string
1043 static int
1044 notin(sh, lg)
1045 char *sh, *lg;
1047 while (*lg != NULLCHAR) {
1048 if (PREFIX(sh, lg))
1049 return(0);
1050 else
1051 lg++;
1053 return(1);
1058 * ifdate(s)
1059 * char *s;
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.
1065 * SIDE EFFECT - Retrytime is set to number following ";"
1066 * SIDE EFFECT - MaxGrade is set to character following "/"
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.
1072 * String alternatives:
1073 * Wk - Mo thru Fr
1074 * zero or one time means all day
1075 * Any - any day
1077 * return codes:
1078 * 0 - not within limits, or grade too low
1079 * 1 - within limits
1082 static int
1083 ifdate(s)
1084 char *s;
1086 char *r;
1087 #ifdef MAXGRADE
1088 char *m, grade;
1089 #endif
1090 struct tm *tp;
1091 time_t clock;
1092 int t__now;
1094 time(&clock);
1095 tp = localtime(&clock);
1096 t__now = tp->tm_hour * 100 + tp->tm_min; /* "navy" time */
1099 * pick up retry time for failures and max grade
1100 * global variables Retrytime and MaxGrade are set here
1102 r = strrchr(s, ';');
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 */
1113 } else
1114 Retrytime = 0; /* use exponential backoff */
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);
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);
1135 #endif /* MAXGRADE */
1138 while (checkdate(s, tp, t__now) == 0) {
1139 s = strchr(s, ',');
1140 if (s == CNULL)
1141 return(0);
1142 s++;
1144 return(1);
1147 /* worker function for ifdate() */
1148 static int
1149 checkdate(s, tp, t__now)
1150 char *s;
1151 struct tm *tp;
1152 int t__now;
1154 static char *days[] = {
1155 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
1157 int i;
1160 * check day of week
1163 while (isalpha(*s)) {
1164 if (PREFIX("Any", s))
1165 return(checktime(s, t__now));
1167 if (PREFIX("Wk", s) && tp->tm_wday >= 1 && tp->tm_wday <= 5)
1168 return(checktime(s, t__now));
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++;
1176 return(0); /* day match failed */
1179 /* day match ok -- check time */
1180 static int
1181 checktime(s, t__now)
1182 char *s;
1183 int t__now;
1185 int t__low, t__high;
1187 while (isalpha(*s)) /* flush day stuff */
1188 s++;
1190 if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2))
1191 return(1); /* time match ok (default) */
1193 if (t__low == t__high)
1194 return(1);
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);
1205 return(0);
1209 * char *
1210 * fdig(cp) find first digit in string
1212 * return - pointer to first digit in string or end of string
1215 GLOBAL char *
1216 fdig(cp)
1217 char *cp;
1219 char *c;
1221 for (c = cp; *c; c++)
1222 if (*c >= '0' && *c <= '9')
1223 break;
1224 return(c);
1228 #ifdef FASTTIMER
1229 /* Sleep in increments of 60ths of second. */
1230 GLOBAL void
1231 nap (time)
1232 int time;
1234 static int fd;
1236 if (fd == 0)
1237 fd = open (FASTTIMER, 0);
1239 (void) (*Read)(fd, 0, time);
1240 return;
1243 #endif /* FASTTIMER */
1245 #if defined(BSD4_2) || defined(ATTSVR4)
1247 /* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */
1248 /* This version uses the select system call */
1251 GLOBAL void
1252 nap(n)
1253 unsigned n;
1255 struct timeval tv;
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;
1265 #endif /* BSD4_2 || ATTSVR4 */
1267 #ifdef NONAP
1269 /* nap(n) where n is ticks
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!
1279 GLOBAL void
1280 nap(n)
1281 unsigned n;
1283 struct tms tbuf;
1284 long endtime;
1285 int i;
1287 if (n > HZ) {
1288 /* > second, use sleep, rounding time */
1289 sleep( (int) (((n)+HZ/2)/HZ) );
1290 return;
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))
1299 return;
1302 #endif /* NONAP */
1306 * altconn - place a telephone call to system
1307 * from cu when telephone number or direct line used
1309 * return codes:
1310 * FAIL - connection failed
1311 * >0 - file no. - connect ok
1312 * When a failure occurs, Uerror is set.
1314 GLOBAL int
1315 altconn(call)
1316 struct call *call;
1318 int fn = FAIL;
1319 char *alt[7];
1320 EXTERN char *Myline;
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;
1330 CDEBUG(4,"altconn called\r\n%s", "");
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 */
1339 if(call->line != NULL ) {
1340 if ( strncmp(call->line, "/dev/", 5) == 0 ) {
1341 Myline = (call->line + 5);
1342 } else {
1343 Myline = call->line;
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";
1355 if (call->type != NULL)
1356 alt[F_TYPE] = call->type;
1357 fn = getto(alt);
1358 CDEBUG(4, "getto ret %d\n", fn);
1360 return(fn);