PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/cmd/mailx/tty.c

https://bitbucket.org/a3217055/illumos-2
C | 681 lines | 569 code | 44 blank | 68 comment | 160 complexity | 9af7c9e6d1529bea7ecf1f9f07643b6f MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, AGPL-3.0, BSD-3-Clause, LGPL-2.0, 0BSD, BSD-2-Clause, BSD-3-Clause-No-Nuclear-License-2014, AGPL-1.0, GPL-2.0
  1. /*
  2. * CDDL HEADER START
  3. *
  4. * The contents of this file are subject to the terms of the
  5. * Common Development and Distribution License, Version 1.0 only
  6. * (the "License"). You may not use this file except in compliance
  7. * with the License.
  8. *
  9. * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10. * or http://www.opensolaris.org/os/licensing.
  11. * See the License for the specific language governing permissions
  12. * and limitations under the License.
  13. *
  14. * When distributing Covered Code, include this CDDL HEADER in each
  15. * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16. * If applicable, add the following below this CDDL HEADER, with the
  17. * fields enclosed by brackets "[]" replaced with your own identifying
  18. * information: Portions Copyright [yyyy] [name of copyright owner]
  19. *
  20. * CDDL HEADER END
  21. */
  22. /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  23. /* All Rights Reserved */
  24. /*
  25. * University Copyright- Copyright (c) 1982, 1986, 1988
  26. * The Regents of the University of California
  27. * All Rights Reserved
  28. *
  29. * University Acknowledgment- Portions of this document are derived from
  30. * software developed by the University of California, Berkeley, and its
  31. * contributors.
  32. */
  33. #pragma ident "%Z%%M% %I% %E% SMI"
  34. /*
  35. * mailx -- a modified version of a University of California at Berkeley
  36. * mail program
  37. *
  38. * Generally useful tty stuff.
  39. */
  40. #include "rcv.h"
  41. #include <locale.h>
  42. #ifdef USG_TTY
  43. static char *readtty(char pr[], char src[]);
  44. static int savetty(void);
  45. static void ttycont(int);
  46. static int c_erase; /* Current erase char */
  47. static int c_kill; /* Current kill char */
  48. static int c_intr; /* interrupt char */
  49. static int c_quit; /* quit character */
  50. static struct termio savtty;
  51. static char canonb[LINESIZE]; /* canonical buffer for input */
  52. /* processing */
  53. #ifndef TIOCSTI
  54. static void Echo(int cc);
  55. static int countcol(void);
  56. static void outstr(register char *s);
  57. static void resetty(void);
  58. static void rubout(register char *cp);
  59. static int setty(void);
  60. static int c_word; /* Current word erase char */
  61. static int Col; /* current output column */
  62. static int Pcol; /* end column of prompt string */
  63. static int Out; /* file descriptor of stdout */
  64. static int erasing; /* we are erasing characters */
  65. static struct termio ttybuf;
  66. #else
  67. static jmp_buf rewrite; /* Place to go when continued */
  68. #endif
  69. #ifdef SIGCONT
  70. # ifdef preSVr4
  71. typedef int sig_atomic_t;
  72. # endif
  73. static sig_atomic_t hadcont; /* Saw continue signal */
  74. /*ARGSUSED*/
  75. static void
  76. #ifdef __cplusplus
  77. ttycont(int)
  78. #else
  79. /* ARGSUSED */
  80. ttycont(int s)
  81. #endif
  82. {
  83. hadcont++;
  84. longjmp(rewrite, 1);
  85. }
  86. #ifndef TIOCSTI
  87. /*ARGSUSED*/
  88. static void
  89. ttystop(int s)
  90. {
  91. resetty();
  92. kill(mypid, SIGSTOP);
  93. }
  94. #endif
  95. #endif
  96. /*
  97. * Read all relevant header fields.
  98. */
  99. int
  100. grabh(register struct header *hp, int gflags, int subjtop)
  101. {
  102. #ifdef SIGCONT
  103. void (*savecont)(int);
  104. #ifndef TIOCSTI
  105. void (*savestop)(int);
  106. #endif
  107. #endif
  108. if (savetty())
  109. return -1;
  110. #ifdef SIGCONT
  111. savecont = sigset(SIGCONT, ttycont);
  112. #ifndef TIOCSTI
  113. savestop = sigset(SIGTSTP, ttystop);
  114. #endif
  115. #endif
  116. if (gflags & GTO) {
  117. hp->h_to = addto(NOSTR, readtty("To: ", hp->h_to));
  118. if (hp->h_to != NOSTR)
  119. hp->h_seq++;
  120. }
  121. if (gflags & GSUBJECT && subjtop) {
  122. hp->h_subject = readtty("Subject: ", hp->h_subject);
  123. if (hp->h_subject != NOSTR)
  124. hp->h_seq++;
  125. }
  126. if (gflags & GCC) {
  127. hp->h_cc = addto(NOSTR, readtty("Cc: ", hp->h_cc));
  128. if (hp->h_cc != NOSTR)
  129. hp->h_seq++;
  130. }
  131. if (gflags & GBCC) {
  132. hp->h_bcc = addto(NOSTR, readtty("Bcc: ", hp->h_bcc));
  133. if (hp->h_bcc != NOSTR)
  134. hp->h_seq++;
  135. }
  136. if (gflags & GSUBJECT && !subjtop) {
  137. hp->h_subject = readtty("Subject: ", hp->h_subject);
  138. if (hp->h_subject != NOSTR)
  139. hp->h_seq++;
  140. }
  141. #ifdef SIGCONT
  142. (void) sigset(SIGCONT, savecont);
  143. #ifndef TIOCSTI
  144. (void) sigset(SIGTSTP, savestop);
  145. #endif
  146. #endif
  147. return(0);
  148. }
  149. /*
  150. * Read up a header from standard input.
  151. * The source string has the preliminary contents to
  152. * be read.
  153. *
  154. */
  155. static char *
  156. readtty(char pr[], char src[])
  157. {
  158. int c;
  159. register char *cp;
  160. #ifndef TIOCSTI
  161. register char *cp2;
  162. erasing = 0;
  163. Col = 0;
  164. outstr(pr);
  165. Pcol = Col;
  166. #else
  167. fputs(pr, stdout);
  168. #endif
  169. fflush(stdout);
  170. if (src != NOSTR && (int)strlen(src) > LINESIZE - 2) {
  171. printf(gettext("too long to edit\n"));
  172. return(src);
  173. }
  174. #ifndef TIOCSTI
  175. if (setty())
  176. return(src);
  177. cp2 = src==NOSTR ? "" : src;
  178. for (cp=canonb; *cp2; cp++, cp2++)
  179. *cp = *cp2;
  180. *cp = '\0';
  181. outstr(canonb);
  182. #else
  183. cp = src == NOSTR ? "" : src;
  184. while (c = *cp++) {
  185. char ch;
  186. if (c == c_erase || c == c_kill) {
  187. ch = '\\';
  188. ioctl(0, TIOCSTI, &ch);
  189. }
  190. ch = c;
  191. ioctl(0, TIOCSTI, &ch);
  192. }
  193. cp = canonb;
  194. *cp = 0;
  195. if (setjmp(rewrite))
  196. goto redo;
  197. #endif
  198. for (;;) {
  199. fflush(stdout);
  200. #ifdef SIGCONT
  201. hadcont = 0;
  202. #endif
  203. c = getc(stdin);
  204. #ifndef TIOCSTI
  205. if (c==c_erase) {
  206. if (cp > canonb)
  207. if (cp[-1]=='\\' && !erasing) {
  208. *cp++ = (char)c;
  209. Echo(c);
  210. } else {
  211. rubout(--cp);
  212. }
  213. } else if (c==c_kill) {
  214. if (cp > canonb && cp[-1]=='\\') {
  215. *cp++ = (char)c;
  216. Echo(c);
  217. } else while (cp > canonb) {
  218. rubout(--cp);
  219. }
  220. } else if (c==c_word) {
  221. if (cp > canonb)
  222. if (cp[-1]=='\\' && !erasing) {
  223. *cp++ = (char)c;
  224. Echo(c);
  225. } else {
  226. while (--cp >= canonb)
  227. if (!isspace(*cp))
  228. break;
  229. else
  230. rubout(cp);
  231. while (cp >= canonb)
  232. if (!isspace(*cp))
  233. rubout(cp--);
  234. else
  235. break;
  236. if (cp < canonb)
  237. cp = canonb;
  238. else if (*cp)
  239. cp++;
  240. }
  241. } else
  242. #endif
  243. if (c==EOF || ferror(stdin) || c==c_intr || c==c_quit) {
  244. #ifdef SIGCONT
  245. if (hadcont) {
  246. #ifndef TIOCSTI
  247. (void) setty();
  248. outstr("(continue)\n");
  249. Col = 0;
  250. outstr(pr);
  251. *cp = '\0';
  252. outstr(canonb);
  253. clearerr(stdin);
  254. continue;
  255. #else
  256. redo:
  257. hadcont = 0;
  258. cp = canonb[0] != 0 ? canonb : src;
  259. clearerr(stdin);
  260. return(readtty(pr, cp));
  261. #endif
  262. }
  263. #endif
  264. #ifndef TIOCSTI
  265. resetty();
  266. #endif
  267. savedead(c==c_quit? SIGQUIT: SIGINT);
  268. } else switch (c) {
  269. case '\n':
  270. case '\r':
  271. #ifndef TIOCSTI
  272. resetty();
  273. putchar('\n');
  274. fflush(stdout);
  275. #endif
  276. if (canonb[0]=='\0')
  277. return(NOSTR);
  278. return(savestr(canonb));
  279. default:
  280. *cp++ = (char)c;
  281. *cp = '\0';
  282. #ifndef TIOCSTI
  283. erasing = 0;
  284. Echo(c);
  285. #endif
  286. }
  287. }
  288. }
  289. static int
  290. savetty(void)
  291. {
  292. if (ioctl(fileno(stdout), TCGETA, &savtty) < 0)
  293. { perror("ioctl");
  294. return(-1);
  295. }
  296. c_erase = savtty.c_cc[VERASE];
  297. c_kill = savtty.c_cc[VKILL];
  298. c_intr = savtty.c_cc[VINTR];
  299. c_quit = savtty.c_cc[VQUIT];
  300. #ifndef TIOCSTI
  301. c_word = 'W' & 037; /* erase word character */
  302. Out = fileno(stdout);
  303. ttybuf = savtty;
  304. #ifdef u370
  305. ttybuf.c_cflag &= ~PARENB; /* disable parity */
  306. ttybuf.c_cflag |= CS8; /* character size = 8 */
  307. #endif /* u370 */
  308. ttybuf.c_cc[VTIME] = 0;
  309. ttybuf.c_cc[VMIN] = 1;
  310. ttybuf.c_iflag &= ~(BRKINT);
  311. ttybuf.c_lflag &= ~(ICANON|ISIG|ECHO);
  312. #endif
  313. return 0;
  314. }
  315. #ifndef TIOCSTI
  316. static int
  317. setty(void)
  318. {
  319. if (ioctl(Out, TCSETAW, &ttybuf) < 0) {
  320. perror("ioctl");
  321. return(-1);
  322. }
  323. return(0);
  324. }
  325. static void
  326. resetty(void)
  327. {
  328. if (ioctl(Out, TCSETAW, &savtty) < 0)
  329. perror("ioctl");
  330. }
  331. static void
  332. outstr(register char *s)
  333. {
  334. while (*s)
  335. Echo(*s++);
  336. }
  337. static void
  338. rubout(register char *cp)
  339. {
  340. register int oldcol;
  341. register int c = *cp;
  342. erasing = 1;
  343. *cp = '\0';
  344. switch (c) {
  345. case '\t':
  346. oldcol = countcol();
  347. do
  348. putchar('\b');
  349. while (--Col > oldcol);
  350. break;
  351. case '\b':
  352. if (isprint(cp[-1]))
  353. putchar(*(cp-1));
  354. else
  355. putchar(' ');
  356. Col++;
  357. break;
  358. default:
  359. if (isprint(c)) {
  360. fputs("\b \b", stdout);
  361. Col--;
  362. }
  363. }
  364. }
  365. static int
  366. countcol(void)
  367. {
  368. register int col;
  369. register char *s;
  370. for (col=Pcol, s=canonb; *s; s++)
  371. switch (*s) {
  372. case '\t':
  373. while (++col % 8)
  374. ;
  375. break;
  376. case '\b':
  377. col--;
  378. break;
  379. default:
  380. if (isprint(*s))
  381. col++;
  382. }
  383. return(col);
  384. }
  385. static void
  386. Echo(int cc)
  387. {
  388. char c = (char)cc;
  389. switch (c) {
  390. case '\t':
  391. do
  392. putchar(' ');
  393. while (++Col % 8);
  394. break;
  395. case '\b':
  396. if (Col > 0) {
  397. putchar('\b');
  398. Col--;
  399. }
  400. break;
  401. case '\r':
  402. case '\n':
  403. Col = 0;
  404. fputs("\r\n", stdout);
  405. break;
  406. default:
  407. if (isprint(c)) {
  408. Col++;
  409. putchar(c);
  410. }
  411. }
  412. }
  413. #endif
  414. #else
  415. #ifdef SIGCONT
  416. static void signull(int);
  417. #endif
  418. static int c_erase; /* Current erase char */
  419. static int c_kill; /* Current kill char */
  420. static int hadcont; /* Saw continue signal */
  421. static jmp_buf rewrite; /* Place to go when continued */
  422. #ifndef TIOCSTI
  423. static int ttyset; /* We must now do erase/kill */
  424. #endif
  425. /*
  426. * Read all relevant header fields.
  427. */
  428. int
  429. grabh(struct header *hp, int gflags, int subjtop)
  430. {
  431. struct sgttyb ttybuf;
  432. void (*savecont)(int);
  433. register int s;
  434. int errs;
  435. #ifndef TIOCSTI
  436. void (*savesigs[2])(int);
  437. #endif
  438. #ifdef SIGCONT
  439. savecont = sigset(SIGCONT, signull);
  440. #endif
  441. errs = 0;
  442. #ifndef TIOCSTI
  443. ttyset = 0;
  444. #endif
  445. if (gtty(fileno(stdin), &ttybuf) < 0) {
  446. perror("gtty");
  447. return(-1);
  448. }
  449. c_erase = ttybuf.sg_erase;
  450. c_kill = ttybuf.sg_kill;
  451. #ifndef TIOCSTI
  452. ttybuf.sg_erase = 0;
  453. ttybuf.sg_kill = 0;
  454. for (s = SIGINT; s <= SIGQUIT; s++)
  455. if ((savesigs[s-SIGINT] = sigset(s, SIG_IGN)) == SIG_DFL)
  456. sigset(s, SIG_DFL);
  457. #endif
  458. if (gflags & GTO) {
  459. #ifndef TIOCSTI
  460. if (!ttyset && hp->h_to != NOSTR)
  461. ttyset++, stty(fileno(stdin), &ttybuf);
  462. #endif
  463. hp->h_to = addto(NOSTR, readtty("To: ", hp->h_to));
  464. if (hp->h_to != NOSTR)
  465. hp->h_seq++;
  466. }
  467. if (gflags & GSUBJECT && subjtop) {
  468. #ifndef TIOCSTI
  469. if (!ttyset && hp->h_subject != NOSTR)
  470. ttyset++, stty(fileno(stdin), &ttybuf);
  471. #endif
  472. hp->h_subject = readtty("Subject: ", hp->h_subject);
  473. if (hp->h_subject != NOSTR)
  474. hp->h_seq++;
  475. }
  476. if (gflags & GCC) {
  477. #ifndef TIOCSTI
  478. if (!ttyset && hp->h_cc != NOSTR)
  479. ttyset++, stty(fileno(stdin), &ttybuf);
  480. #endif
  481. hp->h_cc = addto(NOSTR, readtty("Cc: ", hp->h_cc));
  482. if (hp->h_cc != NOSTR)
  483. hp->h_seq++;
  484. }
  485. if (gflags & GBCC) {
  486. #ifndef TIOCSTI
  487. if (!ttyset && hp->h_bcc != NOSTR)
  488. ttyset++, stty(fileno(stdin), &ttybuf);
  489. #endif
  490. hp->h_bcc = addto(NOSTR, readtty("Bcc: ", hp->h_bcc));
  491. if (hp->h_bcc != NOSTR)
  492. hp->h_seq++;
  493. }
  494. if (gflags & GSUBJECT && !subjtop) {
  495. #ifndef TIOCSTI
  496. if (!ttyset && hp->h_subject != NOSTR)
  497. ttyset++, stty(fileno(stdin), &ttybuf);
  498. #endif
  499. hp->h_subject = readtty("Subject: ", hp->h_subject);
  500. if (hp->h_subject != NOSTR)
  501. hp->h_seq++;
  502. }
  503. #ifdef SIGCONT
  504. sigset(SIGCONT, savecont);
  505. #endif
  506. #ifndef TIOCSTI
  507. ttybuf.sg_erase = c_erase;
  508. ttybuf.sg_kill = c_kill;
  509. if (ttyset)
  510. stty(fileno(stdin), &ttybuf);
  511. for (s = SIGINT; s <= SIGQUIT; s++)
  512. sigset(s, savesigs[s-SIGINT]);
  513. #endif
  514. return(errs);
  515. }
  516. /*
  517. * Read up a header from standard input.
  518. * The source string has the preliminary contents to
  519. * be read.
  520. *
  521. */
  522. char *
  523. readtty(char pr[], char src[])
  524. {
  525. char ch, canonb[LINESIZE];
  526. int c;
  527. register char *cp, *cp2;
  528. fputs(pr, stdout);
  529. fflush(stdout);
  530. if (src != NOSTR && strlen(src) > LINESIZE - 2) {
  531. printf(gettext("too long to edit\n"));
  532. return(src);
  533. }
  534. #ifndef TIOCSTI
  535. if (src != NOSTR)
  536. cp = copy(src, canonb);
  537. else
  538. cp = copy("", canonb);
  539. fputs(canonb, stdout);
  540. fflush(stdout);
  541. #else
  542. cp = src == NOSTR ? "" : src;
  543. while (c = *cp++) {
  544. if (c == c_erase || c == c_kill) {
  545. ch = '\\';
  546. ioctl(0, TIOCSTI, &ch);
  547. }
  548. ch = c;
  549. ioctl(0, TIOCSTI, &ch);
  550. }
  551. cp = canonb;
  552. *cp = 0;
  553. #endif
  554. cp2 = cp;
  555. while (cp2 < canonb + LINESIZE)
  556. *cp2++ = 0;
  557. cp2 = cp;
  558. if (setjmp(rewrite))
  559. goto redo;
  560. #ifdef SIGCONT
  561. sigset(SIGCONT, ttycont);
  562. #endif
  563. clearerr(stdin);
  564. while (cp2 < canonb + LINESIZE) {
  565. c = getc(stdin);
  566. if (c == EOF || c == '\n')
  567. break;
  568. *cp2++ = c;
  569. }
  570. *cp2 = 0;
  571. #ifdef SIGCONT
  572. sigset(SIGCONT, signull);
  573. #endif
  574. if (c == EOF && ferror(stdin) && hadcont) {
  575. redo:
  576. hadcont = 0;
  577. cp = strlen(canonb) > 0 ? canonb : NOSTR;
  578. clearerr(stdin);
  579. return(readtty(pr, cp));
  580. }
  581. clearerr(stdin);
  582. #ifndef TIOCSTI
  583. if (cp == NOSTR || *cp == '\0')
  584. return(src);
  585. cp2 = cp;
  586. if (!ttyset)
  587. return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR);
  588. while (*cp != '\0') {
  589. c = *cp++;
  590. if (c == c_erase) {
  591. if (cp2 == canonb)
  592. continue;
  593. if (cp2[-1] == '\\') {
  594. cp2[-1] = c;
  595. continue;
  596. }
  597. cp2--;
  598. continue;
  599. }
  600. if (c == c_kill) {
  601. if (cp2 == canonb)
  602. continue;
  603. if (cp2[-1] == '\\') {
  604. cp2[-1] = c;
  605. continue;
  606. }
  607. cp2 = canonb;
  608. continue;
  609. }
  610. *cp2++ = c;
  611. }
  612. *cp2 = '\0';
  613. #endif
  614. if (equal("", canonb))
  615. return(NOSTR);
  616. return(savestr(canonb));
  617. }
  618. #ifdef SIGCONT
  619. /*
  620. * Receipt continuation.
  621. */
  622. /*ARGSUSED*/
  623. void
  624. ttycont(int)
  625. {
  626. hadcont++;
  627. longjmp(rewrite, 1);
  628. }
  629. /*
  630. * Null routine to allow us to hold SIGCONT
  631. */
  632. /*ARGSUSED*/
  633. static void
  634. signull(int)
  635. {}
  636. #endif
  637. #endif /* USG_TTY */