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
editor(int * msgvec)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
visual(int * msgvec)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
edit1(int * msgvec,char * ed)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