xref: /illumos-gate/usr/src/cmd/mailx/edit.c (revision a28480febf31f0e61debac062a55216a98a05a92)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
42 
43 #include "rcv.h"
44 #include <locale.h>
45 
46 
47 /*
48  * mailx -- a modified version of a University of California at Berkeley
49  *	mail program
50  *
51  * Perform message editing functions.
52  */
53 
54 static void edit1(int *msgvec, char *ed);
55 
56 /*
57  * Edit a message list.
58  */
59 
60 int
61 editor(int *msgvec)
62 {
63 	char *edname;
64 
65 	if ((edname = value("EDITOR")) == NOSTR || *edname == '\0')
66 		edname = EDITOR;
67 	edit1(msgvec, edname);
68 	return(0);
69 }
70 
71 /*
72  * Invoke the visual editor on a message list.
73  */
74 
75 int
76 visual(int *msgvec)
77 {
78 	char *edname;
79 
80 	if ((edname = value("VISUAL")) == NOSTR || *edname == '\0')
81 		edname = VISUAL;
82 	edit1(msgvec, edname);
83 	return(0);
84 }
85 
86 /*
87  * Edit a message by writing the message into a funnily-named file
88  * (which should not exist) and forking an editor on it.
89  * We get the editor from the stuff above.
90  */
91 
92 static void
93 edit1(int *msgvec, char *ed)
94 {
95 	register int c, lastc = '\n';
96 	pid_t pid;
97 	int *ip, mesg, blank = 1;
98 	long ms, lines;
99 	void (*sigint)(int), (*sigquit)(int);
100 	FILE *ibuf, *obuf;
101 	struct message *mp;
102 	off_t size;
103 	struct stat statb;
104 	long modtime;
105 	int fd = -1;
106 
107 	/*
108 	 * Set signals; locate editor.
109 	 */
110 
111 	sigint = sigset(SIGINT, SIG_IGN);
112 	sigquit = sigset(SIGQUIT, SIG_IGN);
113 	ed = safeexpand(ed);
114 
115 	/*
116 	 * Deal with each message to be edited . . .
117 	 */
118 
119 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
120 		mesg = *ip;
121 		touch(mesg);
122 		mp = &message[mesg-1];
123 		dot = mp;
124 		if (mp->m_text) {
125 			if (!access(tempZedit, 2)) {
126 				printf(gettext("%s: file exists\n"), tempZedit);
127 				goto out;
128 			}
129 
130 			/*
131 			 * Copy the message into the edit file.
132 			 */
133 
134 			if ((fd = open(tempZedit, O_RDWR|O_CREAT|
135 					O_EXCL, 0600)) < 0 ||
136 				(obuf = fdopen(fd, "w")) == NULL) {
137 				perror(tempZedit);
138 				goto out;
139 			}
140 			if (msend(mp, obuf, 0, fputs) < 0) {
141 				perror(tempZedit);
142 				fclose(obuf);
143 				removefile(tempZedit);
144 				goto out;
145 			}
146 			fflush(obuf);
147 			if (fferror(obuf)) {
148 				perror(tempZedit);
149 				fclose(obuf);
150 				removefile(tempZedit);
151 				goto out;
152 			}
153 			fclose(obuf);
154 
155 			/*
156 			 * If we are in read only mode, make the
157 			 * temporary message file readonly as well.
158 			 */
159 
160 			if (readonly)
161 				chmod(tempZedit, 0400);
162 
163 			/*
164 			 * Fork/execl the editor on the edit file.
165 			 */
166 
167 			if (stat(tempZedit, &statb) < 0)
168 				modtime = 0;
169 			else
170 				modtime = statb.st_mtime;
171 			pid = vfork();
172 			if (pid == (pid_t)-1) {
173 				perror("fork");
174 				removefile(tempZedit);
175 				goto out;
176 			}
177 			if (pid == 0) {
178 				sigchild();
179 				if (sigint != SIG_IGN)
180 					sigset(SIGINT, SIG_DFL);
181 				if (sigquit != SIG_IGN)
182 					sigset(SIGQUIT, SIG_DFL);
183 				execlp(ed, ed, tempZedit, (char *)0);
184 				perror(ed);
185 				_exit(1);
186 			}
187 			while (wait(&mesg) != pid)
188 				;
189 
190 			/*
191 			 * If in read only mode, just remove the editor
192 			 * temporary and return.
193 			 */
194 
195 			if (readonly) {
196 				removefile(tempZedit);
197 				continue;
198 			}
199 
200 			/*
201 			 * Now copy the message to the end of the
202 			 * temp file.
203 			 */
204 
205 			if (stat(tempZedit, &statb) < 0) {
206 				perror(tempZedit);
207 				continue;
208 			}
209 			if (modtime == statb.st_mtime) {
210 				removefile(tempZedit);
211 				continue;
212 			}
213 			if ((ibuf = fopen(tempZedit, "r")) == NULL) {
214 				perror(tempZedit);
215 				removefile(tempZedit);
216 				continue;
217 			}
218 			removefile(tempZedit);
219 			fseek(otf, (long) 0, 2);
220 			size = fsize(otf);
221 			mp->m_flag |= MODIFY;
222 			mp->m_offset = size;
223 			ms = 0L;
224 			lines = 0;
225 			while ((c = getc(ibuf)) != EOF) {
226 				if (c == '\n') {
227 					lines++;
228 					blank = lastc == '\n';
229 				}
230 				lastc = c;
231 				putc(c, otf);
232 				if (ferror(otf))
233 					break;
234 				ms++;
235 			}
236 			if (!blank) {
237 				putc('\n', otf);
238 				ms++;
239 				lines++;
240 			}
241 			mp->m_size = ms;
242 			mp->m_lines = lines;
243 			fflush(otf);
244 			if (fferror(otf))
245 				perror("/tmp");
246 			fclose(ibuf);
247 			setclen(mp);
248 		} else {
249 			printf("\n%s\n", gettext(
250 "*** Message content is not printable: pipe to command or save to a file ***"));
251 		}
252 	}
253 
254 	/*
255 	 * Restore signals and return.
256 	 */
257 
258 out:
259 	sigset(SIGINT, sigint);
260 	sigset(SIGQUIT, sigquit);
261 }
262