No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / mail / edit.c
blobafcd9f1a50286e0658db49beeb36fd0c3b8a4ad9
1 /* $NetBSD: edit.c,v 1.24 2007/10/29 23:20:38 christos Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93";
36 #else
37 __RCSID("$NetBSD: edit.c,v 1.24 2007/10/29 23:20:38 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include "rcv.h"
42 #include "extern.h"
43 #include "thread.h"
44 #include "sig.h"
47 * Mail -- a mail program
49 * Perform message editing functions.
53 * Run an editor on the file at "fpp" of "size" bytes,
54 * and return a new file pointer.
55 * Signals must be handled by the caller.
56 * "Editortype" is 'e' for _PATH_EX, 'v' for _PATH_VI.
58 PUBLIC FILE *
59 run_editor(FILE *fp, off_t size, int editortype, int readonlyflag)
61 FILE *nf = NULL;
62 int t;
63 time_t modtime;
64 const char *editcmd;
65 char tempname[PATHSIZE];
66 struct stat statb;
68 (void)snprintf(tempname, sizeof(tempname),
69 "%s/mail.ReXXXXXXXXXX", tmpdir);
70 if ((t = mkstemp(tempname)) == -1) {
71 warn("%s", tempname);
72 goto out;
74 if (readonlyflag && fchmod(t, 0400) == -1) {
75 (void)close(t);
76 warn("%s", tempname);
77 (void)unlink(tempname);
78 goto out;
80 if ((nf = Fdopen(t, "w")) == NULL) {
81 (void)close(t);
82 warn("%s", tempname);
83 (void)unlink(tempname);
84 goto out;
86 if (size >= 0)
87 while (--size >= 0 && (t = getc(fp)) != EOF)
88 (void)putc(t, nf);
89 else
90 while ((t = getc(fp)) != EOF)
91 (void)putc(t, nf);
92 (void)fflush(nf);
93 if (ferror(nf)) {
94 (void)Fclose(nf);
95 warn("%s", tempname);
96 (void)unlink(tempname);
97 nf = NULL;
98 goto out;
100 if (fstat(fileno(nf), &statb) < 0)
101 modtime = 0;
102 else
103 modtime = statb.st_mtime;
104 if (Fclose(nf) < 0) {
105 warn("%s", tempname);
106 (void)unlink(tempname);
107 nf = NULL;
108 goto out;
110 nf = NULL;
111 editcmd = value(editortype == 'e' ? ENAME_EDITOR : ENAME_VISUAL);
112 if (editcmd == NULL)
113 editcmd = editortype == 'e' ? _PATH_EX : _PATH_VI;
114 if (run_command(editcmd, NULL, 0, -1, tempname, NULL) < 0) {
115 (void)unlink(tempname);
116 goto out;
119 * If in read only mode or file unchanged, just remove the editor
120 * temporary and return.
122 if (readonlyflag) {
123 (void)unlink(tempname);
124 goto out;
126 if (stat(tempname, &statb) < 0) {
127 warn("%s", tempname);
128 goto out;
130 if (modtime == statb.st_mtime) {
131 (void)unlink(tempname);
132 goto out;
135 * Now switch to new file.
137 if ((nf = Fopen(tempname, "a+")) == NULL) {
138 warn("%s", tempname);
139 (void)unlink(tempname);
140 goto out;
142 (void)unlink(tempname);
143 out:
144 return nf;
148 * Edit a message by writing the message into a funnily-named file
149 * (which should not exist) and forking an editor on it.
150 * We get the editor from the stuff above.
152 static int
153 edit1(int *msgvec, int editortype)
155 int c;
156 int i;
157 int msgCount;
158 FILE *fp;
159 struct message *mp;
160 off_t size;
163 * Deal with each message to be edited . . .
165 msgCount = get_msgCount();
166 for (i = 0; msgvec[i] && i < msgCount; i++) {
167 sigset_t oset;
168 struct sigaction osa;
170 if (i > 0) {
171 char buf[100];
172 char *p;
174 (void)printf("Edit message %d [ynq]? ", msgvec[i]);
175 if (fgets(buf, (int)sizeof(buf), stdin) == 0)
176 break;
177 p = skip_WSP(buf);
178 if (*p == 'q')
179 break;
180 if (*p == 'n')
181 continue;
183 dot = mp = get_message(msgvec[i]);
184 touch(mp);
185 sig_check();
186 (void)sig_ignore(SIGINT, &osa, &oset);
187 fp = run_editor(setinput(mp), mp->m_size, editortype,
188 readonly);
189 if (fp != NULL) {
190 (void)fseek(otf, 0L, 2);
191 size = ftell(otf);
192 mp->m_block = blockof(size);
193 mp->m_offset = blkoffsetof(size);
194 mp->m_size = fsize(fp);
195 mp->m_lines = 0;
196 mp->m_blines = 0;
197 mp->m_flag |= MMODIFY;
198 rewind(fp);
199 while ((c = getc(fp)) != EOF) {
201 * XXX. if you edit a message, we treat
202 * header lines as body lines in the recount.
203 * This is because the original message copy
204 * and the edit reread use different code to
205 * count the lines, and this one here is
206 * simple-minded.
208 if (c == '\n') {
209 mp->m_lines++;
210 mp->m_blines++;
212 if (putc(c, otf) == EOF)
213 break;
215 if (ferror(otf))
216 warn("/tmp");
217 (void)Fclose(fp);
219 (void)sig_restore(SIGINT, &osa, &oset);
220 sig_check();
222 return 0;
226 * Edit a message list.
228 PUBLIC int
229 editor(void *v)
231 int *msgvec = v;
233 return edit1(msgvec, 'e');
237 * Invoke the visual editor on a message list.
239 PUBLIC int
240 visual(void *v)
242 int *msgvec = v;
244 return edit1(msgvec, 'v');