113642Ssam #ifndef lint 2*25127Sbloom static char sccsid[] = "@(#)conn.c 5.7 (Berkeley) 10/09/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 */ 44*25127Sbloom /* 45*25127Sbloom * 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); 90*25127Sbloom 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 109*25127Sbloom if (nf <= 0) { 110*25127Sbloom fclose(fsys); 11117834Sralph return fcode ? fcode : nf; 112*25127Sbloom } 11313642Ssam 11413642Ssam DEBUG(4, "login %s\n", "called"); 11517834Sralph ret = login(nf, Flds, fn); 11623596Sbloom if (ret != SUCCESS) { 11713642Ssam clsacu(); 118*25127Sbloom if (ret == ABORT) { 119*25127Sbloom fcode = CF_DIAL; 120*25127Sbloom goto keeplooking; 121*25127Sbloom } else { 122*25127Sbloom fclose(fsys); 12323596Sbloom return CF_LOGIN; 124*25127Sbloom } 12513642Ssam } 126*25127Sbloom fclose(fsys); 12713642Ssam fioclex(fn); 12817834Sralph return fn; 12913642Ssam } 13013642Ssam 131*25127Sbloom /* 132*25127Sbloom * 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(); 144*25127Sbloom char *line; 14513642Ssam 14617834Sralph DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); 14713642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 14813642Ssam 149*25127Sbloom if (snccmp(flds[F_LINE], "LOCAL") == SAME) 150*25127Sbloom line = "ACU"; 151*25127Sbloom else 152*25127Sbloom line = flds[F_LINE]; 153*25127Sbloom #ifdef DIALINOUT 154*25127Sbloom if (snccmp(line, "ACU") != SAME) 155*25127Sbloom reenable(); 156*25127Sbloom #endif DIALINOUT 15713642Ssam CU_end = nulldev; 15813642Ssam for (cd = condevs; cd->CU_meth != NULL; cd++) { 159*25127Sbloom 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 } 164*25127Sbloom DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]); 16517834Sralph return diropn(flds); /* search failed, so use direct */ 16617834Sralph } 16713642Ssam 168*25127Sbloom /* 169*25127Sbloom * 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 203*25127Sbloom /* 204*25127Sbloom * 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 47417834Sralph #define MR 100 47513642Ssam 47618619Sralph /* 47718619Sralph * look for expected string 47813642Ssam * 47913642Ssam * return codes: 48013642Ssam * 0 - found 48113642Ssam * FAIL - lost line or too many characters read 48213642Ssam * some character - timed out 48313642Ssam */ 48413642Ssam 48513642Ssam expect(str, fn) 48613642Ssam register char *str; 48713642Ssam int fn; 48813642Ssam { 48914592Skarels char rdvec[MR]; 49017834Sralph register char *rp = rdvec, *strptr; 49117834Sralph int kr, cnt_char; 49213642Ssam char nextch; 493*25127Sbloom int timo = MAXMSGTIME; 49413642Ssam 49517834Sralph if (*str == '\0' || strcmp(str, "\"\"") == SAME) 49617834Sralph return SUCCESS; 49717834Sralph /* Cleanup str, convert \0xx strings to one char */ 49817834Sralph for (strptr = str; *strptr; strptr++) { 49917834Sralph if (*strptr == '\\') 50017834Sralph switch(*++strptr) { 50117834Sralph case 's': 50217834Sralph DEBUG(5, "BLANK\n", CNULL); 50317834Sralph *strptr = ' '; 50417834Sralph break; 50517834Sralph default: 50617834Sralph strptr--; /* back up to backslash */ 50717834Sralph sscanf(strptr + 1,"%o", &cnt_char); 50817834Sralph DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); 50917834Sralph *strptr = (char) (cnt_char); 51017834Sralph strcpy(&strptr[1], &strptr[4]); 51117834Sralph } 51217834Sralph } 51317834Sralph 514*25127Sbloom strptr = index(str, '~'); 515*25127Sbloom if (strptr != NULL) { 516*25127Sbloom *strptr++ = '\0'; 517*25127Sbloom timo = atoi(strptr); 518*25127Sbloom if (timo <= 0) 519*25127Sbloom timo = MAXMSGTIME; 520*25127Sbloom } 521*25127Sbloom 52217834Sralph if (setjmp(Sjbuf)) 52317834Sralph return FAIL; 52413642Ssam signal(SIGALRM, alarmtr); 525*25127Sbloom alarm(timo); 526*25127Sbloom *rp = 0; 52713642Ssam while (notin(str, rdvec)) { 52817834Sralph if(AbortOn != NULL && !notin(AbortOn, rdvec)) { 52917834Sralph DEBUG(1, "Call aborted on '%s'\n", AbortOn); 53017834Sralph alarm(0); 53117834Sralph return ABORT; 53217834Sralph } 53313642Ssam kr = read(fn, &nextch, 1); 53413642Ssam if (kr <= 0) { 53513642Ssam alarm(0); 53613642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 53713642Ssam logent("LOGIN", "LOST LINE"); 53817834Sralph return FAIL; 53913642Ssam } 54013642Ssam { 54113642Ssam int c; 54213642Ssam c = nextch & 0177; 54313642Ssam DEBUG(4, c >= 040 ? "%c" : "\\%03o", c); 54417834Sralph if (c == '\n') 54517834Sralph DEBUG(4,"\n", CNULL); 54613642Ssam } 54713642Ssam if ((*rp = nextch & 0177) != '\0') 54813642Ssam rp++; 54913642Ssam if (rp >= rdvec + MR) { 55017834Sralph register char *p; 55117834Sralph for (p = rdvec+MR/2; p < rp; p++) 55217834Sralph *(p-MR/2) = *p; 55317834Sralph rp -= MR/2; 55413642Ssam } 55513642Ssam *rp = '\0'; 55613642Ssam } 55713642Ssam alarm(0); 55817834Sralph return SUCCESS; 55913642Ssam } 56013642Ssam 56113642Ssam 56213642Ssam /* 56313642Ssam * Determine next file descriptor that would be allocated. 56413642Ssam * This permits later closing of a file whose open was interrupted. 56513642Ssam * It is a UNIX kernel problem, but it has to be handled. 56613642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 56713642Ssam */ 56813642Ssam getnextfd() 56913642Ssam { 57013642Ssam close(next_fd = open("/", 0)); 57113642Ssam } 57213642Ssam 57317834Sralph /* 57417834Sralph * send line of login sequence 57513642Ssam * 57613642Ssam * return codes: none 57713642Ssam */ 57813642Ssam sendthem(str, fn) 57913642Ssam register char *str; 58013642Ssam int fn; 58113642Ssam { 58213642Ssam register char *strptr; 58313642Ssam int i, n, cr = 1; 58417834Sralph register char c; 58513642Ssam static int p_init = 0; 58613642Ssam 58713642Ssam DEBUG(5, "send %s\n", str); 58813642Ssam 58913642Ssam if (!p_init) { 59013642Ssam p_init++; 59113642Ssam bld_partab(P_EVEN); 59213642Ssam } 59313642Ssam 59413642Ssam if (prefix("BREAK", str)) { 59513642Ssam sscanf(&str[5], "%1d", &i); 59613642Ssam if (i <= 0 || i > 10) 59713642Ssam i = 3; 59813642Ssam /* send break */ 59913642Ssam genbrk(fn, i); 60013642Ssam return; 60113642Ssam } 60213642Ssam 60313642Ssam if (prefix("PAUSE", str)) { 60413642Ssam sscanf(&str[5], "%1d", &i); 60513642Ssam if (i <= 0 || i > 10) 60613642Ssam i = 3; 60713642Ssam /* pause for a while */ 60813642Ssam sleep((unsigned)i); 60913642Ssam return; 61013642Ssam } 61113642Ssam 61213642Ssam if (strcmp(str, "EOT") == SAME) { 61313642Ssam p_chwrite(fn, '\04'); 61413642Ssam return; 61513642Ssam } 61613642Ssam 61713642Ssam /* Send a '\n' */ 61813642Ssam if (strcmp(str, "LF") == SAME) 61913642Ssam str = "\\n\\c"; 62013642Ssam 62113642Ssam /* Send a '\r' */ 62213642Ssam if (strcmp(str, "CR") == SAME) 62313642Ssam str = "\\r\\c"; 62413642Ssam 62513642Ssam /* Set parity as needed */ 62613642Ssam if (strcmp(str, "P_ZERO") == SAME) { 62713642Ssam bld_partab(P_ZERO); 62813642Ssam return; 62913642Ssam } 63013642Ssam if (strcmp(str, "P_ONE") == SAME) { 63113642Ssam bld_partab(P_ONE); 63213642Ssam return; 63313642Ssam } 63413642Ssam if (strcmp(str, "P_EVEN") == SAME) { 63513642Ssam bld_partab(P_EVEN); 63613642Ssam return; 63713642Ssam } 63813642Ssam if (strcmp(str, "P_ODD") == SAME) { 63913642Ssam bld_partab(P_ODD); 64013642Ssam return; 64113642Ssam } 64213642Ssam 64313642Ssam /* If "", just send '\r' */ 64417834Sralph if (strcmp(str, "\"\"") == SAME) { 64517834Sralph p_chwrite(fn, '\r'); 64617834Sralph return; 64717834Sralph } 64817834Sralph 64917834Sralph for (strptr = str; c = *strptr++;) { 65017834Sralph if (c == '\\') { 65117834Sralph switch(*strptr++) { 65217834Sralph case 's': 65317834Sralph DEBUG(5, "BLANK\n", CNULL); 65417834Sralph p_chwrite(fn, ' '); 65517834Sralph break; 65617834Sralph case 'd': 65717834Sralph DEBUG(5, "DELAY\n", CNULL); 65817834Sralph sleep(1); 65917834Sralph continue; 66017834Sralph case 'r': 66117834Sralph DEBUG(5, "RETURN\n", CNULL); 66217834Sralph p_chwrite(fn, '\r'); 66317834Sralph break; 66417834Sralph case 'b': 66517834Sralph if (isdigit(*strptr)) { 66617834Sralph i = (*strptr++ - '0'); 66717834Sralph if (i <= 0 || i > 10) 66817834Sralph i = 3; 66917834Sralph } else 67013642Ssam i = 3; 67117834Sralph /* send break */ 67217834Sralph genbrk(fn, i); 67317834Sralph if (*strptr == '\0') 67417834Sralph cr = 0; 67513642Ssam continue; 67617834Sralph case 'c': 67717834Sralph if (*strptr == '\0') { 67817834Sralph DEBUG(5, "NO CR\n", CNULL); 67917834Sralph cr = 0; 68017834Sralph continue; 68117834Sralph } 68217834Sralph DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL); 68313642Ssam continue; 68417834Sralph default: 68517834Sralph if (isdigit(*strptr)) { 68617834Sralph i = 0; 68717834Sralph n = 0; 68817834Sralph while (isdigit(*strptr) && ++n <= 3) 68917834Sralph i = i*8 + (*strptr++ - '0'); 69017834Sralph p_chwrite(fn, (char)i); 69117834Sralph continue; 69217834Sralph } 69317834Sralph DEBUG(5, "BACKSLASH\n", CNULL); 69417834Sralph --strptr; 69513642Ssam } 69617834Sralph } else 69717834Sralph p_chwrite(fn, c); 69813642Ssam } 69913642Ssam 70013642Ssam if (cr) 70113642Ssam p_chwrite(fn, '\r'); 70213642Ssam return; 70313642Ssam } 70413642Ssam 70513642Ssam p_chwrite(fd, c) 70613642Ssam int fd; 70717834Sralph char c; 70813642Ssam { 70917834Sralph c = par_tab[c&0177]; 71017834Sralph if (write(fd, &c, 1) != 1) { 71117834Sralph logent(sys_errlist[errno], "BAD WRITE"); 71217834Sralph longjmp(Cjbuf, 2); 71317834Sralph } 71413642Ssam } 71513642Ssam 71613642Ssam /* 71713642Ssam * generate parity table for use by p_chwrite. 71813642Ssam */ 71913642Ssam bld_partab(type) 72013642Ssam int type; 72113642Ssam { 72213642Ssam register int i, j, n; 72313642Ssam 72413642Ssam for (i = 0; i < sizeof(par_tab); i++) { 72513642Ssam n = 0; 72613642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 72713642Ssam n++; 72813642Ssam par_tab[i] = i; 72913642Ssam if (type == P_ONE 73013642Ssam || (type == P_EVEN && (n&01) != 0) 73113642Ssam || (type == P_ODD && (n&01) == 0)) 73213642Ssam par_tab[i] |= sizeof(par_tab); 73313642Ssam } 73413642Ssam } 73513642Ssam 73613642Ssam #define BSPEED B150 73713642Ssam 73818619Sralph /* 73918619Sralph * send a break 74013642Ssam */ 74113642Ssam genbrk(fn, bnulls) 74213642Ssam register int fn, bnulls; 74313642Ssam { 74417834Sralph #ifdef USG 74523596Sbloom if (ioctl(fn, TCSBRK, STBNULL) < 0) 74623596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 74717834Sralph #else !USG 74823596Sbloom struct sgttyb ttbuf; 74923596Sbloom register int sospeed; 75023596Sbloom # ifdef TIOCSBRK 75123596Sbloom if (ioctl(fn, TIOCSBRK, STBNULL) < 0) 75223596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 75323596Sbloom # ifdef TIOCCBRK 75413642Ssam sleep(1); 75523596Sbloom if (ioctl(fn, TIOCCBRK, STBNULL) < 0) 75623596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 75723596Sbloom # endif TIOCCBRK 75817834Sralph DEBUG(4, "ioctl %d second break\n", bnulls ); 75923596Sbloom # else !TIOCSBRK 76013642Ssam 76123596Sbloom if (ioctl(fn, TIOCGETP, &ttbuf) < 0) 76223596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 76313642Ssam sospeed = ttbuf.sg_ospeed; 76413642Ssam ttbuf.sg_ospeed = BSPEED; 76523596Sbloom if (ioctl(fn, TIOCSETP, &ttbuf) < 0) 76623596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 76723596Sbloom if (write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls) != bnulls) { 76817834Sralph badbreak: 76917834Sralph logent(sys_errlist[errno], "BAD WRITE genbrk"); 77017834Sralph alarm(0); 77117834Sralph longjmp(Sjbuf, 3); 77217834Sralph } 77313642Ssam ttbuf.sg_ospeed = sospeed; 77423596Sbloom if (ioctl(fn, TIOCSETP, &ttbuf) < 0) 77523596Sbloom DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 77623596Sbloom if (write(fn, "@", 1) != 1) 77717834Sralph goto badbreak; 77813642Ssam DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 77917834Sralph #endif !TIOCSBRK 78017834Sralph #endif !USG 78113642Ssam } 78213642Ssam 78318619Sralph /* 78418619Sralph * check for occurrence of substring "sh" 78513642Ssam * 78613642Ssam * return codes: 78713642Ssam * 0 - found the string 78813642Ssam * 1 - not in the string 78913642Ssam */ 79013642Ssam notin(sh, lg) 79113642Ssam register char *sh, *lg; 79213642Ssam { 79313642Ssam while (*lg != '\0') { 79413642Ssam if (wprefix(sh, lg)) 79518619Sralph return 0; 79613642Ssam else 79713642Ssam lg++; 79813642Ssam } 79918619Sralph return 1; 80013642Ssam } 80113642Ssam 80218619Sralph /* 80323596Sbloom * Allow multiple date specifications separated by ','. 80413642Ssam */ 80518619Sralph ifdate(p) 80618619Sralph register char *p; 80713642Ssam { 80823596Sbloom register char *np, c; 80918619Sralph register int ret, g; 81023596Sbloom int rtime, i; 81113642Ssam 81223596Sbloom /* pick up retry time for failures */ 81323596Sbloom /* global variable Retrytime is set here */ 81423596Sbloom if ((np = index(p, ';')) == NULL) { 81523596Sbloom Retrytime = RETRYTIME; 81623596Sbloom } else { 81723596Sbloom i = sscanf(np+1, "%d", &rtime); 81823596Sbloom if (i < 1 || rtime < 0) 81923596Sbloom rtime = 5; 82023596Sbloom Retrytime = rtime * 60; 82123596Sbloom } 82223596Sbloom 82318619Sralph ret = FAIL; 82418619Sralph MaxGrade = '\0'; 82518619Sralph do { 82623596Sbloom np = strpbrk(p, ",|"); /* prefer , but allow | for compat */ 82723596Sbloom if (np) 82823596Sbloom *np = '\0'; 82918619Sralph g = ifadate(p); 83018619Sralph DEBUG(11,"ifadate returns %o\n", g); 83118619Sralph if (g != FAIL) { 83218619Sralph ret = SUCCESS; 83318619Sralph if (g > MaxGrade) 83418619Sralph MaxGrade = g; 83518619Sralph } 83623596Sbloom if (np) 83723596Sbloom *np = ','; 83823596Sbloom p = np + 1; 83923596Sbloom } while (np); 84023596Sbloom if (MaxGrade == '\0') 84123596Sbloom MaxGrade = DefMaxGrade; 84218619Sralph return ret; 84313642Ssam } 84413642Ssam 84518619Sralph /* 84618619Sralph * this routine will check a string (string) 84713642Ssam * like "MoTu0800-1730" to see if the present 84813642Ssam * time is within the given limits. 84913642Ssam * SIDE EFFECT - Retrytime is set 85013642Ssam * 85113642Ssam * return codes: 85213642Ssam * 0 - not within limits 85313642Ssam * 1 - within limits 85413642Ssam */ 85513642Ssam 85618619Sralph ifadate(string) 85718619Sralph char *string; 85813642Ssam { 85913642Ssam static char *days[]={ 86013642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 86113642Ssam }; 86213642Ssam time_t clock; 86318619Sralph register char *s = string; 86417834Sralph int i, tl, th, tn, dayok=0; 86513642Ssam struct tm *localtime(); 86613642Ssam struct tm *tp; 86718619Sralph char *p, MGrade; 86813642Ssam 86923596Sbloom if ((p = index(s, '/')) == NULL) 87018619Sralph MGrade = DefMaxGrade; 87118619Sralph else 87218619Sralph MGrade = p[1]; 87318619Sralph 87413642Ssam time(&clock); 87513642Ssam tp = localtime(&clock); 87617834Sralph while (isascii(*s) && isalpha(*s)) { 87713642Ssam for (i = 0; days[i]; i++) { 87813642Ssam if (prefix(days[i], s)) 87913642Ssam if (tp->tm_wday == i) 88013642Ssam dayok = 1; 88113642Ssam } 88213642Ssam 88313642Ssam if (prefix("Wk", s)) 88413642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 88513642Ssam dayok = 1; 88613642Ssam if (prefix("Any", s)) 88713642Ssam dayok = 1; 88817834Sralph if (prefix("Evening", s)) { 88917834Sralph /* Sat or Sun */ 89017834Sralph if (tp->tm_wday == 6 || tp->tm_wday == 0 89117834Sralph || tp->tm_hour >= 17 || tp->tm_hour < 8) 89217834Sralph dayok = 1; 89317834Sralph } 89417834Sralph if (prefix("Night", s)) { 89517834Sralph if (tp->tm_wday == 6 /* Sat */ 89618619Sralph || tp->tm_hour >= 23 || tp->tm_hour < 8 89718619Sralph /* Sunday before 5pm */ 89818619Sralph || (tp->tm_wday == 0 && tp->tm_hour < 17)) 89917834Sralph dayok = 1; 90017834Sralph } 90113642Ssam s++; 90213642Ssam } 90313642Ssam 90418619Sralph if (dayok == 0 && s != string) 90518619Sralph return FAIL; 90613642Ssam i = sscanf(s, "%d-%d", &tl, &th); 90718619Sralph if (i < 2) 90818619Sralph return MGrade; 90918619Sralph tn = tp->tm_hour * 100 + tp->tm_min; 91018619Sralph if (th < tl) { /* crosses midnight */ 91118619Sralph if (tl <= tn || tn < th) 91218619Sralph return MGrade; 91318619Sralph } else 91418619Sralph 91513642Ssam if (i < 2) 91618619Sralph return MGrade; 91718619Sralph if (th < tl) { /* crosses midnight */ 91817834Sralph if (tl <= tn || tn < th) 91918619Sralph return MGrade; 92017834Sralph } else 92117834Sralph if (tl <= tn && tn < th) 92218619Sralph return MGrade; 92318619Sralph return FAIL; 92413642Ssam } 92513642Ssam 92618619Sralph /* 92718619Sralph * find first digit in string 92813642Ssam * 92913642Ssam * return - pointer to first digit in string or end of string 93013642Ssam */ 93113642Ssam char * 93213642Ssam fdig(cp) 93313642Ssam register char *cp; 93413642Ssam { 93513642Ssam register char *c; 93613642Ssam 93713642Ssam for (c = cp; *c; c++) 93813642Ssam if (*c >= '0' && *c <= '9') 93913642Ssam break; 94017834Sralph return c; 94113642Ssam } 94213642Ssam 94313642Ssam /* 94413642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 94513642Ssam * Strings are compared as if they contain all capital letters. 94613642Ssam */ 94713642Ssam snccmp(s1, s2) 94813642Ssam register char *s1, *s2; 94913642Ssam { 95013642Ssam char c1, c2; 95113642Ssam 952*25127Sbloom if (islower(*s1)) 953*25127Sbloom c1 = toupper(*s1); 954*25127Sbloom else 955*25127Sbloom c1 = *s1; 956*25127Sbloom if (islower(*s2)) 957*25127Sbloom c2 = toupper(*s2); 958*25127Sbloom else 959*25127Sbloom c2 = *s2; 96013642Ssam 96113642Ssam while (c1 == c2) { 962*25127Sbloom if (*s1++ == '\0') 96317834Sralph return 0; 96413642Ssam s2++; 965*25127Sbloom if (islower(*s1)) 966*25127Sbloom c1 = toupper(*s1); 967*25127Sbloom else 968*25127Sbloom c1 = *s1; 969*25127Sbloom if (islower(*s2)) 970*25127Sbloom c2 = toupper(*s2); 971*25127Sbloom else 972*25127Sbloom c2 = *s2; 97313642Ssam } 97417834Sralph return c1 - c2; 97513642Ssam } 976*25127Sbloom 97717834Sralph /* 978*25127Sbloom * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 979*25127Sbloom * Strings are compared as if they contain all capital letters. 980*25127Sbloom */ 981*25127Sbloom sncncmp(s1, s2, n) 982*25127Sbloom register char *s1, *s2; 983*25127Sbloom register int n; 984*25127Sbloom { 985*25127Sbloom char c1, c2; 986*25127Sbloom 987*25127Sbloom if (islower(*s1)) 988*25127Sbloom c1 = toupper(*s1); 989*25127Sbloom else 990*25127Sbloom c1 = *s1; 991*25127Sbloom if (islower(*s2)) 992*25127Sbloom c2 = toupper(*s2); 993*25127Sbloom else 994*25127Sbloom c2 = *s2; 995*25127Sbloom 996*25127Sbloom while ( --n >= 0 && c1 == c2) { 997*25127Sbloom if (*s1++ == '\0') 998*25127Sbloom return 0; 999*25127Sbloom s2++; 1000*25127Sbloom if (islower(*s1)) 1001*25127Sbloom c1 = toupper(*s1); 1002*25127Sbloom else 1003*25127Sbloom c1 = *s1; 1004*25127Sbloom if (islower(*s2)) 1005*25127Sbloom c2 = toupper(*s2); 1006*25127Sbloom else 1007*25127Sbloom c2 = *s2; 1008*25127Sbloom } 1009*25127Sbloom return n<0 ? 0 : (c1 - c2); 1010*25127Sbloom } 1011*25127Sbloom /* 101217834Sralph * do chat script 101317834Sralph * occurs after local port is opened, 101417834Sralph * before 'dialing' the other machine. 101517834Sralph */ 101617834Sralph dochat(dev, flds, fd) 101717834Sralph register struct Devices *dev; 101817834Sralph char *flds[]; 101917834Sralph int fd; 102017834Sralph { 102117834Sralph register int i; 102217834Sralph register char *p; 102317834Sralph char bfr[sizeof(dev->D_argbfr)]; 102417834Sralph 102517834Sralph if (dev->D_numargs <= 5) 102617834Sralph return(0); 102717834Sralph DEBUG(4, "dochat called %d\n", dev->D_numargs); 102817834Sralph for (i = 0; i < dev->D_numargs-5; i++) { 102917834Sralph sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); 103017834Sralph if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { 103117834Sralph p = malloc((unsigned)strlen(bfr)+1); 103217834Sralph if (p != NULL) { 103317834Sralph strcpy(p, bfr); 103417834Sralph dev->D_arg[D_CHAT+i] = p; 103517834Sralph } 103617834Sralph } 103717834Sralph } 103817834Sralph /* following is a kludge because login() arglist is a kludge */ 103917834Sralph i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); 104017834Sralph /* 104117834Sralph * If login() last did a sendthem(), must pause so things can settle. 104217834Sralph * But don't bother if chat failed. 104317834Sralph */ 104417834Sralph if (i == 0 && (dev->D_numargs&01)) 104517834Sralph sleep(2); 104617834Sralph return(i); 104717834Sralph } 1048