/usr.bin/mail/tty.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 289 lines · 231 code · 13 blank · 45 comment · 76 complexity · adde904d37034ec58709659fd6047edd MD5 · raw file

  1. /*
  2. * Copyright (c) 1980, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #ifndef lint
  30. #if 0
  31. static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93";
  32. #endif
  33. #endif /* not lint */
  34. #include <sys/cdefs.h>
  35. __FBSDID("$FreeBSD$");
  36. /*
  37. * Mail -- a mail program
  38. *
  39. * Generally useful tty stuff.
  40. */
  41. #include "rcv.h"
  42. #include "extern.h"
  43. static cc_t c_erase; /* Current erase char */
  44. static cc_t c_kill; /* Current kill char */
  45. static jmp_buf rewrite; /* Place to go when continued */
  46. static jmp_buf intjmp; /* Place to go when interrupted */
  47. #ifndef TIOCSTI
  48. static int ttyset; /* We must now do erase/kill */
  49. #endif
  50. /*
  51. * Read all relevant header fields.
  52. */
  53. int
  54. grabh(struct header *hp, int gflags)
  55. {
  56. struct termios ttybuf;
  57. sig_t saveint;
  58. sig_t savetstp;
  59. sig_t savettou;
  60. sig_t savettin;
  61. int errs;
  62. #ifndef TIOCSTI
  63. sig_t savequit;
  64. #else
  65. # ifdef TIOCEXT
  66. int extproc, flag;
  67. # endif /* TIOCEXT */
  68. #endif /* TIOCSTI */
  69. savetstp = signal(SIGTSTP, SIG_DFL);
  70. savettou = signal(SIGTTOU, SIG_DFL);
  71. savettin = signal(SIGTTIN, SIG_DFL);
  72. errs = 0;
  73. #ifndef TIOCSTI
  74. ttyset = 0;
  75. #endif
  76. if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
  77. warn("tcgetattr(stdin)");
  78. return (-1);
  79. }
  80. c_erase = ttybuf.c_cc[VERASE];
  81. c_kill = ttybuf.c_cc[VKILL];
  82. #ifndef TIOCSTI
  83. ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
  84. ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
  85. if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
  86. (void)signal(SIGINT, SIG_DFL);
  87. if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
  88. (void)signal(SIGQUIT, SIG_DFL);
  89. #else
  90. # ifdef TIOCEXT
  91. extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
  92. if (extproc) {
  93. flag = 0;
  94. if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
  95. warn("TIOCEXT: off");
  96. }
  97. # endif /* TIOCEXT */
  98. if (setjmp(intjmp))
  99. goto out;
  100. saveint = signal(SIGINT, ttyint);
  101. #endif
  102. if (gflags & GTO) {
  103. #ifndef TIOCSTI
  104. if (!ttyset && hp->h_to != NULL)
  105. ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
  106. #endif
  107. hp->h_to =
  108. extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
  109. }
  110. if (gflags & GSUBJECT) {
  111. #ifndef TIOCSTI
  112. if (!ttyset && hp->h_subject != NULL)
  113. ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
  114. #endif
  115. hp->h_subject = readtty("Subject: ", hp->h_subject);
  116. }
  117. if (gflags & GCC) {
  118. #ifndef TIOCSTI
  119. if (!ttyset && hp->h_cc != NULL)
  120. ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
  121. #endif
  122. hp->h_cc =
  123. extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
  124. }
  125. if (gflags & GBCC) {
  126. #ifndef TIOCSTI
  127. if (!ttyset && hp->h_bcc != NULL)
  128. ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
  129. #endif
  130. hp->h_bcc =
  131. extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
  132. }
  133. out:
  134. (void)signal(SIGTSTP, savetstp);
  135. (void)signal(SIGTTOU, savettou);
  136. (void)signal(SIGTTIN, savettin);
  137. #ifndef TIOCSTI
  138. ttybuf.c_cc[VERASE] = c_erase;
  139. ttybuf.c_cc[VKILL] = c_kill;
  140. if (ttyset)
  141. tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
  142. (void)signal(SIGQUIT, savequit);
  143. #else
  144. # ifdef TIOCEXT
  145. if (extproc) {
  146. flag = 1;
  147. if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
  148. warn("TIOCEXT: on");
  149. }
  150. # endif /* TIOCEXT */
  151. #endif
  152. (void)signal(SIGINT, saveint);
  153. return (errs);
  154. }
  155. /*
  156. * Read up a header from standard input.
  157. * The source string has the preliminary contents to
  158. * be read.
  159. *
  160. */
  161. char *
  162. readtty(const char *pr, char src[])
  163. {
  164. char ch, canonb[BUFSIZ];
  165. int c;
  166. char *cp, *cp2;
  167. fputs(pr, stdout);
  168. (void)fflush(stdout);
  169. if (src != NULL && strlen(src) > BUFSIZ - 2) {
  170. printf("too long to edit\n");
  171. return (src);
  172. }
  173. #ifndef TIOCSTI
  174. if (src != NULL)
  175. strlcpy(canonb, src, sizeof(canonb));
  176. else
  177. *canonb = '\0';
  178. fputs(canonb, stdout);
  179. (void)fflush(stdout);
  180. #else
  181. cp = src == NULL ? "" : src;
  182. while ((c = *cp++) != '\0') {
  183. if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
  184. (c_kill != _POSIX_VDISABLE && c == c_kill)) {
  185. ch = '\\';
  186. ioctl(0, TIOCSTI, &ch);
  187. }
  188. ch = c;
  189. ioctl(0, TIOCSTI, &ch);
  190. }
  191. cp = canonb;
  192. *cp = '\0';
  193. #endif
  194. cp2 = cp;
  195. while (cp2 < canonb + BUFSIZ)
  196. *cp2++ = '\0';
  197. cp2 = cp;
  198. if (setjmp(rewrite))
  199. goto redo;
  200. (void)signal(SIGTSTP, ttystop);
  201. (void)signal(SIGTTOU, ttystop);
  202. (void)signal(SIGTTIN, ttystop);
  203. clearerr(stdin);
  204. while (cp2 < canonb + BUFSIZ) {
  205. c = getc(stdin);
  206. if (c == EOF || c == '\n')
  207. break;
  208. *cp2++ = c;
  209. }
  210. *cp2 = '\0';
  211. (void)signal(SIGTSTP, SIG_DFL);
  212. (void)signal(SIGTTOU, SIG_DFL);
  213. (void)signal(SIGTTIN, SIG_DFL);
  214. if (c == EOF && ferror(stdin)) {
  215. redo:
  216. cp = strlen(canonb) > 0 ? canonb : NULL;
  217. clearerr(stdin);
  218. return (readtty(pr, cp));
  219. }
  220. #ifndef TIOCSTI
  221. if (cp == NULL || *cp == '\0')
  222. return (src);
  223. cp2 = cp;
  224. if (!ttyset)
  225. return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
  226. while (*cp != '\0') {
  227. c = *cp++;
  228. if (c_erase != _POSIX_VDISABLE && c == c_erase) {
  229. if (cp2 == canonb)
  230. continue;
  231. if (cp2[-1] == '\\') {
  232. cp2[-1] = c;
  233. continue;
  234. }
  235. cp2--;
  236. continue;
  237. }
  238. if (c_kill != _POSIX_VDISABLE && c == c_kill) {
  239. if (cp2 == canonb)
  240. continue;
  241. if (cp2[-1] == '\\') {
  242. cp2[-1] = c;
  243. continue;
  244. }
  245. cp2 = canonb;
  246. continue;
  247. }
  248. *cp2++ = c;
  249. }
  250. *cp2 = '\0';
  251. #endif
  252. if (equal("", canonb))
  253. return (NULL);
  254. return (savestr(canonb));
  255. }
  256. /*
  257. * Receipt continuation.
  258. */
  259. void
  260. ttystop(int s)
  261. {
  262. sig_t old_action = signal(s, SIG_DFL);
  263. sigset_t nset;
  264. (void)sigemptyset(&nset);
  265. (void)sigaddset(&nset, s);
  266. (void)sigprocmask(SIG_BLOCK, &nset, NULL);
  267. kill(0, s);
  268. (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
  269. (void)signal(s, old_action);
  270. longjmp(rewrite, 1);
  271. }
  272. void
  273. ttyint(int s __unused)
  274. {
  275. longjmp(intjmp, 1);
  276. }