xref: /illumos-gate/usr/src/cmd/mailx/edit.c (revision 2a295025ab352ac2f6469a947d5b5e2f9379f943)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California
34  * All Rights Reserved
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
40 
41 #include "rcv.h"
42 #include <locale.h>
43 
44 
45 /*
46  * mailx -- a modified version of a University of California at Berkeley
47  *	mail program
48  *
49  * Perform message editing functions.
50  */
51 
52 static void edit1(int *msgvec, char *ed);
53 
54 /*
55  * Edit a message list.
56  */
57 
58 int
59 editor(int *msgvec)
60 {
61 	char *edname;
62 
63 	if ((edname = value("EDITOR")) == NOSTR || *edname == '\0')
64 		edname = EDITOR;
65 	edit1(msgvec, edname);
66 	return(0);
67 }
68 
69 /*
70  * Invoke the visual editor on a message list.
71  */
72 
73 int
74 visual(int *msgvec)
75 {
76 	char *edname;
77 
78 	if ((edname = value("VISUAL")) == NOSTR || *edname == '\0')
79 		edname = VISUAL;
80 	edit1(msgvec, edname);
81 	return(0);
82 }
83 
84 /*
85  * Edit a message by writing the message into a funnily-named file
86  * (which should not exist) and forking an editor on it.
87  * We get the editor from the stuff above.
88  */
89 
90 static void
91 edit1(int *msgvec, char *ed)
92 {
93 	register int c, lastc = '\n';
94 	pid_t pid;
95 	int *ip, mesg, blank = 1;
96 	long ms, lines;
97 	void (*sigint)(int), (*sigquit)(int);
98 	FILE *ibuf, *obuf;
99 	struct message *mp;
100 	off_t size;
101 	struct stat statb;
102 	long modtime;
103 	int fd = -1;
104 
105 	/*
106 	 * Set signals; locate editor.
107 	 */
108 
109 	sigint = sigset(SIGINT, SIG_IGN);
110 	sigquit = sigset(SIGQUIT, SIG_IGN);
111 	ed = safeexpand(ed);
112 
113 	/*
114 	 * Deal with each message to be edited . . .
115 	 */
116 
117 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
118 		mesg = *ip;
119 		touch(mesg);
120 		mp = &message[mesg-1];
121 		dot = mp;
122 		if (mp->m_text) {
123 			if (!access(tempZedit, 2)) {
124 				printf(gettext("%s: file exists\n"), tempZedit);
125 				goto out;
126 			}
127 
128 			/*
129 			 * Copy the message into the edit file.
130 			 */
131 
132 			if ((fd = open(tempZedit, O_RDWR|O_CREAT|
133 					O_EXCL, 0600)) < 0 ||
134 				(obuf = fdopen(fd, "w")) == NULL) {
135 				perror(tempZedit);
136 				goto out;
137 			}
138 			if (msend(mp, obuf, 0, fputs) < 0) {
139 				perror(tempZedit);
140 				fclose(obuf);
141 				removefile(tempZedit);
142 				goto out;
143 			}
144 			fflush(obuf);
145 			if (fferror(obuf)) {
146 				perror(tempZedit);
147 				fclose(obuf);
148 				removefile(tempZedit);
149 				goto out;
150 			}
151 			fclose(obuf);
152 
153 			/*
154 			 * If we are in read only mode, make the
155 			 * temporary message file readonly as well.
156 			 */
157 
158 			if (readonly)
159 				chmod(tempZedit, 0400);
160 
161 			/*
162 			 * Fork/execl the editor on the edit file.
163 			 */
164 
165 			if (stat(tempZedit, &statb) < 0)
166 				modtime = 0;
167 			else
168 				modtime = statb.st_mtime;
169 			pid = vfork();
170 			if (pid == (pid_t)-1) {
171 				perror("fork");
172 				removefile(tempZedit);
173 				goto out;
174 			}
175 			if (pid == 0) {
176 				sigchild();
177 				if (sigint != SIG_IGN)
178 					sigset(SIGINT, SIG_DFL);
179 				if (sigquit != SIG_IGN)
180 					sigset(SIGQUIT, SIG_DFL);
181 				execlp(ed, ed, tempZedit, (char *)0);
182 				perror(ed);
183 				_exit(1);
184 			}
185 			while (wait(&mesg) != pid)
186 				;
187 
188 			/*
189 			 * If in read only mode, just remove the editor
190 			 * temporary and return.
191 			 */
192 
193 			if (readonly) {
194 				removefile(tempZedit);
195 				continue;
196 			}
197 
198 			/*
199 			 * Now copy the message to the end of the
200 			 * temp file.
201 			 */
202 
203 			if (stat(tempZedit, &statb) < 0) {
204 				perror(tempZedit);
205 				continue;
206 			}
207 			if (modtime == statb.st_mtime) {
208 				removefile(tempZedit);
209 				continue;
210 			}
211 			if ((ibuf = fopen(tempZedit, "r")) == NULL) {
212 				perror(tempZedit);
213 				removefile(tempZedit);
214 				continue;
215 			}
216 			removefile(tempZedit);
217 			fseek(otf, (long) 0, 2);
218 			size = fsize(otf);
219 			mp->m_flag |= MODIFY;
220 			mp->m_offset = size;
221 			ms = 0L;
222 			lines = 0;
223 			while ((c = getc(ibuf)) != EOF) {
224 				if (c == '\n') {
225 					lines++;
226 					blank = lastc == '\n';
227 				}
228 				lastc = c;
229 				putc(c, otf);
230 				if (ferror(otf))
231 					break;
232 				ms++;
233 			}
234 			if (!blank) {
235 				putc('\n', otf);
236 				ms++;
237 				lines++;
238 			}
239 			mp->m_size = ms;
240 			mp->m_lines = lines;
241 			fflush(otf);
242 			if (fferror(otf))
243 				perror("/tmp");
244 			fclose(ibuf);
245 			setclen(mp);
246 		} else {
247 			printf("\n%s\n", gettext(
248 "*** Message content is not printable: pipe to command or save to a file ***"));
249 		}
250 	}
251 
252 	/*
253 	 * Restore signals and return.
254 	 */
255 
256 out:
257 	sigset(SIGINT, sigint);
258 	sigset(SIGQUIT, sigquit);
259 }
260