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 if (_bang_buf
!= NULL
) {
125 sz
= strlen(_bang_buf
);
126 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
127 memcpy(bangbuf
+ j
, _bang_buf
, sz
+ 1);
135 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
140 bangbuf
[j
++] = (*str
)[i
++];
144 printf("!%s\n", bangbuf
);
149 *str
= srealloc(*str
, *size
= sz
);
150 memcpy(*str
, bangbuf
, sz
);
152 _bang_buf
= srealloc(_bang_buf
, _bang_size
= sz
);
153 memcpy(_bang_buf
, bangbuf
, sz
);
159 make_ref_and_cs(struct message
*mp
, struct header
*head
) /* TODO rewrite FAST */
161 char *oldref
, *oldmsgid
, *newref
, *cp
;
162 size_t oldreflen
= 0, oldmsgidlen
= 0, reflen
;
167 oldref
= hfield1("references", mp
);
168 oldmsgid
= hfield1("message-id", mp
);
169 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
176 oldreflen
= strlen(oldref
);
177 reflen
+= oldreflen
+ 2;
180 oldmsgidlen
= strlen(oldmsgid
);
181 reflen
+= oldmsgidlen
;
184 newref
= smalloc(reflen
);
185 if (oldref
!= NULL
) {
186 memcpy(newref
, oldref
, oldreflen
+1);
187 if (oldmsgid
!= NULL
) {
188 newref
[oldreflen
++] = ',';
189 newref
[oldreflen
++] = ' ';
190 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+1);
193 memcpy(newref
, oldmsgid
, oldmsgidlen
+1);
194 n
= extract(newref
, GREF
);
197 /* Limit number of references TODO better on parser side */
198 while (n
->n_flink
!= NULL
)
200 for (i
= 1; i
<= REFERENCES_MAX
; ++i
) {
201 if (n
->n_blink
!= NULL
)
208 if (ok_blook(reply_in_same_charset
) &&
209 (cp
= hfield1("content-type", mp
)) != NULL
)
210 head
->h_charset
= mime_param_get("charset", cp
);
216 _list_reply(int *msgvec
, enum header_flags hf
)
220 char const *reply_to
, *rcv
, *cp
;
222 struct name
*rt
, *mft
, *np
;
226 /* TODO Since we may recur and do stuff with message lists we need to save
227 * TODO away the argument vector as long as that isn't done by machinery */
230 for (i
= 0; msgvec
[i
] != 0; ++i
)
233 save_msgvec
= ac_alloc(sizeof(*save_msgvec
) * i
);
235 save_msgvec
[i
] = msgvec
[i
];
236 msgvec
= save_msgvec
;
240 mp
= message
+ *msgvec
- 1;
244 memset(&head
, 0, sizeof head
);
247 head
.h_subject
= _reedit(hfield1("subject", mp
));
248 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
252 if ((reply_to
= hfield1("reply-to", mp
)) != NULL
&&
253 (cp
= ok_vlook(reply_to_honour
)) != NULL
&&
254 (rt
= checkaddrs(lextract(reply_to
, GTO
| gf
), EACM_STRICT
, NULL
)
256 char const *tr
= _("Reply-To \"%s%s\"");
257 size_t l
= strlen(tr
) + strlen(rt
->n_name
) + 3 +1;
258 char *sp
= salloc(l
);
260 snprintf(sp
, l
, tr
, rt
->n_name
, (rt
->n_flink
!= NULL
? "..." : ""));
261 if (quadify(cp
, UIZ_MAX
, sp
, TRU1
) > FAL0
)
265 if (rcv
== NULL
&& (rcv
= hfield1("from", mp
)) == NULL
)
270 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
271 np
= lextract(cp
, GCC
| gf
);
272 if ((cp
= hfield1("cc", mp
)) != NULL
)
273 np
= cat(np
, lextract(cp
, GCC
| gf
));
275 head
.h_cc
= delete_alternates(np
);
280 np
= (rcv
== reply_to
) ? namelist_dup(rt
, GTO
| gf
)
281 : lextract(rcv
, GTO
| gf
);
282 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
283 np
= cat(np
, lextract(cp
, GTO
| gf
));
284 /* Delete my name from reply list, and with it, all my alternate names */
285 np
= delete_alternates(np
);
287 np
= lextract(rcv
, GTO
| gf
);
290 /* The user may have send this to himself, don't ignore that */
291 namelist_vaporise_head(&head
, EACM_NORMAL
, FAL0
, NULL
);
292 if (head
.h_to
== NULL
)
295 /* Mail-Followup-To: */
297 if (ok_vlook(followup_to_honour
) != NULL
&&
298 (cp
= hfield1("mail-followup-to", mp
)) != NULL
&&
299 (mft
= np
= checkaddrs(lextract(cp
, GTO
| gf
), EACM_STRICT
, NULL
)
301 char const *tr
= _("Followup-To \"%s%s\"");
302 size_t l
= strlen(tr
) + strlen(np
->n_name
) + 3 +1;
303 char *sp
= salloc(l
);
305 snprintf(sp
, l
, tr
, np
->n_name
, (np
->n_flink
!= NULL
? "..." : ""));
306 if (quadify(ok_vlook(followup_to_honour
), UIZ_MAX
, sp
, TRU1
) > FAL0
) {
310 mft
= namelist_vaporise_head(&head
, EACM_STRICT
, FAL0
, NULL
);
315 /* Special massage for list (follow-up) messages */
316 if (mft
!= NULL
|| (hf
& HF_LIST_REPLY
) || ok_blook(followup_to
)) {
317 /* Learn about a possibly sending mailing list; use do for break; */
318 if ((cp
= hfield1("list-post", mp
)) != NULL
) do {
321 if ((x
= lextract(cp
, GEXTRA
| GSKIN
)) == NULL
|| x
->n_flink
!= NULL
||
322 (cp
= url_mailto_to_address(x
->n_name
)) == NULL
||
323 /* XXX terribly wasteful to create a new name, and can't we find
324 * XXX a way to mitigate that?? */
325 is_addr_invalid(x
= nalloc(cp
, 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"));
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
) {
513 printf(_("No messages to forward.\n"));
517 } else if (getmsglist(str
, msgvec
, 0) < 0)
521 if (pstate
& PS_HOOK_MASK
) {
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
) {
605 puts(_("No applicable messages."));
609 } else if (getmsglist(str
, msgvec
, 0) < 0)
613 if (pstate
& PS_HOOK_MASK
) {
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
));
660 check_folder_hook(FAL0
);
662 if (i
> 0 && !ok_blook(emptystart
)) {
666 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
676 char const *sh
= NULL
;
680 sighandler_type sigint
;
683 cmd
= smalloc(cmdsize
= strlen(str
) +1);
684 memcpy(cmd
, str
, cmdsize
);
685 _bangexp(&cmd
, &cmdsize
);
686 if ((sh
= ok_vlook(SHELL
)) == NULL
)
689 sigint
= safe_signal(SIGINT
, SIG_IGN
);
691 run_command(sh
, &mask
, -1, -1, "-c", cmd
, NULL
);
692 safe_signal(SIGINT
, sigint
);
703 sighandler_type sigint
;
708 if ((sh
= ok_vlook(SHELL
)) == NULL
)
711 sigint
= safe_signal(SIGINT
, SIG_IGN
);
712 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
713 safe_signal(SIGINT
, sigint
);
729 #ifdef HAVE_DOCSTRINGS
730 ret
= !print_comm_docstr(arg
);
732 n_err(_("Unknown command: `%s'\n"), arg
);
734 ret
= c_cmdnotsupp(NULL
);
739 /* Very ugly, but take care for compiler supported string lengths :( */
740 fputs(progname
, stdout
);
742 " commands -- \"<msglist>\" denotes message specifications,\n"
743 "e.g., \"1-5\", \":n\" or \".\", separated by spaces:\n"), stdout
);
746 "type <msglist> type (alias: `print') messages (honour `retain' etc.)\n"
747 "Type <msglist> like `type' but always show all headers\n"
748 "next goto and type next message\n"
749 "from <msglist> print header summary for the given list (\"search\")\n"
750 "headers header summary for messages surrounding \"dot\"\n"
751 "delete <msglist> delete messages (can be `undelete'd)\n"),
756 "save <msglist> folder append messages to folder and mark as saved\n"
757 "copy <msglist> folder like `save', but don't mark them (`move' moves)\n"
758 "write <msglist> file write message contents to file (prompts for parts)\n"
759 "Reply <msglist> reply to message senders only\n"
760 "reply <msglist> like `Reply', but address all recipients\n"
761 "Lreply <msglist> forced mailing-list `reply' (see `mlist')\n"),
766 "mail <recipients> compose a mail for the given recipients\n"
767 "file folder change to another mailbox\n"
768 "File folder like `file', but open readonly\n"
769 "quit quit and apply changes to the current mailbox\n"
770 "xit or exit like `quit', but discard changes\n"
771 "!shell command shell escape\n"
772 "list list names of all available commands\n"),
783 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
786 if (getcwd(buf
, sizeof buf
) != NULL
) {
790 n_perr(_("getcwd"), 0);
804 if (*arglist
== NULL
)
806 else if ((cp
= file_expand(*arglist
)) == NULL
)
808 if (chdir(cp
) == -1) {
823 rv
= (*_reply_or_Reply('r'))(v
, FAL0
);
834 rv
= _reply(v
, FAL0
);
840 c_replysender(void *v
)
845 rv
= _Reply(v
, FAL0
);
856 rv
= (*_reply_or_Reply('R'))(v
, FAL0
);
867 rv
= _list_reply(v
, HF_LIST_REPLY
);
878 rv
= (*_reply_or_Reply('r'))(v
, TRU1
);
884 c_followupall(void *v
)
889 rv
= _reply(v
, TRU1
);
895 c_followupsender(void *v
)
900 rv
= _Reply(v
, TRU1
);
911 rv
= (*_reply_or_Reply('R'))(v
, TRU1
);
944 rv
= _resend1(v
, TRU1
);
955 rv
= _resend1(v
, FAL0
);
963 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
967 if (pstate
& PS_EDIT
) {
968 printf(_("Cannot \"preserve\" in a system mailbox\n"));
972 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
974 mp
= message
+ mesg
- 1;
975 mp
->m_flag
|= MPRESERVE
;
978 pstate
|= PS_DID_PRINT_DOT
;
989 int *msgvec
= v
, *ip
;
992 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
993 setdot(message
+ *ip
- 1);
994 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
995 dot
->m_flag
|= MSTATUS
;
997 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
998 imap_unread(message
+ *ip
- 1, *ip
); /* TODO return? */
1000 pstate
|= PS_DID_PRINT_DOT
;
1009 int *msgvec
= v
, *ip
;
1012 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1013 struct message
*mp
= message
+ *ip
- 1;
1024 int *msgvec
= v
, *ip
, mesg
;
1028 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1030 mp
= message
+ mesg
- 1;
1031 printf("%d: ", mesg
);
1032 if (mp
->m_xlines
> 0)
1033 printf("%ld", mp
->m_xlines
);
1036 printf("/%lu\n", (ul_i
)mp
->m_xsize
);
1048 rv
= _c_file(v
, FEDIT_NONE
);
1059 rv
= _c_file(v
, FEDIT_RDONLY
);
1067 char const **argv
= v
, **ap
, *cp
;
1071 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1073 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1077 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1079 /* \c ends overall processing */
1099 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1101 (val
= setfile(mailname
,
1102 FEDIT_NEWMAIL
| ((mb
.mb_perm
& MB_DELE
) ? 0 : FEDIT_RDONLY
))
1105 setdot(message
+ mdot
- 1);
1115 int *msgvec
= v
, *ip
;
1118 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1119 m
= message
+ *ip
- 1;
1121 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1122 m
->m_flag
|= MFLAG
| MFLAGGED
;
1132 int *msgvec
= v
, *ip
;
1135 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1136 m
= message
+ *ip
- 1;
1138 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1139 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1140 m
->m_flag
|= MUNFLAG
;
1151 int *msgvec
= v
, *ip
;
1154 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1155 m
= message
+ *ip
- 1;
1157 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1158 m
->m_flag
|= MANSWER
| MANSWERED
;
1165 c_unanswered(void *v
)
1168 int *msgvec
= v
, *ip
;
1171 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1172 m
= message
+ *ip
- 1;
1174 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1175 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1176 m
->m_flag
|= MUNANSWER
;
1187 int *msgvec
= v
, *ip
;
1190 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1191 m
= message
+ *ip
- 1;
1193 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1194 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1204 int *msgvec
= v
, *ip
;
1207 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1208 m
= message
+ *ip
- 1;
1210 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1211 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1212 m
->m_flag
|= MUNDRAFT
;
1226 switch (mb
.mb_type
) {
1231 rv
= c_cmdnotsupp(NULL
);
1238 rv
= c_cmdnotsupp(NULL
);
1253 char **args
= v
, *name
;
1257 if (*args
== NULL
) {
1258 n_err(_("Synopsis: remove: <mailbox>...\n"));
1263 fmt
= _("Remove \"%s\" (y/n) ? ");
1264 fmt_len
= strlen(fmt
);
1266 if ((name
= expand(*args
)) == NULL
)
1269 if (!strcmp(name
, mailname
)) {
1270 n_err(_("Cannot remove current mailbox \"%s\"\n"), name
);
1275 size_t vl
= strlen(name
) + fmt_len
+1;
1276 char *vb
= ac_alloc(vl
);
1278 snprintf(vb
, vl
, fmt
, name
);
1279 asw
= getapproval(vb
, TRU1
);
1285 switch (which_protocol(name
)) {
1287 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1293 n_err(_("Cannot remove POP3 mailbox \"%s\"\n"),name
);
1298 if (imap_remove(name
) != OKAY
)
1303 if (maildir_remove(name
) != OKAY
)
1307 n_err(_("Unknown protocol in \"%s\"; not removed\n"), name
);
1311 } while (*++args
!= NULL
);
1320 char **args
= v
, *old
, *new;
1321 enum protocol oldp
, newp
;
1327 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1328 n_err(_("Synopsis: rename: <old> <new>\n"));
1332 if ((old
= expand(args
[0])) == NULL
)
1334 oldp
= which_protocol(old
);
1335 if ((new = expand(args
[1])) == NULL
)
1337 newp
= which_protocol(new);
1339 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1340 n_err(_("Cannot rename current mailbox \"%s\"\n"), old
);
1343 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1344 fprintf(stderr
, _("Can only rename folders of same type.\n"));
1350 if (newp
== PROTO_POP3
)
1354 if (link(old
, new) == -1) {
1369 } else if (unlink(old
) == -1) {
1375 if (rename(old
, new) == -1) {
1382 n_err(_("Cannot rename POP3 mailboxes\n"));
1387 if (imap_rename(old
, new) != OKAY
)
1393 n_err(_("Unknown protocol in \"%s\" and \"%s\"; not renamed\n"),
1404 c_urlencode(void *v
) /* XXX IDNA?? */
1409 OBSOLETE("`urlencode': please use `urlcodec enc[ode]' instead");
1411 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1412 char *in
= *ap
, *out
= urlxenc(in
, FAL0
);
1414 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1415 in
, strlen(in
), out
, strlen(out
));
1422 c_urldecode(void *v
) /* XXX IDNA?? */
1427 OBSOLETE("`urldecode': please use `urlcodec dec[ode]' instead");
1429 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1430 char *in
= *ap
, *out
= urlxdec(in
);
1432 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1433 in
, strlen(in
), out
, strlen(out
));