xref: /dragonfly/usr.bin/mail/edit.c (revision b40e316c)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)edit.c	8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.bin/mail/edit.c,v 1.2.6.4 2003/01/06 05:46:03 mikeh Exp $
35  * $DragonFly: src/usr.bin/mail/edit.c,v 1.4 2004/09/08 03:01:11 joerg Exp $
36  */
37 
38 #include "rcv.h"
39 #include <fcntl.h>
40 #include "extern.h"
41 
42 /*
43  * Mail -- a mail program
44  *
45  * Perform message editing functions.
46  */
47 
48 /*
49  * Edit a message list.
50  */
51 int
52 editor(int *msgvec)
53 {
54 	return (edit1(msgvec, 'e'));
55 }
56 
57 /*
58  * Invoke the visual editor on a message list.
59  */
60 int
61 visual(int *msgvec)
62 {
63 	return (edit1(msgvec, 'v'));
64 }
65 
66 /*
67  * Edit a message by writing the message into a funnily-named file
68  * (which should not exist) and forking an editor on it.
69  * We get the editor from the stuff above.
70  */
71 int
72 edit1(int *msgvec, int type)
73 {
74 	int c, i;
75 	FILE *fp;
76 	struct message *mp;
77 	off_t size;
78 
79 	/*
80 	 * Deal with each message to be edited . . .
81 	 */
82 	for (i = 0; msgvec[i] && i < msgCount; i++) {
83 		sig_t sigint;
84 
85 		if (i > 0) {
86 			char buf[100];
87 			char *p;
88 
89 			printf("Edit message %d [ynq]? ", msgvec[i]);
90 			if (fgets(buf, sizeof(buf), stdin) == 0)
91 				break;
92 			for (p = buf; *p == ' ' || *p == '\t'; p++)
93 				;
94 			if (*p == 'q')
95 				break;
96 			if (*p == 'n')
97 				continue;
98 		}
99 		dot = mp = &message[msgvec[i] - 1];
100 		touch(mp);
101 		sigint = signal(SIGINT, SIG_IGN);
102 		fp = run_editor(setinput(mp), mp->m_size, type, readonly);
103 		if (fp != NULL) {
104 			fseeko(otf, (off_t)0, SEEK_END);
105 			size = ftello(otf);
106 			mp->m_block = blockof(size);
107 			mp->m_offset = boffsetof(size);
108 			mp->m_size = (long)fsize(fp);
109 			mp->m_lines = 0;
110 			mp->m_flag |= MODIFY;
111 			rewind(fp);
112 			while ((c = getc(fp)) != EOF) {
113 				if (c == '\n')
114 					mp->m_lines++;
115 				if (putc(c, otf) == EOF)
116 					break;
117 			}
118 			if (ferror(otf))
119 				warnx("/tmp");
120 			Fclose(fp);
121 		}
122 		signal(SIGINT, sigint);
123 	}
124 	return (0);
125 }
126 
127 /*
128  * Run an editor on the file at "fpp" of "size" bytes,
129  * and return a new file pointer.
130  * Signals must be handled by the caller.
131  * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
132  */
133 FILE *
134 run_editor(FILE *fp, off_t size, int type, int readonly)
135 {
136 	FILE *nf = NULL;
137 	int t;
138 	time_t modtime;
139 	char *edit, tempname[PATHSIZE];
140 	struct stat statb;
141 
142 	snprintf(tempname, sizeof(tempname), "%s/mail.ReXXXXXXXXXX", tmpdir);
143 	if ((t = mkstemp(tempname)) == -1 ||
144 	    (nf = Fdopen(t, "w")) == NULL) {
145 		warn("%s", tempname);
146 		goto out;
147 	}
148 	if (readonly && fchmod(t, 0400) == -1) {
149 		warn("%s", tempname);
150 		rm(tempname);
151 		goto out;
152 	}
153 	if (size >= 0)
154 		while (--size >= 0 && (t = getc(fp)) != EOF)
155 			putc(t, nf);
156 	else
157 		while ((t = getc(fp)) != EOF)
158 			putc(t, nf);
159 	fflush(nf);
160 	if (fstat(fileno(nf), &statb) < 0)
161 		modtime = 0;
162 	else
163 		modtime = statb.st_mtime;
164 	if (ferror(nf)) {
165 		Fclose(nf);
166 		warnx("%s", tempname);
167 		rm(tempname);
168 		nf = NULL;
169 		goto out;
170 	}
171 	if (Fclose(nf) < 0) {
172 		warn("%s", tempname);
173 		rm(tempname);
174 		nf = NULL;
175 		goto out;
176 	}
177 	nf = NULL;
178 	if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL)
179 		edit = type == 'e' ? _PATH_EX : _PATH_VI;
180 	if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) {
181 		rm(tempname);
182 		goto out;
183 	}
184 	/*
185 	 * If in read only mode or file unchanged, just remove the editor
186 	 * temporary and return.
187 	 */
188 	if (readonly) {
189 		rm(tempname);
190 		goto out;
191 	}
192 	if (stat(tempname, &statb) < 0) {
193 		warn("%s", tempname);
194 		goto out;
195 	}
196 	if (modtime == statb.st_mtime) {
197 		rm(tempname);
198 		goto out;
199 	}
200 	/*
201 	 * Now switch to new file.
202 	 */
203 	if ((nf = Fopen(tempname, "a+")) == NULL) {
204 		warn("%s", tempname);
205 		rm(tempname);
206 		goto out;
207 	}
208 	rm(tempname);
209 out:
210 	return (nf);
211 }
212