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