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 - 2014 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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #ifndef HAVE_AMALGAMATION
45 struct cond_stack
*c_outer
;
46 bool_t c_noop
; /* Outer stack !c_go, entirely no-op */
47 bool_t c_go
; /* Green light */
48 bool_t c_else
; /* In `else' clause */
52 static struct cond_stack
*_cond_stack
;
53 static char *_bang_buf
;
54 static size_t _bang_size
;
56 /* Modify subject we reply to to begin with Re: if it does not already */
57 static char * _reedit(char *subj
);
59 /* Expand the shell escape by expanding unescaped !'s into the last issued
60 * command where possible */
61 static void _bangexp(char **str
, size_t *size
);
63 static void make_ref_and_cs(struct message
*mp
, struct header
*head
);
65 /* Get PTF to implementation of command `c' (i.e., take care for *flipr*) */
66 static int (* respond_or_Respond(int c
))(int *, int);
68 /* Reply to a single message. Extract each name from the message header and
69 * send them off to mail1() */
70 static int respond_internal(int *msgvec
, int recipient_record
);
72 /* Reply to a series of messages by simply mailing to the senders and not
73 * messing around with the To: and Cc: lists as in normal reply */
74 static int Respond_internal(int *msgvec
, int recipient_record
);
76 /* Forward a message to a new recipient, in the sense of RFC 2822 */
77 static int _fwd(char *str
, int recipient_record
);
79 /* Modify the subject we are replying to to begin with Fwd: */
80 static char * __fwdedit(char *subj
);
82 /* Sort the passed string vecotor into ascending dictionary order */
83 static void asort(char **list
);
85 /* Do a dictionary order comparison of the arguments from qsort */
86 static int diction(void const *a
, void const *b
);
88 /* Do the real work of resending */
89 static int _resend1(void *v
, bool_t add_resent
);
92 static int _c_file(void *v
, enum fedit_mode fm
);
95 static void list_shortcuts(void);
98 static enum okay
delete_shortcut(char const *str
);
104 char *newsubj
= NULL
;
107 if (subj
== NULL
|| *subj
== '\0')
112 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
114 if ((newsubj
= subject_re_trim(out
.s
)) != out
.s
)
115 newsubj
= savestr(out
.s
);
117 newsubj
= salloc(out
.l
+ 4 +1);
118 sstpcpy(sstpcpy(newsubj
, "Re: "), out
.s
);
128 _bangexp(char **str
, size_t *size
)
133 size_t sz
, i
, j
, bangbufsize
;
136 dobang
= ok_blook(bang
);
138 bangbuf
= smalloc(bangbufsize
= *size
);
142 if ((*str
)[i
] == '!') {
143 sz
= strlen(_bang_buf
);
144 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
146 memcpy(bangbuf
+ j
, _bang_buf
, sz
+ 1);
152 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
157 bangbuf
[j
++] = (*str
)[i
++];
161 printf("!%s\n", bangbuf
);
166 *str
= srealloc(*str
, *size
= sz
);
167 memcpy(*str
, bangbuf
, sz
);
169 _bang_buf
= srealloc(_bang_buf
, _bang_size
= sz
);
170 memcpy(_bang_buf
, bangbuf
, sz
);
176 make_ref_and_cs(struct message
*mp
, struct header
*head
)
178 char *oldref
, *oldmsgid
, *newref
, *cp
;
179 size_t oldreflen
= 0, oldmsgidlen
= 0, reflen
;
184 oldref
= hfield1("references", mp
);
185 oldmsgid
= hfield1("message-id", mp
);
186 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
193 oldreflen
= strlen(oldref
);
194 reflen
+= oldreflen
+ 2;
197 oldmsgidlen
= strlen(oldmsgid
);
198 reflen
+= oldmsgidlen
;
201 newref
= ac_alloc(reflen
);
202 if (oldref
!= NULL
) {
203 memcpy(newref
, oldref
, oldreflen
+1);
204 if (oldmsgid
!= NULL
) {
205 newref
[oldreflen
++] = ',';
206 newref
[oldreflen
++] = ' ';
207 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+1);
210 memcpy(newref
, oldmsgid
, oldmsgidlen
+1);
211 n
= extract(newref
, GREF
);
214 /* Limit number of references */
215 while (n
->n_flink
!= NULL
)
217 for (i
= 1; i
< 21; ++i
) { /* XXX no magics */
218 if (n
->n_blink
!= NULL
)
225 if (ok_blook(reply_in_same_charset
) &&
226 (cp
= hfield1("content-type", mp
)) != NULL
)
227 head
->h_charset
= mime_getparam("charset", cp
);
233 (*respond_or_Respond(int c
))(int *, int)
236 int (*rv
)(int*, int);
239 opt
= ok_blook(Replyall
);
240 opt
+= ok_blook(flipr
);
241 rv
= ((opt
== 1) ^ (c
== 'R')) ? &Respond_internal
: &respond_internal
;
247 respond_internal(int *msgvec
, int recipient_record
)
252 struct name
*np
= NULL
;
257 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
259 if (msgvec
[1] != 0) {
261 "Sorry, can't reply to multiple messages at once\n"));
265 mp
= message
+ msgvec
[0] - 1;
269 if ((rcv
= hfield1("reply-to", mp
)) == NULL
)
270 if ((rcv
= hfield1("from", mp
)) == NULL
)
273 np
= lextract(rcv
, GTO
| gf
);
274 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
275 np
= cat(np
, lextract(cp
, GTO
| gf
));
276 /* Delete my name from reply list, and with it, all my alternate names */
277 np
= elide(delete_alternates(np
));
279 np
= lextract(rcv
, GTO
| gf
);
281 memset(&head
, 0, sizeof head
);
283 head
.h_subject
= hfield1("subject", mp
);
284 head
.h_subject
= _reedit(head
.h_subject
);
288 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
289 np
= lextract(cp
, GCC
| gf
);
290 if ((cp
= hfield1("cc", mp
)) != NULL
)
291 np
= cat(np
, lextract(cp
, GCC
| gf
));
293 head
.h_cc
= elide(delete_alternates(np
));
294 make_ref_and_cs(mp
, &head
);
296 if (ok_blook(quote_as_attachment
)) {
297 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
298 head
.h_attach
->a_msgno
= *msgvec
;
299 head
.h_attach
->a_content_description
= _(
300 "Original message content");
303 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
304 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
305 mp
->m_flag
|= MANSWER
| MANSWERED
;
313 Respond_internal(int *msgvec
, int recipient_record
)
322 memset(&head
, 0, sizeof head
);
323 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
325 for (ap
= msgvec
; *ap
!= 0; ++ap
) {
326 mp
= message
+ *ap
- 1;
329 if ((cp
= hfield1("reply-to", mp
)) == NULL
)
330 if ((cp
= hfield1("from", mp
)) == NULL
)
332 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
334 if (head
.h_to
== NULL
)
337 mp
= message
+ msgvec
[0] - 1;
338 head
.h_subject
= hfield1("subject", mp
);
339 head
.h_subject
= _reedit(head
.h_subject
);
340 make_ref_and_cs(mp
, &head
);
342 if (ok_blook(quote_as_attachment
)) {
343 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
344 head
.h_attach
->a_msgno
= *msgvec
;
345 head
.h_attach
->a_content_description
= _(
346 "Original message content");
349 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
350 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
351 mp
->m_flag
|= MANSWER
| MANSWERED
;
358 _fwd(char *str
, int recipient_record
)
364 bool_t f
, forward_as_attachment
;
367 if ((recipient
= laststring(str
, &f
, TRU1
)) == NULL
) {
368 puts(_("No recipient specified."));
372 forward_as_attachment
= ok_blook(forward_as_attachment
);
373 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
376 *msgvec
= first(0, MMNORM
);
382 printf("No messages to forward.\n");
386 } else if (getmsglist(str
, msgvec
, 0) < 0)
394 printf("No applicable messages.\n");
397 if (msgvec
[1] != 0) {
398 printf("Cannot forward multiple messages at once\n");
402 memset(&head
, 0, sizeof head
);
403 if ((head
.h_to
= lextract(recipient
,
404 (GTO
| (ok_blook(fullnames
) ? GFULL
: GSKIN
)))) == NULL
)
407 mp
= message
+ *msgvec
- 1;
409 if (forward_as_attachment
) {
410 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
411 head
.h_attach
->a_msgno
= *msgvec
;
412 head
.h_attach
->a_content_description
= "Forwarded message";
417 head
.h_subject
= hfield1("subject", mp
);
418 head
.h_subject
= __fwdedit(head
.h_subject
);
419 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
), NULL
, recipient_record
,
428 __fwdedit(char *subj
)
431 char *newsubj
= NULL
;
434 if (subj
== NULL
|| *subj
== '\0')
439 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
441 newsubj
= salloc(out
.l
+ 6);
442 memcpy(newsubj
, "Fwd: ", 5); /* XXX localizable */
443 memcpy(newsubj
+ 5, out
.s
, out
.l
+1);
457 for (ap
= list
; *ap
!= NULL
; ++ap
)
459 if ((i
= PTR2SIZE(ap
- list
)) >= 2)
460 qsort(list
, i
, sizeof *list
, diction
);
465 diction(void const *a
, void const *b
)
470 rv
= strcmp(*(char**)UNCONST(a
), *(char**)UNCONST(b
));
476 _resend1(void *v
, bool_t add_resent
)
479 struct name
*to
, *sn
;
485 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
486 name
= laststring(str
, &f
, TRU1
);
488 puts(_("No recipient specified."));
493 *msgvec
= first(0, MMNORM
);
499 puts(_("No applicable messages."));
503 } else if (getmsglist(str
, msgvec
, 0) < 0)
511 printf("No applicable messages.\n");
515 sn
= nalloc(name
, GTO
| GSKIN
);
516 to
= usermap(sn
, FAL0
);
517 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
519 if (resend_msg(message
+ *ip
- 1, to
, add_resent
) != OKAY
)
528 _c_file(void *v
, enum fedit_mode fm
)
541 fprintf(stderr
, _("Cannot change folder from within a hook.\n"));
546 save_mbox_for_possible_quitstuff();
548 i
= setfile(*argv
, fm
);
553 callhook(mailname
, 0);
554 if (i
> 0 && !ok_blook(emptystart
)) {
558 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
571 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
572 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
577 delete_shortcut(char const *str
)
579 struct shortcut
*sp
, *sq
;
583 for (sp
= shortcuts
, sq
= NULL
; sp
!= NULL
; sq
= sp
, sp
= sp
->sh_next
) {
584 if (!strcmp(sp
->sh_short
, str
)) {
588 sq
->sh_next
= sp
->sh_next
;
590 shortcuts
= sp
->sh_next
;
603 char const *sh
= NULL
;
607 sighandler_type sigint
;
610 cmd
= smalloc(cmdsize
= strlen(str
) +1);
611 memcpy(cmd
, str
, cmdsize
);
612 _bangexp(&cmd
, &cmdsize
);
613 if ((sh
= ok_vlook(SHELL
)) == NULL
)
616 sigint
= safe_signal(SIGINT
, SIG_IGN
);
618 run_command(sh
, &mask
, -1, -1, "-c", cmd
, NULL
);
619 safe_signal(SIGINT
, sigint
);
630 sighandler_type sigint
;
635 if ((sh
= ok_vlook(SHELL
)) == NULL
)
638 sigint
= safe_signal(SIGINT
, SIG_IGN
);
639 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
640 safe_signal(SIGINT
, sigint
);
656 #ifdef HAVE_DOCSTRINGS
657 ret
= !print_comm_docstr(arg
);
659 fprintf(stderr
, _("Unknown command: `%s'\n"), arg
);
661 ret
= c_cmdnotsupp(NULL
);
666 /* Very ugly, but take care for compiler supported string lengths :( */
667 printf(_("%s commands:\n"), progname
);
669 "type <message list> type messages\n"
670 "next goto and type next message\n"
671 "from <message list> give head lines of messages\n"
672 "headers print out active message headers\n"
673 "delete <message list> delete messages\n"
674 "undelete <message list> undelete messages\n"));
676 "save <message list> folder append messages to folder and mark as saved\n"
677 "copy <message list> folder append messages to folder without marking them\n"
678 "write <message list> file append message texts to file, save attachments\n"
679 "preserve <message list> keep incoming messages in mailbox even if saved\n"
680 "Reply <message list> reply to message senders\n"
681 "reply <message list> reply to message senders and all recipients\n"));
683 "mail addresses mail to specific recipients\n"
684 "file folder change to another folder\n"
685 "quit quit and apply changes to folder\n"
686 "xit quit and discard changes made to folder\n"
688 "cd <directory> chdir to directory or home if none given\n"
689 "list list names of all available commands\n"));
691 "A <message list> consists of integers, ranges of same, or other criteria\n"
692 "separated by spaces. If omitted, %s uses the last message typed.\n"),
703 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
706 if (getcwd(buf
, sizeof buf
) != NULL
) {
724 if (*arglist
== NULL
)
726 else if ((cp
= file_expand(*arglist
)) == NULL
)
728 if (chdir(cp
) == -1) {
743 rv
= (*respond_or_Respond('r'))(v
, 0);
749 c_respondall(void *v
)
754 rv
= respond_internal(v
, 0);
760 c_respondsender(void *v
)
765 rv
= Respond_internal(v
, 0);
776 rv
= (*respond_or_Respond('R'))(v
, 0);
787 rv
= (*respond_or_Respond('r'))(v
, 1);
793 c_followupall(void *v
)
798 rv
= respond_internal(v
, 1);
804 c_followupsender(void *v
)
809 rv
= Respond_internal(v
, 1);
820 rv
= (*respond_or_Respond('R'))(v
, 1);
853 rv
= _resend1(v
, TRU1
);
864 rv
= _resend1(v
, FAL0
);
872 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
877 printf(_("Cannot \"preserve\" in edit mode\n"));
881 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
883 mp
= message
+ mesg
- 1;
884 mp
->m_flag
|= MPRESERVE
;
887 did_print_dot
= TRU1
;
898 int *msgvec
= v
, *ip
;
901 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
902 setdot(message
+ *ip
- 1);
903 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
904 dot
->m_flag
|= MSTATUS
;
906 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
907 imap_unread(message
+ *ip
- 1, *ip
); /* TODO return? */
909 did_print_dot
= TRU1
;
918 int *msgvec
= v
, *ip
;
921 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
922 struct message
*mp
= message
+ *ip
- 1;
933 int *msgvec
= v
, *ip
, mesg
;
937 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
939 mp
= message
+ mesg
- 1;
940 printf("%d: ", mesg
);
941 if (mp
->m_xlines
> 0)
942 printf("%ld", mp
->m_xlines
);
945 printf("/%lu\n", (ul_i
)mp
->m_xsize
);
966 char **argv
= v
, **ap
, *gname
, **p
;
967 struct grouphead
*gh
;
973 for (h
= 0, s
= 1; h
< HSHSIZE
; ++h
)
974 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
976 ap
= salloc(s
* sizeof *ap
);
978 for (h
= 0, p
= ap
; h
< HSHSIZE
; ++h
)
979 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
985 for (p
= ap
; *p
!= NULL
; ++p
)
990 if (argv
[1] == NULL
) {
997 if ((gh
= findgroup(gname
)) == NULL
) {
998 gh
= scalloc(1, sizeof *gh
);
999 gh
->g_name
= sstrdup(gname
);
1001 gh
->g_link
= groups
[h
];
1005 /* Insert names from the command list into the group. Who cares if there
1006 * are duplicates? They get tossed later anyway */
1007 for (ap
= argv
+ 1; *ap
!= NULL
; ++ap
) {
1008 gp
= scalloc(1, sizeof *gp
);
1009 gp
->ge_name
= sstrdup(*ap
);
1010 gp
->ge_link
= gh
->g_list
;
1025 if (*argv
== NULL
) {
1026 fprintf(stderr
, _("Must specify alias to remove\n"));
1031 remove_group(*argv
);
1032 while (*++argv
!= NULL
);
1045 rv
= _c_file(v
, FEDIT_NONE
);
1056 rv
= _c_file(v
, FEDIT_RDONLY
);
1064 char const **argv
= v
, **ap
, *cp
;
1068 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1070 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1074 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1076 /* \c ends overall processing */
1090 struct cond_stack
*csp
;
1092 char **argv
= v
, *cp
, *op
;
1095 csp
= smalloc(sizeof *csp
);
1096 csp
->c_outer
= _cond_stack
;
1097 csp
->c_noop
= condstack_isskip();
1103 if (*cp
!= '$' && argv
[1] != NULL
) {
1105 fprintf(stderr
, _("Invalid conditional expression \"%s %s %s\"\n"),
1106 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
1107 (argv
[2] != NULL
? argv
[2] : ""));
1116 csp
->c_go
= !(options
& OPT_SENDMODE
);
1119 csp
->c_go
= ((options
& OPT_SENDMODE
) != 0);
1122 csp
->c_go
= ((options
& OPT_TTYIN
) != 0);
1125 /* Look up the value in question, we need it anyway */
1126 v
= vok_vlook(++cp
);
1128 /* Single argument, "implicit boolean" form? */
1129 if ((op
= argv
[1]) == NULL
) {
1130 csp
->c_go
= (v
!= NULL
);
1134 /* Three argument comparison form? */
1135 if (argv
[2] == NULL
|| op
[0] == '\0' ||
1137 (op
[1] != '=' && op
[1] != '~') ||
1144 /* A null value is treated as the empty string */
1151 if (regcomp(&re
, argv
[2], REG_EXTENDED
| REG_ICASE
| REG_NOSUB
))
1153 if (regexec(&re
, v
, 0,NULL
, 0) == REG_NOMATCH
)
1158 if (strcmp(v
, argv
[2]))
1163 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1170 fprintf(stderr
, _("Unrecognized if-keyword: \"%s\"\n"), cp
);
1184 struct cond_stack
*csp
;
1188 if ((csp
= _cond_stack
) == NULL
|| csp
->c_else
) {
1189 fprintf(stderr
, _("`elif' without matching `if'\n"));
1192 csp
->c_go
= !csp
->c_go
;
1194 _cond_stack
->c_outer
= csp
->c_outer
;
1208 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1209 fprintf(stderr
, _("`else' without matching `if'\n"));
1212 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1213 _cond_stack
->c_else
= TRU1
;
1223 struct cond_stack
*csp
;
1228 if ((csp
= _cond_stack
) == NULL
) {
1229 fprintf(stderr
, _("`endif' without matching `if'\n"));
1232 _cond_stack
= csp
->c_outer
;
1241 condstack_isskip(void)
1246 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1252 condstack_release(void)
1264 condstack_take(void *self
)
1266 struct cond_stack
*csp
;
1270 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1272 _cond_stack
= csp
->c_outer
;
1274 } while ((csp
= _cond_stack
) != NULL
);
1282 c_alternates(void *v
)
1285 char **namelist
= v
, **ap
, **ap2
, *cp
;
1288 l
= argcount(namelist
) + 1;
1290 if (altnames
== NULL
)
1292 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1298 if (altnames
!= NULL
) {
1299 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1303 altnames
= smalloc(l
* sizeof(char*));
1304 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1305 l
= strlen(*ap
) + 1;
1325 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1327 (val
= setfile(mailname
,
1328 FEDIT_NEWMAIL
| ((mb
.mb_perm
& MB_DELE
) ? 0 : FEDIT_RDONLY
))
1331 setdot(message
+ mdot
- 1);
1345 if (args
[0] == NULL
) {
1352 if (args
[1] == NULL
) {
1353 fprintf(stderr
, _("expansion name for shortcut missing\n"));
1356 if (args
[2] != NULL
) {
1357 fprintf(stderr
, _("too many arguments\n"));
1361 if ((s
= get_shortcut(args
[0])) != NULL
) {
1363 s
->sh_long
= sstrdup(args
[1]);
1365 s
= scalloc(1, sizeof *s
);
1366 s
->sh_short
= sstrdup(args
[0]);
1367 s
->sh_long
= sstrdup(args
[1]);
1368 s
->sh_next
= shortcuts
;
1377 FL
struct shortcut
*
1378 get_shortcut(char const *str
)
1383 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
1384 if (!strcmp(str
, s
->sh_short
))
1391 c_unshortcut(void *v
)
1397 if (args
[0] == NULL
) {
1398 fprintf(stderr
, _("need shortcut names to remove\n"));
1403 while (*args
!= NULL
) {
1404 if (delete_shortcut(*args
) != OKAY
) {
1406 fprintf(stderr
, _("%s: no such shortcut\n"), *args
);
1419 int *msgvec
= v
, *ip
;
1422 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1423 m
= message
+ *ip
- 1;
1425 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1426 m
->m_flag
|= MFLAG
| MFLAGGED
;
1436 int *msgvec
= v
, *ip
;
1439 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1440 m
= message
+ *ip
- 1;
1442 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1443 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1444 m
->m_flag
|= MUNFLAG
;
1455 int *msgvec
= v
, *ip
;
1458 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1459 m
= message
+ *ip
- 1;
1461 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1462 m
->m_flag
|= MANSWER
| MANSWERED
;
1469 c_unanswered(void *v
)
1472 int *msgvec
= v
, *ip
;
1475 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1476 m
= message
+ *ip
- 1;
1478 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1479 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1480 m
->m_flag
|= MUNANSWER
;
1491 int *msgvec
= v
, *ip
;
1494 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1495 m
= message
+ *ip
- 1;
1497 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1498 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1508 int *msgvec
= v
, *ip
;
1511 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1512 m
= message
+ *ip
- 1;
1514 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1515 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1516 m
->m_flag
|= MUNDRAFT
;
1530 switch (mb
.mb_type
) {
1535 rv
= c_cmdnotsupp(NULL
);
1542 rv
= c_cmdnotsupp(NULL
);
1557 char **args
= v
, *name
;
1561 if (*args
== NULL
) {
1562 fprintf(stderr
, _("Syntax is: remove mailbox ...\n"));
1567 fmt
= _("Remove \"%s\" (y/n) ? ");
1568 fmt_len
= strlen(fmt
);
1570 if ((name
= expand(*args
)) == NULL
)
1573 if (!strcmp(name
, mailname
)) {
1574 fprintf(stderr
, _("Cannot remove current mailbox \"%s\".\n"),
1580 size_t vl
= strlen(name
) + fmt_len
+1;
1581 char *vb
= ac_alloc(vl
);
1583 snprintf(vb
, vl
, fmt
, name
);
1584 asw
= getapproval(vb
, TRU1
);
1590 switch (which_protocol(name
)) {
1592 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1598 fprintf(stderr
, _("Cannot remove POP3 mailbox \"%s\".\n"),name
);
1603 if (imap_remove(name
) != OKAY
)
1608 if (maildir_remove(name
) != OKAY
)
1612 fprintf(stderr
, _("Unknown protocol in \"%s\". Not removed.\n"),
1617 } while (*++args
!= NULL
);
1626 char **args
= v
, *old
, *new;
1627 enum protocol oldp
, newp
;
1633 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1634 fprintf(stderr
, "Syntax: rename old new\n");
1638 if ((old
= expand(args
[0])) == NULL
)
1640 oldp
= which_protocol(old
);
1641 if ((new = expand(args
[1])) == NULL
)
1643 newp
= which_protocol(new);
1645 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1646 fprintf(stderr
, _("Cannot rename current mailbox \"%s\".\n"), old
);
1649 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1650 fprintf(stderr
, _("Can only rename folders of same type.\n"));
1656 if (newp
== PROTO_POP3
)
1660 if (link(old
, new) == -1) {
1674 } else if (unlink(old
) == -1) {
1680 if (rename(old
, new) == -1) {
1687 fprintf(stderr
, _("Cannot rename POP3 mailboxes.\n"));
1692 if (imap_rename(old
, new) != OKAY
)
1699 "Unknown protocol in \"%s\" and \"%s\". Not renamed.\n"), old
, new);
1709 c_urlencode(void *v
) /* XXX IDNA?? */
1714 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1715 char *in
= *ap
, *out
= urlxenc(in
, FAL0
);
1717 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1718 in
, strlen(in
), out
, strlen(out
));
1725 c_urldecode(void *v
) /* XXX IDNA?? */
1730 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1731 char *in
= *ap
, *out
= urlxdec(in
);
1733 printf(" in: <%s> (%" PRIuZ
" bytes)\nout: <%s> (%" PRIuZ
" bytes)\n",
1734 in
, strlen(in
), out
, strlen(out
));