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
;
225 mp
= message
+ *msgvec
- 1;
229 memset(&head
, 0, sizeof head
);
232 head
.h_subject
= _reedit(hfield1("subject", mp
));
233 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
237 if ((reply_to
= hfield1("reply-to", mp
)) != NULL
&&
238 (cp
= ok_vlook(reply_to_honour
)) != NULL
&&
239 (rt
= checkaddrs(lextract(reply_to
, GTO
| gf
), EACM_STRICT
, NULL
)
241 char const *tr
= _("Reply-To \"%s%s\"");
242 size_t l
= strlen(tr
) + strlen(rt
->n_name
) + 3 +1;
243 char *sp
= salloc(l
);
245 snprintf(sp
, l
, tr
, rt
->n_name
, (rt
->n_flink
!= NULL
? "..." : ""));
246 if (quadify(cp
, UIZ_MAX
, sp
, TRU1
) > FAL0
)
250 if (rcv
== NULL
&& (rcv
= hfield1("from", mp
)) == NULL
)
255 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
256 np
= lextract(cp
, GCC
| gf
);
257 if ((cp
= hfield1("cc", mp
)) != NULL
)
258 np
= cat(np
, lextract(cp
, GCC
| gf
));
260 head
.h_cc
= delete_alternates(np
);
265 np
= (rcv
== reply_to
) ? namelist_dup(rt
, GTO
| gf
)
266 : lextract(rcv
, GTO
| gf
);
267 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
268 np
= cat(np
, lextract(cp
, GTO
| gf
));
269 /* Delete my name from reply list, and with it, all my alternate names */
270 np
= delete_alternates(np
);
272 np
= lextract(rcv
, GTO
| gf
);
275 /* The user may have send this to himself, don't ignore that */
276 namelist_vaporise_head(&head
, EACM_NORMAL
, FAL0
, NULL
);
277 if (head
.h_to
== NULL
)
280 /* Mail-Followup-To: */
282 if (ok_vlook(followup_to_honour
) != NULL
&&
283 (cp
= hfield1("mail-followup-to", mp
)) != NULL
&&
284 (mft
= np
= checkaddrs(lextract(cp
, GTO
| gf
), EACM_STRICT
, NULL
)
286 char const *tr
= _("Followup-To \"%s%s\"");
287 size_t l
= strlen(tr
) + strlen(np
->n_name
) + 3 +1;
288 char *sp
= salloc(l
);
290 snprintf(sp
, l
, tr
, np
->n_name
, (np
->n_flink
!= NULL
? "..." : ""));
291 if (quadify(ok_vlook(followup_to_honour
), UIZ_MAX
, sp
, TRU1
) > FAL0
) {
295 mft
= namelist_vaporise_head(&head
, EACM_STRICT
, FAL0
, NULL
);
300 /* Special massage for list (follow-up) messages */
301 if (mft
!= NULL
|| (hf
& HF_LIST_REPLY
) || ok_blook(followup_to
)) {
302 /* Learn about a possibly sending mailing list; use do for break; */
303 if ((cp
= hfield1("list-post", mp
)) != NULL
) do {
304 struct name
*x
= lextract(cp
, GEXTRA
| GSKIN
);
305 if (x
== NULL
|| x
->n_flink
!= NULL
||
306 !is_prefix("mailto:", x
->n_name
) ||
307 /* XXX the mailto: prefix causes failure (":" invalid character)
308 * XXX which is why need to recreate a struct name with an
309 * XXX updated name; this is terribly wasteful and can't we find
310 * XXX a way to mitigate that?? */
311 is_addr_invalid(x
= nalloc(x
->n_name
+ sizeof("mailto:") -1,
312 GEXTRA
| GSKIN
), EACM_STRICT
)) {
313 if (options
& OPT_D_V
)
314 n_err(_("Message contains invalid \"List-Post:\" header\n"));
320 /* A special case has been seen on e.g. ietf-announce@ietf.org:
321 * these usually post to multiple groups, with ietf-announce@
322 * in List-Post:, but with Reply-To: set to ietf@ietf.org (since
323 * -announce@ is only used for announcements, say).
324 * So our desire is to honour this request and actively overwrite
325 * List-Post: for our purpose; but only if its a single address.
326 * However, to avoid ambiguities with users that place themselve in
327 * Reply-To: and mailing lists which don't overwrite this (or only
328 * extend this, shall such exist), only do so if reply_to exists of
329 * a single address which points to the same domain as List-Post: */
330 if (reply_to
!= NULL
&& rt
->n_flink
== NULL
&&
331 name_is_same_domain(x
, rt
))
332 cp
= rt
->n_name
; /* rt is EACM_STRICT tested */
334 /* "Automatically `mlist'" the List-Post: address temporarily */
335 if (is_mlist(cp
, FAL0
) == MLIST_OTHER
)
336 head
.h_list_post
= cp
;
341 /* In case of list replies we actively sort out any non-list recipient,
342 * but _only_ if we did not honour a MFT:, assuming that members of MFT
343 * were there for a reason; cp is still List-Post:/eqivalent */
344 if ((hf
& HF_LIST_REPLY
) && mft
== NULL
) {
345 struct name
*nhp
= head
.h_to
;
348 while (nhp
!= NULL
) {
352 if ((cp
!= NULL
&& !asccasecmp(cp
, np
->n_name
)) ||
353 is_mlist(np
->n_name
, FAL0
) != MLIST_OTHER
) {
354 np
->n_type
= (np
->n_type
& ~GMASK
) | GTO
;
355 np
->n_flink
= head
.h_to
;
359 if ((nhp
= head
.h_cc
) != NULL
) {
366 make_ref_and_cs(mp
, &head
);
368 if (ok_blook(quote_as_attachment
)) {
369 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
370 head
.h_attach
->a_msgno
= *msgvec
;
371 head
.h_attach
->a_content_description
= _("Original message content");
374 if (mail1(&head
, 1, mp
, NULL
, !!(hf
& HF_RECIPIENT_RECORD
), 0) == OKAY
&&
375 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
376 mp
->m_flag
|= MANSWER
| MANSWERED
;
378 if (*++msgvec
!= 0) {
379 /* TODO message (error) ring.., less sleep */
380 printf(_("Waiting a second before proceeding to the next message..\n"));
391 (*_reply_or_Reply(char c
))(int *, bool_t
)
393 int (*rv
)(int*, bool_t
);
396 rv
= (ok_blook(flipr
) ^ (c
== 'R')) ? &_Reply
: &_reply
;
402 _reply(int *msgvec
, bool_t recipient_record
)
407 rv
= _list_reply(msgvec
, recipient_record
? HF_RECIPIENT_RECORD
: HF_NONE
);
413 _Reply(int *msgvec
, bool_t recipient_record
)
422 memset(&head
, 0, sizeof head
);
423 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
425 for (ap
= msgvec
; *ap
!= 0; ++ap
) {
429 mp
= message
+ *ap
- 1;
433 if ((rp
= hfield1("reply-to", mp
)) != NULL
&&
434 (cp
= ok_vlook(reply_to_honour
)) != NULL
&&
435 (rt
= checkaddrs(lextract(rp
, GTO
| gf
), EACM_STRICT
, NULL
)
437 char const *tr
= _("Reply-To \"%s%s\"");
438 size_t l
= strlen(tr
) + strlen(rt
->n_name
) + 3 +1;
439 char *sp
= salloc(l
);
441 snprintf(sp
, l
, tr
, rt
->n_name
, (rt
->n_flink
!= NULL
? "..." : ""));
442 if (quadify(cp
, UIZ_MAX
, sp
, TRU1
) > FAL0
) {
443 head
.h_to
= cat(head
.h_to
, rt
);
448 if ((cp
= hfield1("from", mp
)) == NULL
)
450 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
452 if (head
.h_to
== NULL
)
455 mp
= message
+ msgvec
[0] - 1;
456 head
.h_subject
= hfield1("subject", mp
);
457 head
.h_subject
= _reedit(head
.h_subject
);
458 make_ref_and_cs(mp
, &head
);
460 if (ok_blook(quote_as_attachment
)) {
461 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
462 head
.h_attach
->a_msgno
= *msgvec
;
463 head
.h_attach
->a_content_description
= _("Original message content");
466 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
467 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
468 mp
->m_flag
|= MANSWER
| MANSWERED
;
475 _fwd(char *str
, int recipient_record
)
481 bool_t f
, forward_as_attachment
;
484 if ((recipient
= laststring(str
, &f
, TRU1
)) == NULL
) {
485 puts(_("No recipient specified."));
489 forward_as_attachment
= ok_blook(forward_as_attachment
);
490 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
493 *msgvec
= first(0, MMNORM
);
495 if (pstate
& PS_HOOK_MASK
) {
499 printf(_("No messages to forward.\n"));
503 } else if (getmsglist(str
, msgvec
, 0) < 0)
507 if (pstate
& PS_HOOK_MASK
) {
511 printf(_("No applicable messages.\n"));
514 if (msgvec
[1] != 0) {
515 printf(_("Cannot forward multiple messages at once\n"));
519 memset(&head
, 0, sizeof head
);
520 if ((head
.h_to
= lextract(recipient
,
521 (GTO
| (ok_blook(fullnames
) ? GFULL
: GSKIN
)))) == NULL
)
524 mp
= message
+ *msgvec
- 1;
526 if (forward_as_attachment
) {
527 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
528 head
.h_attach
->a_msgno
= *msgvec
;
529 head
.h_attach
->a_content_description
= _("Forwarded message");
534 head
.h_subject
= hfield1("subject", mp
);
535 head
.h_subject
= __fwdedit(head
.h_subject
);
536 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
), NULL
, recipient_record
,
545 __fwdedit(char *subj
)
548 char *newsubj
= NULL
;
551 if (subj
== NULL
|| *subj
== '\0')
556 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
558 newsubj
= salloc(out
.l
+ 6);
559 memcpy(newsubj
, "Fwd: ", 5); /* XXX localizable */
560 memcpy(newsubj
+ 5, out
.s
, out
.l
+1);
568 _resend1(void *v
, bool_t add_resent
)
571 struct name
*to
, *sn
;
577 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
578 name
= laststring(str
, &f
, TRU1
);
580 puts(_("No recipient specified."));
585 *msgvec
= first(0, MMNORM
);
587 if (pstate
& PS_HOOK_MASK
) {
591 puts(_("No applicable messages."));
595 } else if (getmsglist(str
, msgvec
, 0) < 0)
599 if (pstate
& PS_HOOK_MASK
) {
603 printf("No applicable messages.\n");
607 sn
= nalloc(name
, GTO
| GSKIN
);
608 to
= usermap(sn
, FAL0
);
609 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
611 if (resend_msg(message
+ *ip
- 1, to
, add_resent
) != OKAY
)
620 _c_file(void *v
, enum fedit_mode fm
)
632 if (pstate
& PS_HOOK_MASK
) {
633 n_err(_("Cannot change folder from within a hook\n"));
638 save_mbox_for_possible_quitstuff();
640 i
= setfile(*argv
, fm
);
645 assert(!(fm
& FEDIT_NEWMAIL
));
646 check_folder_hook(FAL0
);
648 if (i
> 0 && !ok_blook(emptystart
)) {
652 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
662 char const *sh
= NULL
;
666 sighandler_type sigint
;
669 cmd
= smalloc(cmdsize
= strlen(str
) +1);
670 memcpy(cmd
, str
, cmdsize
);
671 _bangexp(&cmd
, &cmdsize
);
672 if ((sh
= ok_vlook(SHELL
)) == NULL
)
675 sigint
= safe_signal(SIGINT
, SIG_IGN
);
677 run_command(sh
, &mask
, -1, -1, "-c", cmd
, NULL
);
678 safe_signal(SIGINT
, sigint
);
689 sighandler_type sigint
;
694 if ((sh
= ok_vlook(SHELL
)) == NULL
)
697 sigint
= safe_signal(SIGINT
, SIG_IGN
);
698 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
699 safe_signal(SIGINT
, sigint
);
715 #ifdef HAVE_DOCSTRINGS
716 ret
= !print_comm_docstr(arg
);
718 n_err(_("Unknown command: `%s'\n"), arg
);
720 ret
= c_cmdnotsupp(NULL
);
725 /* Very ugly, but take care for compiler supported string lengths :( */
726 printf(_("%s commands:\n"), progname
);
728 "type <message list> type messages\n"
729 "next goto and type next message\n"
730 "from <message list> give head lines of messages\n"
731 "headers print out active message headers\n"
732 "delete <message list> delete messages\n"
733 "undelete <message list> undelete messages\n"));
735 "save <message list> folder append messages to folder and mark as saved\n"
736 "copy <message list> folder append messages to folder without marking them\n"
737 "write <message list> file append message texts to file, save attachments\n"
738 "preserve <message list> keep incoming messages in mailbox even if saved\n"
739 "Reply <message list> reply to message senders\n"
740 "reply <message list> reply to message senders and all recipients\n"));
742 "mail addresses mail to specific recipients\n"
743 "file folder change to another folder\n"
744 "quit quit and apply changes to folder\n"
745 "xit quit and discard changes made to folder\n"
747 "cd <directory> chdir to directory or home if none given\n"
748 "list list names of all available commands\n"));
750 "A <message list> consists of integers, ranges of same, or other criteria\n"
751 "separated by spaces. If omitted, %s uses the last message typed.\n"),
762 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
765 if (getcwd(buf
, sizeof buf
) != NULL
) {
769 n_perr(_("getcwd"), 0);
783 if (*arglist
== NULL
)
785 else if ((cp
= file_expand(*arglist
)) == NULL
)
787 if (chdir(cp
) == -1) {
802 rv
= (*_reply_or_Reply('r'))(v
, FAL0
);
813 rv
= _reply(v
, FAL0
);
819 c_replysender(void *v
)
824 rv
= _Reply(v
, FAL0
);
835 rv
= (*_reply_or_Reply('R'))(v
, FAL0
);
846 rv
= _list_reply(v
, HF_LIST_REPLY
);
857 rv
= (*_reply_or_Reply('r'))(v
, TRU1
);
863 c_followupall(void *v
)
868 rv
= _reply(v
, TRU1
);
874 c_followupsender(void *v
)
879 rv
= _Reply(v
, TRU1
);
890 rv
= (*_reply_or_Reply('R'))(v
, TRU1
);
923 rv
= _resend1(v
, TRU1
);
934 rv
= _resend1(v
, FAL0
);
942 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
946 if (pstate
& PS_EDIT
) {
947 printf(_("Cannot \"preserve\" in a system mailbox\n"));
951 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
953 mp
= message
+ mesg
- 1;
954 mp
->m_flag
|= MPRESERVE
;
957 pstate
|= PS_DID_PRINT_DOT
;
968 int *msgvec
= v
, *ip
;
971 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
972 setdot(message
+ *ip
- 1);
973 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
974 dot
->m_flag
|= MSTATUS
;
976 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
977 imap_unread(message
+ *ip
- 1, *ip
); /* TODO return? */
979 pstate
|= PS_DID_PRINT_DOT
;
988 int *msgvec
= v
, *ip
;
991 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
992 struct message
*mp
= message
+ *ip
- 1;
1003 int *msgvec
= v
, *ip
, mesg
;
1007 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1009 mp
= message
+ mesg
- 1;
1010 printf("%d: ", mesg
);
1011 if (mp
->m_xlines
> 0)
1012 printf("%ld", mp
->m_xlines
);
1015 printf("/%lu\n", (ul_i
)mp
->m_xsize
);
1027 rv
= _c_file(v
, FEDIT_NONE
);
1038 rv
= _c_file(v
, FEDIT_RDONLY
);
1046 char const **argv
= v
, **ap
, *cp
;
1050 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1052 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1056 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1058 /* \c ends overall processing */
1078 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1080 (val
= setfile(mailname
,
1081 FEDIT_NEWMAIL
| ((mb
.mb_perm
& MB_DELE
) ? 0 : FEDIT_RDONLY
))
1084 setdot(message
+ mdot
- 1);
1094 int *msgvec
= v
, *ip
;
1097 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1098 m
= message
+ *ip
- 1;
1100 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1101 m
->m_flag
|= MFLAG
| MFLAGGED
;
1111 int *msgvec
= v
, *ip
;
1114 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1115 m
= message
+ *ip
- 1;
1117 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1118 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1119 m
->m_flag
|= MUNFLAG
;
1130 int *msgvec
= v
, *ip
;
1133 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1134 m
= message
+ *ip
- 1;
1136 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1137 m
->m_flag
|= MANSWER
| MANSWERED
;
1144 c_unanswered(void *v
)
1147 int *msgvec
= v
, *ip
;
1150 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1151 m
= message
+ *ip
- 1;
1153 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1154 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1155 m
->m_flag
|= MUNANSWER
;
1166 int *msgvec
= v
, *ip
;
1169 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1170 m
= message
+ *ip
- 1;
1172 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1173 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1183 int *msgvec
= v
, *ip
;
1186 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1187 m
= message
+ *ip
- 1;
1189 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1190 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1191 m
->m_flag
|= MUNDRAFT
;
1205 switch (mb
.mb_type
) {
1210 rv
= c_cmdnotsupp(NULL
);
1217 rv
= c_cmdnotsupp(NULL
);
1232 char **args
= v
, *name
;
1236 if (*args
== NULL
) {
1237 n_err(_("Synopsis: `remove' mailbox ...\n"));
1242 fmt
= _("Remove \"%s\" (y/n) ? ");
1243 fmt_len
= strlen(fmt
);
1245 if ((name
= expand(*args
)) == NULL
)
1248 if (!strcmp(name
, mailname
)) {
1249 n_err(_("Cannot remove current mailbox \"%s\"\n"), name
);
1254 size_t vl
= strlen(name
) + fmt_len
+1;
1255 char *vb
= ac_alloc(vl
);
1257 snprintf(vb
, vl
, fmt
, name
);
1258 asw
= getapproval(vb
, TRU1
);
1264 switch (which_protocol(name
)) {
1266 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1272 n_err(_("Cannot remove POP3 mailbox \"%s\"\n"),name
);
1277 if (imap_remove(name
) != OKAY
)
1282 if (maildir_remove(name
) != OKAY
)
1286 n_err(_("Unknown protocol in \"%s\"; not removed\n"), name
);
1290 } while (*++args
!= NULL
);
1299 char **args
= v
, *old
, *new;
1300 enum protocol oldp
, newp
;
1306 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1307 n_err(_("Synopsis: `rename' old new\n"));
1311 if ((old
= expand(args
[0])) == NULL
)
1313 oldp
= which_protocol(old
);
1314 if ((new = expand(args
[1])) == NULL
)
1316 newp
= which_protocol(new);
1318 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1319 n_err(_("Cannot rename current mailbox \"%s\"\n"), old
);
1322 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1323 fprintf(stderr
, _("Can only rename folders of same type.\n"));
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 if (imap_rename(old
, new) != OKAY
)
1372 n_err(_("Unknown protocol in \"%s\" and \"%s\"; not renamed\n"),
1383 c_urlencode(void *v
) /* XXX IDNA?? */
1388 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1389 char *in
= *ap
, *out
= urlxenc(in
, FAL0
);
1391 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1392 in
, strlen(in
), out
, strlen(out
));
1399 c_urldecode(void *v
) /* XXX IDNA?? */
1404 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1405 char *in
= *ap
, *out
= urlxdec(in
);
1407 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1408 in
, strlen(in
), out
, strlen(out
));