1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Still more user commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
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
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
38 #ifndef HAVE_AMALGAMATION
42 static char *_bang_buf
;
43 static size_t _bang_size
;
45 /* Modify subject we reply to to begin with Re: if it does not already */
46 static char * _reedit(char *subj
);
48 /* Expand the shell escape by expanding unescaped !'s into the last issued
49 * command where possible */
50 static void _bangexp(char **str
, size_t *size
);
52 static void make_ref_and_cs(struct message
*mp
, struct header
*head
);
54 /* `reply' and `Lreply' workhorse */
55 static int _list_reply(int *msgvec
, enum header_flags hf
);
57 /* Get PTF to implementation of command c (i.e., take care for *flipr*) */
58 static int (* _reply_or_Reply(char c
))(int *, bool_t
);
60 /* Reply to a single message. Extract each name from the message header and
61 * send them off to mail1() */
62 static int _reply(int *msgvec
, bool_t recipient_record
);
64 /* Reply to a series of messages by simply mailing to the senders and not
65 * messing around with the To: and Cc: lists as in normal reply */
66 static int _Reply(int *msgvec
, bool_t recipient_record
);
68 /* Forward a message to a new recipient, in the sense of RFC 2822 */
69 static int _fwd(char *str
, int recipient_record
);
71 /* Modify the subject we are replying to to begin with Fwd: */
72 static char * __fwdedit(char *subj
);
74 /* Do the real work of resending */
75 static int _resend1(void *v
, bool_t add_resent
);
78 static int _c_file(void *v
, enum fedit_mode fm
);
87 if (subj
== NULL
|| *subj
== '\0')
92 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
94 if ((newsubj
= subject_re_trim(out
.s
)) != out
.s
)
95 newsubj
= savestr(out
.s
);
97 /* RFC mandates english "Re: " */
98 newsubj
= salloc(out
.l
+ 4 +1);
99 sstpcpy(sstpcpy(newsubj
, "Re: "), out
.s
);
109 _bangexp(char **str
, size_t *size
)
114 size_t sz
, i
, j
, bangbufsize
;
117 dobang
= ok_blook(bang
);
119 bangbuf
= smalloc(bangbufsize
= *size
);
123 if ((*str
)[i
] == '!') {
124 sz
= strlen(_bang_buf
);
125 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
127 memcpy(bangbuf
+ j
, _bang_buf
, sz
+ 1);
133 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
138 bangbuf
[j
++] = (*str
)[i
++];
142 printf("!%s\n", bangbuf
);
147 *str
= srealloc(*str
, *size
= sz
);
148 memcpy(*str
, bangbuf
, sz
);
150 _bang_buf
= srealloc(_bang_buf
, _bang_size
= sz
);
151 memcpy(_bang_buf
, bangbuf
, sz
);
157 make_ref_and_cs(struct message
*mp
, struct header
*head
) /* TODO rewrite FAST */
159 char *oldref
, *oldmsgid
, *newref
, *cp
;
160 size_t oldreflen
= 0, oldmsgidlen
= 0, reflen
;
165 oldref
= hfield1("references", mp
);
166 oldmsgid
= hfield1("message-id", mp
);
167 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
174 oldreflen
= strlen(oldref
);
175 reflen
+= oldreflen
+ 2;
178 oldmsgidlen
= strlen(oldmsgid
);
179 reflen
+= oldmsgidlen
;
182 newref
= smalloc(reflen
);
183 if (oldref
!= NULL
) {
184 memcpy(newref
, oldref
, oldreflen
+1);
185 if (oldmsgid
!= NULL
) {
186 newref
[oldreflen
++] = ',';
187 newref
[oldreflen
++] = ' ';
188 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+1);
191 memcpy(newref
, oldmsgid
, oldmsgidlen
+1);
192 n
= extract(newref
, GREF
);
195 /* Limit number of references TODO better on parser side */
196 while (n
->n_flink
!= NULL
)
198 for (i
= 1; i
<= REFERENCES_MAX
; ++i
) {
199 if (n
->n_blink
!= NULL
)
206 if (ok_blook(reply_in_same_charset
) &&
207 (cp
= hfield1("content-type", mp
)) != NULL
)
208 head
->h_charset
= mime_param_get("charset", cp
);
214 _list_reply(int *msgvec
, enum header_flags hf
)
218 char const *reply_to
, *rcv
, *cp
;
220 struct name
*rt
, *mft
, *np
;
224 /* TODO Since we may recur and do stuff with message lists we need to save
225 * TODO away the argument vector as long as that isn't done by machinery */
228 for (i
= 0; msgvec
[i
] != 0; ++i
)
231 save_msgvec
= ac_alloc(sizeof(*save_msgvec
) * i
);
233 save_msgvec
[i
] = msgvec
[i
];
234 msgvec
= save_msgvec
;
238 mp
= message
+ *msgvec
- 1;
242 memset(&head
, 0, sizeof head
);
245 head
.h_subject
= _reedit(hfield1("subject", mp
));
246 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
250 if ((reply_to
= hfield1("reply-to", mp
)) != NULL
&&
251 (cp
= ok_vlook(reply_to_honour
)) != NULL
&&
252 (rt
= checkaddrs(lextract(reply_to
, GTO
| gf
), EACM_STRICT
, NULL
)
254 char const *tr
= _("Reply-To \"%s%s\"");
255 size_t l
= strlen(tr
) + strlen(rt
->n_name
) + 3 +1;
256 char *sp
= salloc(l
);
258 snprintf(sp
, l
, tr
, rt
->n_name
, (rt
->n_flink
!= NULL
? "..." : ""));
259 if (quadify(cp
, UIZ_MAX
, sp
, TRU1
) > FAL0
)
263 if (rcv
== NULL
&& (rcv
= hfield1("from", mp
)) == NULL
)
268 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
269 np
= lextract(cp
, GCC
| gf
);
270 if ((cp
= hfield1("cc", mp
)) != NULL
)
271 np
= cat(np
, lextract(cp
, GCC
| gf
));
273 head
.h_cc
= delete_alternates(np
);
278 np
= (rcv
== reply_to
) ? namelist_dup(rt
, GTO
| gf
)
279 : lextract(rcv
, GTO
| gf
);
280 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
281 np
= cat(np
, lextract(cp
, GTO
| gf
));
282 /* Delete my name from reply list, and with it, all my alternate names */
283 np
= delete_alternates(np
);
285 np
= lextract(rcv
, GTO
| gf
);
288 /* The user may have send this to himself, don't ignore that */
289 namelist_vaporise_head(&head
, EACM_NORMAL
, FAL0
, NULL
);
290 if (head
.h_to
== NULL
)
293 /* Mail-Followup-To: */
295 if (ok_vlook(followup_to_honour
) != NULL
&&
296 (cp
= hfield1("mail-followup-to", mp
)) != NULL
&&
297 (mft
= np
= checkaddrs(lextract(cp
, GTO
| gf
), EACM_STRICT
, NULL
)
299 char const *tr
= _("Followup-To \"%s%s\"");
300 size_t l
= strlen(tr
) + strlen(np
->n_name
) + 3 +1;
301 char *sp
= salloc(l
);
303 snprintf(sp
, l
, tr
, np
->n_name
, (np
->n_flink
!= NULL
? "..." : ""));
304 if (quadify(ok_vlook(followup_to_honour
), UIZ_MAX
, sp
, TRU1
) > FAL0
) {
308 mft
= namelist_vaporise_head(&head
, EACM_STRICT
, FAL0
, NULL
);
313 /* Special massage for list (follow-up) messages */
314 if (mft
!= NULL
|| (hf
& HF_LIST_REPLY
) || ok_blook(followup_to
)) {
315 /* Learn about a possibly sending mailing list; use do for break; */
316 if ((cp
= hfield1("list-post", mp
)) != NULL
) do {
317 struct name
*x
= lextract(cp
, GEXTRA
| GSKIN
);
318 if (x
== NULL
|| x
->n_flink
!= NULL
||
319 !is_prefix("mailto:", x
->n_name
) ||
320 /* XXX the mailto: prefix causes failure (":" invalid character)
321 * XXX which is why need to recreate a struct name with an
322 * XXX updated name; this is terribly wasteful and can't we find
323 * XXX a way to mitigate that?? */
324 is_addr_invalid(x
= nalloc(x
->n_name
+ sizeof("mailto:") -1,
325 GEXTRA
| GSKIN
), EACM_STRICT
)) {
326 if (options
& OPT_D_V
)
327 n_err(_("Message contains invalid \"List-Post:\" header\n"));
333 /* A special case has been seen on e.g. ietf-announce@ietf.org:
334 * these usually post to multiple groups, with ietf-announce@
335 * in List-Post:, but with Reply-To: set to ietf@ietf.org (since
336 * -announce@ is only used for announcements, say).
337 * So our desire is to honour this request and actively overwrite
338 * List-Post: for our purpose; but only if its a single address.
339 * However, to avoid ambiguities with users that place themselve in
340 * Reply-To: and mailing lists which don't overwrite this (or only
341 * extend this, shall such exist), only do so if reply_to exists of
342 * a single address which points to the same domain as List-Post: */
343 if (reply_to
!= NULL
&& rt
->n_flink
== NULL
&&
344 name_is_same_domain(x
, rt
))
345 cp
= rt
->n_name
; /* rt is EACM_STRICT tested */
347 /* "Automatically `mlist'" the List-Post: address temporarily */
348 if (is_mlist(cp
, FAL0
) == MLIST_OTHER
)
349 head
.h_list_post
= cp
;
354 /* In case of list replies we actively sort out any non-list recipient,
355 * but _only_ if we did not honour a MFT:, assuming that members of MFT
356 * were there for a reason; cp is still List-Post:/eqivalent */
357 if ((hf
& HF_LIST_REPLY
) && mft
== NULL
) {
358 struct name
*nhp
= head
.h_to
;
361 while (nhp
!= NULL
) {
365 if ((cp
!= NULL
&& !asccasecmp(cp
, np
->n_name
)) ||
366 is_mlist(np
->n_name
, FAL0
) != MLIST_OTHER
) {
367 np
->n_type
= (np
->n_type
& ~GMASK
) | GTO
;
368 np
->n_flink
= head
.h_to
;
372 if ((nhp
= head
.h_cc
) != NULL
) {
379 make_ref_and_cs(mp
, &head
);
381 if (ok_blook(quote_as_attachment
)) {
382 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
383 head
.h_attach
->a_msgno
= *msgvec
;
384 head
.h_attach
->a_content_description
= _("Original message content");
387 if (mail1(&head
, 1, mp
, NULL
, !!(hf
& HF_RECIPIENT_RECORD
), 0) == OKAY
&&
388 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
389 mp
->m_flag
|= MANSWER
| MANSWERED
;
391 if (*++msgvec
!= 0) {
392 /* TODO message (error) ring.., less sleep */
393 printf(_("Waiting a second before proceeding to the next message..\n"));
395 n_msleep(1000, FAL0
);
399 ac_free(save_msgvec
);
405 (*_reply_or_Reply(char c
))(int *, bool_t
)
407 int (*rv
)(int*, bool_t
);
410 rv
= (ok_blook(flipr
) ^ (c
== 'R')) ? &_Reply
: &_reply
;
416 _reply(int *msgvec
, bool_t recipient_record
)
421 rv
= _list_reply(msgvec
, recipient_record
? HF_RECIPIENT_RECORD
: HF_NONE
);
427 _Reply(int *msgvec
, bool_t recipient_record
)
436 memset(&head
, 0, sizeof head
);
437 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
439 for (ap
= msgvec
; *ap
!= 0; ++ap
) {
443 mp
= message
+ *ap
- 1;
447 if ((rp
= hfield1("reply-to", mp
)) != NULL
&&
448 (cp
= ok_vlook(reply_to_honour
)) != NULL
&&
449 (rt
= checkaddrs(lextract(rp
, GTO
| gf
), EACM_STRICT
, NULL
)
451 char const *tr
= _("Reply-To \"%s%s\"");
452 size_t l
= strlen(tr
) + strlen(rt
->n_name
) + 3 +1;
453 char *sp
= salloc(l
);
455 snprintf(sp
, l
, tr
, rt
->n_name
, (rt
->n_flink
!= NULL
? "..." : ""));
456 if (quadify(cp
, UIZ_MAX
, sp
, TRU1
) > FAL0
) {
457 head
.h_to
= cat(head
.h_to
, rt
);
462 if ((cp
= hfield1("from", mp
)) == NULL
)
464 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
466 if (head
.h_to
== NULL
)
469 mp
= message
+ msgvec
[0] - 1;
470 head
.h_subject
= hfield1("subject", mp
);
471 head
.h_subject
= _reedit(head
.h_subject
);
472 make_ref_and_cs(mp
, &head
);
474 if (ok_blook(quote_as_attachment
)) {
475 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
476 head
.h_attach
->a_msgno
= *msgvec
;
477 head
.h_attach
->a_content_description
= _("Original message content");
480 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
481 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
482 mp
->m_flag
|= MANSWER
| MANSWERED
;
489 _fwd(char *str
, int recipient_record
)
495 bool_t f
, forward_as_attachment
;
498 if ((recipient
= laststring(str
, &f
, TRU1
)) == NULL
) {
499 puts(_("No recipient specified."));
503 forward_as_attachment
= ok_blook(forward_as_attachment
);
504 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
507 *msgvec
= first(0, MMNORM
);
509 if (pstate
& (PS_HOOK_MASK
| PS_ROBOT
)) {
513 printf(_("No messages to forward.\n"));
517 } else if (getmsglist(str
, msgvec
, 0) < 0)
521 if (pstate
& (PS_HOOK_MASK
| PS_ROBOT
)) {
525 printf(_("No applicable messages.\n"));
528 if (msgvec
[1] != 0) {
529 printf(_("Cannot forward multiple messages at once\n"));
533 memset(&head
, 0, sizeof head
);
534 if ((head
.h_to
= lextract(recipient
,
535 (GTO
| (ok_blook(fullnames
) ? GFULL
: GSKIN
)))) == NULL
)
538 mp
= message
+ *msgvec
- 1;
540 if (forward_as_attachment
) {
541 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
542 head
.h_attach
->a_msgno
= *msgvec
;
543 head
.h_attach
->a_content_description
= _("Forwarded message");
548 head
.h_subject
= hfield1("subject", mp
);
549 head
.h_subject
= __fwdedit(head
.h_subject
);
550 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
), NULL
, recipient_record
,
559 __fwdedit(char *subj
)
562 char *newsubj
= NULL
;
565 if (subj
== NULL
|| *subj
== '\0')
570 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
572 newsubj
= salloc(out
.l
+ 6);
573 memcpy(newsubj
, "Fwd: ", 5); /* XXX localizable */
574 memcpy(newsubj
+ 5, out
.s
, out
.l
+1);
582 _resend1(void *v
, bool_t add_resent
)
585 struct name
*to
, *sn
;
591 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
592 name
= laststring(str
, &f
, TRU1
);
594 puts(_("No recipient specified."));
599 *msgvec
= first(0, MMNORM
);
601 if (pstate
& (PS_HOOK_MASK
| PS_ROBOT
)) {
605 puts(_("No applicable messages."));
609 } else if (getmsglist(str
, msgvec
, 0) < 0)
613 if (pstate
& (PS_HOOK_MASK
| PS_ROBOT
)) {
617 printf("No applicable messages.\n");
621 sn
= nalloc(name
, GTO
| GSKIN
);
622 to
= usermap(sn
, FAL0
);
623 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
625 if (resend_msg(message
+ *ip
- 1, to
, add_resent
) != OKAY
)
634 _c_file(void *v
, enum fedit_mode fm
)
646 if (pstate
& PS_HOOK_MASK
) {
647 n_err(_("Cannot change folder from within a hook\n"));
652 save_mbox_for_possible_quitstuff();
654 i
= setfile(*argv
, fm
);
659 assert(!(fm
& FEDIT_NEWMAIL
)); /* (Prevent implementation error) */
660 if (pstate
& PS_SETFILE_OPENED
)
661 check_folder_hook(FAL0
);
664 /* TODO Don't report "no messages" == 1 == error when we're in, e.g.,
665 * TODO a macro: because that recursed commando loop will terminate the
666 * TODO entire macro due to that! So either the user needs to be able
667 * TODO to react&ignore this "error" (as in "if DOSTUFF" or "DOSTUFF;
668 * TODO if $?", then "overriding an "error"), or we need a different
669 * TODO return that differentiates */
670 i
= (pstate
& PS_ROBOT
) ? 0 : 1;
673 if (pstate
& PS_SETFILE_OPENED
)
674 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
687 sighandler_type sigint
;
690 cmd
= smalloc(cmdsize
= strlen(str
) +1);
691 memcpy(cmd
, str
, cmdsize
);
692 _bangexp(&cmd
, &cmdsize
);
694 sigint
= safe_signal(SIGINT
, SIG_IGN
);
696 run_command(ok_vlook(SHELL
), &mask
, COMMAND_FD_PASS
, COMMAND_FD_PASS
, "-c",
698 safe_signal(SIGINT
, sigint
);
709 sighandler_type sigint
;
713 sigint
= safe_signal(SIGINT
, SIG_IGN
);
714 run_command(ok_vlook(SHELL
), 0, COMMAND_FD_PASS
, COMMAND_FD_PASS
, NULL
,
716 safe_signal(SIGINT
, sigint
);
732 #ifdef HAVE_DOCSTRINGS
733 ret
= !n_print_comm_docstr(arg
);
735 n_err(_("Unknown command: `%s'\n"), arg
);
737 ret
= c_cmdnotsupp(NULL
);
742 /* Very ugly, but take care for compiler supported string lengths :( */
743 fputs(progname
, stdout
);
745 " commands -- \"<msglist>\" denotes message specifications,\n"
746 "e.g., \"1-5\", \":n\" or \".\", separated by spaces:\n"), stdout
);
749 "type <msglist> type (alias: `print') messages (honour `retain' etc.)\n"
750 "Type <msglist> like `type' but always show all headers\n"
751 "next goto and type next message\n"
752 "from <msglist> print header summary for the given list (\"search\")\n"
753 "headers header summary for messages surrounding \"dot\"\n"
754 "delete <msglist> delete messages (can be `undelete'd)\n"),
759 "save <msglist> folder append messages to folder and mark as saved\n"
760 "copy <msglist> folder like `save', but don't mark them (`move' moves)\n"
761 "write <msglist> file write message contents to file (prompts for parts)\n"
762 "Reply <msglist> reply to message senders only\n"
763 "reply <msglist> like `Reply', but address all recipients\n"
764 "Lreply <msglist> forced mailing-list `reply' (see `mlist')\n"),
769 "mail <recipients> compose a mail for the given recipients\n"
770 "file folder change to another mailbox\n"
771 "File folder like `file', but open readonly\n"
772 "quit quit and apply changes to the current mailbox\n"
773 "xit or exit like `quit', but discard changes\n"
774 "!shell command shell escape\n"
775 "list list names of all available commands\n"),
786 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
789 if (getcwd(buf
, sizeof buf
) != NULL
) {
793 n_perr(_("getcwd"), 0);
807 if (*arglist
== NULL
)
809 else if ((cp
= file_expand(*arglist
)) == NULL
)
811 if (chdir(cp
) == -1) {
826 rv
= (*_reply_or_Reply('r'))(v
, FAL0
);
837 rv
= _reply(v
, FAL0
);
843 c_replysender(void *v
)
848 rv
= _Reply(v
, FAL0
);
859 rv
= (*_reply_or_Reply('R'))(v
, FAL0
);
870 rv
= _list_reply(v
, HF_LIST_REPLY
);
881 rv
= (*_reply_or_Reply('r'))(v
, TRU1
);
887 c_followupall(void *v
)
892 rv
= _reply(v
, TRU1
);
898 c_followupsender(void *v
)
903 rv
= _Reply(v
, TRU1
);
914 rv
= (*_reply_or_Reply('R'))(v
, TRU1
);
947 rv
= _resend1(v
, TRU1
);
958 rv
= _resend1(v
, FAL0
);
966 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
970 if (pstate
& PS_EDIT
) {
971 printf(_("Cannot \"preserve\" in a system mailbox\n"));
975 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
977 mp
= message
+ mesg
- 1;
978 mp
->m_flag
|= MPRESERVE
;
981 pstate
|= PS_DID_PRINT_DOT
;
992 int *msgvec
= v
, *ip
;
995 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
996 setdot(message
+ *ip
- 1);
997 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
998 dot
->m_flag
|= MSTATUS
;
999 pstate
|= PS_DID_PRINT_DOT
;
1008 int *msgvec
= v
, *ip
;
1011 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1012 struct message
*mp
= message
+ *ip
- 1;
1023 int *msgvec
= v
, *ip
, mesg
;
1027 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1029 mp
= message
+ mesg
- 1;
1030 printf("%d: ", mesg
);
1031 if (mp
->m_xlines
> 0)
1032 printf("%ld", mp
->m_xlines
);
1035 printf("/%lu\n", (ul_i
)mp
->m_xsize
);
1047 rv
= _c_file(v
, FEDIT_NONE
);
1058 rv
= _c_file(v
, FEDIT_RDONLY
);
1066 char const **argv
= v
, **ap
, *cp
;
1070 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1072 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
| FEXP_NSHELL
)) != NULL
) {
1076 while (*cp
!= '\0' && (c
= n_shell_expand_escape(&cp
, FAL0
)) > 0)
1078 /* \c ends overall processing */
1096 if ((val
= setfile(mailname
,
1097 FEDIT_NEWMAIL
| ((mb
.mb_perm
& MB_DELE
) ? 0 : FEDIT_RDONLY
))
1100 setdot(message
+ mdot
- 1);
1110 int *msgvec
= v
, *ip
;
1113 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1114 m
= message
+ *ip
- 1;
1116 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1117 m
->m_flag
|= MFLAG
| MFLAGGED
;
1127 int *msgvec
= v
, *ip
;
1130 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1131 m
= message
+ *ip
- 1;
1133 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1134 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1135 m
->m_flag
|= MUNFLAG
;
1146 int *msgvec
= v
, *ip
;
1149 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1150 m
= message
+ *ip
- 1;
1152 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1153 m
->m_flag
|= MANSWER
| MANSWERED
;
1160 c_unanswered(void *v
)
1163 int *msgvec
= v
, *ip
;
1166 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1167 m
= message
+ *ip
- 1;
1169 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1170 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1171 m
->m_flag
|= MUNANSWER
;
1182 int *msgvec
= v
, *ip
;
1185 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1186 m
= message
+ *ip
- 1;
1188 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1189 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1199 int *msgvec
= v
, *ip
;
1202 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1203 m
= message
+ *ip
- 1;
1205 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1206 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1207 m
->m_flag
|= MUNDRAFT
;
1221 switch (mb
.mb_type
) {
1226 rv
= c_cmdnotsupp(NULL
);
1241 char **args
= v
, *name
, *ename
;
1245 if (*args
== NULL
) {
1246 n_err(_("Synopsis: remove: <mailbox>...\n"));
1251 fmt
= _("Remove \"%s\"");
1252 fmt_len
= strlen(fmt
);
1254 if ((name
= expand(*args
)) == NULL
)
1256 ename
= string_quote(name
);
1258 if (!strcmp(name
, mailname
)) {
1259 n_err(_("Cannot remove current mailbox \"%s\"\n"), ename
);
1264 size_t vl
= strlen(name
) + fmt_len
+1;
1265 char *vb
= ac_alloc(vl
);
1267 snprintf(vb
, vl
, fmt
, ename
);
1268 asw
= getapproval(vb
, TRU1
);
1274 switch (which_protocol(name
)) {
1276 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1282 n_err(_("Cannot remove POP3 mailbox \"%s\"\n"), ename
);
1286 if (maildir_remove(name
) != OKAY
)
1290 n_err(_("Unknown protocol in \"%s\"; not removed\n"), ename
);
1294 } while (*++args
!= NULL
);
1303 char **args
= v
, *old
, *new;
1304 enum protocol oldp
, newp
;
1310 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1311 n_err(_("Synopsis: rename: <old> <new>\n"));
1315 if ((old
= expand(args
[0])) == NULL
)
1317 oldp
= which_protocol(old
);
1318 if ((new = expand(args
[1])) == NULL
)
1320 newp
= which_protocol(new);
1322 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1323 n_err(_("Cannot rename current mailbox \"%s\"\n"), old
);
1329 if (newp
== PROTO_POP3
)
1333 if (link(old
, new) == -1) {
1348 } else if (unlink(old
) == -1) {
1354 if (rename(old
, new) == -1) {
1361 n_err(_("Cannot rename POP3 mailboxes\n"));
1366 n_err(_("Unknown protocol in \"%s\" and \"%s\"; not renamed\n"),
1377 c_urlencode(void *v
) /* XXX IDNA?? */
1382 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1383 char *in
= *ap
, *out
= urlxenc(in
, FAL0
);
1385 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1386 in
, strlen(in
), out
, strlen(out
));
1393 c_urldecode(void *v
) /* XXX IDNA?? */
1398 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1399 char *in
= *ap
, *out
= urlxdec(in
);
1401 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1402 in
, strlen(in
), out
, strlen(out
));