make-config.in: complete path (leftover of [807f64e2], 2015-12-26!)
[s-mailx.git] / edit.c
blob5cd53fa2851c28c17335e8f38284671734c596bd
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Perform message editing functions.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8 /*
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
36 #undef n_FILE
37 #define n_FILE edit
39 #ifndef HAVE_AMALGAMATION
40 # include "nail.h"
41 #endif
43 /* Edit a message by writing the message into a funnily-named file (which
44 * should not exist) and forking an editor on it */
45 static int edit1(int *msgvec, int viored);
47 static int
48 edit1(int *msgvec, int viored)
50 int c, i;
51 FILE *fp = NULL;
52 struct message *mp;
53 off_t size;
54 bool_t wb, lastnl;
55 NYD_ENTER;
57 wb = ok_blook(writebackedited);
59 /* Deal with each message to be edited... */
60 for (i = 0; msgvec[i] != 0 && i < msgCount; ++i) {
61 sighandler_type sigint;
63 if(i > 0){
64 char prompt[64];
66 snprintf(prompt, sizeof prompt, _("Edit message %d"), msgvec[i]);
67 if(!getapproval(prompt, TRU1))
68 continue;
71 mp = message + msgvec[i] - 1;
72 setdot(mp);
73 n_pstate |= n_PS_DID_PRINT_DOT;
74 touch(mp);
76 sigint = safe_signal(SIGINT, SIG_IGN);
78 --mp->m_size; /* Strip final NL.. TODO MAILVFS->MESSAGE->length() */
79 fp = n_run_editor(fp, -1/*mp->m_size TODO */, viored,
80 ((mb.mb_perm & MB_EDIT) == 0 || !wb), NULL, mp,
81 (wb ? SEND_MBOX : SEND_TODISP_ALL), sigint, NULL);
82 ++mp->m_size; /* And readd it TODO */
84 if (fp != NULL) {
85 fseek(mb.mb_otf, 0L, SEEK_END);
86 size = ftell(mb.mb_otf);
87 mp->m_block = mailx_blockof(size);
88 mp->m_offset = mailx_offsetof(size);
89 mp->m_lines = 0;
90 mp->m_flag |= MODIFY;
91 rewind(fp);
92 lastnl = 0;
93 size = 0;
94 while ((c = getc(fp)) != EOF) {
95 if ((lastnl = (c == '\n')))
96 ++mp->m_lines;
97 if (putc(c, mb.mb_otf) == EOF)
98 break;
99 ++size;
101 if (!lastnl && putc('\n', mb.mb_otf) != EOF)
102 ++size;
103 if (putc('\n', mb.mb_otf) != EOF)
104 ++size;
105 mp->m_size = (size_t)size;
106 if (ferror(mb.mb_otf))
107 n_perr(_("/tmp"), 0);
108 Fclose(fp);
111 safe_signal(SIGINT, sigint);
113 NYD_LEAVE;
114 return 0;
117 FL int
118 c_editor(void *v)
120 int *msgvec = v, rv;
121 NYD_ENTER;
123 rv = edit1(msgvec, 'e');
124 NYD_LEAVE;
125 return rv;
128 FL int
129 c_visual(void *v)
131 int *msgvec = v, rv;
132 NYD_ENTER;
134 rv = edit1(msgvec, 'v');
135 NYD_LEAVE;
136 return rv;
139 FL FILE *
140 n_run_editor(FILE *fp, off_t size, int viored, bool_t readonly,
141 struct header *hp, struct message *mp, enum sendaction action,
142 sighandler_type oldint, char const *pipecmd)
144 struct stat statb;
145 sigset_t cset;
146 int t, ws;
147 time_t modtime;
148 off_t modsize;
149 char *tmp_name;
150 FILE *nf, *nf_pipetmp, *nf_tmp;
151 NYD_ENTER;
153 nf = nf_pipetmp = NULL;
154 tmp_name = NULL;
155 modtime = 0, modsize = 0;
157 if((nf_tmp = Ftmp(&tmp_name, "runed",
158 ((viored == '|' ? OF_RDWR : OF_WRONLY) | OF_REGISTER |
159 OF_REGISTER_UNLINK | OF_FN_AUTOREC))) == NULL){
160 jetempo:
161 n_perr(_("temporary mail edit file"), 0);
162 goto jleave;
165 if(hp != NULL){
166 assert(mp == NULL);
167 if(!n_header_put4compose(nf_tmp, hp))
168 goto jleave;
171 if(mp != NULL){
172 assert(hp == NULL);
173 if(sendmp(mp, nf_tmp, NULL, NULL, action, NULL) < 0){
174 n_err(_("Failed to prepare editable message\n"));
175 goto jleave;
177 }else{
178 if(size >= 0){
179 while(--size >= 0 && (t = getc(fp)) != EOF)
180 if(putc(t, nf_tmp) == EOF)
181 break;
182 }else{
183 while((t = getc(fp)) != EOF)
184 if(putc(t, nf_tmp) == EOF)
185 break;
189 fflush(nf_tmp);
191 if((t = (fp != NULL && ferror(fp))) == 0 && (t = ferror(nf_tmp)) == 0){
192 if(viored != '|'){
193 if(!fstat(fileno(nf_tmp), &statb))
194 modtime = statb.st_mtime, modsize = statb.st_size;
196 if(readonly)
197 t = (fchmod(fileno(nf_tmp), S_IRUSR) != 0);
201 if(t != 0){
202 n_perr(tmp_name, 0);
203 goto jleave;
206 if(viored == '|'){
207 assert(pipecmd != NULL);
208 tmp_name = NULL;
209 if((nf_pipetmp = Ftmp(&tmp_name, "runed", OF_WRONLY | OF_REGISTER |
210 OF_REGISTER_UNLINK | OF_FN_AUTOREC)) == NULL)
211 goto jetempo;
212 really_rewind(nf = nf_tmp);
213 nf_tmp = nf_pipetmp;
214 nf_pipetmp = nf;
215 nf = NULL;
216 if(n_child_run(ok_vlook(SHELL), 0, fileno(nf_pipetmp), fileno(nf_tmp),
217 "-c", pipecmd, NULL, NULL, &ws) < 0 || WEXITSTATUS(ws) != 0)
218 goto jleave;
219 }else{
220 sigemptyset(&cset);
221 if(n_child_run((viored == 'e' ? ok_vlook(EDITOR) : ok_vlook(VISUAL)),
222 (oldint != SIG_IGN ? &cset : NULL),
223 n_CHILD_FD_PASS, n_CHILD_FD_PASS, tmp_name, NULL, NULL, NULL,
224 &ws) < 0 || WEXITSTATUS(ws) != 0)
225 goto jleave;
228 /* If in read only mode or file unchanged, just remove the editor temporary
229 * and return. Otherwise switch to new file */
230 if(viored != '|'){
231 if(readonly)
232 goto jleave;
233 if(stat(tmp_name, &statb) == -1){
234 n_perr(tmp_name, 0);
235 goto jleave;
237 if(modtime == statb.st_mtime && modsize == statb.st_size)
238 goto jleave;
241 if((nf = Fopen(tmp_name, "r+")) == NULL)
242 n_perr(tmp_name, 0);
244 jleave:
245 if(nf_pipetmp != NULL)
246 Fclose(nf_pipetmp);
247 if(nf_tmp != NULL && Fclose(nf_tmp) < 0){
248 if(tmp_name != NULL)
249 n_perr(tmp_name, 0);
250 if(nf != NULL)
251 Fclose(nf);
252 nf = NULL;
254 NYD_LEAVE;
255 return nf;
258 /* s-it-mode */