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
, int 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
, int 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
);
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
;
567 sighandler_type sigint
;
570 cmd
= smalloc(cmdsize
= strlen(str
) +1);
571 memcpy(cmd
, str
, cmdsize
);
572 _bangexp(&cmd
, &cmdsize
);
573 if ((sh
= ok_vlook(SHELL
)) == NULL
)
576 sigint
= safe_signal(SIGINT
, SIG_IGN
);
577 run_command(sh
, 0, -1, -1, "-c", cmd
, NULL
);
578 safe_signal(SIGINT
, sigint
);
589 sighandler_type sigint
;
594 if ((sh
= ok_vlook(SHELL
)) == NULL
)
597 sigint
= safe_signal(SIGINT
, SIG_IGN
);
598 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
599 safe_signal(SIGINT
, sigint
);
615 #ifdef HAVE_DOCSTRINGS
616 ret
= !print_comm_docstr(arg
);
618 fprintf(stderr
, tr(91, "Unknown command: `%s'\n"), arg
);
620 ret
= c_cmdnotsupp(NULL
);
625 /* Very ugly, but take care for compiler supported string lengths :( */
626 printf(tr(295, "%s commands:\n"), progname
);
628 "type <message list> type messages\n"
629 "next goto and type next message\n"
630 "from <message list> give head lines of messages\n"
631 "headers print out active message headers\n"
632 "delete <message list> delete messages\n"
633 "undelete <message list> undelete messages\n"));
635 "save <message list> folder append messages to folder and mark as saved\n"
636 "copy <message list> folder append messages to folder without marking them\n"
637 "write <message list> file append message texts to file, save attachments\n"
638 "preserve <message list> keep incoming messages in mailbox even if saved\n"
639 "Reply <message list> reply to message senders\n"
640 "reply <message list> reply to message senders and all recipients\n"));
642 "mail addresses mail to specific recipients\n"
643 "file folder change to another folder\n"
644 "quit quit and apply changes to folder\n"
645 "xit quit and discard changes made to folder\n"
647 "cd <directory> chdir to directory or home if none given\n"
648 "list list names of all available commands\n"));
650 "\nA <message list> consists of integers, ranges of same, or other criteria\n"
651 "separated by spaces. If omitted, %s uses the last message typed.\n"),
662 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
665 if (getcwd(buf
, sizeof buf
) != NULL
) {
683 if (*arglist
== NULL
)
685 else if ((cp
= file_expand(*arglist
)) == NULL
)
687 if (chdir(cp
) == -1) {
702 rv
= (*respond_or_Respond('r'))(v
, 0);
708 c_respondall(void *v
)
713 rv
= respond_internal(v
, 0);
719 c_respondsender(void *v
)
724 rv
= Respond_internal(v
, 0);
735 rv
= (*respond_or_Respond('R'))(v
, 0);
746 rv
= (*respond_or_Respond('r'))(v
, 1);
752 c_followupall(void *v
)
757 rv
= respond_internal(v
, 1);
763 c_followupsender(void *v
)
768 rv
= Respond_internal(v
, 1);
779 rv
= (*respond_or_Respond('R'))(v
, 1);
831 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
836 printf(tr(39, "Cannot \"preserve\" in edit mode\n"));
840 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
842 mp
= message
+ mesg
- 1;
843 mp
->m_flag
|= MPRESERVE
;
846 did_print_dot
= TRU1
;
857 int *msgvec
= v
, *ip
;
860 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
861 setdot(message
+ *ip
- 1);
862 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
863 dot
->m_flag
|= MSTATUS
;
865 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
866 imap_unread(message
+ *ip
- 1, *ip
); /* TODO return? */
868 did_print_dot
= TRU1
;
877 int *msgvec
= v
, *ip
;
880 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
881 struct message
*mp
= message
+ *ip
- 1;
892 int *msgvec
= v
, *ip
, mesg
;
896 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
898 mp
= message
+ mesg
- 1;
899 printf("%d: ", mesg
);
900 if (mp
->m_xlines
> 0)
901 printf("%ld", mp
->m_xlines
);
904 printf("/%lu\n", (ul_it
)mp
->m_xsize
);
925 char **ap
= v
, *cp
, *cp2
, *varbuf
, c
;
934 for (; *ap
!= NULL
; ++ap
) {
936 cp2
= varbuf
= ac_alloc(strlen(cp
) +1);
937 for (; (c
= *cp
) != '=' && c
!= '\0'; ++cp
)
945 fprintf(stderr
, tr(41, "Non-null variable name required\n"));
949 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
950 errs
+= _var_vokclear(&varbuf
[2]);
952 errs
+= _var_vokset(varbuf
, (uintptr_t)cp
);
969 for (ap
= v
; *ap
!= NULL
; ++ap
)
970 errs
+= _var_vokclear(*ap
);
978 char **argv
= v
, **ap
, *gname
, **p
;
979 struct grouphead
*gh
;
985 for (h
= 0, s
= 1; h
< HSHSIZE
; ++h
)
986 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
988 ap
= salloc(s
* sizeof *ap
);
990 for (h
= 0, p
= ap
; h
< HSHSIZE
; ++h
)
991 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
997 for (p
= ap
; *p
!= NULL
; ++p
)
1002 if (argv
[1] == NULL
) {
1009 if ((gh
= findgroup(gname
)) == NULL
) {
1010 gh
= scalloc(1, sizeof *gh
);
1011 gh
->g_name
= sstrdup(gname
);
1013 gh
->g_link
= groups
[h
];
1017 /* Insert names from the command list into the group. Who cares if there
1018 * are duplicates? They get tossed later anyway */
1019 for (ap
= argv
+ 1; *ap
!= NULL
; ++ap
) {
1020 gp
= scalloc(1, sizeof *gp
);
1021 gp
->ge_name
= sstrdup(*ap
);
1022 gp
->ge_link
= gh
->g_list
;
1037 if (*argv
== NULL
) {
1038 fprintf(stderr
, tr(209, "Must specify alias to remove\n"));
1043 remove_group(*argv
);
1044 while (*++argv
!= NULL
);
1058 if (*argv
== NULL
) {
1065 fprintf(stderr
, tr(516, "Cannot change folder from within a hook.\n"));
1070 save_mbox_for_possible_quitstuff();
1072 i
= setfile(*argv
, 0);
1077 callhook(mailname
, 0);
1078 if (i
> 0 && !ok_blook(emptystart
)) {
1082 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
1092 char const **argv
= v
, **ap
, *cp
;
1096 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1098 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1102 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1104 /* \c ends overall processing */
1118 struct cond_stack
*csp
;
1120 char **argv
= v
, *cp
, *op
;
1123 csp
= smalloc(sizeof *csp
);
1124 csp
->c_outer
= _cond_stack
;
1125 csp
->c_noop
= condstack_isskip();
1131 if (*cp
!= '$' && argv
[1] != NULL
) {
1133 fprintf(stderr
, tr(528, "Invalid conditional expression \"%s %s %s\"\n"),
1134 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
1135 (argv
[2] != NULL
? argv
[2] : ""));
1144 csp
->c_go
= !(options
& OPT_SENDMODE
);
1147 csp
->c_go
= ((options
& OPT_SENDMODE
) != 0);
1150 csp
->c_go
= ((options
& OPT_TTYIN
) != 0);
1153 /* Look up the value in question, we need it anyway */
1154 v
= vok_vlook(++cp
);
1156 /* Single argument, "implicit boolean" form? */
1157 if ((op
= argv
[1]) == NULL
) {
1158 csp
->c_go
= (v
!= NULL
);
1162 /* Three argument comparison form? */
1163 if (argv
[2] == NULL
|| op
[0] == '\0' || op
[1] != '=' || op
[2] != '\0')
1165 /* A null value is treated as the empty string */
1168 if (strcmp(v
, argv
[2]))
1173 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1180 fprintf(stderr
, tr(43, "Unrecognized if-keyword: \"%s\"\n"), cp
);
1198 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1199 fprintf(stderr
, tr(44, "\"else\" without matching \"if\"\n"));
1202 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1203 _cond_stack
->c_else
= TRU1
;
1213 struct cond_stack
*csp
;
1218 if ((csp
= _cond_stack
) == NULL
) {
1219 fprintf(stderr
, tr(46, "\"endif\" without matching \"if\"\n"));
1222 _cond_stack
= csp
->c_outer
;
1231 condstack_isskip(void)
1236 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1242 condstack_release(void)
1254 condstack_take(void *self
)
1256 struct cond_stack
*csp
;
1260 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1262 _cond_stack
= csp
->c_outer
;
1264 } while ((csp
= _cond_stack
) != NULL
);
1272 c_alternates(void *v
)
1275 char **namelist
= v
, **ap
, **ap2
, *cp
;
1278 l
= argcount(namelist
) + 1;
1280 if (altnames
== NULL
)
1282 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1288 if (altnames
!= NULL
) {
1289 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1293 altnames
= smalloc(l
* sizeof(char*));
1294 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1295 l
= strlen(*ap
) + 1;
1315 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1317 (val
= setfile(mailname
, 1)) == 0) {
1319 setdot(message
+ mdot
- 1);
1333 if (args
[0] == NULL
) {
1340 if (args
[1] == NULL
) {
1341 fprintf(stderr
, tr(220, "expansion name for shortcut missing\n"));
1344 if (args
[2] != NULL
) {
1345 fprintf(stderr
, tr(221, "too many arguments\n"));
1349 if ((s
= get_shortcut(args
[0])) != NULL
) {
1351 s
->sh_long
= sstrdup(args
[1]);
1353 s
= scalloc(1, sizeof *s
);
1354 s
->sh_short
= sstrdup(args
[0]);
1355 s
->sh_long
= sstrdup(args
[1]);
1356 s
->sh_next
= shortcuts
;
1365 FL
struct shortcut
*
1366 get_shortcut(char const *str
)
1371 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
1372 if (!strcmp(str
, s
->sh_short
))
1379 c_unshortcut(void *v
)
1385 if (args
[0] == NULL
) {
1386 fprintf(stderr
, tr(222, "need shortcut names to remove\n"));
1391 while (*args
!= NULL
) {
1392 if (delete_shortcut(*args
) != OKAY
) {
1394 fprintf(stderr
, tr(223, "%s: no such shortcut\n"), *args
);
1407 int *msgvec
= v
, *ip
;
1410 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1411 m
= message
+ *ip
- 1;
1413 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1414 m
->m_flag
|= MFLAG
| MFLAGGED
;
1424 int *msgvec
= v
, *ip
;
1427 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1428 m
= message
+ *ip
- 1;
1430 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1431 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1432 m
->m_flag
|= MUNFLAG
;
1443 int *msgvec
= v
, *ip
;
1446 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1447 m
= message
+ *ip
- 1;
1449 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1450 m
->m_flag
|= MANSWER
| MANSWERED
;
1457 c_unanswered(void *v
)
1460 int *msgvec
= v
, *ip
;
1463 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1464 m
= message
+ *ip
- 1;
1466 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1467 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1468 m
->m_flag
|= MUNANSWER
;
1479 int *msgvec
= v
, *ip
;
1482 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1483 m
= message
+ *ip
- 1;
1485 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1486 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1496 int *msgvec
= v
, *ip
;
1499 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1500 m
= message
+ *ip
- 1;
1502 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1503 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1504 m
->m_flag
|= MUNDRAFT
;
1518 switch (mb
.mb_type
) {
1523 rv
= c_cmdnotsupp(NULL
);
1530 rv
= c_cmdnotsupp(NULL
);
1545 char **args
= v
, *name
;
1549 if (*args
== NULL
) {
1550 fprintf(stderr
, tr(290, "Syntax is: remove mailbox ...\n"));
1555 fmt
= tr(287, "Remove \"%s\" (y/n) ? ");
1556 fmt_len
= strlen(fmt
);
1558 if ((name
= expand(*args
)) == NULL
)
1561 if (!strcmp(name
, mailname
)) {
1562 fprintf(stderr
, tr(286, "Cannot remove current mailbox \"%s\".\n"),
1568 size_t vl
= strlen(name
) + fmt_len
+1;
1569 char *vb
= ac_alloc(vl
);
1571 snprintf(vb
, vl
, fmt
, name
);
1572 asw
= getapproval(vb
, TRU1
);
1578 switch (which_protocol(name
)) {
1580 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1586 fprintf(stderr
, tr(288, "Cannot remove POP3 mailbox \"%s\".\n"),name
);
1591 if (imap_remove(name
) != OKAY
)
1596 if (maildir_remove(name
) != OKAY
)
1600 fprintf(stderr
, tr(289, "Unknown protocol in \"%s\". Not removed.\n"),
1605 } while (*++args
!= NULL
);
1614 char **args
= v
, *old
, *new;
1615 enum protocol oldp
, newp
;
1621 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1622 fprintf(stderr
, "Syntax: rename old new\n");
1626 if ((old
= expand(args
[0])) == NULL
)
1628 oldp
= which_protocol(old
);
1629 if ((new = expand(args
[1])) == NULL
)
1631 newp
= which_protocol(new);
1633 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1634 fprintf(stderr
, tr(291, "Cannot rename current mailbox \"%s\".\n"), old
);
1637 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1638 fprintf(stderr
, tr(292, "Can only rename folders of same type.\n"));
1644 if (newp
== PROTO_POP3
)
1648 if (link(old
, new) == -1) {
1662 } else if (unlink(old
) == -1) {
1668 if (rename(old
, new) == -1) {
1675 fprintf(stderr
, tr(293, "Cannot rename POP3 mailboxes.\n"));
1680 if (imap_rename(old
, new) != OKAY
)
1686 fprintf(stderr
, tr(294,
1687 "Unknown protocol in \"%s\" and \"%s\". Not renamed.\n"), old
, new);
1696 /* vim:set fenc=utf-8:s-it-mode */