xref: /netbsd-src/usr.bin/mail/edit.c (revision ce63d6c20fc4ec8ddc95c84bb229e3c4ecf82b69)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * 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 
34 #ifndef lint
35 static char sccsid[] = "@(#)edit.c	5.15 (Berkeley) 6/25/90";
36 #endif /* not lint */
37 
38 #include "rcv.h"
39 #include <sys/stat.h>
40 
41 /*
42  * Mail -- a mail program
43  *
44  * Perform message editing functions.
45  */
46 
47 /*
48  * Edit a message list.
49  */
50 
51 editor(msgvec)
52 	int *msgvec;
53 {
54 
55 	return edit1(msgvec, 'e');
56 }
57 
58 /*
59  * Invoke the visual editor on a message list.
60  */
61 
62 visual(msgvec)
63 	int *msgvec;
64 {
65 
66 	return edit1(msgvec, 'v');
67 }
68 
69 /*
70  * Edit a message by writing the message into a funnily-named file
71  * (which should not exist) and forking an editor on it.
72  * We get the editor from the stuff above.
73  */
74 edit1(msgvec, type)
75 	int *msgvec;
76 	char type;
77 {
78 	register int c;
79 	int i;
80 	FILE *fp;
81 	register struct message *mp;
82 	off_t size;
83 
84 	/*
85 	 * Deal with each message to be edited . . .
86 	 */
87 	for (i = 0; msgvec[i] && i < msgCount; i++) {
88 		sig_t sigint;
89 
90 		if (i > 0) {
91 			char buf[100];
92 			char *p;
93 
94 			printf("Edit message %d [ynq]? ", msgvec[i]);
95 			if (fgets(buf, sizeof buf, stdin) == 0)
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);
106 		sigint = signal(SIGINT, SIG_IGN);
107 		fp = run_editor(setinput(mp), mp->m_size, type, readonly);
108 		if (fp != NULL) {
109 			(void) fseek(otf, (long) 0, 2);
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))
124 				perror("/tmp");
125 			(void) Fclose(fp);
126 		}
127 		(void) signal(SIGINT, sigint);
128 	}
129 	return 0;
130 }
131 
132 /*
133  * Run an editor on the file at "fpp" of "size" bytes,
134  * and return a new file pointer.
135  * Signals must be handled by the caller.
136  * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
137  */
138 FILE *
139 run_editor(fp, size, type, readonly)
140 	register FILE *fp;
141 	off_t size;
142 	char type;
143 {
144 	register FILE *nf = NULL;
145 	register int t;
146 	time_t modtime;
147 	char *edit;
148 	struct stat statb;
149 	extern char tempEdit[];
150 
151 	if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) {
152 		perror(tempEdit);
153 		goto out;
154 	}
155 	if ((nf = Fdopen(t, "w")) == NULL) {
156 		perror(tempEdit);
157 		(void) unlink(tempEdit);
158 		goto out;
159 	}
160 	if (size >= 0)
161 		while (--size >= 0 && (t = getc(fp)) != EOF)
162 			(void) putc(t, nf);
163 	else
164 		while ((t = getc(fp)) != EOF)
165 			(void) putc(t, nf);
166 	(void) fflush(nf);
167 	if (fstat(fileno(nf), &statb) < 0)
168 		modtime = 0;
169 	else
170 		modtime = statb.st_mtime;
171 	if (ferror(nf)) {
172 		(void) Fclose(nf);
173 		perror(tempEdit);
174 		(void) unlink(tempEdit);
175 		nf = NULL;
176 		goto out;
177 	}
178 	if (Fclose(nf) < 0) {
179 		perror(tempEdit);
180 		(void) unlink(tempEdit);
181 		nf = NULL;
182 		goto out;
183 	}
184 	nf = NULL;
185 	if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
186 		edit = type == 'e' ? _PATH_EX : _PATH_VI;
187 	if (run_command(edit, 0, -1, -1, tempEdit, NOSTR) < 0) {
188 		(void) unlink(tempEdit);
189 		goto out;
190 	}
191 	/*
192 	 * If in read only mode or file unchanged, just remove the editor
193 	 * temporary and return.
194 	 */
195 	if (readonly) {
196 		(void) unlink(tempEdit);
197 		goto out;
198 	}
199 	if (stat(tempEdit, &statb) < 0) {
200 		perror(tempEdit);
201 		goto out;
202 	}
203 	if (modtime == statb.st_mtime) {
204 		(void) unlink(tempEdit);
205 		goto out;
206 	}
207 	/*
208 	 * Now switch to new file.
209 	 */
210 	if ((nf = Fopen(tempEdit, "a+")) == NULL) {
211 		perror(tempEdit);
212 		(void) unlink(tempEdit);
213 		goto out;
214 	}
215 	(void) unlink(tempEdit);
216 out:
217 	return nf;
218 }
219