xref: /original-bsd/usr.bin/mail/edit.c (revision cd18b70b)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char *sccsid = "@(#)edit.c	5.4 (Berkeley) 05/18/87";
9 #endif not lint
10 
11 #include "rcv.h"
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #include <sys/wait.h>
15 
16 /*
17  * Mail -- a mail program
18  *
19  * Perform message editing functions.
20  */
21 
22 /*
23  * Edit a message list.
24  */
25 
26 editor(msgvec)
27 	int *msgvec;
28 {
29 	char *edname;
30 
31 	if ((edname = value("EDITOR")) == NOSTR)
32 		edname = EDITOR;
33 	return(edit1(msgvec, edname));
34 }
35 
36 /*
37  * Invoke the visual editor on a message list.
38  */
39 
40 visual(msgvec)
41 	int *msgvec;
42 {
43 	char *edname;
44 
45 	if ((edname = value("VISUAL")) == NOSTR)
46 		edname = VISUAL;
47 	return(edit1(msgvec, edname));
48 }
49 
50 /*
51  * Edit a message by writing the message into a funnily-named file
52  * (which should not exist) and forking an editor on it.
53  * We get the editor from the stuff above.
54  */
55 
56 edit1(msgvec, ed)
57 	int *msgvec;
58 	char *ed;
59 {
60 	register int c;
61 	int *ip, pid, mesg;
62 	int (*sigint)(), (*sigquit)();
63 	FILE *ibuf, *obuf;
64 	char edname[15];
65 	register struct message *mp;
66 	extern char tempEdit[];
67 	off_t fsize(), size;
68 	struct stat statb;
69 	long modtime;
70 	union wait status;
71 
72 	/*
73 	 * Set signals; locate editor.
74 	 */
75 
76 	sigint = signal(SIGINT, SIG_IGN);
77 	sigquit = signal(SIGQUIT, SIG_IGN);
78 
79 	/*
80 	 * Deal with each message to be edited . . .
81 	 */
82 
83 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
84 		mesg = *ip;
85 		mp = &message[mesg-1];
86 		mp->m_flag |= MODIFY;
87 		touch(mesg);
88 		dot = mp;
89 
90 		/*
91 		 * Make up a name for the edit file of the
92 		 * form "Message%d" and make sure it doesn't
93 		 * already exist.
94 		 */
95 		(void) sprintf(edname, "Message%d", mesg);
96 		if (!access(edname, 2)) {
97 			printf("%s: file exists\n", edname);
98 			goto out;
99 		}
100 
101 		/*
102 		 * Copy the message into the edit file.
103 		 */
104 		(void) close(creat(edname, 0600));
105 		if ((obuf = fopen(edname, "w")) == NULL) {
106 			perror(edname);
107 			goto out;
108 		}
109 		if (send(mp, obuf, 0) < 0) {
110 			perror(edname);
111 			(void) fclose(obuf);
112 			(void) remove(edname);
113 			goto out;
114 		}
115 		(void) fflush(obuf);
116 		if (ferror(obuf)) {
117 			(void) remove(edname);
118 			(void) fclose(obuf);
119 			goto out;
120 		}
121 		(void) fclose(obuf);
122 
123 		/*
124 		 * If we are in read only mode, make the
125 		 * temporary message file readonly as well.
126 		 */
127 
128 		if (readonly)
129 			(void) chmod(edname, 0400);
130 
131 		/*
132 		 * Fork/execl the editor on the edit file.
133 		 */
134 
135 		if (stat(edname, &statb) < 0)
136 			modtime = 0;
137 		modtime = statb.st_mtime;
138 		pid = vfork();
139 		if (pid == -1) {
140 			perror("fork");
141 			(void) remove(edname);
142 			goto out;
143 		}
144 		if (pid == 0) {
145 			if (sigint != SIG_IGN)
146 				(void) signal(SIGINT, SIG_DFL);
147 			if (sigquit != SIG_IGN)
148 				(void) signal(SIGQUIT, SIG_DFL);
149 			execl(ed, ed, edname, 0);
150 			perror(ed);
151 			_exit(1);
152 		}
153 		while (wait(&status) != pid)
154 			;
155 
156 		/*
157 		 * If in read only mode, just remove the editor
158 		 * temporary and return.
159 		 */
160 
161 		if (readonly) {
162 			(void) remove(edname);
163 			continue;
164 		}
165 
166 		/*
167 		 * Now copy the message to the end of the
168 		 * temp file.
169 		 */
170 
171 		if (stat(edname, &statb) < 0) {
172 			perror(edname);
173 			goto out;
174 		}
175 		if (modtime == statb.st_mtime) {
176 			(void) remove(edname);
177 			goto out;
178 		}
179 		if ((ibuf = fopen(edname, "r")) == NULL) {
180 			perror(edname);
181 			(void) remove(edname);
182 			goto out;
183 		}
184 		(void) remove(edname);
185 		(void) fseek(otf, (long) 0, 2);
186 		size = ftell(otf);
187 		mp->m_block = blockof(size);
188 		mp->m_offset = offsetof(size);
189 		mp->m_size = fsize(ibuf);
190 		mp->m_lines = 0;
191 		while ((c = getc(ibuf)) != EOF) {
192 			if (c == '\n')
193 				mp->m_lines++;
194 			(void) putc(c, otf);
195 			if (ferror(otf))
196 				break;
197 		}
198 		if (ferror(otf))
199 			perror("/tmp");
200 		(void) fclose(ibuf);
201 	}
202 
203 	/*
204 	 * Restore signals and return.
205 	 */
206 
207 out:
208 	(void) signal(SIGINT, sigint);
209 	(void) signal(SIGQUIT, sigquit);
210 	return 0;
211 }
212