113642Ssam #ifndef lint 2*25518Stef static char sccsid[] = "@(#)conn.c 5.8 (Berkeley) 11/22/85"; 313642Ssam #endif 413642Ssam 523596Sbloom #include <signal.h> 613642Ssam #include "uucp.h" 713642Ssam #include <setjmp.h> 813642Ssam #include <ctype.h> 913642Ssam #include <errno.h> 1017834Sralph #ifdef USG 1113642Ssam #include <termio.h> 1213642Ssam #include <fcntl.h> 1313642Ssam #endif 1417834Sralph #ifndef USG 1513642Ssam #include <sgtty.h> 1613642Ssam #endif 1717834Sralph #ifdef BSD4_2 1817834Sralph #include <sys/time.h> 1917834Sralph #else 2017834Sralph #include <time.h> 2117834Sralph #endif 2213642Ssam 2313642Ssam #define MAXC 1000 2413642Ssam 2513642Ssam extern jmp_buf Sjbuf; 2617834Sralph jmp_buf Cjbuf; 2718619Sralph extern int errno, onesys; 2817834Sralph extern char *sys_errlist[]; 2918619Sralph extern char MaxGrade, DefMaxGrade; 3013642Ssam 3113642Ssam /* Parity control during login procedure */ 3213642Ssam #define P_ZERO 0 3313642Ssam #define P_ONE 1 3413642Ssam #define P_EVEN 2 3513642Ssam #define P_ODD 3 3617834Sralph 3717834Sralph #define ABORT -2 3817834Sralph 3917834Sralph char *AbortOn = NULL; 4013642Ssam char par_tab[128]; /* must be power of two */ 4117834Sralph int linebaudrate; /* used for the sleep test in pk1.c */ 4213642Ssam int next_fd = -1; /* predicted fd to close interrupted opens */ 4313642Ssam /* rti!trt, courtesy unc!smb */ 4425127Sbloom /* 4525127Sbloom * catch alarm routine for "expect". 4613642Ssam */ 4713642Ssam alarmtr() 4813642Ssam { 4913642Ssam signal(SIGALRM, alarmtr); 5013642Ssam if (next_fd >= 0) { 5113642Ssam if (close(next_fd)) 5213642Ssam logent("FAIL", "ACU LINE CLOSE"); 5313642Ssam next_fd = -1; 5413642Ssam } 5513642Ssam longjmp(Sjbuf, 1); 5613642Ssam } 5713642Ssam 5818619Sralph /* 5918619Sralph * place a telephone call to system and login, etc. 6013642Ssam * 6113642Ssam * return codes: 6213642Ssam * CF_SYSTEM: don't know system 6313642Ssam * CF_TIME: wrong time to call 6413642Ssam * CF_DIAL: call failed 6513642Ssam * CF_NODEV: no devices available to place call 6613642Ssam * CF_LOGIN: login/password dialog failed 6713642Ssam * 6813642Ssam * >0 - file no. - connect ok 6913642Ssam */ 7013642Ssam 7113642Ssam int Dcf = -1; 7217834Sralph char *Flds[MAXC/10]; 7317834Sralph extern int LocalOnly; 7413642Ssam 7513642Ssam conn(system) 7613642Ssam char *system; 7713642Ssam { 7813642Ssam int ret, nf; 7917834Sralph register int fn = 0; 8018619Sralph char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE]; 8113642Ssam register FILE *fsys; 8213642Ssam int fcode = 0; 8313642Ssam 8413642Ssam nf = 0; 8513642Ssam 8613642Ssam fsys = fopen(SYSFILE, "r"); 8713642Ssam ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 8813642Ssam 8917834Sralph DEBUG(4, "finds (%s) called\n", system); 9025127Sbloom keeplooking: 9117834Sralph while((nf = finds(fsys, system, info, Flds)) > 0) { 9217834Sralph if (LocalOnly) { 9317834Sralph if (strcmp("TCP", Flds[F_LINE]) 9417834Sralph && strcmp("DIR", Flds[F_LINE]) 9517834Sralph && strcmp("LOCAL", Flds[F_LINE]) ) 9617834Sralph fn = CF_TIME; 9717834Sralph } 9823596Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 9918619Sralph if (!onesys && MaxGrade != DefMaxGrade && 10018619Sralph !iswrk(file, "chk", Spool, wkpre)) 10118619Sralph fn = CF_TIME; 10217834Sralph if (fn != CF_TIME && (fn = getto(Flds)) > 0) { 10313642Ssam Dcf = fn; 10413642Ssam break; 10513642Ssam } 10613642Ssam fcode = (fn == FAIL ? CF_DIAL : fn); 10713642Ssam } 10813642Ssam 10925127Sbloom if (nf <= 0) { 11025127Sbloom fclose(fsys); 11117834Sralph return fcode ? fcode : nf; 11225127Sbloom } 11313642Ssam 11413642Ssam DEBUG(4, "login %s\n", "called"); 11517834Sralph ret = login(nf, Flds, fn); 11623596Sbloom if (ret != SUCCESS) { 11713642Ssam clsacu(); 11825127Sbloom if (ret == ABORT) { 11925127Sbloom fcode = CF_DIAL; 12025127Sbloom goto keeplooking; 12125127Sbloom } else { 12225127Sbloom fclose(fsys); 12323596Sbloom return CF_LOGIN; 12425127Sbloom } 12513642Ssam } 12625127Sbloom fclose(fsys); 12713642Ssam fioclex(fn); 12817834Sralph return fn; 12913642Ssam } 13013642Ssam 13125127Sbloom /* 13225127Sbloom * connect to remote machine 13313642Ssam * 13413642Ssam * return codes: 13513642Ssam * >0 - file number - ok 13613642Ssam * FAIL - failed 13713642Ssam */ 13813642Ssam 13913642Ssam getto(flds) 14013642Ssam register char *flds[]; 14113642Ssam { 14213642Ssam register struct condev *cd; 14313642Ssam int nulldev(), diropn(); 14425127Sbloom char *line; 14513642Ssam 14617834Sralph DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); 14713642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 14813642Ssam 14925127Sbloom if (snccmp(flds[F_LINE], "LOCAL") == SAME) 15025127Sbloom line = "ACU"; 15125127Sbloom else 15225127Sbloom line = flds[F_LINE]; 15325127Sbloom #ifdef DIALINOUT 15425127Sbloom if (snccmp(line, "ACU") != SAME) 15525127Sbloom reenable(); 15625127Sbloom #endif DIALINOUT 15713642Ssam CU_end = nulldev; 15813642Ssam for (cd = condevs; cd->CU_meth != NULL; cd++) { 15925127Sbloom if (snccmp(cd->CU_meth, line) == SAME) { 16013642Ssam DEBUG(4, "Using %s to call\n", cd->CU_meth); 16117834Sralph return (*(cd->CU_gen))(flds); 16213642Ssam } 16313642Ssam } 16425127Sbloom DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]); 16517834Sralph return diropn(flds); /* search failed, so use direct */ 16617834Sralph } 16713642Ssam 16825127Sbloom /* 16925127Sbloom * close call unit 17013642Ssam * 17113642Ssam * return codes: none 17213642Ssam */ 17313642Ssam 17413642Ssam int (*CU_end)() = nulldev; 17513642Ssam clsacu() 17613642Ssam { 17717834Sralph /* make *sure* Dcf is no longer exclusive. 17817834Sralph * Otherwise dual call-in/call-out modems could get stuck. 17917834Sralph * Unfortunately, doing this here is not ideal, but it is the 18017834Sralph * easiest place to put the call. 18117834Sralph * Hopefully everyone honors the LCK protocol, of course 18217834Sralph */ 18317834Sralph #ifndef USG 18423596Sbloom if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0) 18523596Sbloom DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]); 18617834Sralph #endif 18717834Sralph if (setjmp(Sjbuf)) 18817834Sralph logent(Rmtname, "CLOSE TIMEOUT"); 18917834Sralph else { 19017834Sralph signal(SIGALRM, alarmtr); 19117834Sralph alarm(20); 19217834Sralph (*(CU_end))(Dcf); 19317834Sralph alarm(0); 19417834Sralph } 19513642Ssam if (close(Dcf) == 0) { 19613642Ssam DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 19713642Ssam logent("clsacu", "NOT CLOSED by CU_clos"); 19813642Ssam } 19913642Ssam Dcf = -1; 20013642Ssam CU_end = nulldev; 20113642Ssam } 20213642Ssam 20325127Sbloom /* 20425127Sbloom * expand phone number for given prefix and number 20513642Ssam */ 20613642Ssam 20713642Ssam exphone(in, out) 20813642Ssam register char *in, *out; 20913642Ssam { 21013642Ssam FILE *fn; 21113642Ssam char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 21213642Ssam char buf[BUFSIZ]; 21313642Ssam register char *s1; 21413642Ssam 21517834Sralph if (!isascii(*in) || !isalpha(*in)) { 21613642Ssam strcpy(out, in); 21713642Ssam return; 21813642Ssam } 21913642Ssam 22013642Ssam s1=pre; 22117834Sralph while (isascii(*in) && isalpha(*in)) 22213642Ssam *s1++ = *in++; 22313642Ssam *s1 = '\0'; 22413642Ssam s1 = npart; 22513642Ssam while (*in != '\0') 22613642Ssam *s1++ = *in++; 22713642Ssam *s1 = '\0'; 22813642Ssam 22913642Ssam tpre[0] = '\0'; 23013642Ssam if ((fn = fopen(DIALFILE, "r")) == NULL) 23113642Ssam DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 23213642Ssam else { 23313642Ssam while (cfgets(buf, BUFSIZ, fn)) { 23417834Sralph if (sscanf(buf, "%s%s", p, tpre) != 2) 23517834Sralph continue; 23613642Ssam if (strcmp(p, pre) == SAME) 23713642Ssam goto found; 23813642Ssam tpre[0] = '\0'; 23913642Ssam } 24013642Ssam DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 24113642Ssam found:; 24213642Ssam fclose(fn); 24313642Ssam } 24413642Ssam 24513642Ssam strcpy(out, tpre); 24613642Ssam strcat(out, npart); 24713642Ssam } 24813642Ssam 24918619Sralph /* 25018619Sralph * read and decode a line from device file 25113642Ssam * 25213642Ssam * return code - FAIL at end-of file; 0 otherwise 25313642Ssam */ 25413642Ssam 25513642Ssam rddev(fp, dev) 25613642Ssam register struct Devices *dev; 25713642Ssam FILE *fp; 25813642Ssam { 25917834Sralph register int na; 26013642Ssam 26117834Sralph if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp)) 26217834Sralph return FAIL; 26317834Sralph na = getargs(dev->D_argbfr, dev->D_arg, 20); 26417834Sralph ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0); 26517834Sralph if (na == 4) { 26617834Sralph dev->D_brand = ""; 26717834Sralph na++; 26817834Sralph } 26913642Ssam dev->D_speed = atoi(fdig(dev->D_class)); 27017834Sralph dev->D_numargs = na; 27117834Sralph return 0; 27213642Ssam } 27313642Ssam 27418619Sralph /* 27518619Sralph * set system attribute vector 27613642Ssam * 27713642Ssam * return codes: 27813642Ssam * >0 - number of arguments in vector - succeeded 27913642Ssam * CF_SYSTEM - system name not found 28013642Ssam * CF_TIME - wrong time to call 28113642Ssam */ 28213642Ssam 28313642Ssam finds(fsys, sysnam, info, flds) 28413642Ssam char *sysnam, info[], *flds[]; 28513642Ssam FILE *fsys; 28613642Ssam { 28713642Ssam int na; 28813642Ssam int fcode = 0; 28913642Ssam 29013642Ssam /* format of fields 29113642Ssam * 0 name; 29213642Ssam * 1 time 29313642Ssam * 2 acu/hardwired 29413642Ssam * 3 speed 29513642Ssam * etc 29613642Ssam */ 29713642Ssam while (cfgets(info, MAXC, fsys) != NULL) { 29817834Sralph na = getargs(info, flds, MAXC/10); 29923596Sbloom if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME) 30013642Ssam continue; 30118619Sralph if (ifdate(flds[F_TIME]) != FAIL) 30213642Ssam /* found a good entry */ 30317834Sralph return na; 30413642Ssam DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 30513642Ssam fcode = CF_TIME; 30613642Ssam } 30717834Sralph return fcode ? fcode : CF_SYSTEM; 30813642Ssam } 30913642Ssam 31018619Sralph /* 31118619Sralph * do login conversation 31213642Ssam * 31323596Sbloom * return codes: SUCCESS | FAIL 31413642Ssam */ 31513642Ssam 31613642Ssam login(nf, flds, fn) 31713642Ssam register char *flds[]; 31813642Ssam int nf, fn; 31913642Ssam { 32013642Ssam register char *want, *altern; 32113642Ssam int k, ok; 32213642Ssam 32317834Sralph ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf); 32417834Sralph if (setjmp(Cjbuf)) 32517834Sralph return FAIL; 32617834Sralph AbortOn = NULL; 32713642Ssam for (k = F_LOGIN; k < nf; k += 2) { 32813642Ssam want = flds[k]; 32913642Ssam ok = FAIL; 33017834Sralph while (ok != SUCCESS) { 33113642Ssam altern = index(want, '-'); 33213642Ssam if (altern != NULL) 33313642Ssam *altern++ = '\0'; 33417834Sralph if (strcmp(want, "ABORT") == 0) { 33517834Sralph AbortOn = flds[k+1]; 33617834Sralph DEBUG(4, "ABORT ON: %s\n", AbortOn); 33717834Sralph goto nextfield; 33817834Sralph } 33917834Sralph DEBUG(4, "wanted: %s\n", want); 34013642Ssam ok = expect(want, fn); 34117834Sralph DEBUG(4, "got: %s\n", ok ? "?" : "that"); 34217834Sralph if (ok == FAIL) { 34317834Sralph if (altern == NULL) { 34417834Sralph logent("LOGIN", _FAILED); 34517834Sralph return FAIL; 34617834Sralph } 34717834Sralph want = index(altern, '-'); 34817834Sralph if (want != NULL) 34917834Sralph *want++ = '\0'; 35017834Sralph sendthem(altern, fn); 35117834Sralph } else 35217834Sralph if (ok == ABORT) { 35317834Sralph logent("LOGIN ABORTED", _FAILED); 35423596Sbloom return ABORT; 35517834Sralph } 35613642Ssam } 35717834Sralph sleep(1); 35813642Ssam if (k+1 < nf) 35913642Ssam sendthem(flds[k+1], fn); 36017834Sralph nextfield: ; 36113642Ssam } 36217834Sralph return SUCCESS; 36313642Ssam } 36413642Ssam 36513642Ssam 36617834Sralph /* conditional table generation to support odd speeds */ 36713642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = { 36813642Ssam #ifdef B50 36913642Ssam { 50, B50}, 37013642Ssam #endif 37113642Ssam #ifdef B75 37213642Ssam { 75, B75}, 37313642Ssam #endif 37413642Ssam #ifdef B110 37513642Ssam { 110, B110}, 37613642Ssam #endif 37713642Ssam #ifdef B150 37813642Ssam { 150, B150}, 37913642Ssam #endif 38013642Ssam #ifdef B200 38113642Ssam { 200, B200}, 38213642Ssam #endif 38313642Ssam #ifdef B300 38413642Ssam { 300, B300}, 38513642Ssam #endif 38613642Ssam #ifdef B600 38713642Ssam {600, B600}, 38813642Ssam #endif 38913642Ssam #ifdef B1200 39013642Ssam {1200, B1200}, 39113642Ssam #endif 39213642Ssam #ifdef B1800 39313642Ssam {1800, B1800}, 39413642Ssam #endif 39513642Ssam #ifdef B2000 39613642Ssam {2000, B2000}, 39713642Ssam #endif 39813642Ssam #ifdef B2400 39913642Ssam {2400, B2400}, 40013642Ssam #endif 40113642Ssam #ifdef B3600 40213642Ssam {3600, B3600}, 40313642Ssam #endif 40413642Ssam #ifdef B4800 40513642Ssam {4800, B4800}, 40613642Ssam #endif 40713642Ssam #ifdef B7200 40813642Ssam {7200, B7200}, 40913642Ssam #endif 41013642Ssam #ifdef B9600 41113642Ssam {9600, B9600}, 41213642Ssam #endif 41313642Ssam #ifdef B19200 41417834Sralph {19200, B19200}, 41513642Ssam #endif 41617834Sralph #ifdef EXTA 41717834Sralph {19200, EXTA}, 41817834Sralph #endif 41913642Ssam {0, 0} 42013642Ssam }; 42113642Ssam 42218619Sralph /* 42318619Sralph * set speed/echo/mode... 42413642Ssam * 42513642Ssam * return codes: none 42613642Ssam */ 42713642Ssam 42813642Ssam fixline(tty, spwant) 42913642Ssam int tty, spwant; 43013642Ssam { 43117834Sralph #ifdef USG 43213642Ssam struct termio ttbuf; 43317834Sralph #else !USG 43413642Ssam struct sgttyb ttbuf; 43517834Sralph #endif !USG 43613642Ssam register struct sg_spds *ps; 43713642Ssam int speed = -1; 43813642Ssam 43913642Ssam for (ps = spds; ps->sp_val; ps++) 44013642Ssam if (ps->sp_val == spwant) 44113642Ssam speed = ps->sp_name; 44217834Sralph ASSERT(speed >= 0, "BAD SPEED", CNULL, speed); 44317834Sralph #ifdef USG 44423596Sbloom if (ioctl(tty, TCGETA, &ttbuf) < 0) 44523596Sbloom return FAIL; 44613642Ssam /* ttbuf.sg_flags = (ANYP|RAW); 44713642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 44813642Ssam ttbuf.c_iflag = (ushort)0; 44913642Ssam ttbuf.c_oflag = (ushort)0; 45013642Ssam ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 45113642Ssam ttbuf.c_lflag = (ushort)0; 45213642Ssam ttbuf.c_cc[VMIN] = 6; 45313642Ssam ttbuf.c_cc[VTIME] = 1; 45423596Sbloom if (ioctl(tty, TCSETA, &ttbuf) < 0) 45523596Sbloom return FAIL; 45617834Sralph #else !USG 45723596Sbloom if (ioctl(tty, TIOCGETP, &ttbuf) < 0) 45823596Sbloom return FAIL; 45913642Ssam ttbuf.sg_flags = (ANYP|RAW); 46013642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 46123596Sbloom if (ioctl(tty, TIOCSETP, &ttbuf) < 0) 46223596Sbloom return FAIL; 46313642Ssam #endif 46417834Sralph #ifndef USG 46523596Sbloom if (ioctl(tty, TIOCHPCL, STBNULL) < 0) 46623596Sbloom return FAIL; 46723596Sbloom if (ioctl(tty, TIOCEXCL, STBNULL) < 0) 46823596Sbloom return FAIL; 46913642Ssam #endif 47017834Sralph linebaudrate = spwant; 47123596Sbloom return SUCCESS; 47213642Ssam } 47313642Ssam 474*25518Stef /*** 475*25518Stef * getbaud(tty) set linebaudrate variable 476*25518Stef * 477*25518Stef * return codes: none 478*25518Stef */ 479*25518Stef 480*25518Stef getbaud(tty) 481*25518Stef int tty; 482*25518Stef { 483*25518Stef #ifdef USG 484*25518Stef struct termio ttbuf; 485*25518Stef #else 486*25518Stef struct sgttyb ttbuf; 487*25518Stef #endif 488*25518Stef register struct sg_spds *ps; 489*25518Stef register int name; 490*25518Stef 491*25518Stef if (IsTcpIp) 492*25518Stef return; 493*25518Stef #ifdef USG 494*25518Stef ioctl(tty, TCGETA, &ttbuf); 495*25518Stef name = ttbuf.c_cflag & CBAUD; 496*25518Stef #else 497*25518Stef ioctl(tty, TIOCGETP, &ttbuf); 498*25518Stef name = ttbuf.sg_ispeed; 499*25518Stef #endif 500*25518Stef for (ps = spds; ps->sp_val; ps++) 501*25518Stef if (ps->sp_name == name) { 502*25518Stef linebaudrate = ps->sp_val; 503*25518Stef break; 504*25518Stef } 505*25518Stef } 506*25518Stef 50717834Sralph #define MR 100 50813642Ssam 50918619Sralph /* 51018619Sralph * look for expected string 51113642Ssam * 51213642Ssam * return codes: 51313642Ssam * 0 - found 51413642Ssam * FAIL - lost line or too many characters read 51513642Ssam * some character - timed out 51613642Ssam */ 51713642Ssam 51813642Ssam expect(str, fn) 51913642Ssam register char *str; 52013642Ssam int fn; 52113642Ssam { 52214592Skarels char rdvec[MR]; 52317834Sralph register char *rp = rdvec, *strptr; 52417834Sralph int kr, cnt_char; 52513642Ssam char nextch; 52625127Sbloom int timo = MAXMSGTIME; 52713642Ssam 52817834Sralph if (*str == '\0' || strcmp(str, "\"\"") == SAME) 52917834Sralph return SUCCESS; 53017834Sralph /* Cleanup str, convert \0xx strings to one char */ 53117834Sralph for (strptr = str; *strptr; strptr++) { 53217834Sralph if (*strptr == '\\') 53317834Sralph switch(*++strptr) { 53417834Sralph case 's': 53517834Sralph DEBUG(5, "BLANK\n", CNULL); 53617834Sralph *strptr = ' '; 53717834Sralph break; 53817834Sralph default: 53917834Sralph strptr--; /* back up to backslash */ 54017834Sralph sscanf(strptr + 1,"%o", &cnt_char); 54117834Sralph DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); 54217834Sralph *strptr = (char) (cnt_char); 54317834Sralph strcpy(&strptr[1], &strptr[4]); 54417834Sralph } 54517834Sralph } 54617834Sralph 54725127Sbloom strptr = index(str, '~'); 54825127Sbloom if (strptr != NULL) { 54925127Sbloom *strptr++ = '\0'; 55025127Sbloom timo = atoi(strptr); 55125127Sbloom if (timo <= 0) 55225127Sbloom timo = MAXMSGTIME; 55325127Sbloom } 55425127Sbloom 55517834Sralph if (setjmp(Sjbuf)) 55617834Sralph return FAIL; 55713642Ssam signal(SIGALRM, alarmtr); 55825127Sbloom alarm(timo); 55925127Sbloom *rp = 0; 56013642Ssam while (notin(str, rdvec)) { 56117834Sralph if(AbortOn != NULL && !notin(AbortOn, rdvec)) { 56217834Sralph DEBUG(1, "Call aborted on '%s'\n", AbortOn); 56317834Sralph alarm(0); 56417834Sralph return ABORT; 56517834Sralph } 56613642Ssam kr = read(fn, &nextch, 1); 56713642Ssam if (kr <= 0) { 56813642Ssam alarm(0); 56913642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 57013642Ssam logent("LOGIN", "LOST LINE"); 57117834Sralph return FAIL; 57213642Ssam } 57313642Ssam { 57413642Ssam int c; 57513642Ssam c = nextch & 0177; 57613642Ssam DEBUG(4, c >= 040 ? "%c" : "\\%03o", c); 57717834Sralph if (c == '\n') 57817834Sralph DEBUG(4,"\n", CNULL); 57913642Ssam } 58013642Ssam if ((*rp = nextch & 0177) != '\0') 58113642Ssam rp++; 58213642Ssam if (rp >= rdvec + MR) { 58317834Sralph register char *p; 58417834Sralph for (p = rdvec+MR/2; p < rp; p++) 58517834Sralph *(p-MR/2) = *p; 58617834Sralph rp -= MR/2; 58713642Ssam } 58813642Ssam *rp = '\0'; 58913642Ssam } 59013642Ssam alarm(0); 59117834Sralph return SUCCESS; 59213642Ssam } 59313642Ssam 59413642Ssam 59513642Ssam /* 59613642Ssam * Determine next file descriptor that would be allocated. 59713642Ssam * This permits later closing of a file whose open was interrupted. 59813642Ssam * It is a UNIX kernel problem, but it has to be handled. 59913642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 60013642Ssam */ 60113642Ssam getnextfd() 60213642Ssam { 60313642Ssam close(next_fd = open("/", 0)); 60413642Ssam } 60513642Ssam 60617834Sralph /* 60717834Sralph * send line of login sequence 60813642Ssam * 60913642Ssam * return codes: none 61013642Ssam */ 61113642Ssam sendthem(str, fn) 61213642Ssam register char *str; 61313642Ssam int fn; 61413642Ssam { 61513642Ssam register char *strptr; 61613642Ssam int i, n, cr = 1; 61717834Sralph register char c; 61813642Ssam static int p_init = 0; 61913642Ssam 62013642Ssam DEBUG(5, "send %s\n", str); 62113642Ssam 62213642Ssam if (!p_init) { 62313642Ssam p_init++; 62413642Ssam bld_partab(P_EVEN); 62513642Ssam } 62613642Ssam 62713642Ssam if (prefix("BREAK", str)) { 62813642Ssam sscanf(&str[5], "%1d", &i); 62913642Ssam if (i <= 0 || i > 10) 63013642Ssam i = 3; 63113642Ssam /* send break */ 63213642Ssam genbrk(fn, i); 63313642Ssam return; 63413642Ssam } 63513642Ssam 63613642Ssam if (prefix("PAUSE", str)) { 63713642Ssam sscanf(&str[5], "%1d", &i); 63813642Ssam if (i <= 0 || i > 10) 63913642Ssam i = 3; 64013642Ssam /* pause for a while */ 64113642Ssam sleep((unsigned)i); 64213642Ssam return; 64313642Ssam } 64413642Ssam 64513642Ssam if (strcmp(str, "EOT") == SAME) { 64613642Ssam p_chwrite(fn, '\04'); 64713642Ssam return; 64813642Ssam } 64913642Ssam 65013642Ssam /* Send a '\n' */ 65113642Ssam if (strcmp(str, "LF") == SAME) 65213642Ssam str = "\\n\\c"; 65313642Ssam 65413642Ssam /* Send a '\r' */ 65513642Ssam if (strcmp(str, "CR") == SAME) 65613642Ssam str = "\\r\\c"; 65713642Ssam 65813642Ssam /* Set parity as needed */ 65913642Ssam if (strcmp(str, "P_ZERO") == SAME) { 66013642Ssam bld_partab(P_ZERO); 66113642Ssam return; 66213642Ssam } 66313642Ssam if (strcmp(str, "P_ONE") == SAME) { 66413642Ssam bld_partab(P_ONE); 66513642Ssam return; 66613642Ssam } 66713642Ssam if (strcmp(str, "P_EVEN") == SAME) { 66813642Ssam bld_partab(P_EVEN); 66913642Ssam return; 67013642Ssam } 67113642Ssam if (strcmp(str, "P_ODD") == SAME) { 67213642Ssam bld_partab(P_ODD); 67313642Ssam return; 67413642Ssam } 67513642Ssam 67613642Ssam /* If "", just send '\r' */ 67717834Sralph if (strcmp(str, "\"\"") == SAME) { 67817834Sralph p_chwrite(fn, '\r'); 67917834Sralph return; 68017834Sralph } 68117834Sralph 68217834Sralph for (strptr = str; c = *strptr++;) { 68317834Sralph if (c == '\\') { 68417834Sralph switch(*strptr++) { 68517834Sralph case 's': 68617834Sralph DEBUG(5, "BLANK\n", CNULL); 68717834Sralph p_chwrite(fn, ' '); 68817834Sralph break; 68917834Sralph case 'd': 69017834Sralph DEBUG(5, "DELAY\n", CNULL); 69117834Sralph sleep(1); 69217834Sralph continue; 69317834Sralph case 'r': 69417834Sralph DEBUG(5, "RETURN\n", CNULL); 69517834Sralph p_chwrite(fn, '\r'); 69617834Sralph break; 69717834Sralph case 'b': 69817834Sralph if (isdigit(*strptr)) { 69917834Sralph i = (*strptr++ - '0'); 70017834Sralph if (i <= 0 || i > 10) 70117834Sralph i = 3; 70217834Sralph } else 70313642Ssam i = 3; 70417834Sralph /* send break */ 70517834Sralph genbrk(fn, i); 70617834Sralph if (*strptr == '\0') 70717834Sralph cr = 0; 70813642Ssam continue; 70917834Sralph case 'c': 71017834Sralph if (*strptr == '\0') { 71117834Sralph DEBUG(5, "NO CR\n", CNULL); 71217834Sralph cr = 0; 71317834Sralph continue; 71417834Sralph } 71517834Sralph DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL); 71613642Ssam continue; 71717834Sralph default: 71817834Sralph if (isdigit(*strptr)) { 71917834Sralph i = 0; 72017834Sralph n = 0; 72117834Sralph while (isdigit(*strptr) && ++n <= 3) 72217834Sralph i = i*8 + (*strptr++ - '0'); 72317834Sralph p_chwrite(fn, (char)i); 72417834Sralph continue; 72517834Sralph } 72617834Sralph DEBUG(5, "BACKSLASH\n", CNULL); 72717834Sralph --strptr; 72813642Ssam } 72917834Sralph } else 73017834Sralph p_chwrite(fn, c); 73113642Ssam } 73213642Ssam 73313642Ssam if (cr) 73413642Ssam p_chwrite(fn, '\r'); 73513642Ssam return; 73613642Ssam } 73713642Ssam 73813642Ssam p_chwrite(fd, c) 73913642Ssam int fd; 74017834Sralph char c; 74113642Ssam { 74217834Sralph c = par_tab[c&0177]; 74317834Sralph if (write(fd, &c, 1) != 1) { 74417834Sralph logent(sys_errlist[errno], "BAD WRITE"); 74517834Sralph longjmp(Cjbuf, 2); 74617834Sralph } 74713642Ssam } 74813642Ssam 74913642Ssam /* 75013642Ssam * generate parity table for use by p_chwrite. 75113642Ssam */ 75213642Ssam bld_partab(type) 75313642Ssam int type; 75413642Ssam { 75513642Ssam register int i, j, n; 75613642Ssam 75713642Ssam for (i = 0; i < sizeof(par_tab); i++) { 75813642Ssam n = 0; 75913642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 76013642Ssam n++; 76113642Ssam par_tab[i] = i; 76213642Ssam if (type == P_ONE 76313642Ssam || (type == P_EVEN && (n&01) != 0) 76413642Ssam || (type == P_ODD && (n&01) == 0)) 76513642Ssam par_tab[i] |= sizeof(par_tab); 76613642Ssam } 76713642Ssam } 76813642Ssam 76913642Ssam #define BSPEED B150 77013642Ssam 77118619Sralph /* 77218619Sralph * send a break 77313642Ssam */ 77413642Ssam genbrk(fn, bnulls) 77513642Ssam register int fn, bnulls; 77613642Ssam { 77717834Sralph #ifdef USG 77823596Sbloom if (ioctl(fn, TCSBRK, STBNULL) < 0) 77923596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 78017834Sralph #else !USG 78123596Sbloom struct sgttyb ttbuf; 78223596Sbloom register int sospeed; 78323596Sbloom # ifdef TIOCSBRK 78423596Sbloom if (ioctl(fn, TIOCSBRK, STBNULL) < 0) 78523596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 78623596Sbloom # ifdef TIOCCBRK 78713642Ssam sleep(1); 78823596Sbloom if (ioctl(fn, TIOCCBRK, STBNULL) < 0) 78923596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 79023596Sbloom # endif TIOCCBRK 79117834Sralph DEBUG(4, "ioctl %d second break\n", bnulls ); 79223596Sbloom # else !TIOCSBRK 79313642Ssam 79423596Sbloom if (ioctl(fn, TIOCGETP, &ttbuf) < 0) 79523596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 79613642Ssam sospeed = ttbuf.sg_ospeed; 79713642Ssam ttbuf.sg_ospeed = BSPEED; 79823596Sbloom if (ioctl(fn, TIOCSETP, &ttbuf) < 0) 79923596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 80023596Sbloom if (write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls) != bnulls) { 80117834Sralph badbreak: 80217834Sralph logent(sys_errlist[errno], "BAD WRITE genbrk"); 80317834Sralph alarm(0); 80417834Sralph longjmp(Sjbuf, 3); 80517834Sralph } 80613642Ssam ttbuf.sg_ospeed = sospeed; 80723596Sbloom if (ioctl(fn, TIOCSETP, &ttbuf) < 0) 80823596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 80923596Sbloom if (write(fn, "@", 1) != 1) 81017834Sralph goto badbreak; 81113642Ssam DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 81217834Sralph #endif !TIOCSBRK 81317834Sralph #endif !USG 81413642Ssam } 81513642Ssam 81618619Sralph /* 81718619Sralph * check for occurrence of substring "sh" 81813642Ssam * 81913642Ssam * return codes: 82013642Ssam * 0 - found the string 82113642Ssam * 1 - not in the string 82213642Ssam */ 82313642Ssam notin(sh, lg) 82413642Ssam register char *sh, *lg; 82513642Ssam { 82613642Ssam while (*lg != '\0') { 82713642Ssam if (wprefix(sh, lg)) 82818619Sralph return 0; 82913642Ssam else 83013642Ssam lg++; 83113642Ssam } 83218619Sralph return 1; 83313642Ssam } 83413642Ssam 83518619Sralph /* 83623596Sbloom * Allow multiple date specifications separated by ','. 83713642Ssam */ 83818619Sralph ifdate(p) 83918619Sralph register char *p; 84013642Ssam { 84123596Sbloom register char *np, c; 84218619Sralph register int ret, g; 84323596Sbloom int rtime, i; 84413642Ssam 84523596Sbloom /* pick up retry time for failures */ 84623596Sbloom /* global variable Retrytime is set here */ 84723596Sbloom if ((np = index(p, ';')) == NULL) { 84823596Sbloom Retrytime = RETRYTIME; 84923596Sbloom } else { 85023596Sbloom i = sscanf(np+1, "%d", &rtime); 85123596Sbloom if (i < 1 || rtime < 0) 85223596Sbloom rtime = 5; 85323596Sbloom Retrytime = rtime * 60; 85423596Sbloom } 85523596Sbloom 85618619Sralph ret = FAIL; 85718619Sralph MaxGrade = '\0'; 85818619Sralph do { 85923596Sbloom np = strpbrk(p, ",|"); /* prefer , but allow | for compat */ 86023596Sbloom if (np) 86123596Sbloom *np = '\0'; 86218619Sralph g = ifadate(p); 86318619Sralph DEBUG(11,"ifadate returns %o\n", g); 86418619Sralph if (g != FAIL) { 86518619Sralph ret = SUCCESS; 86618619Sralph if (g > MaxGrade) 86718619Sralph MaxGrade = g; 86818619Sralph } 86923596Sbloom if (np) 87023596Sbloom *np = ','; 87123596Sbloom p = np + 1; 87223596Sbloom } while (np); 87323596Sbloom if (MaxGrade == '\0') 87423596Sbloom MaxGrade = DefMaxGrade; 87518619Sralph return ret; 87613642Ssam } 87713642Ssam 87818619Sralph /* 87918619Sralph * this routine will check a string (string) 88013642Ssam * like "MoTu0800-1730" to see if the present 88113642Ssam * time is within the given limits. 88213642Ssam * SIDE EFFECT - Retrytime is set 88313642Ssam * 88413642Ssam * return codes: 88513642Ssam * 0 - not within limits 88613642Ssam * 1 - within limits 88713642Ssam */ 88813642Ssam 88918619Sralph ifadate(string) 89018619Sralph char *string; 89113642Ssam { 89213642Ssam static char *days[]={ 89313642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 89413642Ssam }; 89513642Ssam time_t clock; 89618619Sralph register char *s = string; 89717834Sralph int i, tl, th, tn, dayok=0; 89813642Ssam struct tm *localtime(); 89913642Ssam struct tm *tp; 90018619Sralph char *p, MGrade; 90113642Ssam 90223596Sbloom if ((p = index(s, '/')) == NULL) 90318619Sralph MGrade = DefMaxGrade; 90418619Sralph else 90518619Sralph MGrade = p[1]; 90618619Sralph 90713642Ssam time(&clock); 90813642Ssam tp = localtime(&clock); 90917834Sralph while (isascii(*s) && isalpha(*s)) { 91013642Ssam for (i = 0; days[i]; i++) { 91113642Ssam if (prefix(days[i], s)) 91213642Ssam if (tp->tm_wday == i) 91313642Ssam dayok = 1; 91413642Ssam } 91513642Ssam 91613642Ssam if (prefix("Wk", s)) 91713642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 91813642Ssam dayok = 1; 91913642Ssam if (prefix("Any", s)) 92013642Ssam dayok = 1; 92117834Sralph if (prefix("Evening", s)) { 92217834Sralph /* Sat or Sun */ 92317834Sralph if (tp->tm_wday == 6 || tp->tm_wday == 0 92417834Sralph || tp->tm_hour >= 17 || tp->tm_hour < 8) 92517834Sralph dayok = 1; 92617834Sralph } 92717834Sralph if (prefix("Night", s)) { 92817834Sralph if (tp->tm_wday == 6 /* Sat */ 92918619Sralph || tp->tm_hour >= 23 || tp->tm_hour < 8 93018619Sralph /* Sunday before 5pm */ 93118619Sralph || (tp->tm_wday == 0 && tp->tm_hour < 17)) 93217834Sralph dayok = 1; 93317834Sralph } 93413642Ssam s++; 93513642Ssam } 93613642Ssam 93718619Sralph if (dayok == 0 && s != string) 93818619Sralph return FAIL; 93913642Ssam i = sscanf(s, "%d-%d", &tl, &th); 94018619Sralph if (i < 2) 94118619Sralph return MGrade; 94218619Sralph tn = tp->tm_hour * 100 + tp->tm_min; 94318619Sralph if (th < tl) { /* crosses midnight */ 94418619Sralph if (tl <= tn || tn < th) 94518619Sralph return MGrade; 94618619Sralph } else 94718619Sralph 94813642Ssam if (i < 2) 94918619Sralph return MGrade; 95018619Sralph if (th < tl) { /* crosses midnight */ 95117834Sralph if (tl <= tn || tn < th) 95218619Sralph return MGrade; 95317834Sralph } else 95417834Sralph if (tl <= tn && tn < th) 95518619Sralph return MGrade; 95618619Sralph return FAIL; 95713642Ssam } 95813642Ssam 95918619Sralph /* 96018619Sralph * find first digit in string 96113642Ssam * 96213642Ssam * return - pointer to first digit in string or end of string 96313642Ssam */ 96413642Ssam char * 96513642Ssam fdig(cp) 96613642Ssam register char *cp; 96713642Ssam { 96813642Ssam register char *c; 96913642Ssam 97013642Ssam for (c = cp; *c; c++) 97113642Ssam if (*c >= '0' && *c <= '9') 97213642Ssam break; 97317834Sralph return c; 97413642Ssam } 97513642Ssam 97613642Ssam /* 97713642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 97813642Ssam * Strings are compared as if they contain all capital letters. 97913642Ssam */ 98013642Ssam snccmp(s1, s2) 98113642Ssam register char *s1, *s2; 98213642Ssam { 98313642Ssam char c1, c2; 98413642Ssam 98525127Sbloom if (islower(*s1)) 98625127Sbloom c1 = toupper(*s1); 98725127Sbloom else 98825127Sbloom c1 = *s1; 98925127Sbloom if (islower(*s2)) 99025127Sbloom c2 = toupper(*s2); 99125127Sbloom else 99225127Sbloom c2 = *s2; 99313642Ssam 99413642Ssam while (c1 == c2) { 99525127Sbloom if (*s1++ == '\0') 99617834Sralph return 0; 99713642Ssam s2++; 99825127Sbloom if (islower(*s1)) 99925127Sbloom c1 = toupper(*s1); 100025127Sbloom else 100125127Sbloom c1 = *s1; 100225127Sbloom if (islower(*s2)) 100325127Sbloom c2 = toupper(*s2); 100425127Sbloom else 100525127Sbloom c2 = *s2; 100613642Ssam } 100717834Sralph return c1 - c2; 100813642Ssam } 100925127Sbloom 101017834Sralph /* 101125127Sbloom * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 101225127Sbloom * Strings are compared as if they contain all capital letters. 101325127Sbloom */ 101425127Sbloom sncncmp(s1, s2, n) 101525127Sbloom register char *s1, *s2; 101625127Sbloom register int n; 101725127Sbloom { 101825127Sbloom char c1, c2; 101925127Sbloom 102025127Sbloom if (islower(*s1)) 102125127Sbloom c1 = toupper(*s1); 102225127Sbloom else 102325127Sbloom c1 = *s1; 102425127Sbloom if (islower(*s2)) 102525127Sbloom c2 = toupper(*s2); 102625127Sbloom else 102725127Sbloom c2 = *s2; 102825127Sbloom 102925127Sbloom while ( --n >= 0 && c1 == c2) { 103025127Sbloom if (*s1++ == '\0') 103125127Sbloom return 0; 103225127Sbloom s2++; 103325127Sbloom if (islower(*s1)) 103425127Sbloom c1 = toupper(*s1); 103525127Sbloom else 103625127Sbloom c1 = *s1; 103725127Sbloom if (islower(*s2)) 103825127Sbloom c2 = toupper(*s2); 103925127Sbloom else 104025127Sbloom c2 = *s2; 104125127Sbloom } 104225127Sbloom return n<0 ? 0 : (c1 - c2); 104325127Sbloom } 104425127Sbloom /* 104517834Sralph * do chat script 104617834Sralph * occurs after local port is opened, 104717834Sralph * before 'dialing' the other machine. 104817834Sralph */ 104917834Sralph dochat(dev, flds, fd) 105017834Sralph register struct Devices *dev; 105117834Sralph char *flds[]; 105217834Sralph int fd; 105317834Sralph { 105417834Sralph register int i; 105517834Sralph register char *p; 105617834Sralph char bfr[sizeof(dev->D_argbfr)]; 105717834Sralph 105817834Sralph if (dev->D_numargs <= 5) 105917834Sralph return(0); 106017834Sralph DEBUG(4, "dochat called %d\n", dev->D_numargs); 106117834Sralph for (i = 0; i < dev->D_numargs-5; i++) { 106217834Sralph sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); 106317834Sralph if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { 106417834Sralph p = malloc((unsigned)strlen(bfr)+1); 106517834Sralph if (p != NULL) { 106617834Sralph strcpy(p, bfr); 106717834Sralph dev->D_arg[D_CHAT+i] = p; 106817834Sralph } 106917834Sralph } 107017834Sralph } 107117834Sralph /* following is a kludge because login() arglist is a kludge */ 107217834Sralph i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); 107317834Sralph /* 107417834Sralph * If login() last did a sendthem(), must pause so things can settle. 107517834Sralph * But don't bother if chat failed. 107617834Sralph */ 107717834Sralph if (i == 0 && (dev->D_numargs&01)) 107817834Sralph sleep(2); 107917834Sralph return(i); 108017834Sralph } 1081