tty.c revision 1.28 1 1.28 christos /* $NetBSD: tty.c,v 1.28 2009/04/10 13:08:25 christos Exp $ */
2 1.5 christos
3 1.1 cgd /*
4 1.3 deraadt * Copyright (c) 1980, 1993
5 1.3 deraadt * 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.17 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.8 lukem #include <sys/cdefs.h>
33 1.1 cgd #ifndef lint
34 1.5 christos #if 0
35 1.6 tls static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93";
36 1.5 christos #else
37 1.28 christos __RCSID("$NetBSD: tty.c,v 1.28 2009/04/10 13:08:25 christos Exp $");
38 1.5 christos #endif
39 1.1 cgd #endif /* not lint */
40 1.1 cgd
41 1.1 cgd /*
42 1.1 cgd * Mail -- a mail program
43 1.1 cgd *
44 1.1 cgd * Generally useful tty stuff.
45 1.1 cgd */
46 1.1 cgd
47 1.1 cgd #include "rcv.h"
48 1.3 deraadt #include "extern.h"
49 1.25 christos #ifdef USE_EDITLINE
50 1.28 christos # include "complete.h"
51 1.21 christos #endif
52 1.28 christos #include "sig.h"
53 1.1 cgd
54 1.28 christos static jmp_buf tty_jmpbuf; /* Place to go when interrupted */
55 1.28 christos
56 1.28 christos #ifndef USE_EDITLINE
57 1.4 mycroft static cc_t c_erase; /* Current erase char */
58 1.4 mycroft static cc_t c_kill; /* Current kill char */
59 1.28 christos # ifndef TIOCSTI
60 1.1 cgd static int ttyset; /* We must now do erase/kill */
61 1.28 christos # endif
62 1.28 christos #endif /* USE_EDITLINE */
63 1.24 christos
64 1.1 cgd /*
65 1.27 christos * Read up a header from standard input.
66 1.27 christos * The source string has the preliminary contents to
67 1.27 christos * be read.
68 1.27 christos *
69 1.28 christos * Returns: an salloc'ed copy of the line read if successful, or NULL
70 1.28 christos * if no characters were read or if an error occurred.
71 1.28 christos *
72 1.27 christos */
73 1.27 christos #ifdef USE_EDITLINE
74 1.27 christos static char *
75 1.28 christos readtty(const char *pr, char *src)
76 1.27 christos {
77 1.27 christos char *line;
78 1.28 christos
79 1.27 christos line = my_gets(&elm.string, pr, src);
80 1.28 christos sig_check();
81 1.28 christos if (line == NULL)
82 1.28 christos (void)putc('\n', stdout);
83 1.28 christos
84 1.27 christos return line ? savestr(line) : __UNCONST("");
85 1.27 christos }
86 1.27 christos
87 1.28 christos #else /* not USE_EDITLINE */
88 1.27 christos
89 1.27 christos static char *
90 1.28 christos readtty(const char *pr, char *src)
91 1.27 christos {
92 1.27 christos char canonb[LINESIZE];
93 1.28 christos char *cp, *cp2;
94 1.27 christos int c;
95 1.27 christos #ifdef TIOCSTI
96 1.27 christos char ch;
97 1.27 christos #endif
98 1.28 christos
99 1.27 christos (void)fputs(pr, stdout);
100 1.27 christos (void)fflush(stdout);
101 1.27 christos if (src != NULL && strlen(src) > sizeof(canonb) - 2) {
102 1.27 christos (void)printf("too long to edit\n");
103 1.27 christos return src;
104 1.27 christos }
105 1.27 christos #ifndef TIOCSTI
106 1.27 christos if (src != NULL)
107 1.27 christos cp = copy(src, canonb);
108 1.27 christos else
109 1.28 christos cp = copy(__UNCONST(""), canonb);
110 1.28 christos c = *cp;
111 1.27 christos (void)fputs(canonb, stdout);
112 1.27 christos (void)fflush(stdout);
113 1.27 christos #else
114 1.28 christos cp = src == NULL ? __UNCONST("") : src;
115 1.27 christos while ((c = *cp++) != '\0') {
116 1.27 christos if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
117 1.27 christos (c_kill != _POSIX_VDISABLE && c == c_kill)) {
118 1.27 christos ch = '\\';
119 1.27 christos (void)ioctl(0, TIOCSTI, &ch);
120 1.27 christos }
121 1.27 christos ch = c;
122 1.27 christos (void)ioctl(0, TIOCSTI, &ch);
123 1.27 christos }
124 1.27 christos cp = canonb;
125 1.28 christos *cp = '\0';
126 1.27 christos #endif
127 1.28 christos clearerr(stdin);
128 1.27 christos cp2 = cp;
129 1.28 christos while (cp2 < canonb + sizeof(canonb) - 1) {
130 1.27 christos c = getc(stdin);
131 1.28 christos sig_check();
132 1.28 christos if (c == EOF) {
133 1.28 christos if (feof(stdin))
134 1.28 christos (void)putc('\n', stdout);
135 1.28 christos break;
136 1.28 christos }
137 1.28 christos if (c == '\n')
138 1.27 christos break;
139 1.27 christos *cp2++ = c;
140 1.27 christos }
141 1.28 christos *cp2 = '\0';
142 1.28 christos
143 1.27 christos if (c == EOF && ferror(stdin)) {
144 1.27 christos cp = strlen(canonb) > 0 ? canonb : NULL;
145 1.27 christos clearerr(stdin);
146 1.27 christos return readtty(pr, cp);
147 1.27 christos }
148 1.27 christos #ifndef TIOCSTI
149 1.27 christos if (cp == NULL || *cp == '\0')
150 1.27 christos return src;
151 1.28 christos if (ttyset == 0)
152 1.28 christos return strlen(canonb) > 0 ? savestr(canonb) : NULL;
153 1.28 christos
154 1.28 christos /*
155 1.28 christos * Do erase and kill.
156 1.28 christos */
157 1.27 christos cp2 = cp;
158 1.27 christos while (*cp != '\0') {
159 1.27 christos c = *cp++;
160 1.27 christos if (c_erase != _POSIX_VDISABLE && c == c_erase) {
161 1.27 christos if (cp2 == canonb)
162 1.27 christos continue;
163 1.27 christos if (cp2[-1] == '\\') {
164 1.27 christos cp2[-1] = c;
165 1.27 christos continue;
166 1.27 christos }
167 1.27 christos cp2--;
168 1.27 christos continue;
169 1.27 christos }
170 1.27 christos if (c_kill != _POSIX_VDISABLE && c == c_kill) {
171 1.27 christos if (cp2 == canonb)
172 1.27 christos continue;
173 1.27 christos if (cp2[-1] == '\\') {
174 1.27 christos cp2[-1] = c;
175 1.27 christos continue;
176 1.27 christos }
177 1.27 christos cp2 = canonb;
178 1.27 christos continue;
179 1.27 christos }
180 1.27 christos *cp2++ = c;
181 1.27 christos }
182 1.27 christos *cp2 = '\0';
183 1.27 christos #endif
184 1.28 christos if (canonb[0] == '\0')
185 1.28 christos return __UNCONST("");
186 1.27 christos return savestr(canonb);
187 1.27 christos }
188 1.27 christos #endif /* USE_EDITLINE */
189 1.27 christos
190 1.28 christos #ifdef USE_EDITLINE
191 1.28 christos # define save_erase_and_kill(t) 0
192 1.28 christos #else
193 1.28 christos static int
194 1.28 christos save_erase_and_kill(struct termios *t)
195 1.28 christos {
196 1.28 christos
197 1.28 christos # ifndef TIOCSTI
198 1.28 christos ttyset = 0;
199 1.28 christos #endif
200 1.28 christos if (tcgetattr(fileno(stdin), t) == -1) {
201 1.28 christos warn("tcgetattr");
202 1.28 christos return -1;
203 1.28 christos }
204 1.28 christos c_erase = t->c_cc[VERASE];
205 1.28 christos c_kill = t->c_cc[VKILL];
206 1.28 christos return 0;
207 1.28 christos }
208 1.28 christos #endif
209 1.28 christos
210 1.28 christos #if defined(USE_EDITLINE) || defined(TIOCSTI)
211 1.28 christos # define disable_erase_and_kill(t)
212 1.28 christos #else
213 1.28 christos static void
214 1.28 christos disable_erase_and_kill(struct termios *t)
215 1.28 christos {
216 1.28 christos
217 1.28 christos if (ttyset == 0) {
218 1.28 christos ttyset = 1;
219 1.28 christos t->c_cc[VERASE] = _POSIX_VDISABLE;
220 1.28 christos t->c_cc[VKILL] = _POSIX_VDISABLE;
221 1.28 christos (void)tcsetattr(fileno(stdin), TCSADRAIN, t);
222 1.28 christos }
223 1.28 christos }
224 1.28 christos #endif
225 1.28 christos
226 1.28 christos #if defined(USE_EDITLINE) || defined(TIOCSTI)
227 1.28 christos # define restore_erase_and_kill(t)
228 1.28 christos #else
229 1.28 christos static void
230 1.28 christos restore_erase_and_kill(struct termios *t)
231 1.28 christos {
232 1.28 christos
233 1.28 christos if (ttyset != 0) {
234 1.28 christos ttyset = 0;
235 1.28 christos t->c_cc[VERASE] = c_erase;
236 1.28 christos t->c_cc[VKILL] = c_kill;
237 1.28 christos (void)tcsetattr(fileno(stdin), TCSADRAIN, t);
238 1.28 christos }
239 1.28 christos }
240 1.28 christos #endif
241 1.28 christos
242 1.28 christos /*
243 1.28 christos * Do a shell-like extraction of a line
244 1.28 christos * and make a list of name from it.
245 1.28 christos * Return the list or NULL if none found.
246 1.28 christos */
247 1.28 christos static struct name *
248 1.28 christos shextract(char *line, int ntype)
249 1.28 christos {
250 1.28 christos struct name *begin, *np, *t;
251 1.28 christos char *argv[MAXARGC];
252 1.28 christos size_t argc, i;
253 1.28 christos
254 1.28 christos begin = NULL;
255 1.28 christos if (line) {
256 1.28 christos np = NULL;
257 1.28 christos argc = getrawlist(line, argv, (int)__arraycount(argv));
258 1.28 christos for (i = 0; i < argc; i++) {
259 1.28 christos t = nalloc(argv[i], ntype);
260 1.28 christos if (begin == NULL)
261 1.28 christos begin = t;
262 1.28 christos else
263 1.28 christos np->n_flink = t;
264 1.28 christos t->n_blink = np;
265 1.28 christos np = t;
266 1.28 christos }
267 1.28 christos }
268 1.28 christos return begin;
269 1.28 christos }
270 1.27 christos
271 1.27 christos /*ARGSUSED*/
272 1.27 christos static void
273 1.28 christos tty_sigint(int signo __unused)
274 1.27 christos {
275 1.28 christos
276 1.28 christos longjmp(tty_jmpbuf, 1);
277 1.27 christos }
278 1.27 christos
279 1.27 christos /*
280 1.1 cgd * Read all relevant header fields.
281 1.28 christos * Returns 0 on success; 1 if there was an error or signal.
282 1.1 cgd */
283 1.27 christos PUBLIC int
284 1.12 wiz grabh(struct header *hp, int gflags)
285 1.1 cgd {
286 1.28 christos sig_t volatile old_sigint;
287 1.28 christos int retval;
288 1.28 christos #ifndef USE_EDITLINE
289 1.4 mycroft struct termios ttybuf;
290 1.28 christos # if defined(TIOCSTI) && defined(TIOCEXT)
291 1.28 christos int extproc;
292 1.28 christos # endif
293 1.24 christos
294 1.28 christos if (save_erase_and_kill(&ttybuf))
295 1.28 christos return -1;
296 1.10 christos
297 1.28 christos # if defined(TIOCSTI) && defined(TIOCEXT)
298 1.6 tls extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
299 1.6 tls if (extproc) {
300 1.25 christos int flag;
301 1.28 christos
302 1.6 tls flag = 0;
303 1.28 christos if (ioctl(fileno(stdin), TIOCEXT, &flag) == -1)
304 1.16 wiz warn("TIOCEXT: off");
305 1.6 tls }
306 1.28 christos # endif
307 1.28 christos #endif /* USE_EDITLINE */
308 1.28 christos
309 1.28 christos sig_check();
310 1.28 christos old_sigint = sig_signal(SIGINT, tty_sigint);
311 1.28 christos
312 1.28 christos /* return here if we detect a SIGINT */
313 1.28 christos if ((retval = setjmp(tty_jmpbuf)) != 0) {
314 1.28 christos (void)putc('\n', stdout);
315 1.1 cgd goto out;
316 1.22 christos }
317 1.28 christos
318 1.28 christos /*
319 1.28 christos * Do this irrespective of whether the initial string is empty.
320 1.28 christos * Otherwise, the editing is inconsistent.
321 1.28 christos */
322 1.28 christos disable_erase_and_kill(&ttybuf);
323 1.28 christos
324 1.1 cgd if (gflags & GTO) {
325 1.1 cgd hp->h_to =
326 1.28 christos extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
327 1.1 cgd }
328 1.1 cgd if (gflags & GSUBJECT) {
329 1.1 cgd hp->h_subject = readtty("Subject: ", hp->h_subject);
330 1.1 cgd }
331 1.1 cgd if (gflags & GCC) {
332 1.1 cgd hp->h_cc =
333 1.28 christos extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
334 1.1 cgd }
335 1.1 cgd if (gflags & GBCC) {
336 1.1 cgd hp->h_bcc =
337 1.28 christos extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
338 1.1 cgd }
339 1.21 christos if (gflags & GSMOPTS) {
340 1.28 christos hp->h_smopts =
341 1.28 christos shextract(readtty("Smopts: ", detract(hp->h_smopts, 0)),
342 1.28 christos GSMOPTS);
343 1.28 christos }
344 1.25 christos #ifdef MIME_SUPPORT
345 1.28 christos if (gflags & GSMOPTS) { /* XXX - Use a new flag for this? */
346 1.25 christos if (hp->h_attach) {
347 1.25 christos struct attachment *ap;
348 1.25 christos int i;
349 1.28 christos
350 1.25 christos i = 0;
351 1.25 christos for (ap = hp->h_attach; ap; ap = ap->a_flink)
352 1.25 christos i++;
353 1.25 christos (void)printf("Attachment%s: %d\n", i > 1 ? "s" : "", i);
354 1.25 christos }
355 1.21 christos }
356 1.25 christos #endif
357 1.28 christos out:
358 1.28 christos restore_erase_and_kill(&ttybuf);
359 1.28 christos
360 1.28 christos #ifndef USE_EDITLINE
361 1.28 christos # if defined(TIOCSTI) && defined(TIOCEXT)
362 1.6 tls if (extproc) {
363 1.25 christos int flag;
364 1.6 tls flag = 1;
365 1.28 christos if (ioctl(fileno(stdin), TIOCEXT, &flag) == -1)
366 1.16 wiz warn("TIOCEXT: on");
367 1.6 tls }
368 1.28 christos # endif
369 1.1 cgd #endif
370 1.28 christos (void)sig_signal(SIGINT, old_sigint);
371 1.28 christos sig_check();
372 1.26 christos return retval;
373 1.1 cgd }
374