1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the BSD package               *
4 *Copyright (c) 1978-2006 The Regents of the University of California an*
5 *                                                                      *
6 * Redistribution and use in source and binary forms, with or           *
7 * without modification, are permitted provided that the following      *
8 * conditions are met:                                                  *
9 *                                                                      *
10 *    1. Redistributions of source code must retain the above           *
11 *       copyright notice, this list of conditions and the              *
12 *       following disclaimer.                                          *
13 *                                                                      *
14 *    2. Redistributions in binary form must reproduce the above        *
15 *       copyright notice, this list of conditions and the              *
16 *       following disclaimer in the documentation and/or other         *
17 *       materials provided with the distribution.                      *
18 *                                                                      *
19 *    3. Neither the name of The Regents of the University of California*
20 *       names of its contributors may be used to endorse or            *
21 *       promote products derived from this software without            *
22 *       specific prior written permission.                             *
23 *                                                                      *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND               *
25 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,          *
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF             *
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE             *
28 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS    *
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,             *
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED      *
31 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,        *
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    *
33 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,      *
34 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY       *
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE              *
36 * POSSIBILITY OF SUCH DAMAGE.                                          *
37 *                                                                      *
38 * Redistribution and use in source and binary forms, with or without   *
39 * modification, are permitted provided that the following conditions   *
40 * are met:                                                             *
41 * 1. Redistributions of source code must retain the above copyright    *
42 *    notice, this list of conditions and the following disclaimer.     *
43 * 2. Redistributions in binary form must reproduce the above copyright *
44 *    notice, this list of conditions and the following disclaimer in   *
45 *    the documentation and/or other materials provided with the        *
46 *    distribution.                                                     *
47 * 3. Neither the name of the University nor the names of its           *
48 *    contributors may be used to endorse or promote products derived   *
49 *    from this software without specific prior written permission.     *
50 *                                                                      *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS"    *
52 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED    *
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A      *
54 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS    *
55 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      *
56 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
57 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF     *
58 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND  *
59 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,   *
60 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT   *
61 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   *
62 * SUCH DAMAGE.                                                         *
63 *                                                                      *
64 *                          Kurt Shoens (UCB)                           *
65 *                                 gsf                                  *
66 *                                                                      *
67 ***********************************************************************/
68 #pragma prototyped
69 /*
70  * Mail -- a mail program
71  *
72  * Interactive header editing.
73  */
74 
75 #include "mailx.h"
76 
77 /*
78  * tty stuff swiped from ksh
79  */
80 
81 #ifdef _hdr_termios
82 #   include	<termios.h>
83 #   if __sgi__ || sgi	/* special hack to eliminate ^M problem */
84 #	ifndef ECHOCTL
85 #	    define ECHOCTL	ECHOE
86 #	endif /* ECHOCTL */
87 #	ifndef CNSUSP
88 #	    define CNSUSP	CNSWTCH
89 #	endif /* CNSUSP */
90 #   endif /* sgi */
91 #   ifdef _NEXT_SOURCE
92 #	define _lib_tcgetattr	1
93 #	define _lib_tcgetpgrp	1
94 #   endif /* _NEXT_SOURCE */
95 #else
96 #   if defined(_sys_termios) && defined(_lib_tcgetattr)
97 #	include	<sys/termios.h>
98 #	define _hdr_termios
99 #   else
100 #	undef _sys_termios
101 #   endif /* _sys_termios */
102 #endif /* _hdr_termios */
103 
104 #ifdef _hdr_termios
105 #   undef _hdr_sgtty
106 #   undef tcgetattr
107 #   undef tcsetattr
108 #   undef tcgetpgrp
109 #   undef tcsetpgrp
110 #   undef cfgetospeed
111 #   ifndef TCSANOW
112 #	define TCSANOW		TCSETS
113 #	define TCSADRAIN	TCSETSW
114 #	define TCSAFLUSH	TCSETSF
115 #   endif /* TCSANOW */
116     /* The following corrects bugs in some implementations */
117 #   if defined(TCSADFLUSH) && !defined(TCSAFLUSH)
118 #	define TCSAFLUSH	TCSADFLUSH
119 #   endif /* TCSADFLUSH */
120 #   ifndef _lib_tcgetattr
121 #	undef  tcgetattr
122 #	define tcgetattr(fd,tty)	ioctl(fd, TCGETS, tty)
123 #	undef  tcsetattr
124 #	define tcsetattr(fd,action,tty)	ioctl(fd, action, tty)
125 #	undef  cfgetospeed
126 #	define cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
127 #   endif /* _lib_tcgetattr */
128 #   undef TIOCGETC
129 #   if SHOPT_OLDTERMIO  /* use both termios and termio */
130 #	ifdef _hdr_termio
131 #	    include	<termio.h>
132 #	else
133 #	    ifdef _sys_termio
134 #		include	<sys/termio.h>
135 #		define _hdr_termio 1
136 #	    else
137 #		undef SHOPT_OLDTERMIO
138 #	    endif /* _sys_termio */
139 #	endif /* _hdr_termio */
140 #   endif /* SHOPT_OLDTERMIO */
141 #else
142 #   define cfgetospeed(tp)	((tp)->c_cflag & CBAUD)
143 #   undef SHOPT_OLDTERMIO
144 #   ifdef _hdr_termio
145 #	include	<termio.h>
146 #   else
147 #	ifdef _sys_termio
148 #	    include	<sys/termio.h>
149 #	    define _hdr_termio 1
150 #	endif /* _sys_termio */
151 #   endif /* _hdr_termio */
152 #   ifdef _hdr_termio
153 #	define termios termio
154 #	undef TIOCGETC
155 #	define tcgetattr(fd,tty)		ioctl(fd, TCGETA, tty)
156 #	define tcsetattr(fd,action,tty)	ioctl(fd, action, tty)
157 
158 #	ifdef _sys_bsdtty
159 #	   include	<sys/bsdtty.h>
160 #	endif /* _sys_bsdtty */
161 #   else
162 #	ifdef _hdr_sgtty
163 #	    include	<sgtty.h>
164 #	    ifndef LPENDIN
165 #	        ifdef _sys_nttyio
166 #		    include	<sys/nttyio.h>
167 #	        endif /* _sys_nttyio */
168 #	    endif /* LPENDIN */
169 #	    define termios sgttyb
170 #	    ifdef TIOCSETN
171 #	 	undef TCSETAW
172 #	    endif /* TIOCSETN */
173 #	    ifdef TIOCGETP
174 #		define tcgetattr(fd,tty)		ioctl(fd, TIOCGETP, tty)
175 #		define tcsetattr(fd,action,tty)	ioctl(fd, action, tty)
176 #	    else
177 #		define tcgetattr(fd,tty)	gtty(fd, tty)
178 #		define tcsetattr(fd,action,tty)	stty(fd, tty)
179 #	    endif /* TIOCGETP */
180 #	endif /* _hdr_sgtty */
181 #   endif /* hdr_termio */
182 
183 #   ifndef TCSANOW
184 #	ifdef TCSETAW
185 #	    define TCSANOW	TCSETA
186 #	    ifdef u370
187 	    /* delays are too long, don't wait for output to drain */
188 #		define TCSADRAIN	TCSETA
189 #	    else
190 #		define TCSADRAIN	TCSETAW
191 #	    endif /* u370 */
192 #	    define TCSAFLUSH	TCSETAF
193 #	else
194 #	    ifdef TIOCSETN
195 #		define TCSANOW	TIOCSETN
196 #		define TCSADRAIN	TIOCSETN
197 #		define TCSAFLUSH	TIOCSETP
198 #	    endif /* TIOCSETN */
199 #	endif /* TCSETAW */
200 #   endif /* TCSANOW */
201 #endif /* _hdr_termios */
202 
203 /* set ECHOCTL if driver can echo control charaters as ^c */
204 #ifdef LCTLECH
205 #   ifndef ECHOCTL
206 #	define ECHOCTL	LCTLECH
207 #   endif /* !ECHOCTL */
208 #endif /* LCTLECH */
209 #ifdef LNEW_CTLECH
210 #   ifndef ECHOCTL
211 #	define ECHOCTL  LNEW_CTLECH
212 #   endif /* !ECHOCTL */
213 #endif /* LNEW_CTLECH */
214 #ifdef LNEW_PENDIN
215 #   ifndef PENDIN
216 #	define PENDIN LNEW_PENDIN
217 #  endif /* !PENDIN */
218 #endif /* LNEW_PENDIN */
219 #ifndef ECHOCTL
220 #   ifndef VEOL
221 #	define RAWONLY	1
222 #   endif /* !VEOL */
223 #endif /* !ECHOCTL */
224 
225 /*
226  * Output label on wfd and return next char on rfd with no echo.
227  * Return < -1 is -(signal + 1).
228  */
229 
230 int
ttyquery(int rfd,int wfd,const char * label)231 ttyquery(int rfd, int wfd, const char* label)
232 {
233 	register int	r;
234 	int		n;
235 	unsigned char	c;
236 	struct termios	old;
237 	struct termios	tty;
238 
239 	if (!label)
240 		n = 0;
241 	else if (n = strlen(label))
242 		write(wfd, label, n);
243 	tcgetattr(rfd, &old);
244 	tty = old;
245 	tty.c_cc[VTIME] = 0;
246 	tty.c_cc[VMIN] = 1;
247 	tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);
248 	tcsetattr(rfd, TCSADRAIN, &tty);
249 	if ((r = read(rfd, &c, 1)) == 1) {
250 		if (c == old.c_cc[VEOF])
251 			r = -1;
252 		else if (c == old.c_cc[VINTR])
253 			r = -(SIGINT + 1);
254 		else if (c == old.c_cc[VQUIT])
255 			r = -(SIGQUIT + 1);
256 		else if (c == '\r')
257 			r = '\n';
258 		else
259 			r = c;
260 	}
261 	tcsetattr(rfd, TCSADRAIN, &old);
262 	if (n) {
263 		write(wfd, "\r", 1);
264 		while (n-- > 0)
265 			write(wfd, " ", 1);
266 		write(wfd, "\r", 1);
267 	}
268 	return r;
269 }
270 
271 /*
272  * Edit buf on rfd,wfd with label.
273  * Do not backspace over label.
274  */
275 
276 int
ttyedit(int rfd,int wfd,const char * label,char * buf,size_t size)277 ttyedit(int rfd, int wfd, const char* label, char* buf, size_t size)
278 {
279 	register int	r;
280 	register int	last = strlen(buf);
281 	unsigned char	c;
282 	struct termios	old;
283 	struct termios	tty;
284 
285 	size--;
286 	if (label)
287 		write(wfd, label, strlen(label));
288 	if (last)
289 		write(wfd, buf, last);
290 	tcgetattr(rfd, &old);
291 	tty = old;
292 	tty.c_cc[VTIME] = 0;
293 	tty.c_cc[VMIN] = 1;
294 	tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);
295 	tcsetattr(rfd, TCSADRAIN, &tty);
296 	for (;;) {
297 		if ((r = read(rfd, &c, 1)) <= 0)
298 			break;
299 		if (c == old.c_cc[VERASE]) {
300 			if (last == 0)
301 				write(wfd, "\a", 1);
302 			else {
303 				write(wfd, "\b \b", 3);
304 				last--;
305 			}
306 		}
307 		else if (c == old.c_cc[VKILL]) {
308 			memset(buf, '\b', last);
309 			write(wfd, buf, last);
310 			memset(buf, ' ', last);
311 			write(wfd, buf, last);
312 			memset(buf, '\b', last);
313 			write(wfd, buf, last);
314 			last = 0;
315 		}
316 		else if (c == old.c_cc[VEOF]) {
317 			r = last;
318 			break;
319 		}
320 		else if (c == old.c_cc[VINTR]) {
321 			r = -(SIGINT + 1);
322 			break;
323 		}
324 		else if (c == old.c_cc[VQUIT]) {
325 			r = -(SIGQUIT + 1);
326 			break;
327 		}
328 		else if (last > size) {
329 			r = -1;
330 			break;
331 		}
332 		else {
333 			if (c == '\r')
334 				c = '\n';
335 			buf[last++] = c;
336 			write(wfd, &buf[last - 1], 1);
337 			if (c == '\n') {
338 				r = --last;
339 				break;
340 			}
341 			r = last;
342 		}
343 	}
344 	tcsetattr(rfd, TCSADRAIN, &old);
345 	if (r >= 0)
346 		buf[last] = 0;
347 	return r;
348 }
349 
350 /*
351  * Edit the fields in type.
352  */
353 
354 void
grabedit(struct header * hp,unsigned long type)355 grabedit(struct header* hp, unsigned long type)
356 {
357 	register char*			s;
358 	register const struct lab*	lp;
359 	int				r;
360 	sig_t				saveint;
361 	sig_t				savequit;
362 	char				buf[LINESIZE];
363 
364 	fflush(stdout);
365 	if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
366 		signal(SIGINT, SIG_DFL);
367 	if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
368 		signal(SIGQUIT, SIG_DFL);
369 	r = 0;
370 	for (lp = state.hdrtab; lp->name; lp++)
371 		if (type & lp->type) {
372 			if (!(s = detract(hp, lp->type)))
373 				s = "";
374 			if (strlen(s) >= sizeof(buf)) {
375 				note(0, "%sfield too long to edit", lp->name);
376 				continue;
377 			}
378 			strcpy(buf, s);
379 			if ((r = ttyedit(0, 1, lp->name, buf, sizeof(buf))) < 0)
380 				break;
381 			headclear(hp, lp->type);
382 			extract(hp, lp->type, buf);
383 		}
384 	if (saveint != SIG_DFL)
385 		signal(SIGINT, saveint);
386 	if (savequit != SIG_DFL)
387 		signal(SIGQUIT, savequit);
388 	if (r < -1)
389 		kill(0, -(r + 1));
390 }
391