sendout.c:_sendbundle_setup_creds(): fix !HAVE_SMTP (CONFIG=NULL tests)
[s-mailx.git] / cmd-write.c
blob2b12c5afaa93296ca2ec08ce2c8d9af1fcc8f2ca
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ User commands which save, copy, write (parts of) messages.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 #undef n_FILE
36 #define n_FILE cmd_write
38 #ifndef HAVE_AMALGAMATION
39 # include "nail.h"
40 #endif
42 /* Save/copy the indicated messages at the end of the passed file name.
43 * If mark is true, mark the message "saved" */
44 static int save1(char *str, int domark, char const *cmd,
45 struct n_ignore const *itp, int convert, int sender_record,
46 int domove);
48 /* Snarf the file from the end of the command line and return a pointer to it.
49 * If there is no file attached, return the mbox file. Put a null in front of
50 * the file name so that the message list processing won't see it, unless the
51 * file name is the only thing on the line, in which case, return 0 in the
52 * reference flag variable */
53 static char * snarf(char *linebuf, bool_t *flag, bool_t usembox);
55 static int
56 save1(char *str, int domark, char const *cmd, struct n_ignore const *itp,
57 int convert, int sender_record, int domove)
59 ui64_t mstats[1], tstats[2];
60 struct stat st;
61 int last = 0, *msgvec, *ip;
62 struct message *mp;
63 char *file = NULL, *cp, *cq;
64 char const *disp = n_empty, *shell = NULL;
65 FILE *obuf;
66 bool_t success = FAL0, isflag;
67 NYD_ENTER;
69 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
70 if (sender_record) {
71 for (cp = str; *cp != '\0' && spacechar(*cp); ++cp)
73 isflag = (*cp != '\0');
74 } else {
75 if ((file = snarf(str, &isflag, convert != SEND_TOFILE)) == NULL)
76 goto jleave;
77 while(spacechar(*file))
78 ++file;
79 if (*file == '|') {
80 ++file;
81 shell = ok_vlook(SHELL);
85 if (!isflag) {
86 *msgvec = first(0, MMNORM);
87 msgvec[1] = 0;
88 } else if (getmsglist(str, msgvec, 0) < 0)
89 goto jleave;
90 if (*msgvec == 0) {
91 if (n_pstate & (n_PS_HOOK_MASK | n_PS_ROBOT)) {
92 success = TRU1;
93 goto jleave;
95 fprintf(n_stdout, _("No messages to %s.\n"), cmd);
96 goto jleave;
99 if (sender_record) {
100 if ((cp = nameof(message + *msgvec - 1, 0)) == NULL) {
101 fprintf(n_stdout, _("Cannot determine message sender to %s.\n"), cmd);
102 goto jleave;
105 for (cq = cp; *cq != '\0' && *cq != '@'; cq++)
107 *cq = '\0';
108 if (ok_blook(outfolder)) {
109 size_t sz = strlen(cp) +1;
110 file = salloc(sz + 1);
111 file[0] = '+';
112 memcpy(file + 1, cp, sz);
113 } else
114 file = cp;
117 /* Pipe target is special TODO hacked in later, normalize flow! */
118 if (shell != NULL) {
119 if ((obuf = Popen(file, "w", shell, NULL, 1)) == NULL) {
120 int esave;
122 esave = n_err_no;
123 n_perr(file, esave);
124 n_err_no = esave;
125 goto jleave;
127 isflag = FAL0;
128 disp = _("[Piped]");
129 goto jsend;
132 if ((file = fexpand(file, FEXP_FULL)) == NULL)
133 goto jleave;
135 obuf = ((convert == SEND_TOFILE) ? Fopen(file, "a+") : Zopen(file, "a+"));
136 if (obuf == NULL) {
137 obuf = ((convert == SEND_TOFILE) ? Fopen(file, "wx") : Zopen(file, "wx"));
138 if (obuf == NULL) {
139 n_perr(file, 0);
140 goto jleave;
142 isflag = TRU1;
143 disp = _("[New file]");
144 } else {
145 isflag = FAL0;
146 disp = _("[Appended]");
149 /* TODO RETURN check, but be aware of protocols: v15: Mailbox->lock()! */
150 n_file_lock(fileno(obuf), FLT_WRITE, 0,0, UIZ_MAX);
152 if (!isflag && !fstat(fileno(obuf), &st) && S_ISREG(st.st_mode) &&
153 fseek(obuf, -2L, SEEK_END) == 0) {
154 char buf[2];
155 int prependnl = 0;
157 switch (fread(buf, sizeof *buf, 2, obuf)) {
158 case 2:
159 if (buf[1] != '\n') {
160 prependnl = 1;
161 break;
163 /* FALLTHRU */
164 case 1:
165 if (buf[0] != '\n')
166 prependnl = 1;
167 break;
168 default:
169 if (ferror(obuf)) {
170 n_perr(file, 0);
171 goto jleave;
173 prependnl = 0;
176 fflush(obuf);
177 if (prependnl) {
178 putc('\n', obuf);
179 fflush(obuf);
183 jsend:
184 success = TRU1;
185 tstats[0] = tstats[1] = 0;
187 srelax_hold();
188 for (ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
189 ++ip) {
190 mp = message + *ip - 1;
191 if (sendmp(mp, obuf, itp, NULL, convert, mstats) < 0) {
192 success = FAL0;
193 goto jferr;
195 srelax();
197 touch(mp);
198 if (domark)
199 mp->m_flag |= MSAVED;
200 if (domove) {
201 mp->m_flag |= MDELETED | MSAVED;
202 last = *ip;
205 tstats[0] += mstats[0];
206 tstats[1] += mp->m_lines;/* TODO won't work, need target! v15!! */
208 srelax_rele();
210 fflush(obuf);
211 if (ferror(obuf)) {
212 jferr:
213 n_perr(file, 0);
214 if (!success)
215 srelax_rele();
216 success = FAL0;
218 if (shell != NULL) {
219 if (!Pclose(obuf, TRU1))
220 success = FAL0;
221 } else if (Fclose(obuf) != 0)
222 success = FAL0;
224 if (success) {
225 fprintf(n_stdout, "%s %s %" /*PRIu64 "/%"*/ PRIu64 " bytes\n",
226 n_shexp_quote_cp(file, FAL0), disp,
227 /*tstats[1], TODO v15: lines written */ tstats[0]);
228 } else if (domark) {
229 for (ip = msgvec; *ip != 0 &&
230 UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip) {
231 mp = message + *ip - 1;
232 mp->m_flag &= ~MSAVED;
234 } else if (domove) {
235 for (ip = msgvec; *ip != 0 &&
236 UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip) {
237 mp = message + *ip - 1;
238 mp->m_flag &= ~(MSAVED | MDELETED);
242 if (domove && last && success) {
243 setdot(message + last - 1);
244 last = first(0, MDELETED);
245 setdot(message + (last != 0 ? last - 1 : 0));
247 jleave:
248 NYD_LEAVE;
249 return (success == FAL0);
252 static char *
253 snarf(char *linebuf, bool_t *flag, bool_t usembox)
255 char *cp;
256 NYD_ENTER;
258 if ((cp = laststring(linebuf, flag, TRU1)) == NULL) {
259 if (usembox) {
260 *flag = FAL0;
261 cp = fexpand("&", FEXP_FULL);
262 } else
263 n_err(_("No file specified\n"));
265 NYD_LEAVE;
266 return cp;
269 FL int
270 c_save(void *v)
272 char *str = v;
273 int rv;
274 NYD_ENTER;
276 rv = save1(str, 1, "save", n_IGNORE_SAVE, SEND_MBOX, 0, 0);
277 NYD_LEAVE;
278 return rv;
281 FL int
282 c_Save(void *v)
284 char *str = v;
285 int rv;
286 NYD_ENTER;
288 rv = save1(str, 1, "save", n_IGNORE_SAVE, SEND_MBOX, 1, 0);
289 NYD_LEAVE;
290 return rv;
293 FL int
294 c_copy(void *v)
296 char *str = v;
297 int rv;
298 NYD_ENTER;
300 rv = save1(str, 0, "copy", n_IGNORE_SAVE, SEND_MBOX, 0, 0);
301 NYD_LEAVE;
302 return rv;
305 FL int
306 c_Copy(void *v)
308 char *str = v;
309 int rv;
310 NYD_ENTER;
312 rv = save1(str, 0, "copy", n_IGNORE_SAVE, SEND_MBOX, 1, 0);
313 NYD_LEAVE;
314 return rv;
317 FL int
318 c_move(void *v)
320 char *str = v;
321 int rv;
322 NYD_ENTER;
324 rv = save1(str, 0, "move", n_IGNORE_SAVE, SEND_MBOX, 0, 1);
325 NYD_LEAVE;
326 return rv;
329 FL int
330 c_Move(void *v)
332 char *str = v;
333 int rv;
334 NYD_ENTER;
336 rv = save1(str, 0, "move", n_IGNORE_SAVE, SEND_MBOX, 1, 1);
337 NYD_LEAVE;
338 return rv;
341 FL int
342 c_decrypt(void *v)
344 char *str = v;
345 int rv;
346 NYD_ENTER;
348 rv = save1(str, 0, "decrypt", n_IGNORE_SAVE, SEND_DECRYPT, 0, 0);
349 NYD_LEAVE;
350 return rv;
353 FL int
354 c_Decrypt(void *v)
356 char *str = v;
357 int rv;
358 NYD_ENTER;
360 rv = save1(str, 0, "decrypt", n_IGNORE_SAVE, SEND_DECRYPT, 1, 0);
361 NYD_LEAVE;
362 return rv;
365 FL int
366 c_write(void *v)
368 char *str = v;
369 int rv;
370 NYD_ENTER;
372 if (str == NULL || *str == '\0')
373 str = savestr("/dev/null");
374 rv = save1(str, 0, "write", n_IGNORE_ALL, SEND_TOFILE, 0, 0);
375 NYD_LEAVE;
376 return rv;
379 /* s-it-mode */