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 void list_shortcuts(void);
95 static enum okay
delete_shortcut(char const *str
);
101 char *newsubj
= NULL
;
104 if (subj
== NULL
|| *subj
== '\0')
109 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
111 /* TODO _reedit: should be localizable (see cmd1.c:__subject_trim()!) */
112 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
113 (out
.s
[1] == 'e' || out
.s
[1] == 'E') && out
.s
[2] == ':') {
114 newsubj
= savestr(out
.s
);
117 newsubj
= salloc(out
.l
+ 4 +1);
118 sstpcpy(sstpcpy(newsubj
, "Re: "), out
.s
);
127 _bangexp(char **str
, size_t *size
)
132 size_t sz
, i
, j
, bangbufsize
;
135 dobang
= ok_blook(bang
);
137 bangbuf
= smalloc(bangbufsize
= *size
);
141 if ((*str
)[i
] == '!') {
142 sz
= strlen(_bang_buf
);
143 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
145 memcpy(bangbuf
+ j
, _bang_buf
, sz
+ 1);
151 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
156 bangbuf
[j
++] = (*str
)[i
++];
160 printf("!%s\n", bangbuf
);
165 *str
= srealloc(*str
, *size
= sz
);
166 memcpy(*str
, bangbuf
, sz
);
168 _bang_buf
= srealloc(_bang_buf
, _bang_size
= sz
);
169 memcpy(_bang_buf
, bangbuf
, sz
);
175 make_ref_and_cs(struct message
*mp
, struct header
*head
)
177 char *oldref
, *oldmsgid
, *newref
, *cp
;
178 size_t oldreflen
= 0, oldmsgidlen
= 0, reflen
;
183 oldref
= hfield1("references", mp
);
184 oldmsgid
= hfield1("message-id", mp
);
185 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
192 oldreflen
= strlen(oldref
);
193 reflen
+= oldreflen
+ 2;
196 oldmsgidlen
= strlen(oldmsgid
);
197 reflen
+= oldmsgidlen
;
200 newref
= ac_alloc(reflen
);
201 if (oldref
!= NULL
) {
202 memcpy(newref
, oldref
, oldreflen
+1);
203 if (oldmsgid
!= NULL
) {
204 newref
[oldreflen
++] = ',';
205 newref
[oldreflen
++] = ' ';
206 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+1);
209 memcpy(newref
, oldmsgid
, oldmsgidlen
+1);
210 n
= extract(newref
, GREF
);
213 /* Limit number of references */
214 while (n
->n_flink
!= NULL
)
216 for (i
= 1; i
< 21; ++i
) { /* XXX no magics */
217 if (n
->n_blink
!= NULL
)
224 if (ok_blook(reply_in_same_charset
) &&
225 (cp
= hfield1("content-type", mp
)) != NULL
)
226 head
->h_charset
= mime_getparam("charset", cp
);
232 (*respond_or_Respond(int c
))(int *, int)
235 int (*rv
)(int*, int);
238 opt
= ok_blook(Replyall
);
239 opt
+= ok_blook(flipr
);
240 rv
= ((opt
== 1) ^ (c
== 'R')) ? &Respond_internal
: &respond_internal
;
246 respond_internal(int *msgvec
, int recipient_record
)
251 struct name
*np
= NULL
;
256 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
258 if (msgvec
[1] != 0) {
259 fprintf(stderr
, tr(37,
260 "Sorry, can't reply to multiple messages at once\n"));
264 mp
= message
+ msgvec
[0] - 1;
268 if ((rcv
= hfield1("reply-to", mp
)) == NULL
)
269 if ((rcv
= hfield1("from", mp
)) == NULL
)
272 np
= lextract(rcv
, GTO
| gf
);
273 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
274 np
= cat(np
, lextract(cp
, GTO
| gf
));
275 /* Delete my name from reply list, and with it, all my alternate names */
276 np
= elide(delete_alternates(np
));
278 np
= lextract(rcv
, GTO
| gf
);
280 memset(&head
, 0, sizeof head
);
282 head
.h_subject
= hfield1("subject", mp
);
283 head
.h_subject
= _reedit(head
.h_subject
);
287 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
288 np
= lextract(cp
, GCC
| gf
);
289 if ((cp
= hfield1("cc", mp
)) != NULL
)
290 np
= cat(np
, lextract(cp
, GCC
| gf
));
292 head
.h_cc
= elide(delete_alternates(np
));
293 make_ref_and_cs(mp
, &head
);
295 if (ok_blook(quote_as_attachment
)) {
296 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
297 head
.h_attach
->a_msgno
= *msgvec
;
298 head
.h_attach
->a_content_description
= tr(512,
299 "Original message content");
302 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
303 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
304 mp
->m_flag
|= MANSWER
| MANSWERED
;
312 Respond_internal(int *msgvec
, int recipient_record
)
321 memset(&head
, 0, sizeof head
);
322 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
324 for (ap
= msgvec
; *ap
!= 0; ++ap
) {
325 mp
= message
+ *ap
- 1;
328 if ((cp
= hfield1("reply-to", mp
)) == NULL
)
329 if ((cp
= hfield1("from", mp
)) == NULL
)
331 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
333 if (head
.h_to
== NULL
)
336 mp
= message
+ msgvec
[0] - 1;
337 head
.h_subject
= hfield1("subject", mp
);
338 head
.h_subject
= _reedit(head
.h_subject
);
339 make_ref_and_cs(mp
, &head
);
341 if (ok_blook(quote_as_attachment
)) {
342 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
343 head
.h_attach
->a_msgno
= *msgvec
;
344 head
.h_attach
->a_content_description
= tr(512,
345 "Original message content");
348 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
349 ok_blook(markanswered
) && !(mp
->m_flag
& MANSWERED
))
350 mp
->m_flag
|= MANSWER
| MANSWERED
;
357 forward1(char *str
, int recipient_record
)
363 bool_t f
, forward_as_attachment
;
366 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
367 puts(tr(47, "No recipient specified."));
371 forward_as_attachment
= ok_blook(forward_as_attachment
);
372 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
375 *msgvec
= first(0, MMNORM
);
381 printf("No messages to forward.\n");
385 } else if (getmsglist(str
, msgvec
, 0) < 0)
393 printf("No applicable messages.\n");
396 if (msgvec
[1] != 0) {
397 printf("Cannot forward multiple messages at once\n");
401 memset(&head
, 0, sizeof head
);
402 if ((head
.h_to
= lextract(recipient
,
403 (GTO
| (ok_blook(fullnames
) ? GFULL
: GSKIN
)))) == NULL
)
406 mp
= message
+ *msgvec
- 1;
408 if (forward_as_attachment
) {
409 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
410 head
.h_attach
->a_msgno
= *msgvec
;
411 head
.h_attach
->a_content_description
= "Forwarded message";
416 head
.h_subject
= hfield1("subject", mp
);
417 head
.h_subject
= fwdedit(head
.h_subject
);
418 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
), NULL
, recipient_record
,
430 char *newsubj
= NULL
;
433 if (subj
== NULL
|| *subj
== '\0')
438 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
440 newsubj
= salloc(out
.l
+ 6);
441 memcpy(newsubj
, "Fwd: ", 5); /* XXX localizable */
442 memcpy(newsubj
+ 5, out
.s
, out
.l
+ 1);
456 for (ap
= list
; *ap
!= NULL
; ++ap
)
458 if ((i
= PTR2SIZE(ap
- list
)) >= 2)
459 qsort(list
, i
, sizeof *list
, diction
);
464 diction(void const *a
, void const *b
)
469 rv
= strcmp(*(char**)UNCONST(a
), *(char**)UNCONST(b
));
475 _resend1(void *v
, bool_t add_resent
)
478 struct name
*to
, *sn
;
484 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
485 name
= laststring(str
, &f
, 1);
487 puts(tr(47, "No recipient specified."));
492 *msgvec
= first(0, MMNORM
);
498 puts(tr(48, "No applicable messages."));
502 } else if (getmsglist(str
, msgvec
, 0) < 0)
510 printf("No applicable messages.\n");
514 sn
= nalloc(name
, GTO
| GSKIN
);
515 to
= usermap(sn
, FAL0
);
516 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
518 if (resend_msg(message
+ *ip
- 1, to
, add_resent
) != OKAY
)
532 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
533 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
538 delete_shortcut(char const *str
)
540 struct shortcut
*sp
, *sq
;
544 for (sp
= shortcuts
, sq
= NULL
; sp
!= NULL
; sq
= sp
, sp
= sp
->sh_next
) {
545 if (!strcmp(sp
->sh_short
, str
)) {
549 sq
->sh_next
= sp
->sh_next
;
551 shortcuts
= sp
->sh_next
;
564 char const *sh
= NULL
;
568 sighandler_type sigint
;
571 cmd
= smalloc(cmdsize
= strlen(str
) +1);
572 memcpy(cmd
, str
, cmdsize
);
573 _bangexp(&cmd
, &cmdsize
);
574 if ((sh
= ok_vlook(SHELL
)) == NULL
)
577 sigint
= safe_signal(SIGINT
, SIG_IGN
);
579 run_command(sh
, &mask
, -1, -1, "-c", cmd
, NULL
);
580 safe_signal(SIGINT
, sigint
);
591 sighandler_type sigint
;
596 if ((sh
= ok_vlook(SHELL
)) == NULL
)
599 sigint
= safe_signal(SIGINT
, SIG_IGN
);
600 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
601 safe_signal(SIGINT
, sigint
);
617 #ifdef HAVE_DOCSTRINGS
618 ret
= !print_comm_docstr(arg
);
620 fprintf(stderr
, tr(91, "Unknown command: `%s'\n"), arg
);
622 ret
= c_cmdnotsupp(NULL
);
627 /* Very ugly, but take care for compiler supported string lengths :( */
628 printf(tr(295, "%s commands:\n"), progname
);
630 "type <message list> type messages\n"
631 "next goto and type next message\n"
632 "from <message list> give head lines of messages\n"
633 "headers print out active message headers\n"
634 "delete <message list> delete messages\n"
635 "undelete <message list> undelete messages\n"));
637 "save <message list> folder append messages to folder and mark as saved\n"
638 "copy <message list> folder append messages to folder without marking them\n"
639 "write <message list> file append message texts to file, save attachments\n"
640 "preserve <message list> keep incoming messages in mailbox even if saved\n"
641 "Reply <message list> reply to message senders\n"
642 "reply <message list> reply to message senders and all recipients\n"));
644 "mail addresses mail to specific recipients\n"
645 "file folder change to another folder\n"
646 "quit quit and apply changes to folder\n"
647 "xit quit and discard changes made to folder\n"
649 "cd <directory> chdir to directory or home if none given\n"
650 "list list names of all available commands\n"));
652 "\nA <message list> consists of integers, ranges of same, or other criteria\n"
653 "separated by spaces. If omitted, %s uses the last message typed.\n"),
664 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
667 if (getcwd(buf
, sizeof buf
) != NULL
) {
685 if (*arglist
== NULL
)
687 else if ((cp
= file_expand(*arglist
)) == NULL
)
689 if (chdir(cp
) == -1) {
704 rv
= (*respond_or_Respond('r'))(v
, 0);
710 c_respondall(void *v
)
715 rv
= respond_internal(v
, 0);
721 c_respondsender(void *v
)
726 rv
= Respond_internal(v
, 0);
737 rv
= (*respond_or_Respond('R'))(v
, 0);
748 rv
= (*respond_or_Respond('r'))(v
, 1);
754 c_followupall(void *v
)
759 rv
= respond_internal(v
, 1);
765 c_followupsender(void *v
)
770 rv
= Respond_internal(v
, 1);
781 rv
= (*respond_or_Respond('R'))(v
, 1);
814 rv
= _resend1(v
, TRU1
);
825 rv
= _resend1(v
, FAL0
);
833 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
838 printf(tr(39, "Cannot \"preserve\" in edit mode\n"));
842 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
844 mp
= message
+ mesg
- 1;
845 mp
->m_flag
|= MPRESERVE
;
848 did_print_dot
= TRU1
;
859 int *msgvec
= v
, *ip
;
862 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
863 setdot(message
+ *ip
- 1);
864 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
865 dot
->m_flag
|= MSTATUS
;
867 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
868 imap_unread(message
+ *ip
- 1, *ip
); /* TODO return? */
870 did_print_dot
= TRU1
;
879 int *msgvec
= v
, *ip
;
882 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
883 struct message
*mp
= message
+ *ip
- 1;
894 int *msgvec
= v
, *ip
, mesg
;
898 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
900 mp
= message
+ mesg
- 1;
901 printf("%d: ", mesg
);
902 if (mp
->m_xlines
> 0)
903 printf("%ld", mp
->m_xlines
);
906 printf("/%lu\n", (ul_it
)mp
->m_xsize
);
927 char **argv
= v
, **ap
, *gname
, **p
;
928 struct grouphead
*gh
;
934 for (h
= 0, s
= 1; h
< HSHSIZE
; ++h
)
935 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
937 ap
= salloc(s
* sizeof *ap
);
939 for (h
= 0, p
= ap
; h
< HSHSIZE
; ++h
)
940 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
946 for (p
= ap
; *p
!= NULL
; ++p
)
951 if (argv
[1] == NULL
) {
958 if ((gh
= findgroup(gname
)) == NULL
) {
959 gh
= scalloc(1, sizeof *gh
);
960 gh
->g_name
= sstrdup(gname
);
962 gh
->g_link
= groups
[h
];
966 /* Insert names from the command list into the group. Who cares if there
967 * are duplicates? They get tossed later anyway */
968 for (ap
= argv
+ 1; *ap
!= NULL
; ++ap
) {
969 gp
= scalloc(1, sizeof *gp
);
970 gp
->ge_name
= sstrdup(*ap
);
971 gp
->ge_link
= gh
->g_list
;
987 fprintf(stderr
, tr(209, "Must specify alias to remove\n"));
993 while (*++argv
!= NULL
);
1007 if (*argv
== NULL
) {
1014 fprintf(stderr
, tr(516, "Cannot change folder from within a hook.\n"));
1019 save_mbox_for_possible_quitstuff();
1021 i
= setfile(*argv
, 0);
1026 callhook(mailname
, 0);
1027 if (i
> 0 && !ok_blook(emptystart
)) {
1031 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
1041 char const **argv
= v
, **ap
, *cp
;
1045 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1047 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1051 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1053 /* \c ends overall processing */
1067 struct cond_stack
*csp
;
1069 char **argv
= v
, *cp
, *op
;
1072 csp
= smalloc(sizeof *csp
);
1073 csp
->c_outer
= _cond_stack
;
1074 csp
->c_noop
= condstack_isskip();
1080 if (*cp
!= '$' && argv
[1] != NULL
) {
1082 fprintf(stderr
, tr(528, "Invalid conditional expression \"%s %s %s\"\n"),
1083 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
1084 (argv
[2] != NULL
? argv
[2] : ""));
1093 csp
->c_go
= !(options
& OPT_SENDMODE
);
1096 csp
->c_go
= ((options
& OPT_SENDMODE
) != 0);
1099 csp
->c_go
= ((options
& OPT_TTYIN
) != 0);
1102 /* Look up the value in question, we need it anyway */
1103 v
= vok_vlook(++cp
);
1105 /* Single argument, "implicit boolean" form? */
1106 if ((op
= argv
[1]) == NULL
) {
1107 csp
->c_go
= (v
!= NULL
);
1111 /* Three argument comparison form? */
1112 if (argv
[2] == NULL
|| op
[0] == '\0' ||
1114 (op
[1] != '=' && op
[1] != '~') ||
1121 /* A null value is treated as the empty string */
1128 if (regcomp(&re
, argv
[2], REG_EXTENDED
| REG_ICASE
| REG_NOSUB
))
1130 if (regexec(&re
, v
, 0,NULL
, 0) == REG_NOMATCH
)
1135 if (strcmp(v
, argv
[2]))
1140 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1147 fprintf(stderr
, tr(43, "Unrecognized if-keyword: \"%s\"\n"), cp
);
1161 struct cond_stack
*csp
;
1165 if ((csp
= _cond_stack
) == NULL
|| csp
->c_else
) {
1166 fprintf(stderr
, tr(580, "`elif' without matching `if'\n"));
1169 csp
->c_go
= !csp
->c_go
;
1171 _cond_stack
->c_outer
= csp
->c_outer
;
1185 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1186 fprintf(stderr
, tr(44, "`else' without matching `if'\n"));
1189 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1190 _cond_stack
->c_else
= TRU1
;
1200 struct cond_stack
*csp
;
1205 if ((csp
= _cond_stack
) == NULL
) {
1206 fprintf(stderr
, tr(46, "`endif' without matching `if'\n"));
1209 _cond_stack
= csp
->c_outer
;
1218 condstack_isskip(void)
1223 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1229 condstack_release(void)
1241 condstack_take(void *self
)
1243 struct cond_stack
*csp
;
1247 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1249 _cond_stack
= csp
->c_outer
;
1251 } while ((csp
= _cond_stack
) != NULL
);
1259 c_alternates(void *v
)
1262 char **namelist
= v
, **ap
, **ap2
, *cp
;
1265 l
= argcount(namelist
) + 1;
1267 if (altnames
== NULL
)
1269 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1275 if (altnames
!= NULL
) {
1276 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1280 altnames
= smalloc(l
* sizeof(char*));
1281 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1282 l
= strlen(*ap
) + 1;
1302 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1304 (val
= setfile(mailname
, 1)) == 0) {
1306 setdot(message
+ mdot
- 1);
1320 if (args
[0] == NULL
) {
1327 if (args
[1] == NULL
) {
1328 fprintf(stderr
, tr(220, "expansion name for shortcut missing\n"));
1331 if (args
[2] != NULL
) {
1332 fprintf(stderr
, tr(221, "too many arguments\n"));
1336 if ((s
= get_shortcut(args
[0])) != NULL
) {
1338 s
->sh_long
= sstrdup(args
[1]);
1340 s
= scalloc(1, sizeof *s
);
1341 s
->sh_short
= sstrdup(args
[0]);
1342 s
->sh_long
= sstrdup(args
[1]);
1343 s
->sh_next
= shortcuts
;
1352 FL
struct shortcut
*
1353 get_shortcut(char const *str
)
1358 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
1359 if (!strcmp(str
, s
->sh_short
))
1366 c_unshortcut(void *v
)
1372 if (args
[0] == NULL
) {
1373 fprintf(stderr
, tr(222, "need shortcut names to remove\n"));
1378 while (*args
!= NULL
) {
1379 if (delete_shortcut(*args
) != OKAY
) {
1381 fprintf(stderr
, tr(223, "%s: no such shortcut\n"), *args
);
1394 int *msgvec
= v
, *ip
;
1397 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1398 m
= message
+ *ip
- 1;
1400 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1401 m
->m_flag
|= MFLAG
| MFLAGGED
;
1411 int *msgvec
= v
, *ip
;
1414 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1415 m
= message
+ *ip
- 1;
1417 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1418 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1419 m
->m_flag
|= MUNFLAG
;
1430 int *msgvec
= v
, *ip
;
1433 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1434 m
= message
+ *ip
- 1;
1436 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1437 m
->m_flag
|= MANSWER
| MANSWERED
;
1444 c_unanswered(void *v
)
1447 int *msgvec
= v
, *ip
;
1450 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1451 m
= message
+ *ip
- 1;
1453 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1454 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1455 m
->m_flag
|= MUNANSWER
;
1466 int *msgvec
= v
, *ip
;
1469 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1470 m
= message
+ *ip
- 1;
1472 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1473 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1483 int *msgvec
= v
, *ip
;
1486 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1487 m
= message
+ *ip
- 1;
1489 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1490 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1491 m
->m_flag
|= MUNDRAFT
;
1505 switch (mb
.mb_type
) {
1510 rv
= c_cmdnotsupp(NULL
);
1517 rv
= c_cmdnotsupp(NULL
);
1532 char **args
= v
, *name
;
1536 if (*args
== NULL
) {
1537 fprintf(stderr
, tr(290, "Syntax is: remove mailbox ...\n"));
1542 fmt
= tr(287, "Remove \"%s\" (y/n) ? ");
1543 fmt_len
= strlen(fmt
);
1545 if ((name
= expand(*args
)) == NULL
)
1548 if (!strcmp(name
, mailname
)) {
1549 fprintf(stderr
, tr(286, "Cannot remove current mailbox \"%s\".\n"),
1555 size_t vl
= strlen(name
) + fmt_len
+1;
1556 char *vb
= ac_alloc(vl
);
1558 snprintf(vb
, vl
, fmt
, name
);
1559 asw
= getapproval(vb
, TRU1
);
1565 switch (which_protocol(name
)) {
1567 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1573 fprintf(stderr
, tr(288, "Cannot remove POP3 mailbox \"%s\".\n"),name
);
1578 if (imap_remove(name
) != OKAY
)
1583 if (maildir_remove(name
) != OKAY
)
1587 fprintf(stderr
, tr(289, "Unknown protocol in \"%s\". Not removed.\n"),
1592 } while (*++args
!= NULL
);
1601 char **args
= v
, *old
, *new;
1602 enum protocol oldp
, newp
;
1608 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1609 fprintf(stderr
, "Syntax: rename old new\n");
1613 if ((old
= expand(args
[0])) == NULL
)
1615 oldp
= which_protocol(old
);
1616 if ((new = expand(args
[1])) == NULL
)
1618 newp
= which_protocol(new);
1620 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1621 fprintf(stderr
, tr(291, "Cannot rename current mailbox \"%s\".\n"), old
);
1624 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1625 fprintf(stderr
, tr(292, "Can only rename folders of same type.\n"));
1631 if (newp
== PROTO_POP3
)
1635 if (link(old
, new) == -1) {
1649 } else if (unlink(old
) == -1) {
1655 if (rename(old
, new) == -1) {
1662 fprintf(stderr
, tr(293, "Cannot rename POP3 mailboxes.\n"));
1667 if (imap_rename(old
, new) != OKAY
)
1673 fprintf(stderr
, tr(294,
1674 "Unknown protocol in \"%s\" and \"%s\". Not renamed.\n"), old
, new);
1684 c_urlenc(void *v
) /* XXX IDNA?? */
1689 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1690 char *in
= *ap
, *out
= urlxenc(in
);
1692 printf(" in: <%s> (%" ZFMT
" bytes)\nout: <%s> (%" ZFMT
" bytes)\n",
1693 in
, strlen(in
), out
, strlen(out
));
1700 c_urldec(void *v
) /* XXX IDNA?? */
1705 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1706 char *in
= *ap
, *out
= urlxdec(in
);
1708 printf(" in: <%s> (%" ZFMT
" bytes)\nout: <%s> (%" ZFMT
" bytes)\n",
1709 in
, strlen(in
), out
, strlen(out
));
1715 /* vim:set fenc=utf-8:s-it-mode */