113642Ssam 223596Sbloom #include <signal.h> 313642Ssam #include "uucp.h" 413642Ssam #include <setjmp.h> 513642Ssam #include <ctype.h> 613642Ssam #include <errno.h> 717834Sralph #ifdef USG 813642Ssam #include <termio.h> 913642Ssam #include <fcntl.h> 1013642Ssam #endif 1117834Sralph #ifndef USG 1213642Ssam #include <sgtty.h> 1313642Ssam #endif 1417834Sralph #ifdef BSD4_2 1517834Sralph #include <sys/time.h> 1617834Sralph #else 1717834Sralph #include <time.h> 1817834Sralph #endif 1913642Ssam 2013642Ssam #define MAXC 1000 2113642Ssam 2213642Ssam extern jmp_buf Sjbuf; 2317834Sralph jmp_buf Cjbuf; 2418619Sralph extern int errno, onesys; 2517834Sralph extern char *sys_errlist[]; 2618619Sralph extern char MaxGrade, DefMaxGrade; 2713642Ssam 2813642Ssam /* Parity control during login procedure */ 2913642Ssam #define P_ZERO 0 3013642Ssam #define P_ONE 1 3113642Ssam #define P_EVEN 2 3213642Ssam #define P_ODD 3 3317834Sralph 3417834Sralph #define ABORT -2 3517834Sralph 3617834Sralph char *AbortOn = NULL; 3713642Ssam char par_tab[128]; /* must be power of two */ 3817834Sralph int linebaudrate; /* used for the sleep test in pk1.c */ 3913642Ssam int next_fd = -1; /* predicted fd to close interrupted opens */ 4025705Sbloom 4125705Sbloom char *PCP = "PCP"; /* PC Pursuit device type */ 4225127Sbloom /* 4325127Sbloom * catch alarm routine for "expect". 4413642Ssam */ 4513642Ssam alarmtr() 4613642Ssam { 4713642Ssam signal(SIGALRM, alarmtr); 4813642Ssam if (next_fd >= 0) { 4913642Ssam if (close(next_fd)) 5013642Ssam logent("FAIL", "ACU LINE CLOSE"); 5113642Ssam next_fd = -1; 5213642Ssam } 5313642Ssam longjmp(Sjbuf, 1); 5413642Ssam } 5513642Ssam 5625705Sbloom /* This template is for seismo to call ihnp4 5725705Sbloom * the 3 lines marked ---> will be overwritten for the appropriate city 5825705Sbloom */ 5925705Sbloom #define PCP_BAUD 3 6025705Sbloom #define PCP_PHONE 4 61*33562Srick #define PCP_CITY 14 62*33562Srick #define PCP_PASSWORD 16 63*33562Srick #define PCP_RPHONE 20 64*33562Srick #define NPCFIELDS 23 6525705Sbloom 6625705Sbloom static char *PCFlds[] = { 6725705Sbloom "PC-PURSUIT", 6825705Sbloom "Any", 6925705Sbloom "ACU", 7025705Sbloom "1200", 71*33562Srick CNULL, 72*33562Srick CNULL, 73*33562Srick "P_ZERO", /* Telenet insists on zero parity */ 7425705Sbloom "ABORT", 75*33562Srick "BUSY", /* Abort on Busy Signal */ 76*33562Srick CNULL, 77*33562Srick "\\d\\d\\r\\d\\r", /* Get telenet's attention */ 78*33562Srick "TERMINAL=~3-\r-TERM~3-\r-TERM~5", /* Terminal type ? */ 79*33562Srick "\\r", 80*33562Srick "@", /* telenet's prompt */ 81*33562Srick "D/DCWAS/21,telenetloginstring", /* overwritten later */ 82*33562Srick "PASSWORD", 83*33562Srick CNULL, /* telenet password */ 84*33562Srick "CONNECTED", /* We're now talking to a Hayes in the remote city */ 85*33562Srick "ATZ", /* Reset it */ 86*33562Srick "OK", 87*33562Srick "ATDT6907171", /* overwritten */ 88*33562Srick "CONNECT", 89*33562Srick "\\d\\r", /* We're in !*/ 90*33562Srick CNULL, 9125705Sbloom }; 9225705Sbloom 93*33562Srick static char PCP_brand[25]; 9425705Sbloom 9518619Sralph /* 9618619Sralph * place a telephone call to system and login, etc. 9713642Ssam * 9813642Ssam * return codes: 9913642Ssam * CF_SYSTEM: don't know system 10013642Ssam * CF_TIME: wrong time to call 10113642Ssam * CF_DIAL: call failed 10213642Ssam * CF_NODEV: no devices available to place call 10313642Ssam * CF_LOGIN: login/password dialog failed 10413642Ssam * 10513642Ssam * >0 - file no. - connect ok 10613642Ssam */ 10713642Ssam 10813642Ssam int Dcf = -1; 10917834Sralph char *Flds[MAXC/10]; 11025966Sbloom char LineType[10]; 11117834Sralph extern int LocalOnly; 11213642Ssam 11313642Ssam conn(system) 11413642Ssam char *system; 11513642Ssam { 11625705Sbloom int nf; 11718619Sralph char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE]; 11813642Ssam register FILE *fsys; 11913642Ssam int fcode = 0; 12013642Ssam 12113642Ssam nf = 0; 12213642Ssam 12313642Ssam fsys = fopen(SYSFILE, "r"); 12413642Ssam ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 12513642Ssam 12617834Sralph DEBUG(4, "finds (%s) called\n", system); 12725127Sbloom keeplooking: 12817834Sralph while((nf = finds(fsys, system, info, Flds)) > 0) { 12925966Sbloom strncpy(LineType, Flds[F_LINE], 10); 13017834Sralph if (LocalOnly) { 13125966Sbloom if (strcmp("TCP", LineType) 13225966Sbloom && strcmp("DIR", LineType) 13325966Sbloom && strcmp("LOCAL", LineType) ) { 13425705Sbloom fcode = CF_TIME; 13525705Sbloom continue; 13625705Sbloom } 13717834Sralph } 13823596Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 13918619Sralph if (!onesys && MaxGrade != DefMaxGrade && 14025705Sbloom !iswrk(file, "chk", Spool, wkpre)) { 14125705Sbloom fcode = CF_TIME; 14225705Sbloom continue; 14325705Sbloom } 14425705Sbloom /* For GTE's PC Pursuit */ 14525966Sbloom if (snccmp(LineType, PCP) == SAME) { 14625705Sbloom FILE *dfp; 14725705Sbloom int status; 14825705Sbloom static struct Devices dev; 149*33562Srick 15025705Sbloom dfp = fopen(DEVFILE, "r"); 15125705Sbloom ASSERT(dfp != NULL, "Can't open", DEVFILE, 0); 15225705Sbloom while ((status=rddev(dfp, &dev)) != FAIL 15325705Sbloom && strcmp(PCP, dev.D_type) != SAME) 15425705Sbloom ; 15525705Sbloom fclose(dfp); 15625705Sbloom if (status == FAIL) 15725705Sbloom continue; 15825705Sbloom if (mlock(PCP) == FAIL) { 15925705Sbloom fcode = CF_NODEV; 16025705Sbloom logent("DEVICE", "NO"); 16125705Sbloom continue; 16225705Sbloom } 16325705Sbloom PCFlds[PCP_BAUD] = dev.D_class; 16425705Sbloom PCFlds[PCP_PHONE] = dev.D_calldev; 165*33562Srick sprintf(PCFlds[PCP_CITY], "c d/%s%s,%s", 166*33562Srick Flds[F_CLASS], 167*33562Srick index(Flds[F_CLASS], '/') == NULL ? "/12" : "", 168*33562Srick dev.D_arg[D_CHAT]); 169*33562Srick PCFlds[PCP_PASSWORD] = dev.D_line; 170*33562Srick strncpy(&PCFlds[PCP_RPHONE][4], Flds[F_PHONE], 7); 17125705Sbloom strncpy(PCP_brand, dev.D_brand, sizeof(PCP_brand)); 172*33562Srick if ((fcode = getto(PCFlds)) < 0) { 173*33562Srick rmlock(PCP); 17425705Sbloom continue; 175*33562Srick } 17625705Sbloom Dcf = fcode; 17725705Sbloom fcode = login(NPCFIELDS, PCFlds, Dcf); 178*33562Srick if (fcode == SUCCESS) 179*33562Srick break; 180*33562Srick fcode = CF_DIAL; 181*33562Srick rmlock(PCP); 182*33562Srick /* end PC Pursuit */ 183*33562Srick } else if ((fcode = getto(Flds)) > 0) { 184*33562Srick Dcf = fcode; 18513642Ssam break; 186*33562Srick } 18713642Ssam } 18813642Ssam 18925127Sbloom if (nf <= 0) { 19025127Sbloom fclose(fsys); 19117834Sralph return fcode ? fcode : nf; 19225127Sbloom } 19313642Ssam 19425705Sbloom 19525705Sbloom if (fcode >= 0) { 19625705Sbloom DEBUG(4, "login %s\n", "called"); 197*33562Srick fcode = login(nf, Flds, Dcf); } 19825705Sbloom if (fcode < 0) { 19913642Ssam clsacu(); 20025705Sbloom if (fcode == ABORT) { 20125127Sbloom fcode = CF_DIAL; 20225127Sbloom goto keeplooking; 20325127Sbloom } else { 20425127Sbloom fclose(fsys); 20523596Sbloom return CF_LOGIN; 20625127Sbloom } 20713642Ssam } 20825127Sbloom fclose(fsys); 20925705Sbloom fioclex(Dcf); 21025705Sbloom return Dcf; 21113642Ssam } 21213642Ssam 21325127Sbloom /* 21425127Sbloom * connect to remote machine 21513642Ssam * 21613642Ssam * return codes: 21713642Ssam * >0 - file number - ok 21813642Ssam * FAIL - failed 21913642Ssam */ 22013642Ssam 22113642Ssam getto(flds) 22213642Ssam register char *flds[]; 22313642Ssam { 22413642Ssam register struct condev *cd; 22513642Ssam int nulldev(), diropn(); 22625127Sbloom char *line; 22713642Ssam 22817834Sralph DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); 22913642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 23013642Ssam 23125127Sbloom if (snccmp(flds[F_LINE], "LOCAL") == SAME) 23225127Sbloom line = "ACU"; 23325127Sbloom else 23425127Sbloom line = flds[F_LINE]; 23525127Sbloom #ifdef DIALINOUT 23625127Sbloom if (snccmp(line, "ACU") != SAME) 23725127Sbloom reenable(); 23825127Sbloom #endif DIALINOUT 23913642Ssam CU_end = nulldev; 24025705Sbloom if (snccmp(line, PCP) == SAME) { 24125705Sbloom for(cd = condevs; cd->CU_meth != NULL; cd++) { 24225705Sbloom if (snccmp(PCP_brand, cd->CU_brand) == SAME) { 24325705Sbloom CU_end = cd->CU_clos; 24425705Sbloom return diropn(flds); 24525705Sbloom } 24613642Ssam } 24725705Sbloom logent(PCP_brand, "UNSUPPORTED ACU TYPE"); 24825705Sbloom } else { 24925705Sbloom for (cd = condevs; cd->CU_meth != NULL; cd++) { 25025705Sbloom if (snccmp(cd->CU_meth, line) == SAME) { 25125705Sbloom DEBUG(4, "Using %s to call\n", cd->CU_meth); 25225705Sbloom return (*(cd->CU_gen))(flds); 25325705Sbloom } 25425705Sbloom } 25525705Sbloom DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]); 25613642Ssam } 25717834Sralph return diropn(flds); /* search failed, so use direct */ 25817834Sralph } 25913642Ssam 26025127Sbloom /* 26125127Sbloom * close call unit 26213642Ssam * 26313642Ssam * return codes: none 26413642Ssam */ 26513642Ssam 26613642Ssam int (*CU_end)() = nulldev; 26713642Ssam clsacu() 26813642Ssam { 26917834Sralph /* make *sure* Dcf is no longer exclusive. 27017834Sralph * Otherwise dual call-in/call-out modems could get stuck. 27117834Sralph * Unfortunately, doing this here is not ideal, but it is the 27217834Sralph * easiest place to put the call. 27317834Sralph * Hopefully everyone honors the LCK protocol, of course 27417834Sralph */ 27525705Sbloom #ifdef TIOCNXCL 27623596Sbloom if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0) 27723596Sbloom DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]); 27817834Sralph #endif 27917834Sralph if (setjmp(Sjbuf)) 28017834Sralph logent(Rmtname, "CLOSE TIMEOUT"); 28117834Sralph else { 28217834Sralph signal(SIGALRM, alarmtr); 28317834Sralph alarm(20); 28417834Sralph (*(CU_end))(Dcf); 28517834Sralph alarm(0); 28617834Sralph } 28713642Ssam if (close(Dcf) == 0) { 28813642Ssam DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 28913642Ssam logent("clsacu", "NOT CLOSED by CU_clos"); 29013642Ssam } 29113642Ssam Dcf = -1; 29213642Ssam CU_end = nulldev; 29313642Ssam } 29413642Ssam 29525127Sbloom /* 29625127Sbloom * expand phone number for given prefix and number 29713642Ssam */ 29813642Ssam 29913642Ssam exphone(in, out) 30013642Ssam register char *in, *out; 30113642Ssam { 30213642Ssam FILE *fn; 30313642Ssam char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 30413642Ssam char buf[BUFSIZ]; 30513642Ssam register char *s1; 30613642Ssam 30717834Sralph if (!isascii(*in) || !isalpha(*in)) { 30813642Ssam strcpy(out, in); 30913642Ssam return; 31013642Ssam } 31113642Ssam 31213642Ssam s1=pre; 31317834Sralph while (isascii(*in) && isalpha(*in)) 31413642Ssam *s1++ = *in++; 31513642Ssam *s1 = '\0'; 31613642Ssam s1 = npart; 31713642Ssam while (*in != '\0') 31813642Ssam *s1++ = *in++; 31913642Ssam *s1 = '\0'; 32013642Ssam 32113642Ssam tpre[0] = '\0'; 32213642Ssam if ((fn = fopen(DIALFILE, "r")) == NULL) 32313642Ssam DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 32413642Ssam else { 32513642Ssam while (cfgets(buf, BUFSIZ, fn)) { 32617834Sralph if (sscanf(buf, "%s%s", p, tpre) != 2) 32717834Sralph continue; 32813642Ssam if (strcmp(p, pre) == SAME) 32913642Ssam goto found; 33013642Ssam tpre[0] = '\0'; 33113642Ssam } 33213642Ssam DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 33313642Ssam found:; 33413642Ssam fclose(fn); 33513642Ssam } 33613642Ssam 33713642Ssam strcpy(out, tpre); 33813642Ssam strcat(out, npart); 33913642Ssam } 34013642Ssam 34118619Sralph /* 34218619Sralph * read and decode a line from device file 34313642Ssam * 34413642Ssam * return code - FAIL at end-of file; 0 otherwise 34513642Ssam */ 34613642Ssam 34713642Ssam rddev(fp, dev) 34813642Ssam register struct Devices *dev; 34913642Ssam FILE *fp; 35013642Ssam { 35117834Sralph register int na; 35213642Ssam 35317834Sralph if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp)) 35417834Sralph return FAIL; 35517834Sralph na = getargs(dev->D_argbfr, dev->D_arg, 20); 35617834Sralph ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0); 35717834Sralph if (na == 4) { 35817834Sralph dev->D_brand = ""; 35917834Sralph na++; 36017834Sralph } 36113642Ssam dev->D_speed = atoi(fdig(dev->D_class)); 36217834Sralph dev->D_numargs = na; 36317834Sralph return 0; 36413642Ssam } 36513642Ssam 36618619Sralph /* 36718619Sralph * set system attribute vector 36813642Ssam * 36913642Ssam * return codes: 37013642Ssam * >0 - number of arguments in vector - succeeded 37113642Ssam * CF_SYSTEM - system name not found 37213642Ssam * CF_TIME - wrong time to call 37313642Ssam */ 37413642Ssam 37513642Ssam finds(fsys, sysnam, info, flds) 37613642Ssam char *sysnam, info[], *flds[]; 37713642Ssam FILE *fsys; 37813642Ssam { 37913642Ssam int na; 38013642Ssam int fcode = 0; 38113642Ssam 38213642Ssam /* format of fields 38313642Ssam * 0 name; 38413642Ssam * 1 time 38513642Ssam * 2 acu/hardwired 38613642Ssam * 3 speed 38713642Ssam * etc 38813642Ssam */ 38913642Ssam while (cfgets(info, MAXC, fsys) != NULL) { 39017834Sralph na = getargs(info, flds, MAXC/10); 39123596Sbloom if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME) 39213642Ssam continue; 39318619Sralph if (ifdate(flds[F_TIME]) != FAIL) 39413642Ssam /* found a good entry */ 39517834Sralph return na; 39613642Ssam DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 39713642Ssam fcode = CF_TIME; 39813642Ssam } 39917834Sralph return fcode ? fcode : CF_SYSTEM; 40013642Ssam } 40113642Ssam 40218619Sralph /* 40318619Sralph * do login conversation 40413642Ssam * 40523596Sbloom * return codes: SUCCESS | FAIL 40613642Ssam */ 40713642Ssam 40813642Ssam login(nf, flds, fn) 40913642Ssam register char *flds[]; 41013642Ssam int nf, fn; 41113642Ssam { 41213642Ssam register char *want, *altern; 41313642Ssam int k, ok; 41413642Ssam 41517834Sralph ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf); 41617834Sralph if (setjmp(Cjbuf)) 41717834Sralph return FAIL; 41817834Sralph AbortOn = NULL; 41913642Ssam for (k = F_LOGIN; k < nf; k += 2) { 42013642Ssam want = flds[k]; 421*33562Srick if (want == NULL) 422*33562Srick want = ""; 42313642Ssam ok = FAIL; 42417834Sralph while (ok != SUCCESS) { 42513642Ssam altern = index(want, '-'); 42613642Ssam if (altern != NULL) 42713642Ssam *altern++ = '\0'; 42817834Sralph if (strcmp(want, "ABORT") == 0) { 42917834Sralph AbortOn = flds[k+1]; 43017834Sralph DEBUG(4, "ABORT ON: %s\n", AbortOn); 43117834Sralph goto nextfield; 43217834Sralph } 43325705Sbloom DEBUG(4, "wanted \"%s\"\n", want); 43413642Ssam ok = expect(want, fn); 43517834Sralph DEBUG(4, "got: %s\n", ok ? "?" : "that"); 43617834Sralph if (ok == FAIL) { 43717834Sralph if (altern == NULL) { 43817834Sralph logent("LOGIN", _FAILED); 43917834Sralph return FAIL; 44017834Sralph } 44117834Sralph want = index(altern, '-'); 44217834Sralph if (want != NULL) 44317834Sralph *want++ = '\0'; 44417834Sralph sendthem(altern, fn); 44517834Sralph } else 44617834Sralph if (ok == ABORT) { 447*33562Srick char sbuf[MAXFULLNAME]; 448*33562Srick sprintf(sbuf, "LOGIN ABORTED on \"%s\"", AbortOn); 449*33562Srick logent(sbuf, _FAILED); 45023596Sbloom return ABORT; 45117834Sralph } 45213642Ssam } 45317834Sralph sleep(1); 45413642Ssam if (k+1 < nf) 45513642Ssam sendthem(flds[k+1], fn); 45617834Sralph nextfield: ; 45713642Ssam } 45817834Sralph return SUCCESS; 45913642Ssam } 46013642Ssam 46113642Ssam 46217834Sralph /* conditional table generation to support odd speeds */ 46313642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = { 46413642Ssam #ifdef B50 46513642Ssam { 50, B50}, 46613642Ssam #endif 46713642Ssam #ifdef B75 46813642Ssam { 75, B75}, 46913642Ssam #endif 47013642Ssam #ifdef B110 47113642Ssam { 110, B110}, 47213642Ssam #endif 47313642Ssam #ifdef B150 47413642Ssam { 150, B150}, 47513642Ssam #endif 47613642Ssam #ifdef B200 47713642Ssam { 200, B200}, 47813642Ssam #endif 47913642Ssam #ifdef B300 48013642Ssam { 300, B300}, 48113642Ssam #endif 48213642Ssam #ifdef B600 48313642Ssam {600, B600}, 48413642Ssam #endif 48513642Ssam #ifdef B1200 48613642Ssam {1200, B1200}, 48713642Ssam #endif 48813642Ssam #ifdef B1800 48913642Ssam {1800, B1800}, 49013642Ssam #endif 49113642Ssam #ifdef B2000 49213642Ssam {2000, B2000}, 49313642Ssam #endif 49413642Ssam #ifdef B2400 49513642Ssam {2400, B2400}, 49613642Ssam #endif 49713642Ssam #ifdef B3600 49813642Ssam {3600, B3600}, 49913642Ssam #endif 50013642Ssam #ifdef B4800 50113642Ssam {4800, B4800}, 50213642Ssam #endif 50313642Ssam #ifdef B7200 50413642Ssam {7200, B7200}, 50513642Ssam #endif 50613642Ssam #ifdef B9600 50713642Ssam {9600, B9600}, 50813642Ssam #endif 50913642Ssam #ifdef B19200 51017834Sralph {19200, B19200}, 51113642Ssam #endif 51217834Sralph #ifdef EXTA 51317834Sralph {19200, EXTA}, 51417834Sralph #endif 51513642Ssam {0, 0} 51613642Ssam }; 51713642Ssam 51818619Sralph /* 51918619Sralph * set speed/echo/mode... 52013642Ssam * 52113642Ssam * return codes: none 52213642Ssam */ 52313642Ssam 52413642Ssam fixline(tty, spwant) 52513642Ssam int tty, spwant; 52613642Ssam { 52717834Sralph #ifdef USG 52813642Ssam struct termio ttbuf; 52917834Sralph #else !USG 53013642Ssam struct sgttyb ttbuf; 53117834Sralph #endif !USG 53213642Ssam register struct sg_spds *ps; 53313642Ssam int speed = -1; 53413642Ssam 53513642Ssam for (ps = spds; ps->sp_val; ps++) 53613642Ssam if (ps->sp_val == spwant) 53713642Ssam speed = ps->sp_name; 53817834Sralph ASSERT(speed >= 0, "BAD SPEED", CNULL, speed); 53917834Sralph #ifdef USG 54023596Sbloom if (ioctl(tty, TCGETA, &ttbuf) < 0) 54123596Sbloom return FAIL; 54213642Ssam /* ttbuf.sg_flags = (ANYP|RAW); 54313642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 54413642Ssam ttbuf.c_iflag = (ushort)0; 54513642Ssam ttbuf.c_oflag = (ushort)0; 54613642Ssam ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 54713642Ssam ttbuf.c_lflag = (ushort)0; 54813642Ssam ttbuf.c_cc[VMIN] = 6; 54913642Ssam ttbuf.c_cc[VTIME] = 1; 55023596Sbloom if (ioctl(tty, TCSETA, &ttbuf) < 0) 55123596Sbloom return FAIL; 55217834Sralph #else !USG 55323596Sbloom if (ioctl(tty, TIOCGETP, &ttbuf) < 0) 55423596Sbloom return FAIL; 55513642Ssam ttbuf.sg_flags = (ANYP|RAW); 55613642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 55723596Sbloom if (ioctl(tty, TIOCSETP, &ttbuf) < 0) 55823596Sbloom return FAIL; 55913642Ssam #endif 56017834Sralph #ifndef USG 56123596Sbloom if (ioctl(tty, TIOCHPCL, STBNULL) < 0) 56223596Sbloom return FAIL; 56323596Sbloom if (ioctl(tty, TIOCEXCL, STBNULL) < 0) 56423596Sbloom return FAIL; 56513642Ssam #endif 56617834Sralph linebaudrate = spwant; 56723596Sbloom return SUCCESS; 56813642Ssam } 56913642Ssam 57017834Sralph #define MR 100 57113642Ssam 57218619Sralph /* 57318619Sralph * look for expected string 57413642Ssam * 57513642Ssam * return codes: 57613642Ssam * 0 - found 57713642Ssam * FAIL - lost line or too many characters read 57813642Ssam * some character - timed out 57913642Ssam */ 58013642Ssam 58113642Ssam expect(str, fn) 58213642Ssam register char *str; 58313642Ssam int fn; 58413642Ssam { 58514592Skarels char rdvec[MR]; 58617834Sralph register char *rp = rdvec, *strptr; 58717834Sralph int kr, cnt_char; 58813642Ssam char nextch; 58925127Sbloom int timo = MAXMSGTIME; 59013642Ssam 59117834Sralph if (*str == '\0' || strcmp(str, "\"\"") == SAME) 59217834Sralph return SUCCESS; 59317834Sralph /* Cleanup str, convert \0xx strings to one char */ 59417834Sralph for (strptr = str; *strptr; strptr++) { 59517834Sralph if (*strptr == '\\') 59617834Sralph switch(*++strptr) { 59717834Sralph case 's': 59817834Sralph DEBUG(5, "BLANK\n", CNULL); 59917834Sralph *strptr = ' '; 60017834Sralph break; 60117834Sralph default: 60217834Sralph strptr--; /* back up to backslash */ 60317834Sralph sscanf(strptr + 1,"%o", &cnt_char); 60417834Sralph DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); 60517834Sralph *strptr = (char) (cnt_char); 60617834Sralph strcpy(&strptr[1], &strptr[4]); 60717834Sralph } 60817834Sralph } 60917834Sralph 61025127Sbloom strptr = index(str, '~'); 61125127Sbloom if (strptr != NULL) { 61225127Sbloom *strptr++ = '\0'; 61325127Sbloom timo = atoi(strptr); 61425127Sbloom if (timo <= 0) 61525127Sbloom timo = MAXMSGTIME; 61625127Sbloom } 61725127Sbloom 61817834Sralph if (setjmp(Sjbuf)) 61917834Sralph return FAIL; 62013642Ssam signal(SIGALRM, alarmtr); 62125127Sbloom alarm(timo); 62225127Sbloom *rp = 0; 62313642Ssam while (notin(str, rdvec)) { 62425705Sbloom int c; 62517834Sralph if(AbortOn != NULL && !notin(AbortOn, rdvec)) { 62617834Sralph DEBUG(1, "Call aborted on '%s'\n", AbortOn); 62717834Sralph alarm(0); 62817834Sralph return ABORT; 62917834Sralph } 63013642Ssam kr = read(fn, &nextch, 1); 63113642Ssam if (kr <= 0) { 63213642Ssam alarm(0); 63313642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 63413642Ssam logent("LOGIN", "LOST LINE"); 63517834Sralph return FAIL; 63613642Ssam } 63713642Ssam c = nextch & 0177; 63825705Sbloom if (c == '\0') 63925705Sbloom continue; 64025705Sbloom DEBUG(4, (isprint(c) || isspace(c)) ? "%c" : "\\%03o", c); 64125705Sbloom *rp++ = c; 64213642Ssam if (rp >= rdvec + MR) { 64317834Sralph register char *p; 64417834Sralph for (p = rdvec+MR/2; p < rp; p++) 64517834Sralph *(p-MR/2) = *p; 64617834Sralph rp -= MR/2; 64713642Ssam } 64813642Ssam *rp = '\0'; 64913642Ssam } 65013642Ssam alarm(0); 65117834Sralph return SUCCESS; 65213642Ssam } 65313642Ssam 65413642Ssam 65513642Ssam /* 65613642Ssam * Determine next file descriptor that would be allocated. 65713642Ssam * This permits later closing of a file whose open was interrupted. 65813642Ssam * It is a UNIX kernel problem, but it has to be handled. 65913642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 66013642Ssam */ 66113642Ssam getnextfd() 66213642Ssam { 66313642Ssam close(next_fd = open("/", 0)); 66413642Ssam } 66513642Ssam 66617834Sralph /* 66717834Sralph * send line of login sequence 66813642Ssam * 66913642Ssam * return codes: none 67013642Ssam */ 67113642Ssam sendthem(str, fn) 67213642Ssam register char *str; 67313642Ssam int fn; 67413642Ssam { 67513642Ssam register char *strptr; 67613642Ssam int i, n, cr = 1; 67717834Sralph register char c; 67813642Ssam static int p_init = 0; 67913642Ssam 68025705Sbloom DEBUG(5, "send \"%s\"\n", str); 68113642Ssam 68213642Ssam if (!p_init) { 68313642Ssam p_init++; 68413642Ssam bld_partab(P_EVEN); 68513642Ssam } 68613642Ssam 68713642Ssam if (prefix("BREAK", str)) { 68813642Ssam sscanf(&str[5], "%1d", &i); 68913642Ssam if (i <= 0 || i > 10) 69013642Ssam i = 3; 69113642Ssam /* send break */ 69213642Ssam genbrk(fn, i); 69313642Ssam return; 69413642Ssam } 69513642Ssam 69613642Ssam if (prefix("PAUSE", str)) { 69713642Ssam sscanf(&str[5], "%1d", &i); 69813642Ssam if (i <= 0 || i > 10) 69913642Ssam i = 3; 70013642Ssam /* pause for a while */ 70113642Ssam sleep((unsigned)i); 70213642Ssam return; 70313642Ssam } 70413642Ssam 70513642Ssam if (strcmp(str, "EOT") == SAME) { 70613642Ssam p_chwrite(fn, '\04'); 70713642Ssam return; 70813642Ssam } 70913642Ssam 71013642Ssam /* Send a '\n' */ 71125705Sbloom if (strcmp(str, "LF") == SAME) { 71225705Sbloom p_chwrite(fn, '\n'); 71325705Sbloom return; 71425705Sbloom } 71513642Ssam 71613642Ssam /* Send a '\r' */ 71725705Sbloom if (strcmp(str, "CR") == SAME) { 71825705Sbloom p_chwrite(fn, '\r'); 71925705Sbloom return; 72025705Sbloom } 72113642Ssam 72213642Ssam /* Set parity as needed */ 72313642Ssam if (strcmp(str, "P_ZERO") == SAME) { 72413642Ssam bld_partab(P_ZERO); 72513642Ssam return; 72613642Ssam } 72713642Ssam if (strcmp(str, "P_ONE") == SAME) { 72813642Ssam bld_partab(P_ONE); 72913642Ssam return; 73013642Ssam } 73113642Ssam if (strcmp(str, "P_EVEN") == SAME) { 73213642Ssam bld_partab(P_EVEN); 73313642Ssam return; 73413642Ssam } 73513642Ssam if (strcmp(str, "P_ODD") == SAME) { 73613642Ssam bld_partab(P_ODD); 73713642Ssam return; 73813642Ssam } 73913642Ssam 74013642Ssam /* If "", just send '\r' */ 74117834Sralph if (strcmp(str, "\"\"") == SAME) { 74217834Sralph p_chwrite(fn, '\r'); 74317834Sralph return; 74417834Sralph } 74517834Sralph 74625705Sbloom strptr = str; 74725705Sbloom while ((c = *strptr++) != '\0') { 74817834Sralph if (c == '\\') { 74917834Sralph switch(*strptr++) { 75025705Sbloom case '\0': 75125705Sbloom DEBUG(5, "TRAILING BACKSLASH IGNORED\n", CNULL); 75225705Sbloom --strptr; 75325705Sbloom continue; 75417834Sralph case 's': 75517834Sralph DEBUG(5, "BLANK\n", CNULL); 75625705Sbloom c = ' '; 75717834Sralph break; 75817834Sralph case 'd': 75917834Sralph DEBUG(5, "DELAY\n", CNULL); 76017834Sralph sleep(1); 76117834Sralph continue; 76225705Sbloom case 'n': 76325705Sbloom DEBUG(5, "NEW LINE\n", CNULL); 76425705Sbloom c = '\n'; 76525705Sbloom break; 76617834Sralph case 'r': 76717834Sralph DEBUG(5, "RETURN\n", CNULL); 76825705Sbloom c = '\r'; 76917834Sralph break; 77017834Sralph case 'b': 77117834Sralph if (isdigit(*strptr)) { 77217834Sralph i = (*strptr++ - '0'); 77317834Sralph if (i <= 0 || i > 10) 77417834Sralph i = 3; 77517834Sralph } else 77613642Ssam i = 3; 77717834Sralph /* send break */ 77817834Sralph genbrk(fn, i); 77917834Sralph if (*strptr == '\0') 78017834Sralph cr = 0; 78113642Ssam continue; 78217834Sralph case 'c': 78317834Sralph if (*strptr == '\0') { 78417834Sralph DEBUG(5, "NO CR\n", CNULL); 78517834Sralph cr = 0; 78625705Sbloom } else 78725705Sbloom DEBUG(5, "NO CR - IGNORED NOT EOL\n", CNULL); 78813642Ssam continue; 78925705Sbloom #define isoctal(x) ((x >= '0') && (x <= '7')) 79017834Sralph default: 79125705Sbloom if (isoctal(strptr[-1])) { 79217834Sralph i = 0; 79317834Sralph n = 0; 79425705Sbloom --strptr; 79525705Sbloom while (isoctal(*strptr) && ++n <= 3) 79625705Sbloom i = i * 8 + (*strptr++ - '0'); 79725705Sbloom DEBUG(5, "\\%o\n", i); 79817834Sralph p_chwrite(fn, (char)i); 79917834Sralph continue; 80017834Sralph } 80113642Ssam } 80225705Sbloom } 80325705Sbloom p_chwrite(fn, c); 80413642Ssam } 80513642Ssam 80613642Ssam if (cr) 80713642Ssam p_chwrite(fn, '\r'); 80813642Ssam return; 80913642Ssam } 81013642Ssam 81113642Ssam p_chwrite(fd, c) 81213642Ssam int fd; 81317834Sralph char c; 81413642Ssam { 81517834Sralph c = par_tab[c&0177]; 81617834Sralph if (write(fd, &c, 1) != 1) { 81717834Sralph logent(sys_errlist[errno], "BAD WRITE"); 81817834Sralph longjmp(Cjbuf, 2); 81917834Sralph } 82013642Ssam } 82113642Ssam 82213642Ssam /* 82313642Ssam * generate parity table for use by p_chwrite. 82413642Ssam */ 82513642Ssam bld_partab(type) 82613642Ssam int type; 82713642Ssam { 82813642Ssam register int i, j, n; 82913642Ssam 83013642Ssam for (i = 0; i < sizeof(par_tab); i++) { 83113642Ssam n = 0; 83213642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 83313642Ssam n++; 83413642Ssam par_tab[i] = i; 83513642Ssam if (type == P_ONE 83613642Ssam || (type == P_EVEN && (n&01) != 0) 83713642Ssam || (type == P_ODD && (n&01) == 0)) 83813642Ssam par_tab[i] |= sizeof(par_tab); 83913642Ssam } 84013642Ssam } 84113642Ssam 84218619Sralph /* 84318619Sralph * check for occurrence of substring "sh" 84413642Ssam * 84513642Ssam * return codes: 84613642Ssam * 0 - found the string 84713642Ssam * 1 - not in the string 84813642Ssam */ 84913642Ssam notin(sh, lg) 85013642Ssam register char *sh, *lg; 85113642Ssam { 85213642Ssam while (*lg != '\0') { 85313642Ssam if (wprefix(sh, lg)) 85418619Sralph return 0; 85513642Ssam else 85613642Ssam lg++; 85713642Ssam } 85818619Sralph return 1; 85913642Ssam } 86013642Ssam 86118619Sralph /* 86223596Sbloom * Allow multiple date specifications separated by ','. 86313642Ssam */ 86418619Sralph ifdate(p) 86518619Sralph register char *p; 86613642Ssam { 86725705Sbloom register char *np; 86818619Sralph register int ret, g; 86923596Sbloom int rtime, i; 87013642Ssam 87123596Sbloom /* pick up retry time for failures */ 87223596Sbloom /* global variable Retrytime is set here */ 87323596Sbloom if ((np = index(p, ';')) == NULL) { 87423596Sbloom Retrytime = RETRYTIME; 87523596Sbloom } else { 87623596Sbloom i = sscanf(np+1, "%d", &rtime); 87723596Sbloom if (i < 1 || rtime < 0) 87823596Sbloom rtime = 5; 87923596Sbloom Retrytime = rtime * 60; 88023596Sbloom } 88123596Sbloom 88218619Sralph ret = FAIL; 88318619Sralph MaxGrade = '\0'; 88418619Sralph do { 88523596Sbloom np = strpbrk(p, ",|"); /* prefer , but allow | for compat */ 88623596Sbloom if (np) 88723596Sbloom *np = '\0'; 88818619Sralph g = ifadate(p); 88918619Sralph DEBUG(11,"ifadate returns %o\n", g); 89018619Sralph if (g != FAIL) { 89118619Sralph ret = SUCCESS; 89218619Sralph if (g > MaxGrade) 89318619Sralph MaxGrade = g; 89418619Sralph } 89523596Sbloom if (np) 89623596Sbloom *np = ','; 89723596Sbloom p = np + 1; 89823596Sbloom } while (np); 89923596Sbloom if (MaxGrade == '\0') 90023596Sbloom MaxGrade = DefMaxGrade; 90118619Sralph return ret; 90213642Ssam } 90313642Ssam 90418619Sralph /* 90518619Sralph * this routine will check a string (string) 90613642Ssam * like "MoTu0800-1730" to see if the present 90713642Ssam * time is within the given limits. 90813642Ssam * SIDE EFFECT - Retrytime is set 90913642Ssam * 91013642Ssam * return codes: 91113642Ssam * 0 - not within limits 91213642Ssam * 1 - within limits 91313642Ssam */ 91413642Ssam 91518619Sralph ifadate(string) 91618619Sralph char *string; 91713642Ssam { 91813642Ssam static char *days[]={ 91913642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 92013642Ssam }; 92113642Ssam time_t clock; 92218619Sralph register char *s = string; 92317834Sralph int i, tl, th, tn, dayok=0; 92413642Ssam struct tm *localtime(); 92513642Ssam struct tm *tp; 92618619Sralph char *p, MGrade; 92713642Ssam 92823596Sbloom if ((p = index(s, '/')) == NULL) 92918619Sralph MGrade = DefMaxGrade; 93018619Sralph else 93118619Sralph MGrade = p[1]; 93218619Sralph 93313642Ssam time(&clock); 93413642Ssam tp = localtime(&clock); 93517834Sralph while (isascii(*s) && isalpha(*s)) { 93613642Ssam for (i = 0; days[i]; i++) { 93713642Ssam if (prefix(days[i], s)) 93813642Ssam if (tp->tm_wday == i) 93913642Ssam dayok = 1; 94013642Ssam } 94113642Ssam 94213642Ssam if (prefix("Wk", s)) 94313642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 94413642Ssam dayok = 1; 94513642Ssam if (prefix("Any", s)) 94613642Ssam dayok = 1; 94717834Sralph if (prefix("Evening", s)) { 94817834Sralph /* Sat or Sun */ 94917834Sralph if (tp->tm_wday == 6 || tp->tm_wday == 0 95017834Sralph || tp->tm_hour >= 17 || tp->tm_hour < 8) 95117834Sralph dayok = 1; 95217834Sralph } 95317834Sralph if (prefix("Night", s)) { 95417834Sralph if (tp->tm_wday == 6 /* Sat */ 95518619Sralph || tp->tm_hour >= 23 || tp->tm_hour < 8 95618619Sralph /* Sunday before 5pm */ 95718619Sralph || (tp->tm_wday == 0 && tp->tm_hour < 17)) 95817834Sralph dayok = 1; 95917834Sralph } 96025705Sbloom if (prefix("NonPeak", s)) { /* For Tymnet and PC Pursuit */ 96125705Sbloom /* Sat or Sun */ 96225705Sbloom if (tp->tm_wday == 6 || tp->tm_wday == 0 96325705Sbloom || tp->tm_hour >= 18 || tp->tm_hour < 7) 96425705Sbloom dayok = 1; 96525705Sbloom } 96613642Ssam s++; 96713642Ssam } 96813642Ssam 96918619Sralph if (dayok == 0 && s != string) 97018619Sralph return FAIL; 97113642Ssam i = sscanf(s, "%d-%d", &tl, &th); 97218619Sralph if (i < 2) 97318619Sralph return MGrade; 97418619Sralph tn = tp->tm_hour * 100 + tp->tm_min; 97518619Sralph if (th < tl) { /* crosses midnight */ 97618619Sralph if (tl <= tn || tn < th) 97718619Sralph return MGrade; 97825966Sbloom } else { 97917834Sralph if (tl <= tn && tn < th) 98018619Sralph return MGrade; 98125966Sbloom } 98218619Sralph return FAIL; 98313642Ssam } 98413642Ssam 98518619Sralph /* 98618619Sralph * find first digit in string 98713642Ssam * 98813642Ssam * return - pointer to first digit in string or end of string 98913642Ssam */ 99013642Ssam char * 99113642Ssam fdig(cp) 99213642Ssam register char *cp; 99313642Ssam { 99413642Ssam register char *c; 99513642Ssam 99613642Ssam for (c = cp; *c; c++) 99713642Ssam if (*c >= '0' && *c <= '9') 99813642Ssam break; 99917834Sralph return c; 100013642Ssam } 100113642Ssam 100213642Ssam /* 100313642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 100413642Ssam * Strings are compared as if they contain all capital letters. 100513642Ssam */ 100613642Ssam snccmp(s1, s2) 100713642Ssam register char *s1, *s2; 100813642Ssam { 100913642Ssam char c1, c2; 101013642Ssam 101125127Sbloom if (islower(*s1)) 101225127Sbloom c1 = toupper(*s1); 101325127Sbloom else 101425127Sbloom c1 = *s1; 101525127Sbloom if (islower(*s2)) 101625127Sbloom c2 = toupper(*s2); 101725127Sbloom else 101825127Sbloom c2 = *s2; 101913642Ssam 102013642Ssam while (c1 == c2) { 102125127Sbloom if (*s1++ == '\0') 102217834Sralph return 0; 102313642Ssam s2++; 102425127Sbloom if (islower(*s1)) 102525127Sbloom c1 = toupper(*s1); 102625127Sbloom else 102725127Sbloom c1 = *s1; 102825127Sbloom if (islower(*s2)) 102925127Sbloom c2 = toupper(*s2); 103025127Sbloom else 103125127Sbloom c2 = *s2; 103213642Ssam } 103317834Sralph return c1 - c2; 103413642Ssam } 103525127Sbloom 103617834Sralph /* 103725127Sbloom * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 103825127Sbloom * Strings are compared as if they contain all capital letters. 103925127Sbloom */ 104025127Sbloom sncncmp(s1, s2, n) 104125127Sbloom register char *s1, *s2; 104225127Sbloom register int n; 104325127Sbloom { 104425127Sbloom char c1, c2; 104525127Sbloom 104625127Sbloom if (islower(*s1)) 104725127Sbloom c1 = toupper(*s1); 104825127Sbloom else 104925127Sbloom c1 = *s1; 105025127Sbloom if (islower(*s2)) 105125127Sbloom c2 = toupper(*s2); 105225127Sbloom else 105325127Sbloom c2 = *s2; 105425127Sbloom 105525127Sbloom while ( --n >= 0 && c1 == c2) { 105625127Sbloom if (*s1++ == '\0') 105725127Sbloom return 0; 105825127Sbloom s2++; 105925127Sbloom if (islower(*s1)) 106025127Sbloom c1 = toupper(*s1); 106125127Sbloom else 106225127Sbloom c1 = *s1; 106325127Sbloom if (islower(*s2)) 106425127Sbloom c2 = toupper(*s2); 106525127Sbloom else 106625127Sbloom c2 = *s2; 106725127Sbloom } 106825127Sbloom return n<0 ? 0 : (c1 - c2); 106925127Sbloom } 107025127Sbloom /* 107117834Sralph * do chat script 107217834Sralph * occurs after local port is opened, 107317834Sralph * before 'dialing' the other machine. 107417834Sralph */ 107517834Sralph dochat(dev, flds, fd) 107617834Sralph register struct Devices *dev; 107717834Sralph char *flds[]; 107817834Sralph int fd; 107917834Sralph { 108017834Sralph register int i; 108117834Sralph register char *p; 108217834Sralph char bfr[sizeof(dev->D_argbfr)]; 108317834Sralph 108417834Sralph if (dev->D_numargs <= 5) 108517834Sralph return(0); 108617834Sralph DEBUG(4, "dochat called %d\n", dev->D_numargs); 108717834Sralph for (i = 0; i < dev->D_numargs-5; i++) { 108817834Sralph sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); 108917834Sralph if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { 109017834Sralph p = malloc((unsigned)strlen(bfr)+1); 109117834Sralph if (p != NULL) { 109217834Sralph strcpy(p, bfr); 109317834Sralph dev->D_arg[D_CHAT+i] = p; 109417834Sralph } 109517834Sralph } 109617834Sralph } 109717834Sralph /* following is a kludge because login() arglist is a kludge */ 109817834Sralph i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); 109917834Sralph /* 110017834Sralph * If login() last did a sendthem(), must pause so things can settle. 110117834Sralph * But don't bother if chat failed. 110217834Sralph */ 110317834Sralph if (i == 0 && (dev->D_numargs&01)) 110417834Sralph sleep(2); 110517834Sralph return(i); 110617834Sralph } 110725705Sbloom 110825705Sbloom /* 110925705Sbloom * fix kill/echo/raw on line 111025705Sbloom * 111125705Sbloom * return codes: none 111225705Sbloom */ 111325705Sbloom fixmode(tty) 111425705Sbloom register int tty; 111525705Sbloom { 111625705Sbloom #ifdef USG 111725705Sbloom struct termio ttbuf; 111825705Sbloom #else !USG 111925705Sbloom struct sgttyb ttbuf; 112025705Sbloom #endif !USG 112125705Sbloom register struct sg_spds *ps; 112225705Sbloom int speed; 112325705Sbloom 112425705Sbloom if (IsTcpIp) 112525705Sbloom return; 112625705Sbloom #ifdef USG 112725705Sbloom ioctl(tty, TCGETA, &ttbuf); 112825705Sbloom ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0; 112925705Sbloom speed = ttbuf.c_cflag &= (CBAUD); 113025705Sbloom ttbuf.c_cflag |= (CS8|CREAD); 113125705Sbloom ttbuf.c_cc[VMIN] = 6; 113225705Sbloom ttbuf.c_cc[VTIME] = 1; 113325705Sbloom ioctl(tty, TCSETA, &ttbuf); 113425705Sbloom #else !USG 113525705Sbloom ioctl(tty, TIOCGETP, &ttbuf); 113625705Sbloom ttbuf.sg_flags = (ANYP | RAW); 113725705Sbloom ioctl(tty, TIOCSETP, &ttbuf); 113825705Sbloom speed = ttbuf.sg_ispeed; 113925705Sbloom ioctl(tty, TIOCEXCL, STBNULL); 114025705Sbloom #endif !USG 114125705Sbloom 114225705Sbloom for (ps = spds; ps->sp_val; ps++) 114325705Sbloom if (ps->sp_name == speed) { 114425705Sbloom linebaudrate = ps->sp_val; 114525705Sbloom DEBUG(9,"Incoming baudrate is %d\n", linebaudrate); 114625705Sbloom return; 114725705Sbloom } 114825705Sbloom ASSERT(linebaudrate >= 0, "BAD SPEED", CNULL, speed); 114925705Sbloom } 115025705Sbloom 1151