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