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 forward1(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 /* TODO _reedit: should be localizable (see cmd1.c:__subject_trim()!) */
115 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
116 (out
.s
[1] == 'e' || out
.s
[1] == 'E') && out
.s
[2] == ':') {
117 newsubj
= savestr(out
.s
);
120 newsubj
= salloc(out
.l
+ 4 +1);
121 sstpcpy(sstpcpy(newsubj
, "Re: "), out
.s
);
130 _bangexp(char **str
, size_t *size
)
135 size_t sz
, i
, j
, bangbufsize
;
138 dobang
= ok_blook(bang
);
140 bangbuf
= smalloc(bangbufsize
= *size
);
144 if ((*str
)[i
] == '!') {
145 sz
= strlen(_bang_buf
);
146 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
148 memcpy(bangbuf
+ j
, _bang_buf
, sz
+ 1);
154 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
159 bangbuf
[j
++] = (*str
)[i
++];
163 printf("!%s\n", bangbuf
);
168 *str
= srealloc(*str
, *size
= sz
);
169 memcpy(*str
, bangbuf
, sz
);
171 _bang_buf
= srealloc(_bang_buf
, _bang_size
= sz
);
172 memcpy(_bang_buf
, bangbuf
, sz
);
178 make_ref_and_cs(struct message
*mp
, struct header
*head
)
180 char *oldref
, *oldmsgid
, *newref
, *cp
;
181 size_t oldreflen
= 0, oldmsgidlen
= 0, reflen
;
186 oldref
= hfield1("references", mp
);
187 oldmsgid
= hfield1("message-id", mp
);
188 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
195 oldreflen
= strlen(oldref
);
196 reflen
+= oldreflen
+ 2;
199 oldmsgidlen
= strlen(oldmsgid
);
200 reflen
+= oldmsgidlen
;
203 newref
= ac_alloc(reflen
);
204 if (oldref
!= NULL
) {
205 memcpy(newref
, oldref
, oldreflen
+1);
206 if (oldmsgid
!= NULL
) {
207 newref
[oldreflen
++] = ',';
208 newref
[oldreflen
++] = ' ';
209 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+1);
212 memcpy(newref
, oldmsgid
, oldmsgidlen
+1);
213 n
= extract(newref
, GREF
);
216 /* Limit number of references */
217 while (n
->n_flink
!= NULL
)
219 for (i
= 1; i
< 21; ++i
) { /* XXX no magics */
220 if (n
->n_blink
!= NULL
)
227 if (ok_blook(reply_in_same_charset
) &&
228 (cp
= hfield1("content-type", mp
)) != NULL
)
229 head
->h_charset
= mime_getparam("charset", cp
);
235 (*respond_or_Respond(int c
))(int *, int)
238 int (*rv
)(int*, int);
241 opt
= ok_blook(Replyall
);
242 opt
+= ok_blook(flipr
);
243 rv
= ((opt
== 1) ^ (c
== 'R')) ? &Respond_internal
: &respond_internal
;
249 respond_internal(int *msgvec
, int recipient_record
)
254 struct name
*np
= NULL
;
259 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
261 if (msgvec
[1] != 0) {
263 "Sorry, can't reply to multiple messages at once\n"));
267 mp
= message
+ msgvec
[0] - 1;
271 if ((rcv
= hfield1("reply-to", mp
)) == NULL
)
272 if ((rcv
= hfield1("from", mp
)) == NULL
)
275 np
= lextract(rcv
, GTO
| gf
);
276 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
277 np
= cat(np
, lextract(cp
, GTO
| gf
));
278 /* Delete my name from reply list, and with it, all my alternate names */
279 np
= elide(delete_alternates(np
));
281 np
= lextract(rcv
, GTO
| gf
);
283 memset(&head
, 0, sizeof head
);
285 head
.h_subject
= hfield1("subject", mp
);
286 head
.h_subject
= _reedit(head
.h_subject
);
290 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
291 np
= lextract(cp
, GCC
| gf
);
292 if ((cp
= hfield1("cc", mp
)) != NULL
)
293 np
= cat(np
, lextract(cp
, GCC
| gf
));
295 head
.h_cc
= elide(delete_alternates(np
));
296 make_ref_and_cs(mp
, &head
);
298 if (ok_blook(quote_as_attachment
)) {
299 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
300 head
.h_attach
->a_msgno
= *msgvec
;
301 head
.h_attach
->a_content_description
= _(
302 "Original message content");
305 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
306 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
307 mp
->m_flag
|= MANSWER
| MANSWERED
;
315 Respond_internal(int *msgvec
, int recipient_record
)
324 memset(&head
, 0, sizeof head
);
325 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
327 for (ap
= msgvec
; *ap
!= 0; ++ap
) {
328 mp
= message
+ *ap
- 1;
331 if ((cp
= hfield1("reply-to", mp
)) == NULL
)
332 if ((cp
= hfield1("from", mp
)) == NULL
)
334 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
336 if (head
.h_to
== NULL
)
339 mp
= message
+ msgvec
[0] - 1;
340 head
.h_subject
= hfield1("subject", mp
);
341 head
.h_subject
= _reedit(head
.h_subject
);
342 make_ref_and_cs(mp
, &head
);
344 if (ok_blook(quote_as_attachment
)) {
345 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
346 head
.h_attach
->a_msgno
= *msgvec
;
347 head
.h_attach
->a_content_description
= _(
348 "Original message content");
351 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
352 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
353 mp
->m_flag
|= MANSWER
| MANSWERED
;
360 forward1(char *str
, int recipient_record
)
366 bool_t f
, forward_as_attachment
;
369 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
370 puts(_("No recipient specified."));
374 forward_as_attachment
= ok_blook(forward_as_attachment
);
375 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
378 *msgvec
= first(0, MMNORM
);
384 printf("No messages to forward.\n");
388 } else if (getmsglist(str
, msgvec
, 0) < 0)
396 printf("No applicable messages.\n");
399 if (msgvec
[1] != 0) {
400 printf("Cannot forward multiple messages at once\n");
404 memset(&head
, 0, sizeof head
);
405 if ((head
.h_to
= lextract(recipient
,
406 (GTO
| (ok_blook(fullnames
) ? GFULL
: GSKIN
)))) == NULL
)
409 mp
= message
+ *msgvec
- 1;
411 if (forward_as_attachment
) {
412 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
413 head
.h_attach
->a_msgno
= *msgvec
;
414 head
.h_attach
->a_content_description
= "Forwarded message";
419 head
.h_subject
= hfield1("subject", mp
);
420 head
.h_subject
= fwdedit(head
.h_subject
);
421 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
), NULL
, recipient_record
,
433 char *newsubj
= NULL
;
436 if (subj
== NULL
|| *subj
== '\0')
441 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
443 newsubj
= salloc(out
.l
+ 6);
444 memcpy(newsubj
, "Fwd: ", 5); /* XXX localizable */
445 memcpy(newsubj
+ 5, out
.s
, out
.l
+ 1);
459 for (ap
= list
; *ap
!= NULL
; ++ap
)
461 if ((i
= PTR2SIZE(ap
- list
)) >= 2)
462 qsort(list
, i
, sizeof *list
, diction
);
467 diction(void const *a
, void const *b
)
472 rv
= strcmp(*(char**)UNCONST(a
), *(char**)UNCONST(b
));
478 _resend1(void *v
, bool_t add_resent
)
481 struct name
*to
, *sn
;
487 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
488 name
= laststring(str
, &f
, 1);
490 puts(_("No recipient specified."));
495 *msgvec
= first(0, MMNORM
);
501 puts(_("No applicable messages."));
505 } else if (getmsglist(str
, msgvec
, 0) < 0)
513 printf("No applicable messages.\n");
517 sn
= nalloc(name
, GTO
| GSKIN
);
518 to
= usermap(sn
, FAL0
);
519 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
521 if (resend_msg(message
+ *ip
- 1, to
, add_resent
) != OKAY
)
530 _c_file(void *v
, enum fedit_mode fm
)
543 fprintf(stderr
, _("Cannot change folder from within a hook.\n"));
548 save_mbox_for_possible_quitstuff();
550 i
= setfile(*argv
, fm
);
555 callhook(mailname
, 0);
556 if (i
> 0 && !ok_blook(emptystart
)) {
560 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
573 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
574 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
579 delete_shortcut(char const *str
)
581 struct shortcut
*sp
, *sq
;
585 for (sp
= shortcuts
, sq
= NULL
; sp
!= NULL
; sq
= sp
, sp
= sp
->sh_next
) {
586 if (!strcmp(sp
->sh_short
, str
)) {
590 sq
->sh_next
= sp
->sh_next
;
592 shortcuts
= sp
->sh_next
;
605 char const *sh
= NULL
;
609 sighandler_type sigint
;
612 cmd
= smalloc(cmdsize
= strlen(str
) +1);
613 memcpy(cmd
, str
, cmdsize
);
614 _bangexp(&cmd
, &cmdsize
);
615 if ((sh
= ok_vlook(SHELL
)) == NULL
)
618 sigint
= safe_signal(SIGINT
, SIG_IGN
);
620 run_command(sh
, &mask
, -1, -1, "-c", cmd
, NULL
);
621 safe_signal(SIGINT
, sigint
);
632 sighandler_type sigint
;
637 if ((sh
= ok_vlook(SHELL
)) == NULL
)
640 sigint
= safe_signal(SIGINT
, SIG_IGN
);
641 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
642 safe_signal(SIGINT
, sigint
);
658 #ifdef HAVE_DOCSTRINGS
659 ret
= !print_comm_docstr(arg
);
661 fprintf(stderr
, _("Unknown command: `%s'\n"), arg
);
663 ret
= c_cmdnotsupp(NULL
);
668 /* Very ugly, but take care for compiler supported string lengths :( */
669 printf(_("%s commands:\n"), progname
);
671 "type <message list> type messages\n"
672 "next goto and type next message\n"
673 "from <message list> give head lines of messages\n"
674 "headers print out active message headers\n"
675 "delete <message list> delete messages\n"
676 "undelete <message list> undelete messages\n"));
678 "save <message list> folder append messages to folder and mark as saved\n"
679 "copy <message list> folder append messages to folder without marking them\n"
680 "write <message list> file append message texts to file, save attachments\n"
681 "preserve <message list> keep incoming messages in mailbox even if saved\n"
682 "Reply <message list> reply to message senders\n"
683 "reply <message list> reply to message senders and all recipients\n"));
685 "mail addresses mail to specific recipients\n"
686 "file folder change to another folder\n"
687 "quit quit and apply changes to folder\n"
688 "xit quit and discard changes made to folder\n"
690 "cd <directory> chdir to directory or home if none given\n"
691 "list list names of all available commands\n"));
693 "\nA <message list> consists of integers, ranges of same, or other criteria\n"
694 "separated by spaces. If omitted, %s uses the last message typed.\n"),
705 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
708 if (getcwd(buf
, sizeof buf
) != NULL
) {
726 if (*arglist
== NULL
)
728 else if ((cp
= file_expand(*arglist
)) == NULL
)
730 if (chdir(cp
) == -1) {
745 rv
= (*respond_or_Respond('r'))(v
, 0);
751 c_respondall(void *v
)
756 rv
= respond_internal(v
, 0);
762 c_respondsender(void *v
)
767 rv
= Respond_internal(v
, 0);
778 rv
= (*respond_or_Respond('R'))(v
, 0);
789 rv
= (*respond_or_Respond('r'))(v
, 1);
795 c_followupall(void *v
)
800 rv
= respond_internal(v
, 1);
806 c_followupsender(void *v
)
811 rv
= Respond_internal(v
, 1);
822 rv
= (*respond_or_Respond('R'))(v
, 1);
855 rv
= _resend1(v
, TRU1
);
866 rv
= _resend1(v
, FAL0
);
874 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
879 printf(_("Cannot \"preserve\" in edit mode\n"));
883 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
885 mp
= message
+ mesg
- 1;
886 mp
->m_flag
|= MPRESERVE
;
889 did_print_dot
= TRU1
;
900 int *msgvec
= v
, *ip
;
903 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
904 setdot(message
+ *ip
- 1);
905 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
906 dot
->m_flag
|= MSTATUS
;
908 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
909 imap_unread(message
+ *ip
- 1, *ip
); /* TODO return? */
911 did_print_dot
= TRU1
;
920 int *msgvec
= v
, *ip
;
923 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
924 struct message
*mp
= message
+ *ip
- 1;
935 int *msgvec
= v
, *ip
, mesg
;
939 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
941 mp
= message
+ mesg
- 1;
942 printf("%d: ", mesg
);
943 if (mp
->m_xlines
> 0)
944 printf("%ld", mp
->m_xlines
);
947 printf("/%lu\n", (ul_it
)mp
->m_xsize
);
968 char **argv
= v
, **ap
, *gname
, **p
;
969 struct grouphead
*gh
;
975 for (h
= 0, s
= 1; h
< HSHSIZE
; ++h
)
976 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
978 ap
= salloc(s
* sizeof *ap
);
980 for (h
= 0, p
= ap
; h
< HSHSIZE
; ++h
)
981 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
987 for (p
= ap
; *p
!= NULL
; ++p
)
992 if (argv
[1] == NULL
) {
999 if ((gh
= findgroup(gname
)) == NULL
) {
1000 gh
= scalloc(1, sizeof *gh
);
1001 gh
->g_name
= sstrdup(gname
);
1003 gh
->g_link
= groups
[h
];
1007 /* Insert names from the command list into the group. Who cares if there
1008 * are duplicates? They get tossed later anyway */
1009 for (ap
= argv
+ 1; *ap
!= NULL
; ++ap
) {
1010 gp
= scalloc(1, sizeof *gp
);
1011 gp
->ge_name
= sstrdup(*ap
);
1012 gp
->ge_link
= gh
->g_list
;
1027 if (*argv
== NULL
) {
1028 fprintf(stderr
, _("Must specify alias to remove\n"));
1033 remove_group(*argv
);
1034 while (*++argv
!= NULL
);
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
)) != NULL
) {
1076 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1078 /* \c ends overall processing */
1092 struct cond_stack
*csp
;
1094 char **argv
= v
, *cp
, *op
;
1097 csp
= smalloc(sizeof *csp
);
1098 csp
->c_outer
= _cond_stack
;
1099 csp
->c_noop
= condstack_isskip();
1105 if (*cp
!= '$' && argv
[1] != NULL
) {
1107 fprintf(stderr
, _("Invalid conditional expression \"%s %s %s\"\n"),
1108 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
1109 (argv
[2] != NULL
? argv
[2] : ""));
1118 csp
->c_go
= !(options
& OPT_SENDMODE
);
1121 csp
->c_go
= ((options
& OPT_SENDMODE
) != 0);
1124 csp
->c_go
= ((options
& OPT_TTYIN
) != 0);
1127 /* Look up the value in question, we need it anyway */
1128 v
= vok_vlook(++cp
);
1130 /* Single argument, "implicit boolean" form? */
1131 if ((op
= argv
[1]) == NULL
) {
1132 csp
->c_go
= (v
!= NULL
);
1136 /* Three argument comparison form? */
1137 if (argv
[2] == NULL
|| op
[0] == '\0' ||
1139 (op
[1] != '=' && op
[1] != '~') ||
1146 /* A null value is treated as the empty string */
1153 if (regcomp(&re
, argv
[2], REG_EXTENDED
| REG_ICASE
| REG_NOSUB
))
1155 if (regexec(&re
, v
, 0,NULL
, 0) == REG_NOMATCH
)
1160 if (strcmp(v
, argv
[2]))
1165 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1172 fprintf(stderr
, _("Unrecognized if-keyword: \"%s\"\n"), cp
);
1186 struct cond_stack
*csp
;
1190 if ((csp
= _cond_stack
) == NULL
|| csp
->c_else
) {
1191 fprintf(stderr
, _("`elif' without matching `if'\n"));
1194 csp
->c_go
= !csp
->c_go
;
1196 _cond_stack
->c_outer
= csp
->c_outer
;
1210 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1211 fprintf(stderr
, _("`else' without matching `if'\n"));
1214 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1215 _cond_stack
->c_else
= TRU1
;
1225 struct cond_stack
*csp
;
1230 if ((csp
= _cond_stack
) == NULL
) {
1231 fprintf(stderr
, _("`endif' without matching `if'\n"));
1234 _cond_stack
= csp
->c_outer
;
1243 condstack_isskip(void)
1248 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1254 condstack_release(void)
1266 condstack_take(void *self
)
1268 struct cond_stack
*csp
;
1272 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1274 _cond_stack
= csp
->c_outer
;
1276 } while ((csp
= _cond_stack
) != NULL
);
1284 c_alternates(void *v
)
1287 char **namelist
= v
, **ap
, **ap2
, *cp
;
1290 l
= argcount(namelist
) + 1;
1292 if (altnames
== NULL
)
1294 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1300 if (altnames
!= NULL
) {
1301 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1305 altnames
= smalloc(l
* sizeof(char*));
1306 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1307 l
= strlen(*ap
) + 1;
1327 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1329 (val
= setfile(mailname
, FEDIT_NEWMAIL
)) == 0) {
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> (%" ZFMT
" bytes)\nout: <%s> (%" ZFMT
" 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> (%" ZFMT
" bytes)\nout: <%s> (%" ZFMT
" bytes)\n",
1734 in
, strlen(in
), out
, strlen(out
));
1740 /* vim:set fenc=utf-8:s-it-mode */