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(const void *a
, const void *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 /* XXX _reedit: we should take into account Aw: etc. (see mime.c!) */
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
+ 5);
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') {
191 oldreflen
= strlen(oldref
);
192 reflen
+= oldreflen
+ 2;
195 oldmsgidlen
= strlen(oldmsgid
);
196 reflen
+= oldmsgidlen
;
199 newref
= ac_alloc(reflen
);
200 if (oldref
!= NULL
) {
201 memcpy(newref
, oldref
, oldreflen
+ 1);
202 if (oldmsgid
!= NULL
) {
203 newref
[oldreflen
++] = ',';
204 newref
[oldreflen
++] = ' ';
205 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+ 1);
208 memcpy(newref
, oldmsgid
, oldmsgidlen
+ 1);
209 n
= extract(newref
, GREF
);
212 /* Limit the references to 21 entries */
213 while (n
->n_flink
!= NULL
)
215 for (i
= 1; i
< 21; ++i
) {
216 if (n
->n_blink
!= NULL
)
223 if (ok_blook(reply_in_same_charset
) &&
224 (cp
= hfield1("content-type", mp
)) != NULL
)
225 head
->h_charset
= mime_getparam("charset", cp
);
231 (*respond_or_Respond(int c
))(int *, int)
234 int (*rv
)(int*, int);
237 opt
+= ok_blook(Replyall
);
238 opt
+= ok_blook(flipr
);
239 rv
= ((opt
== 1) ^ (c
== 'R')) ? &Respond_internal
: &respond_internal
;
245 respond_internal(int *msgvec
, int recipient_record
)
250 struct name
*np
= NULL
;
255 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
257 if (msgvec
[1] != 0) {
258 fprintf(stderr
, tr(37,
259 "Sorry, can't reply to multiple messages at once\n"));
263 mp
= &message
[msgvec
[0] - 1];
267 if ((rcv
= hfield1("reply-to", mp
)) == NULL
)
268 if ((rcv
= hfield1("from", mp
)) == NULL
)
271 np
= lextract(rcv
, GTO
| gf
);
272 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
273 np
= cat(np
, lextract(cp
, GTO
| gf
));
274 /* Delete my name from reply list, and with it, all my alternate names */
275 np
= elide(delete_alternates(np
));
277 np
= lextract(rcv
, GTO
| gf
);
279 memset(&head
, 0, sizeof head
);
281 head
.h_subject
= hfield1("subject", mp
);
282 head
.h_subject
= _reedit(head
.h_subject
);
286 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
287 np
= lextract(cp
, GCC
| gf
);
288 if ((cp
= hfield1("cc", mp
)) != NULL
)
289 np
= cat(np
, lextract(cp
, GCC
| gf
));
291 head
.h_cc
= elide(delete_alternates(np
));
292 make_ref_and_cs(mp
, &head
);
294 if (ok_blook(quote_as_attachment
)) {
295 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
296 head
.h_attach
->a_msgno
= *msgvec
;
297 head
.h_attach
->a_content_description
= tr(512,
298 "Original message content");
301 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
302 ok_blook(markanswered
) && (mp
->m_flag
& MANSWERED
) == 0)
303 mp
->m_flag
|= MANSWER
| MANSWERED
;
311 Respond_internal(int *msgvec
, int recipient_record
)
320 memset(&head
, 0, sizeof head
);
321 gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
323 for (ap
= msgvec
; *ap
!= 0; ++ap
) {
324 mp
= &message
[*ap
- 1];
327 if ((cp
= hfield1("reply-to", mp
)) == NULL
)
328 if ((cp
= hfield1("from", mp
)) == NULL
)
330 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
332 if (head
.h_to
== NULL
)
335 mp
= &message
[msgvec
[0] - 1];
336 head
.h_subject
= hfield1("subject", mp
);
337 head
.h_subject
= _reedit(head
.h_subject
);
338 make_ref_and_cs(mp
, &head
);
340 if (ok_blook(quote_as_attachment
)) {
341 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
342 head
.h_attach
->a_msgno
= *msgvec
;
343 head
.h_attach
->a_content_description
= tr(512,
344 "Original message content");
347 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
348 ok_blook(markanswered
) && (mp
->m_flag
& MANSWERED
) == 0)
349 mp
->m_flag
|= MANSWER
| MANSWERED
;
356 forward1(char *str
, int recipient_record
)
362 bool_t f
, forward_as_attachment
;
365 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
366 puts(tr(47, "No recipient specified."));
370 forward_as_attachment
= ok_blook(forward_as_attachment
);
371 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
374 *msgvec
= first(0, MMNORM
);
380 printf("No messages to forward.\n");
384 } else if (getmsglist(str
, msgvec
, 0) < 0)
392 printf("No applicable messages.\n");
395 if (msgvec
[1] != 0) {
396 printf("Cannot forward multiple messages at once\n");
400 memset(&head
, 0, sizeof head
);
401 if ((head
.h_to
= lextract(recipient
, GTO
|
402 (ok_blook(fullnames
) ? GFULL
: GSKIN
))) == NULL
)
405 mp
= &message
[*msgvec
- 1];
407 if (forward_as_attachment
) {
408 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
409 head
.h_attach
->a_msgno
= *msgvec
;
410 head
.h_attach
->a_content_description
= "Forwarded message";
415 head
.h_subject
= hfield1("subject", mp
);
416 head
.h_subject
= fwdedit(head
.h_subject
);
417 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
), NULL
, recipient_record
,
429 char *newsubj
= NULL
;
432 if (subj
== NULL
|| *subj
== '\0')
437 mime_fromhdr(&in
, &out
, TD_ISPR
| TD_ICONV
);
439 newsubj
= salloc(out
.l
+ 6);
440 memcpy(newsubj
, "Fwd: ", 5);
441 memcpy(newsubj
+ 5, out
.s
, out
.l
+ 1);
454 for (ap
= list
; *ap
!= NULL
; ++ap
)
456 if (PTR2SIZE(ap
- list
) >= 2)
457 qsort(list
, PTR2SIZE(ap
- list
), sizeof *list
, diction
);
462 diction(const void *a
, const void *b
)
467 rv
= strcmp(*(char**)UNCONST(a
), *(char**)UNCONST(b
));
473 resend1(void *v
, int add_resent
)
476 struct name
*to
, *sn
;
482 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
483 name
= laststring(str
, &f
, 1);
485 puts(tr(47, "No recipient specified."));
490 *msgvec
= first(0, MMNORM
);
496 puts(tr(48, "No applicable messages."));
500 } else if (getmsglist(str
, msgvec
, 0) < 0)
508 printf("No applicable messages.\n");
512 sn
= nalloc(name
, GTO
);
513 to
= usermap(sn
, FAL0
);
514 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
516 if (resend_msg(&message
[*ip
- 1], to
, add_resent
) != OKAY
)
530 for (s
= shortcuts
; s
; s
= s
->sh_next
)
531 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
536 delete_shortcut(char const *str
)
538 struct shortcut
*sp
, *sq
;
542 for (sp
= shortcuts
, sq
= NULL
; sp
; sq
= sp
, sp
= sp
->sh_next
) {
543 if (!strcmp(sp
->sh_short
, str
)) {
547 sq
->sh_next
= sp
->sh_next
;
549 shortcuts
= sp
->sh_next
;
562 char const *sh
= NULL
;
565 sighandler_type sigint
;
568 cmd
= smalloc(cmdsize
= strlen(str
) + 1);
569 memcpy(cmd
, str
, cmdsize
);
570 _bangexp(&cmd
, &cmdsize
);
571 if ((sh
= ok_vlook(SHELL
)) == NULL
)
574 sigint
= safe_signal(SIGINT
, SIG_IGN
);
575 run_command(sh
, 0, -1, -1, "-c", cmd
, NULL
);
576 safe_signal(SIGINT
, sigint
);
587 sighandler_type sigint
;
592 if ((sh
= ok_vlook(SHELL
)) == NULL
)
595 sigint
= safe_signal(SIGINT
, SIG_IGN
);
596 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
597 safe_signal(SIGINT
, sigint
);
613 #ifdef HAVE_DOCSTRINGS
614 ret
= !print_comm_docstr(arg
);
616 fprintf(stderr
, tr(91, "Unknown command: `%s'\n"), arg
);
618 ret
= c_cmdnotsupp(NULL
);
623 /* Very ugly, but take care for compiler supported string lengths :( */
624 printf(tr(295, "%s commands:\n"), progname
);
626 "type <message list> type messages\n"
627 "next goto and type next message\n"
628 "from <message list> give head lines of messages\n"
629 "headers print out active message headers\n"
630 "delete <message list> delete messages\n"
631 "undelete <message list> undelete messages\n"));
633 "save <message list> folder append messages to folder and mark as saved\n"
634 "copy <message list> folder append messages to folder without marking them\n"
635 "write <message list> file append message texts to file, save attachments\n"
636 "preserve <message list> keep incoming messages in mailbox even if saved\n"
637 "Reply <message list> reply to message senders\n"
638 "reply <message list> reply to message senders and all recipients\n"));
640 "mail addresses mail to specific recipients\n"
641 "file folder change to another folder\n"
642 "quit quit and apply changes to folder\n"
643 "xit quit and discard changes made to folder\n"
645 "cd <directory> chdir to directory or home if none given\n"
646 "list list names of all available commands\n"));
648 "\nA <message list> consists of integers, ranges of same, or other criteria\n"
649 "separated by spaces. If omitted, %s uses the last message typed.\n"),
660 char buf
[PATH_MAX
]; /* TODO getcwd(3) may return a larger value */
663 if (getcwd(buf
, sizeof buf
) != NULL
) {
681 if (*arglist
== NULL
)
683 else if ((cp
= file_expand(*arglist
)) == NULL
)
700 rv
= (*respond_or_Respond('r'))(v
, 0);
706 c_respondall(void *v
)
711 rv
= respond_internal(v
, 0);
717 c_respondsender(void *v
)
722 rv
= Respond_internal(v
, 0);
733 rv
= (*respond_or_Respond('R'))(v
, 0);
744 rv
= (*respond_or_Respond('r'))(v
, 1);
750 c_followupall(void *v
)
755 rv
= respond_internal(v
, 1);
761 c_followupsender(void *v
)
766 rv
= Respond_internal(v
, 1);
777 rv
= (*respond_or_Respond('R'))(v
, 1);
829 int *msgvec
= v
, *ip
, mesg
, rv
= 1;
834 printf(tr(39, "Cannot \"preserve\" in edit mode\n"));
838 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
840 mp
= &message
[mesg
- 1];
841 mp
->m_flag
|= MPRESERVE
;
844 did_print_dot
= TRU1
;
855 int *msgvec
= v
, *ip
;
858 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
859 setdot(&message
[*ip
- 1]);
860 dot
->m_flag
&= ~(MREAD
| MTOUCH
);
861 dot
->m_flag
|= MSTATUS
;
863 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
864 imap_unread(&message
[*ip
- 1], *ip
); /* TODO return? */
866 did_print_dot
= TRU1
;
875 int *msgvec
= v
, *ip
;
878 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
879 setdot(&message
[*ip
- 1]);
880 touch(&message
[*ip
- 1]);
889 int *msgvec
= v
, *ip
, mesg
;
893 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
895 mp
= &message
[mesg
- 1];
896 printf("%d: ", mesg
);
897 if (mp
->m_xlines
> 0)
898 printf("%ld", mp
->m_xlines
);
901 printf("/%lu\n", (ul_it
)mp
->m_xsize
);
923 char **ap
= v
, *cp
, *cp2
, *varbuf
, c
;
932 for (; *ap
!= NULL
; ++ap
) {
934 cp2
= varbuf
= ac_alloc(strlen(cp
) + 1);
935 for (; (c
= *cp
) != '=' && c
!= '\0'; ++cp
)
943 fprintf(stderr
, tr(41, "Non-null variable name required\n"));
947 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
948 errs
+= _var_vokclear(&varbuf
[2]);
950 errs
+= _var_vokset(varbuf
, (uintptr_t)cp
);
967 for (ap
= v
; *ap
!= NULL
; ++ap
)
968 errs
+= _var_vokclear(*ap
);
976 char **argv
= v
, **ap
, *gname
, **p
;
977 struct grouphead
*gh
;
983 for (h
= 0, s
= 1; h
< HSHSIZE
; ++h
)
984 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
986 ap
= salloc(s
* sizeof *ap
);
987 for (h
= 0, p
= ap
; h
< HSHSIZE
; ++h
)
988 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
992 for (p
= ap
; *p
!= NULL
; ++p
)
997 if (argv
[1] == NULL
) {
1004 if ((gh
= findgroup(gname
)) == NULL
) {
1005 gh
= scalloc(1, sizeof *gh
);
1006 gh
->g_name
= sstrdup(gname
);
1008 gh
->g_link
= groups
[h
];
1012 /* Insert names from the command list into the group. Who cares if there
1013 * are duplicates? They get tossed later anyway */
1014 for (ap
= argv
+ 1; *ap
!= NULL
; ++ap
) {
1015 gp
= scalloc(1, sizeof *gp
);
1016 gp
->ge_name
= sstrdup(*ap
);
1017 gp
->ge_link
= gh
->g_list
;
1032 if (*argv
== NULL
) {
1033 fprintf(stderr
, tr(209, "Must specify alias to remove\n"));
1038 remove_group(*argv
);
1039 while (*++argv
!= NULL
);
1053 if (*argv
== NULL
) {
1060 fprintf(stderr
, tr(516, "Cannot change folder from within a hook.\n"));
1065 save_mbox_for_possible_quitstuff();
1067 i
= setfile(*argv
, 0);
1072 callhook(mailname
, 0);
1073 if (i
> 0 && !ok_blook(emptystart
)) {
1077 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
1087 char const **argv
= v
, **ap
, *cp
;
1091 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1093 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1097 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1099 /* \c ends overall processing */
1113 struct cond_stack
*csp
;
1115 char **argv
= v
, *cp
, *op
;
1118 csp
= smalloc(sizeof *csp
);
1119 csp
->c_outer
= _cond_stack
;
1120 csp
->c_noop
= condstack_isskip();
1126 if (*cp
!= '$' && argv
[1] != NULL
) {
1128 fprintf(stderr
, tr(528, "Invalid conditional expression \"%s %s %s\"\n"),
1129 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
1130 (argv
[2] != NULL
? argv
[2] : ""));
1139 csp
->c_go
= !(options
& OPT_SENDMODE
);
1142 csp
->c_go
= ((options
& OPT_SENDMODE
) != 0);
1145 csp
->c_go
= ((options
& OPT_TTYIN
) != 0);
1148 /* Look up the value in question, we need it anyway */
1149 v
= vok_vlook(++cp
);
1151 /* Single argument, "implicit boolean" form? */
1152 if ((op
= argv
[1]) == NULL
) {
1153 csp
->c_go
= (v
!= NULL
);
1157 /* Three argument comparison form? */
1158 if (argv
[2] == NULL
|| op
[0] == '\0' || op
[1] != '=' || op
[2] != '\0')
1160 /* A null value is treated as the empty string */
1163 if (strcmp(v
, argv
[2]))
1168 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1175 fprintf(stderr
, tr(43, "Unrecognized if-keyword: \"%s\"\n"), cp
);
1193 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1194 fprintf(stderr
, tr(44, "\"else\" without matching \"if\"\n"));
1197 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1198 _cond_stack
->c_else
= TRU1
;
1208 struct cond_stack
*csp
;
1213 if ((csp
= _cond_stack
) == NULL
) {
1214 fprintf(stderr
, tr(46, "\"endif\" without matching \"if\"\n"));
1217 _cond_stack
= csp
->c_outer
;
1226 condstack_isskip(void)
1231 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1237 condstack_release(void)
1249 condstack_take(void *self
)
1251 struct cond_stack
*csp
;
1255 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1257 _cond_stack
= csp
->c_outer
;
1259 } while ((csp
= _cond_stack
) != NULL
);
1267 c_alternates(void *v
)
1270 char **namelist
= v
, **ap
, **ap2
, *cp
;
1273 l
= argcount(namelist
) + 1;
1275 if (altnames
== NULL
)
1277 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1283 if (altnames
!= NULL
) {
1284 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1288 altnames
= smalloc(l
* sizeof(char*));
1289 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1290 l
= strlen(*ap
) + 1;
1310 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1312 (val
= setfile(mailname
, 1)) == 0) {
1314 setdot(&message
[mdot
- 1]);
1328 if (args
[0] == NULL
) {
1335 if (args
[1] == NULL
) {
1336 fprintf(stderr
, tr(220, "expansion name for shortcut missing\n"));
1339 if (args
[2] != NULL
) {
1340 fprintf(stderr
, tr(221, "too many arguments\n"));
1344 if ((s
= get_shortcut(args
[0])) != NULL
) {
1346 s
->sh_long
= sstrdup(args
[1]);
1348 s
= scalloc(1, sizeof *s
);
1349 s
->sh_short
= sstrdup(args
[0]);
1350 s
->sh_long
= sstrdup(args
[1]);
1351 s
->sh_next
= shortcuts
;
1360 FL
struct shortcut
*
1361 get_shortcut(char const *str
)
1366 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
1367 if (!strcmp(str
, s
->sh_short
))
1374 c_unshortcut(void *v
)
1380 if (args
[0] == NULL
) {
1381 fprintf(stderr
, tr(222, "need shortcut names to remove\n"));
1386 while (*args
!= NULL
) {
1387 if (delete_shortcut(*args
) != OKAY
) {
1389 fprintf(stderr
, tr(223, "%s: no such shortcut\n"), *args
);
1402 int *msgvec
= v
, *ip
;
1405 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1406 m
= &message
[*ip
- 1];
1408 if ((m
->m_flag
& (MFLAG
| MFLAGGED
)) == 0)
1409 m
->m_flag
|= MFLAG
| MFLAGGED
;
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
);
1427 m
->m_flag
|= MUNFLAG
;
1438 int *msgvec
= v
, *ip
;
1441 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1442 m
= &message
[*ip
- 1];
1444 if ((m
->m_flag
& (MANSWER
| MANSWERED
)) == 0)
1445 m
->m_flag
|= MANSWER
| MANSWERED
;
1452 c_unanswered(void *v
)
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
);
1463 m
->m_flag
|= MUNANSWER
;
1474 int *msgvec
= v
, *ip
;
1477 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1478 m
= &message
[*ip
- 1];
1480 if ((m
->m_flag
& (MDRAFT
| MDRAFTED
)) == 0)
1481 m
->m_flag
|= MDRAFT
| MDRAFTED
;
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
);
1499 m
->m_flag
|= MUNDRAFT
;
1513 switch (mb
.mb_type
) {
1518 rv
= c_cmdnotsupp(NULL
);
1525 rv
= c_cmdnotsupp(NULL
);
1540 char **args
= v
, *name
;
1544 if (*args
== NULL
) {
1545 fprintf(stderr
, tr(290, "Syntax is: remove mailbox ...\n"));
1550 fmt
= tr(287, "Remove \"%s\" (y/n) ? ");
1551 fmt_len
= strlen(fmt
);
1553 if ((name
= expand(*args
)) == NULL
)
1556 if (!strcmp(name
, mailname
)) {
1557 fprintf(stderr
, tr(286, "Cannot remove current mailbox \"%s\".\n"),
1563 size_t vl
= strlen(name
) + fmt_len
+1;
1564 char *vb
= ac_alloc(vl
);
1566 snprintf(vb
, vl
, fmt
, name
);
1567 asw
= getapproval(vb
, TRU1
);
1573 switch (which_protocol(name
)) {
1575 if (unlink(name
) < 0) { /* TODO do not handle .gz .bz2 */
1581 fprintf(stderr
, tr(288, "Cannot remove POP3 mailbox \"%s\".\n"),name
);
1586 if (imap_remove(name
) != OKAY
)
1591 if (maildir_remove(name
) != OKAY
)
1595 fprintf(stderr
, tr(289, "Unknown protocol in \"%s\". Not removed.\n"),
1600 } while (*++args
!= NULL
);
1609 char **args
= v
, *old
, *new;
1610 enum protocol oldp
, newp
;
1616 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1617 fprintf(stderr
, "Syntax: rename old new\n");
1621 if ((old
= expand(args
[0])) == NULL
)
1623 oldp
= which_protocol(old
);
1624 if ((new = expand(args
[1])) == NULL
)
1626 newp
= which_protocol(new);
1628 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1629 fprintf(stderr
, tr(291, "Cannot rename current mailbox \"%s\".\n"), old
);
1632 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1633 fprintf(stderr
, tr(292, "Can only rename folders of same type.\n"));
1639 if (newp
== PROTO_POP3
)
1643 if (link(old
, new) == -1) {
1657 } else if (unlink(old
) == -1) {
1663 if (rename(old
, new) == -1) {
1670 fprintf(stderr
, tr(293, "Cannot rename POP3 mailboxes.\n"));
1675 if (imap_rename(old
, new) != OKAY
)
1681 fprintf(stderr
, tr(294,
1682 "Unknown protocol in \"%s\" and \"%s\". Not renamed.\n"), old
, new);
1691 /* vim:set fenc=utf-8:s-it-mode */