1 1.63 joerg /* $NetBSD: tip.c,v 1.63 2020/04/23 00:35:14 joerg Exp $ */ 2 1.6 jtc 3 1.1 cgd /* 4 1.6 jtc * Copyright (c) 1983, 1993 5 1.6 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.24 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.15 lukem #include <sys/cdefs.h> 33 1.47 hubertf #include <ctype.h> 34 1.48 hubertf #include <libgen.h> 35 1.44 jdc 36 1.1 cgd #ifndef lint 37 1.49 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 38 1.49 lukem The Regents of the University of California. All rights reserved."); 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #ifndef lint 42 1.6 jtc #if 0 43 1.6 jtc static char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93"; 44 1.6 jtc #endif 45 1.63 joerg __RCSID("$NetBSD: tip.c,v 1.63 2020/04/23 00:35:14 joerg Exp $"); 46 1.1 cgd #endif /* not lint */ 47 1.1 cgd 48 1.1 cgd /* 49 1.1 cgd * tip - UNIX link to other systems 50 1.1 cgd * tip [-v] [-speed] system-name 51 1.1 cgd * or 52 1.44 jdc * cu [options] [phone-number|"dir"] 53 1.1 cgd */ 54 1.1 cgd #include "tip.h" 55 1.1 cgd #include "pathnames.h" 56 1.1 cgd 57 1.63 joerg struct termios term; 58 1.63 joerg struct termios defterm; 59 1.63 joerg struct termios defchars; 60 1.63 joerg 61 1.63 joerg FILE *fscript; 62 1.63 joerg 63 1.63 joerg int attndes[2]; 64 1.63 joerg int fildes[2]; 65 1.63 joerg int repdes[2]; 66 1.63 joerg int FD; 67 1.63 joerg #ifndef __lint__ /* not used by hayes.c, but used by some other dialers */ 68 1.63 joerg int AC; 69 1.63 joerg #endif /*__lint__*/ 70 1.63 joerg int sfd; 71 1.63 joerg int pid; 72 1.63 joerg uid_t uid, euid; 73 1.63 joerg gid_t gid, egid; 74 1.63 joerg int stop; 75 1.63 joerg int quit; 76 1.63 joerg int stoprompt; 77 1.63 joerg int timedout; 78 1.63 joerg int cumode; 79 1.63 joerg int bits8; 80 1.63 joerg #define STRIP_PAR (bits8 ? 0377 : 0177) 81 1.63 joerg 82 1.63 joerg char fname[80]; 83 1.63 joerg char copyname[80]; 84 1.63 joerg char ccc; 85 1.63 joerg 86 1.63 joerg int odisc; 87 1.63 joerg int vflag; 88 1.63 joerg 89 1.63 joerg char *DV; 90 1.63 joerg char *EL; 91 1.63 joerg char *CM; 92 1.63 joerg char *IE; 93 1.63 joerg char *OE; 94 1.63 joerg char *CU; 95 1.63 joerg char *AT; 96 1.63 joerg char *PN; 97 1.63 joerg char *DI; 98 1.63 joerg char *PA; 99 1.63 joerg 100 1.63 joerg char *PH; 101 1.63 joerg char *RM; 102 1.63 joerg char *HO; 103 1.63 joerg 104 1.63 joerg long BR; 105 1.63 joerg long FS; 106 1.63 joerg 107 1.63 joerg long DU; 108 1.63 joerg long HW; 109 1.63 joerg char *ES; 110 1.63 joerg char *EX; 111 1.63 joerg char *FO; 112 1.63 joerg char *RC; 113 1.63 joerg char *RE; 114 1.63 joerg char *PR; 115 1.63 joerg long DL; 116 1.63 joerg long CL; 117 1.63 joerg long ET; 118 1.63 joerg long HD; 119 1.63 joerg char DC; 120 1.63 joerg 121 1.51 joerg __dead static void tipusage(void); 122 1.44 jdc 123 1.35 perry int escape(void); 124 1.51 joerg __dead static void intprompt(int); 125 1.51 joerg __dead static void tipin(void); 126 1.15 lukem 127 1.1 cgd char PNbuf[256]; /* This limits the size of a number */ 128 1.1 cgd 129 1.26 christos static char path_phones[] = _PATH_PHONES; 130 1.26 christos 131 1.15 lukem int 132 1.35 perry main(int argc, char *argv[]) 133 1.1 cgd { 134 1.25 christos char *System = NULL; 135 1.44 jdc int c, i; 136 1.15 lukem char *p; 137 1.25 christos const char *q; 138 1.1 cgd char sbuf[12]; 139 1.55 dholland int cmdlineBR; 140 1.18 mellon int fcarg; 141 1.1 cgd 142 1.53 christos setprogname(argv[0]); 143 1.1 cgd gid = getgid(); 144 1.1 cgd egid = getegid(); 145 1.1 cgd uid = getuid(); 146 1.1 cgd euid = geteuid(); 147 1.53 christos if (strcmp(getprogname(), "cu") == 0) { 148 1.1 cgd cumode = 1; 149 1.1 cgd cumain(argc, argv); 150 1.1 cgd goto cucommon; 151 1.1 cgd } 152 1.1 cgd 153 1.58 christos if (argc > 4) 154 1.44 jdc tipusage(); 155 1.58 christos 156 1.58 christos if (!isatty(0)) 157 1.58 christos errx(EXIT_FAILURE, "must be interactive"); 158 1.1 cgd 159 1.55 dholland cmdlineBR = 0; 160 1.44 jdc while((c = getopt(argc, argv, "v0123456789")) != -1) { 161 1.44 jdc switch(c) { 162 1.1 cgd 163 1.1 cgd case 'v': 164 1.1 cgd vflag++; 165 1.1 cgd break; 166 1.1 cgd 167 1.1 cgd case '0': case '1': case '2': case '3': case '4': 168 1.1 cgd case '5': case '6': case '7': case '8': case '9': 169 1.55 dholland cmdlineBR = cmdlineBR * 10 + (c - '0'); 170 1.55 dholland BR = cmdlineBR; 171 1.1 cgd break; 172 1.1 cgd 173 1.1 cgd default: 174 1.32 tls warnx("%s, unknown option", argv[1]); 175 1.1 cgd break; 176 1.1 cgd } 177 1.1 cgd } 178 1.1 cgd 179 1.44 jdc argc -= optind; 180 1.44 jdc argv += optind; 181 1.44 jdc 182 1.44 jdc if (argc != 1) 183 1.44 jdc tipusage(); 184 1.44 jdc else 185 1.44 jdc System = argv[0]; 186 1.44 jdc 187 1.44 jdc 188 1.25 christos if (System == NULL) 189 1.1 cgd goto notnumber; 190 1.25 christos if (isalpha((unsigned char)*System)) 191 1.1 cgd goto notnumber; 192 1.1 cgd /* 193 1.1 cgd * System name is really a phone number... 194 1.1 cgd * Copy the number then stomp on the original (in case the number 195 1.1 cgd * is private, we don't want 'ps' or 'w' to find it). 196 1.1 cgd */ 197 1.25 christos if (strlen(System) > sizeof PNbuf - 1) { 198 1.32 tls errx(1, "phone number too long (max = %d bytes)", 199 1.17 mrg (int)sizeof(PNbuf) - 1); 200 1.1 cgd } 201 1.27 jrf (void)strlcpy(PNbuf, System, sizeof(PNbuf)); 202 1.25 christos for (p = System; *p; p++) 203 1.1 cgd *p = '\0'; 204 1.1 cgd PN = PNbuf; 205 1.15 lukem (void)snprintf(sbuf, sizeof sbuf, "tip%d", (int)BR); 206 1.25 christos System = sbuf; 207 1.1 cgd 208 1.1 cgd notnumber: 209 1.1 cgd (void)signal(SIGINT, cleanup); 210 1.1 cgd (void)signal(SIGQUIT, cleanup); 211 1.1 cgd (void)signal(SIGHUP, cleanup); 212 1.1 cgd (void)signal(SIGTERM, cleanup); 213 1.1 cgd 214 1.25 christos if ((i = hunt(System)) == 0) { 215 1.57 christos errx(3, "all ports busy"); 216 1.1 cgd } 217 1.1 cgd if (i == -1) { 218 1.57 christos errx(3, "link down"); 219 1.1 cgd } 220 1.1 cgd setbuf(stdout, NULL); 221 1.1 cgd 222 1.1 cgd /* 223 1.1 cgd * Kludge, their's no easy way to get the initialization 224 1.1 cgd * in the right order, so force it here 225 1.1 cgd */ 226 1.15 lukem if ((PH = getenv("PHONES")) == NULL) 227 1.26 christos PH = path_phones; 228 1.1 cgd vinit(); /* init variables */ 229 1.31 tls setparity("none"); /* set the parity table */ 230 1.1 cgd 231 1.1 cgd /* 232 1.1 cgd * Hardwired connections require the 233 1.1 cgd * line speed set before they make any transmissions 234 1.1 cgd * (this is particularly true of things like a DF03-AC) 235 1.1 cgd */ 236 1.33 tls if (HW) { 237 1.40 yamt if (ttysetup((speed_t)number(value(BAUDRATE))) != 0) { 238 1.36 perry errx(3, "bad baud rate %d", 239 1.33 tls (int)number(value(BAUDRATE))); 240 1.33 tls } 241 1.33 tls } 242 1.46 christos if ((q = tip_connect()) != NULL) { 243 1.57 christos errx(1, "\07%s\n[EOT]", q); 244 1.1 cgd } 245 1.33 tls if (!HW) { 246 1.40 yamt if (ttysetup((speed_t)number(value(BAUDRATE))) != 0) { 247 1.36 perry errx(3, "bad baud rate %d", 248 1.33 tls (int)number(value(BAUDRATE))); 249 1.33 tls } 250 1.33 tls } 251 1.35 perry 252 1.18 mellon 253 1.41 tls cucommon: 254 1.41 tls /* 255 1.41 tls * From here down the code is shared with 256 1.41 tls * the "cu" version of tip. 257 1.41 tls */ 258 1.41 tls 259 1.19 mellon /* 260 1.19 mellon * Direct connections with no carrier require using O_NONBLOCK on 261 1.19 mellon * open, but we don't want to keep O_NONBLOCK after open because it 262 1.19 mellon * will cause busy waits. 263 1.19 mellon */ 264 1.19 mellon if (DC && 265 1.19 mellon ((fcarg = fcntl(FD, F_GETFL, 0)) < 0 || 266 1.19 mellon fcntl(FD, F_SETFL, fcarg & ~O_NONBLOCK) < 0)) { 267 1.36 perry err(1, "can't clear O_NONBLOCK"); 268 1.18 mellon } 269 1.35 perry 270 1.46 christos (void)tcgetattr(0, &defterm); 271 1.8 pk term = defterm; 272 1.8 pk term.c_lflag &= ~(ICANON|IEXTEN|ECHO); 273 1.8 pk term.c_iflag &= ~(INPCK|ICRNL); 274 1.8 pk term.c_oflag &= ~OPOST; 275 1.8 pk term.c_cc[VMIN] = 1; 276 1.8 pk term.c_cc[VTIME] = 0; 277 1.8 pk defchars = term; 278 1.8 pk term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] = 279 1.35 perry term.c_cc[VDSUSP] = term.c_cc[VDISCARD] = 280 1.8 pk term.c_cc[VLNEXT] = _POSIX_VDISABLE; 281 1.1 cgd raw(); 282 1.1 cgd 283 1.46 christos (void)pipe(attndes); 284 1.46 christos (void)pipe(fildes); 285 1.46 christos (void)pipe(repdes); 286 1.15 lukem (void)signal(SIGALRM, alrmtimeout); 287 1.1 cgd 288 1.1 cgd /* 289 1.1 cgd * Everything's set up now: 290 1.1 cgd * connection established (hardwired or dialup) 291 1.1 cgd * line conditioned (baud rate, mode, etc.) 292 1.1 cgd * internal data structures (variables) 293 1.1 cgd * so, fork one process for local side and one for remote. 294 1.1 cgd */ 295 1.46 christos (void)printf("%s", cumode ? "Connected\r\n" : "\07connected\r\n"); 296 1.15 lukem switch (pid = fork()) { 297 1.15 lukem default: 298 1.1 cgd tipin(); 299 1.15 lukem break; 300 1.15 lukem case 0: 301 1.1 cgd tipout(); 302 1.15 lukem break; 303 1.15 lukem case -1: 304 1.15 lukem err(1, "can't fork"); 305 1.15 lukem } 306 1.1 cgd /*NOTREACHED*/ 307 1.15 lukem exit(0); /* XXX: pacify gcc */ 308 1.1 cgd } 309 1.1 cgd 310 1.1 cgd void 311 1.44 jdc tipusage(void) 312 1.44 jdc { 313 1.46 christos (void)fprintf(stderr, "usage: %s [-v] [-speed] system-name\n", 314 1.44 jdc getprogname()); 315 1.46 christos (void)fprintf(stderr, " %s [-v] [-speed] phone-number\n", 316 1.44 jdc getprogname()); 317 1.44 jdc exit(1); 318 1.44 jdc } 319 1.44 jdc 320 1.44 jdc void 321 1.39 christos /*ARGSUSED*/ 322 1.46 christos cleanup(int dummy __unused) 323 1.1 cgd { 324 1.1 cgd 325 1.1 cgd if (odisc) 326 1.46 christos (void)ioctl(0, TIOCSETD, &odisc); 327 1.56 gson _exit(0); 328 1.1 cgd } 329 1.1 cgd 330 1.1 cgd /* 331 1.1 cgd * put the controlling keyboard into raw mode 332 1.1 cgd */ 333 1.15 lukem void 334 1.35 perry raw(void) 335 1.1 cgd { 336 1.21 mrg 337 1.46 christos (void)tcsetattr(0, TCSADRAIN, &term); 338 1.1 cgd } 339 1.1 cgd 340 1.1 cgd 341 1.1 cgd /* 342 1.1 cgd * return keyboard to normal mode 343 1.1 cgd */ 344 1.15 lukem void 345 1.35 perry unraw(void) 346 1.1 cgd { 347 1.21 mrg 348 1.46 christos (void)tcsetattr(0, TCSADRAIN, &defterm); 349 1.1 cgd } 350 1.1 cgd 351 1.1 cgd static jmp_buf promptbuf; 352 1.1 cgd 353 1.1 cgd /* 354 1.1 cgd * Print string ``s'', then read a string 355 1.1 cgd * in from the terminal. Handles signals & allows use of 356 1.1 cgd * normal erase and kill characters. 357 1.1 cgd */ 358 1.15 lukem int 359 1.45 christos prompt(const char *s, char *volatile p, size_t l) 360 1.1 cgd { 361 1.15 lukem int c; 362 1.15 lukem char *b = p; 363 1.1 cgd sig_t oint, oquit; 364 1.1 cgd 365 1.1 cgd stoprompt = 0; 366 1.1 cgd oint = signal(SIGINT, intprompt); 367 1.1 cgd oquit = signal(SIGQUIT, SIG_IGN); 368 1.1 cgd unraw(); 369 1.46 christos (void)printf("%s", s); 370 1.1 cgd if (setjmp(promptbuf) == 0) 371 1.61 uwe while ((c = getchar()) != EOF && (*p = c) != '\n' && 372 1.21 mrg b + l > p) 373 1.1 cgd p++; 374 1.1 cgd *p = '\0'; 375 1.1 cgd 376 1.1 cgd raw(); 377 1.1 cgd (void)signal(SIGINT, oint); 378 1.1 cgd (void)signal(SIGQUIT, oquit); 379 1.1 cgd return (stoprompt || p == b); 380 1.1 cgd } 381 1.1 cgd 382 1.1 cgd /* 383 1.1 cgd * Interrupt service routine during prompting 384 1.1 cgd */ 385 1.51 joerg static void 386 1.39 christos /*ARGSUSED*/ 387 1.46 christos intprompt(int dummy __unused) 388 1.1 cgd { 389 1.1 cgd 390 1.1 cgd (void)signal(SIGINT, SIG_IGN); 391 1.1 cgd stoprompt = 1; 392 1.46 christos (void)printf("\r\n"); 393 1.1 cgd longjmp(promptbuf, 1); 394 1.1 cgd } 395 1.1 cgd 396 1.1 cgd /* 397 1.61 uwe * getchar() wrapper that checks for EOF on the local end. 398 1.61 uwe */ 399 1.62 gson static int 400 1.61 uwe xgetchar(void) 401 1.61 uwe { 402 1.61 uwe int c = getchar(); 403 1.61 uwe if (__predict_false(c == EOF)) { 404 1.61 uwe cleanup(SIGHUP); 405 1.61 uwe /* NOTREACHED */ 406 1.61 uwe } 407 1.61 uwe 408 1.62 gson return c & STRIP_PAR; 409 1.61 uwe } 410 1.61 uwe 411 1.61 uwe 412 1.61 uwe /* 413 1.1 cgd * ****TIPIN TIPIN**** 414 1.1 cgd */ 415 1.51 joerg static void 416 1.35 perry tipin(void) 417 1.1 cgd { 418 1.1 cgd char gch, bol = 1; 419 1.1 cgd 420 1.1 cgd /* 421 1.1 cgd * Kinda klugey here... 422 1.1 cgd * check for scripting being turned on from the .tiprc file, 423 1.1 cgd * but be careful about just using setscript(), as we may 424 1.1 cgd * send a SIGEMT before tipout has a chance to set up catching 425 1.1 cgd * it; so wait a second, then setscript() 426 1.1 cgd */ 427 1.1 cgd if (boolean(value(SCRIPT))) { 428 1.46 christos (void)sleep(1); 429 1.1 cgd setscript(); 430 1.1 cgd } 431 1.1 cgd 432 1.39 christos for (;;) { 433 1.61 uwe gch = xgetchar(); 434 1.1 cgd if ((gch == character(value(ESCAPE))) && bol) { 435 1.1 cgd if (!(gch = escape())) 436 1.1 cgd continue; 437 1.35 perry } else if (!cumode && 438 1.16 lukem gch && gch == character(value(RAISECHAR))) { 439 1.9 cgd setboolean(value(RAISE), !boolean(value(RAISE))); 440 1.1 cgd continue; 441 1.60 rin } else if (gch == '\r' || gch == '\n') { 442 1.1 cgd bol = 1; 443 1.20 thorpej xpwrite(FD, &gch, 1); 444 1.1 cgd if (boolean(value(HALFDUPLEX))) 445 1.60 rin (void)printf("%s\n", gch == '\r' ? "\r" : ""); 446 1.1 cgd continue; 447 1.16 lukem } else if (!cumode && gch && gch == character(value(FORCE))) 448 1.61 uwe gch = xgetchar(); 449 1.1 cgd bol = any(gch, value(EOL)); 450 1.22 christos if (boolean(value(RAISE)) && islower((unsigned char)gch)) 451 1.28 dsl gch = toupper((unsigned char)gch); 452 1.20 thorpej xpwrite(FD, &gch, 1); 453 1.1 cgd if (boolean(value(HALFDUPLEX))) 454 1.46 christos (void)printf("%c", gch); 455 1.1 cgd } 456 1.1 cgd } 457 1.1 cgd 458 1.1 cgd /* 459 1.1 cgd * Escape handler -- 460 1.1 cgd * called on recognition of ``escapec'' at the beginning of a line 461 1.1 cgd */ 462 1.15 lukem int 463 1.35 perry escape(void) 464 1.1 cgd { 465 1.15 lukem char gch; 466 1.15 lukem esctable_t *p; 467 1.1 cgd char c = character(value(ESCAPE)); 468 1.1 cgd 469 1.61 uwe gch = xgetchar(); 470 1.1 cgd for (p = etable; p->e_char; p++) 471 1.1 cgd if (p->e_char == gch) { 472 1.1 cgd if ((p->e_flags&PRIV) && uid) 473 1.1 cgd continue; 474 1.46 christos (void)printf("%s", ctrl(c)); 475 1.1 cgd (*p->e_func)(gch); 476 1.1 cgd return (0); 477 1.1 cgd } 478 1.1 cgd /* ESCAPE ESCAPE forces ESCAPE */ 479 1.1 cgd if (c != gch) 480 1.20 thorpej xpwrite(FD, &c, 1); 481 1.1 cgd return (gch); 482 1.1 cgd } 483 1.1 cgd 484 1.15 lukem int 485 1.35 perry any(char c, const char *p) 486 1.1 cgd { 487 1.21 mrg 488 1.1 cgd while (p && *p) 489 1.1 cgd if (*p++ == c) 490 1.1 cgd return (1); 491 1.1 cgd return (0); 492 1.1 cgd } 493 1.1 cgd 494 1.1 cgd char * 495 1.35 perry interp(const char *s) 496 1.1 cgd { 497 1.1 cgd static char buf[256]; 498 1.25 christos char *p = buf, c; 499 1.25 christos const char *q; 500 1.1 cgd 501 1.21 mrg while ((c = *s++) != 0 && buf + sizeof buf - p > 2) { 502 1.1 cgd for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 503 1.1 cgd if (*q++ == c) { 504 1.1 cgd *p++ = '\\'; *p++ = *q; 505 1.1 cgd goto next; 506 1.1 cgd } 507 1.1 cgd if (c < 040) { 508 1.1 cgd *p++ = '^'; *p++ = c + 'A'-1; 509 1.1 cgd } else if (c == 0177) { 510 1.1 cgd *p++ = '^'; *p++ = '?'; 511 1.1 cgd } else 512 1.1 cgd *p++ = c; 513 1.1 cgd next: 514 1.1 cgd ; 515 1.1 cgd } 516 1.1 cgd *p = '\0'; 517 1.1 cgd return (buf); 518 1.1 cgd } 519 1.1 cgd 520 1.1 cgd char * 521 1.35 perry ctrl(char c) 522 1.1 cgd { 523 1.1 cgd static char s[3]; 524 1.1 cgd 525 1.1 cgd if (c < 040 || c == 0177) { 526 1.1 cgd s[0] = '^'; 527 1.1 cgd s[1] = c == 0177 ? '?' : c+'A'-1; 528 1.1 cgd s[2] = '\0'; 529 1.1 cgd } else { 530 1.1 cgd s[0] = c; 531 1.1 cgd s[1] = '\0'; 532 1.1 cgd } 533 1.1 cgd return (s); 534 1.1 cgd } 535 1.1 cgd 536 1.1 cgd /* 537 1.1 cgd * Help command 538 1.1 cgd */ 539 1.15 lukem void 540 1.35 perry help(char c) 541 1.1 cgd { 542 1.15 lukem esctable_t *p; 543 1.1 cgd 544 1.46 christos (void)printf("%c\r\n", c); 545 1.1 cgd for (p = etable; p->e_char; p++) { 546 1.1 cgd if ((p->e_flags&PRIV) && uid) 547 1.1 cgd continue; 548 1.46 christos (void)printf("%2s", ctrl(character(value(ESCAPE)))); 549 1.46 christos (void)printf("%-2s %c %s\r\n", ctrl(p->e_char), 550 1.1 cgd p->e_flags&EXP ? '*': ' ', p->e_help); 551 1.1 cgd } 552 1.1 cgd } 553 1.1 cgd 554 1.1 cgd /* 555 1.1 cgd * Set up the "remote" tty's state 556 1.1 cgd */ 557 1.33 tls int 558 1.39 christos ttysetup(speed_t spd) 559 1.1 cgd { 560 1.8 pk struct termios cntrl; 561 1.1 cgd 562 1.46 christos (void)tcgetattr(FD, &cntrl); 563 1.46 christos (void)cfsetospeed(&cntrl, spd); 564 1.46 christos (void)cfsetispeed(&cntrl, spd); 565 1.8 pk cntrl.c_cflag &= ~(CSIZE|PARENB); 566 1.8 pk cntrl.c_cflag |= CS8; 567 1.14 mellon if (DC) 568 1.13 mellon cntrl.c_cflag |= CLOCAL; 569 1.29 yamt if (boolean(value(HARDWAREFLOW))) 570 1.35 perry cntrl.c_cflag |= CRTSCTS; 571 1.8 pk cntrl.c_iflag &= ~(ISTRIP|ICRNL); 572 1.8 pk cntrl.c_oflag &= ~OPOST; 573 1.8 pk cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); 574 1.8 pk cntrl.c_cc[VMIN] = 1; 575 1.8 pk cntrl.c_cc[VTIME] = 0; 576 1.1 cgd if (boolean(value(TAND))) 577 1.54 mlelstv cntrl.c_iflag |= IXOFF|IXON; 578 1.52 christos else 579 1.54 mlelstv cntrl.c_iflag &= ~(IXOFF|IXON); 580 1.46 christos return tcsetattr(FD, TCSAFLUSH, &cntrl); 581 1.1 cgd } 582 1.1 cgd 583 1.1 cgd static char partab[0200]; 584 1.1 cgd 585 1.1 cgd /* 586 1.1 cgd * Do a write to the remote machine with the correct parity. 587 1.1 cgd * We are doing 8 bit wide output, so we just generate a character 588 1.1 cgd * with the right parity and output it. 589 1.1 cgd */ 590 1.15 lukem void 591 1.38 perry xpwrite(int fd, char *buf, size_t n) 592 1.1 cgd { 593 1.50 lukem size_t i; 594 1.15 lukem char *bp; 595 1.1 cgd 596 1.1 cgd bp = buf; 597 1.6 jtc if (bits8 == 0) 598 1.6 jtc for (i = 0; i < n; i++) { 599 1.6 jtc *bp = partab[(*bp) & 0177]; 600 1.6 jtc bp++; 601 1.1 cgd } 602 1.6 jtc if (write(fd, buf, n) < 0) { 603 1.1 cgd if (errno == EIO) 604 1.1 cgd tipabort("Lost carrier."); 605 1.1 cgd /* this is questionable */ 606 1.32 tls warn("write"); 607 1.1 cgd } 608 1.1 cgd } 609 1.1 cgd 610 1.1 cgd /* 611 1.1 cgd * Build a parity table with appropriate high-order bit. 612 1.1 cgd */ 613 1.15 lukem void 614 1.35 perry setparity(const char *defparity) 615 1.1 cgd { 616 1.15 lukem int i, flip, clr, set; 617 1.25 christos const char *parity; 618 1.26 christos static char *curpar; 619 1.1 cgd 620 1.39 christos if (value(PARITY) == NULL || ((char *)value(PARITY))[0] == '\0') { 621 1.26 christos if (curpar != NULL) 622 1.26 christos free(curpar); 623 1.26 christos value(PARITY) = curpar = strdup(defparity); 624 1.26 christos } 625 1.1 cgd parity = value(PARITY); 626 1.53 christos if (strcmp(parity, "none") == 0) { 627 1.1 cgd bits8 = 1; 628 1.1 cgd return; 629 1.1 cgd } 630 1.1 cgd bits8 = 0; 631 1.1 cgd flip = 0; 632 1.1 cgd clr = 0377; 633 1.1 cgd set = 0; 634 1.53 christos if (strcmp(parity, "odd") == 0) 635 1.1 cgd flip = 0200; /* reverse bit 7 */ 636 1.53 christos else if (strcmp(parity, "zero") == 0) 637 1.1 cgd clr = 0177; /* turn off bit 7 */ 638 1.53 christos else if (strcmp(parity, "one") == 0) 639 1.1 cgd set = 0200; /* turn on bit 7 */ 640 1.53 christos else if (strcmp(parity, "even") != 0) { 641 1.46 christos (void)fprintf(stderr, "%s: unknown parity value\r\n", parity); 642 1.46 christos (void)fflush(stderr); 643 1.1 cgd } 644 1.1 cgd for (i = 0; i < 0200; i++) 645 1.15 lukem partab[i] = ((evenpartab[i] ^ flip) | set) & clr; 646 1.1 cgd } 647