GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mail/tty.c Lines: 0 114 0.0 %
Date: 2016-12-06 Branches: 0 75 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: tty.c,v 1.20 2014/01/17 18:42:30 okan Exp $	*/
2
/*	$NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * Mail -- a mail program
35
 *
36
 * Generally useful tty stuff.
37
 */
38
39
#include "rcv.h"
40
#include "extern.h"
41
#include <sys/ioctl.h>
42
#include <errno.h>
43
44
static	cc_t		c_erase;	/* Current erase char */
45
static	cc_t		c_kill;		/* Current kill char */
46
#ifndef TIOCSTI
47
static	int		ttyset;		/* We must now do erase/kill */
48
#endif
49
static	volatile sig_atomic_t	ttysignal;	/* Interrupted by a signal? */
50
51
/*
52
 * Read all relevant header fields.
53
 */
54
int
55
grabh(struct header *hp, int gflags)
56
{
57
	struct termios ttybuf;
58
#ifndef TIOCSTI
59
	struct sigaction savequit;
60
#else
61
# ifdef	TIOCEXT
62
	int extproc;
63
	int flag;
64
# endif /* TIOCEXT */
65
#endif
66
	struct sigaction savetstp;
67
	struct sigaction savettou;
68
	struct sigaction savettin;
69
	struct sigaction act;
70
	char *s;
71
	int error;
72
73
	sigemptyset(&act.sa_mask);
74
	act.sa_flags = SA_RESTART;
75
	act.sa_handler = SIG_DFL;
76
	(void)sigaction(SIGTSTP, &act, &savetstp);
77
	(void)sigaction(SIGTTOU, &act, &savettou);
78
	(void)sigaction(SIGTTIN, &act, &savettin);
79
	error = 1;
80
#ifndef TIOCSTI
81
	ttyset = 0;
82
#endif
83
	if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
84
		warn("tcgetattr");
85
		return(-1);
86
	}
87
	c_erase = ttybuf.c_cc[VERASE];
88
	c_kill = ttybuf.c_cc[VKILL];
89
#ifndef TIOCSTI
90
	ttybuf.c_cc[VERASE] = 0;
91
	ttybuf.c_cc[VKILL] = 0;
92
	act.sa_handler = SIG_IGN;
93
	if (sigaction(SIGQUIT, &act, &savequit) == 0 &&
94
	    savequit.sa_handler == SIG_DFL)
95
		(void)sigaction(SIGQUIT, &savequit, NULL);
96
#else
97
# ifdef	TIOCEXT
98
	extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
99
	if (extproc) {
100
		flag = 0;
101
		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
102
			warn("TIOCEXT: off");
103
	}
104
# endif /* TIOCEXT */
105
#endif
106
	if (gflags & GTO) {
107
#ifndef TIOCSTI
108
		if (!ttyset && hp->h_to != NULL)
109
			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
110
#endif
111
		s = readtty("To: ", detract(hp->h_to, 0));
112
		if (s == NULL)
113
			goto out;
114
		hp->h_to = extract(s, GTO);
115
	}
116
	if (gflags & GSUBJECT) {
117
#ifndef TIOCSTI
118
		if (!ttyset && hp->h_subject != NULL)
119
			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
120
#endif
121
		s = readtty("Subject: ", hp->h_subject);
122
		if (s == NULL)
123
			goto out;
124
		hp->h_subject = s;
125
	}
126
	if (gflags & GCC) {
127
#ifndef TIOCSTI
128
		if (!ttyset && hp->h_cc != NULL)
129
			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
130
#endif
131
		s = readtty("Cc: ", detract(hp->h_cc, 0));
132
		if (s == NULL)
133
			goto out;
134
		hp->h_cc = extract(s, GCC);
135
	}
136
	if (gflags & GBCC) {
137
#ifndef TIOCSTI
138
		if (!ttyset && hp->h_bcc != NULL)
139
			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
140
#endif
141
		s = readtty("Bcc: ", detract(hp->h_bcc, 0));
142
		if (s == NULL)
143
			goto out;
144
		hp->h_bcc = extract(s, GBCC);
145
	}
146
	error = 0;
147
out:
148
	(void)sigaction(SIGTSTP, &savetstp, NULL);
149
	(void)sigaction(SIGTTOU, &savettou, NULL);
150
	(void)sigaction(SIGTTIN, &savettin, NULL);
151
#ifndef TIOCSTI
152
	ttybuf.c_cc[VERASE] = c_erase;
153
	ttybuf.c_cc[VKILL] = c_kill;
154
	if (ttyset)
155
		tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
156
	(void)sigaction(SIGQUIT, &savequit, NULL);
157
#else
158
# ifdef	TIOCEXT
159
	if (extproc) {
160
		flag = 1;
161
		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
162
			warn("TIOCEXT: on");
163
	}
164
# endif /* TIOCEXT */
165
#endif
166
	return(error);
167
}
168
169
/*
170
 * Read up a header from standard input.
171
 * The source string has the preliminary contents to
172
 * be read.
173
 *
174
 */
175
char *
176
readtty(char *pr, char *src)
177
{
178
	struct sigaction act, saveint;
179
	char ch, canonb[BUFSIZ];
180
	char *cp, *cp2;
181
	sigset_t oset;
182
	int c;
183
184
	fputs(pr, stdout);
185
	fflush(stdout);
186
	if (src != NULL && strlen(src) > sizeof(canonb) - 2) {
187
		puts("too long to edit");
188
		return(src);
189
	}
190
#ifndef TIOCSTI
191
	if (src != NULL)
192
		cp = copy(src, canonb);	/* safe, bounds checked above */
193
	else
194
		cp = copy("", canonb);
195
	fputs(canonb, stdout);
196
	fflush(stdout);
197
#else
198
	cp = src == NULL ? "" : src;
199
	while ((c = (unsigned char)*cp++) != '\0') {
200
		if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
201
		    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
202
			ch = '\\';
203
			ioctl(0, TIOCSTI, &ch);
204
		}
205
		ch = c;
206
		ioctl(0, TIOCSTI, &ch);
207
	}
208
	cp = canonb;
209
	*cp = 0;
210
#endif
211
	sigemptyset(&act.sa_mask);
212
	act.sa_flags = 0;		/* Note: will not restart syscalls */
213
	act.sa_handler = ttyint;
214
	(void)sigaction(SIGINT, &act, &saveint);
215
	act.sa_handler = ttystop;
216
	(void)sigaction(SIGTSTP, &act, NULL);
217
	(void)sigaction(SIGTTOU, &act, NULL);
218
	(void)sigaction(SIGTTIN, &act, NULL);
219
	(void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
220
	clearerr(stdin);
221
	memset(cp, 0, canonb + sizeof(canonb) - cp);
222
	for (cp2 = cp; cp2 < canonb + sizeof(canonb) - 1; ) {
223
		c = getc(stdin);
224
		switch (ttysignal) {
225
			case SIGINT:
226
				ttysignal = 0;
227
				cp2 = NULL;
228
				c = EOF;
229
				/* FALLTHROUGH */
230
			case 0:
231
				break;
232
			default:
233
				ttysignal = 0;
234
				goto redo;
235
		}
236
		if (c == EOF || c == '\n')
237
			break;
238
		*cp2++ = c;
239
	}
240
	act.sa_handler = SIG_DFL;
241
	sigemptyset(&act.sa_mask);
242
	act.sa_flags = SA_RESTART;
243
	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
244
	(void)sigaction(SIGTSTP, &act, NULL);
245
	(void)sigaction(SIGTTOU, &act, NULL);
246
	(void)sigaction(SIGTTIN, &act, NULL);
247
	(void)sigaction(SIGINT, &saveint, NULL);
248
	if (cp2 == NULL)
249
		return(NULL);			/* user hit ^C */
250
	*cp2 = '\0';
251
	if (c == EOF && ferror(stdin)) {
252
redo:
253
		cp = strlen(canonb) > 0 ? canonb : NULL;
254
		clearerr(stdin);
255
		/* XXX - make iterative, not recursive */
256
		return(readtty(pr, cp));
257
	}
258
#ifndef TIOCSTI
259
	if (cp == NULL || *cp == '\0')
260
		return(src);
261
	cp2 = cp;
262
	if (!ttyset)
263
		return(strlen(canonb) > 0 ? savestr(canonb) : NULL);
264
	while (*cp != '\0') {
265
		c = (unsigned char)*cp++;
266
		if (c_erase != _POSIX_VDISABLE && c == c_erase) {
267
			if (cp2 == canonb)
268
				continue;
269
			if (cp2[-1] == '\\') {
270
				cp2[-1] = c;
271
				continue;
272
			}
273
			cp2--;
274
			continue;
275
		}
276
		if (c_kill != _POSIX_VDISABLE && c == c_kill) {
277
			if (cp2 == canonb)
278
				continue;
279
			if (cp2[-1] == '\\') {
280
				cp2[-1] = c;
281
				continue;
282
			}
283
			cp2 = canonb;
284
			continue;
285
		}
286
		*cp2++ = c;
287
	}
288
	*cp2 = '\0';
289
#endif
290
	if (equal("", canonb))
291
		return("");
292
	return(savestr(canonb));
293
}
294
295
/*
296
 * Receipt continuation.
297
 */
298
void
299
ttystop(int s)
300
{
301
	struct sigaction act, oact;
302
	sigset_t nset;
303
	int save_errno;
304
305
	/*
306
	 * Save old handler and set to default.
307
	 * Unblock receipt of 's' and then resend it.
308
	 */
309
	save_errno = errno;
310
	(void)sigemptyset(&act.sa_mask);
311
	act.sa_flags = SA_RESTART;
312
	act.sa_handler = SIG_DFL;
313
	(void)sigaction(s, &act, &oact);
314
	(void)sigemptyset(&nset);
315
	(void)sigaddset(&nset, s);
316
	(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
317
	(void)kill(0, s);
318
	(void)sigprocmask(SIG_BLOCK, &nset, NULL);
319
	(void)sigaction(s, &oact, NULL);
320
	ttysignal = s;
321
	errno = save_errno;
322
}
323
324
/*ARGSUSED*/
325
void
326
ttyint(int s)
327
{
328
329
	ttysignal = s;
330
}