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