Annotation of src/usr.bin/mail/edit.c, Revision 1.16
1.16 ! tobias 1: /* $OpenBSD: edit.c,v 1.15 2007/08/31 23:14:21 ray Exp $ */
1.2 deraadt 2: /* $NetBSD: edit.c,v 1.5 1996/06/08 19:48:20 christos Exp $ */
3:
1.1 deraadt 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.
1.12 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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: #ifndef lint
1.2 deraadt 34: #if 0
1.11 millert 35: static const char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93";
1.2 deraadt 36: #else
1.16 ! tobias 37: static const char rcsid[] = "$OpenBSD: edit.c,v 1.15 2007/08/31 23:14:21 ray Exp $";
1.2 deraadt 38: #endif
1.1 deraadt 39: #endif /* not lint */
40:
1.15 ray 41: #include <sys/types.h>
42: #include <sys/wait.h>
43:
1.1 deraadt 44: #include "rcv.h"
1.15 ray 45: #include <errno.h>
1.1 deraadt 46: #include <fcntl.h>
47: #include "extern.h"
48:
1.15 ray 49: int editit(const char *, const char *);
50:
1.1 deraadt 51: /*
52: * Mail -- a mail program
53: *
54: * Perform message editing functions.
55: */
56:
57: /*
58: * Edit a message list.
59: */
60: int
1.11 millert 61: editor(void *v)
1.1 deraadt 62: {
1.2 deraadt 63: int *msgvec = v;
1.1 deraadt 64:
1.3 millert 65: return(edit1(msgvec, 'e'));
1.1 deraadt 66: }
67:
68: /*
69: * Invoke the visual editor on a message list.
70: */
71: int
1.11 millert 72: visual(void *v)
1.1 deraadt 73: {
1.2 deraadt 74: int *msgvec = v;
1.1 deraadt 75:
1.3 millert 76: return(edit1(msgvec, 'v'));
1.1 deraadt 77: }
78:
79: /*
80: * Edit a message by writing the message into a funnily-named file
81: * (which should not exist) and forking an editor on it.
82: * We get the editor from the stuff above.
83: */
84: int
1.11 millert 85: edit1(int *msgvec, int type)
1.1 deraadt 86: {
1.7 millert 87: int c, i;
1.1 deraadt 88: FILE *fp;
1.10 millert 89: struct sigaction oact;
90: sigset_t oset;
1.7 millert 91: struct message *mp;
1.1 deraadt 92: off_t size;
93:
94: /*
95: * Deal with each message to be edited . . .
96: */
97: for (i = 0; msgvec[i] && i < msgCount; i++) {
98: if (i > 0) {
99: char buf[100];
100: char *p;
101:
102: printf("Edit message %d [ynq]? ", msgvec[i]);
1.14 cloder 103: if (fgets(buf, sizeof(buf), stdin) == NULL)
1.1 deraadt 104: break;
105: for (p = buf; *p == ' ' || *p == '\t'; p++)
106: ;
107: if (*p == 'q')
108: break;
109: if (*p == 'n')
110: continue;
111: }
112: dot = mp = &message[msgvec[i] - 1];
113: touch(mp);
1.10 millert 114: (void)ignoresig(SIGINT, &oact, &oset);
1.13 deraadt 115: fp = run_editor(setinput(mp), (off_t)mp->m_size, type, readonly);
1.1 deraadt 116: if (fp != NULL) {
1.16 ! tobias 117: (void)fseek(otf, 0L, SEEK_END);
1.1 deraadt 118: size = ftell(otf);
119: mp->m_block = blockof(size);
120: mp->m_offset = offsetof(size);
121: mp->m_size = fsize(fp);
122: mp->m_lines = 0;
123: mp->m_flag |= MODIFY;
124: rewind(fp);
125: while ((c = getc(fp)) != EOF) {
126: if (c == '\n')
127: mp->m_lines++;
128: if (putc(c, otf) == EOF)
129: break;
130: }
131: if (ferror(otf))
1.3 millert 132: warn("/tmp");
133: (void)Fclose(fp);
1.1 deraadt 134: }
1.10 millert 135: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
136: (void)sigaction(SIGINT, &oact, NULL);
1.1 deraadt 137: }
1.3 millert 138: return(0);
1.1 deraadt 139: }
140:
141: /*
142: * Run an editor on the file at "fpp" of "size" bytes,
143: * and return a new file pointer.
144: * Signals must be handled by the caller.
145: * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
146: */
147: FILE *
1.11 millert 148: run_editor(FILE *fp, off_t size, int type, int readonly)
1.1 deraadt 149: {
1.7 millert 150: FILE *nf = NULL;
151: int t;
1.1 deraadt 152: time_t modtime;
1.6 millert 153: char *edit, tempname[PATHSIZE];
1.1 deraadt 154: struct stat statb;
155:
1.6 millert 156: (void)snprintf(tempname, sizeof(tempname),
157: "%s/mail.ReXXXXXXXXXX", tmpdir);
158: if ((t = mkstemp(tempname)) == -1 ||
159: (nf = Fdopen(t, "w")) == NULL) {
1.8 millert 160: warn("%s", tempname);
1.1 deraadt 161: goto out;
162: }
1.6 millert 163: if (readonly && fchmod(t, 0400) == -1) {
1.8 millert 164: warn("%s", tempname);
1.6 millert 165: (void)rm(tempname);
1.1 deraadt 166: goto out;
167: }
168: if (size >= 0)
169: while (--size >= 0 && (t = getc(fp)) != EOF)
1.4 millert 170: (void)putc(t, nf);
1.1 deraadt 171: else
172: while ((t = getc(fp)) != EOF)
1.4 millert 173: (void)putc(t, nf);
174: (void)fflush(nf);
1.1 deraadt 175: if (fstat(fileno(nf), &statb) < 0)
176: modtime = 0;
177: else
178: modtime = statb.st_mtime;
179: if (ferror(nf)) {
1.4 millert 180: (void)Fclose(nf);
1.8 millert 181: warn("%s", tempname);
1.6 millert 182: (void)rm(tempname);
1.1 deraadt 183: nf = NULL;
184: goto out;
185: }
186: if (Fclose(nf) < 0) {
1.8 millert 187: warn("%s", tempname);
1.6 millert 188: (void)rm(tempname);
1.1 deraadt 189: nf = NULL;
190: goto out;
191: }
192: nf = NULL;
1.15 ray 193: if (type == 'e') {
194: edit = value("EDITOR");
195: if (edit == NULL || edit[0] == '\0')
196: edit = _PATH_EX;
197: } else {
198: edit = value("VISUAL");
199: if (edit == NULL || edit[0] == '\0')
200: edit = _PATH_VI;
201: }
202: if (editit(edit, tempname) == -1) {
1.6 millert 203: (void)rm(tempname);
1.1 deraadt 204: goto out;
205: }
206: /*
207: * If in read only mode or file unchanged, just remove the editor
208: * temporary and return.
209: */
210: if (readonly) {
1.6 millert 211: (void)rm(tempname);
1.1 deraadt 212: goto out;
213: }
1.6 millert 214: if (stat(tempname, &statb) < 0) {
1.8 millert 215: warn("%s", tempname);
1.1 deraadt 216: goto out;
217: }
218: if (modtime == statb.st_mtime) {
1.6 millert 219: (void)rm(tempname);
1.1 deraadt 220: goto out;
221: }
222: /*
223: * Now switch to new file.
224: */
1.6 millert 225: if ((nf = Fopen(tempname, "a+")) == NULL) {
1.8 millert 226: warn("%s", tempname);
1.6 millert 227: (void)rm(tempname);
1.1 deraadt 228: goto out;
229: }
1.6 millert 230: (void)rm(tempname);
1.1 deraadt 231: out:
1.3 millert 232: return(nf);
1.15 ray 233: }
234:
235: /*
236: * Execute an editor on the specified pathname, which is interpreted
237: * from the shell. This means flags may be included.
238: *
239: * Returns -1 on error, or the exit value on success.
240: */
241: int
242: editit(const char *ed, const char *pathname)
243: {
244: char *argp[] = {"sh", "-c", NULL, NULL}, *p;
245: sig_t sighup, sigint, sigquit;
246: pid_t pid;
247: int saved_errno, st;
248:
249: if (ed == NULL)
250: ed = getenv("VISUAL");
251: if (ed == NULL || ed[0] == '\0')
252: ed = getenv("EDITOR");
253: if (ed == NULL || ed[0] == '\0')
254: ed = _PATH_VI;
255: if (asprintf(&p, "%s %s", ed, pathname) == -1)
256: return (-1);
257: argp[2] = p;
258:
259: sighup = signal(SIGHUP, SIG_IGN);
260: sigint = signal(SIGINT, SIG_IGN);
261: sigquit = signal(SIGQUIT, SIG_IGN);
262: if ((pid = fork()) == -1)
263: goto fail;
264: if (pid == 0) {
265: execv(_PATH_BSHELL, argp);
266: _exit(127);
267: }
268: while (waitpid(pid, &st, 0) == -1)
269: if (errno != EINTR)
270: goto fail;
271: free(p);
272: (void)signal(SIGHUP, sighup);
273: (void)signal(SIGINT, sigint);
274: (void)signal(SIGQUIT, sigquit);
275: if (!WIFEXITED(st)) {
276: errno = EINTR;
277: return (-1);
278: }
279: return (WEXITSTATUS(st));
280:
281: fail:
282: saved_errno = errno;
283: (void)signal(SIGHUP, sighup);
284: (void)signal(SIGINT, sigint);
285: (void)signal(SIGQUIT, sigquit);
286: free(p);
287: errno = saved_errno;
288: return (-1);
1.1 deraadt 289: }