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 **ap
= v
, *cp
, *cp2
, *varbuf
, c
;
936 for (; *ap
!= NULL
; ++ap
) {
938 cp2
= varbuf
= ac_alloc(strlen(cp
) +1);
939 for (; (c
= *cp
) != '=' && c
!= '\0'; ++cp
)
947 fprintf(stderr
, tr(41, "Non-null variable name required\n"));
951 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
952 errs
+= _var_vokclear(&varbuf
[2]);
954 errs
+= _var_vokset(varbuf
, (uintptr_t)cp
);
971 for (ap
= v
; *ap
!= NULL
; ++ap
)
972 errs
+= _var_vokclear(*ap
);
980 char **argv
= v
, **ap
, *gname
, **p
;
981 struct grouphead
*gh
;
987 for (h
= 0, s
= 1; h
< HSHSIZE
; ++h
)
988 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
990 ap
= salloc(s
* sizeof *ap
);
992 for (h
= 0, p
= ap
; h
< HSHSIZE
; ++h
)
993 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
999 for (p
= ap
; *p
!= NULL
; ++p
)
1004 if (argv
[1] == NULL
) {
1011 if ((gh
= findgroup(gname
)) == NULL
) {
1012 gh
= scalloc(1, sizeof *gh
);
1013 gh
->g_name
= sstrdup(gname
);
1015 gh
->g_link
= groups
[h
];
1019 /* Insert names from the command list into the group. Who cares if there
1020 * are duplicates? They get tossed later anyway */
1021 for (ap
= argv
+ 1; *ap
!= NULL
; ++ap
) {
1022 gp
= scalloc(1, sizeof *gp
);
1023 gp
->ge_name
= sstrdup(*ap
);
1024 gp
->ge_link
= gh
->g_list
;
1039 if (*argv
== NULL
) {
1040 fprintf(stderr
, tr(209, "Must specify alias to remove\n"));
1045 remove_group(*argv
);
1046 while (*++argv
!= NULL
);
1060 if (*argv
== NULL
) {
1067 fprintf(stderr
, tr(516, "Cannot change folder from within a hook.\n"));
1072 save_mbox_for_possible_quitstuff();
1074 i
= setfile(*argv
, 0);
1079 callhook(mailname
, 0);
1080 if (i
> 0 && !ok_blook(emptystart
)) {
1084 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
1094 char const **argv
= v
, **ap
, *cp
;
1098 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
1100 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
1104 while (*cp
!= '\0' && (c
= expand_shell_escape(&cp
, FAL0
)) > 0)
1106 /* \c ends overall processing */
1120 struct cond_stack
*csp
;
1122 char **argv
= v
, *cp
, *op
;
1125 csp
= smalloc(sizeof *csp
);
1126 csp
->c_outer
= _cond_stack
;
1127 csp
->c_noop
= condstack_isskip();
1133 if (*cp
!= '$' && argv
[1] != NULL
) {
1135 fprintf(stderr
, tr(528, "Invalid conditional expression \"%s %s %s\"\n"),
1136 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
1137 (argv
[2] != NULL
? argv
[2] : ""));
1146 csp
->c_go
= !(options
& OPT_SENDMODE
);
1149 csp
->c_go
= ((options
& OPT_SENDMODE
) != 0);
1152 csp
->c_go
= ((options
& OPT_TTYIN
) != 0);
1155 /* Look up the value in question, we need it anyway */
1156 v
= vok_vlook(++cp
);
1158 /* Single argument, "implicit boolean" form? */
1159 if ((op
= argv
[1]) == NULL
) {
1160 csp
->c_go
= (v
!= NULL
);
1164 /* Three argument comparison form? */
1165 if (argv
[2] == NULL
|| op
[0] == '\0' || op
[1] != '=' || op
[2] != '\0')
1167 /* A null value is treated as the empty string */
1170 if (strcmp(v
, argv
[2]))
1175 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1182 fprintf(stderr
, tr(43, "Unrecognized if-keyword: \"%s\"\n"), cp
);
1200 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1201 fprintf(stderr
, tr(44, "\"else\" without matching \"if\"\n"));
1204 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1205 _cond_stack
->c_else
= TRU1
;
1215 struct cond_stack
*csp
;
1220 if ((csp
= _cond_stack
) == NULL
) {
1221 fprintf(stderr
, tr(46, "\"endif\" without matching \"if\"\n"));
1224 _cond_stack
= csp
->c_outer
;
1233 condstack_isskip(void)
1238 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1244 condstack_release(void)
1256 condstack_take(void *self
)
1258 struct cond_stack
*csp
;
1262 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1264 _cond_stack
= csp
->c_outer
;
1266 } while ((csp
= _cond_stack
) != NULL
);
1274 c_alternates(void *v
)
1277 char **namelist
= v
, **ap
, **ap2
, *cp
;
1280 l
= argcount(namelist
) + 1;
1282 if (altnames
== NULL
)
1284 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1290 if (altnames
!= NULL
) {
1291 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1295 altnames
= smalloc(l
* sizeof(char*));
1296 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1297 l
= strlen(*ap
) + 1;
1317 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1319 (val
= setfile(mailname
, 1)) == 0) {
1321 setdot(message
+ mdot
- 1);
1335 if (args
[0] == NULL
) {
1342 if (args
[1] == NULL
) {
1343 fprintf(stderr
, tr(220, "expansion name for shortcut missing\n"));
1346 if (args
[2] != NULL
) {
1347 fprintf(stderr
, tr(221, "too many arguments\n"));
1351 if ((s
= get_shortcut(args
[0])) != NULL
) {
1353 s
->sh_long
= sstrdup(args
[1]);
1355 s
= scalloc(1, sizeof *s
);
1356 s
->sh_short
= sstrdup(args
[0]);
1357 s
->sh_long
= sstrdup(args
[1]);
1358 s
->sh_next
= shortcuts
;
1367 FL
struct shortcut
*
1368 get_shortcut(char const *str
)
1373 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
1374 if (!strcmp(str
, s
->sh_short
))
1381 c_unshortcut(void *v
)
1387 if (args
[0] == NULL
) {
1388 fprintf(stderr
, tr(222, "need shortcut names to remove\n"));
1393 while (*args
!= NULL
) {
1394 if (delete_shortcut(*args
) != OKAY
) {
1396 fprintf(stderr
, tr(223, "%s: no such shortcut\n"), *args
);
1409 int *msgvec
= v
, *ip
;
1412 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1413 m
= message
+ *ip
- 1;
1415 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1416 m
->m_flag
|= MFLAG
| MFLAGGED
;
1426 int *msgvec
= v
, *ip
;
1429 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1430 m
= message
+ *ip
- 1;
1432 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1433 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1434 m
->m_flag
|= MUNFLAG
;
1445 int *msgvec
= v
, *ip
;
1448 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1449 m
= message
+ *ip
- 1;
1451 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1452 m
->m_flag
|= MANSWER
| MANSWERED
;
1459 c_unanswered(void *v
)
1462 int *msgvec
= v
, *ip
;
1465 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1466 m
= message
+ *ip
- 1;
1468 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1469 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1470 m
->m_flag
|= MUNANSWER
;
1481 int *msgvec
= v
, *ip
;
1484 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1485 m
= message
+ *ip
- 1;
1487 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1488 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1498 int *msgvec
= v
, *ip
;
1501 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1502 m
= message
+ *ip
- 1;
1504 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1505 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1506 m
->m_flag
|= MUNDRAFT
;
1520 switch (mb
.mb_type
) {
1525 rv
= c_cmdnotsupp(NULL
);
1532 rv
= c_cmdnotsupp(NULL
);
1547 char **args
= v
, *name
;
1551 if (*args
== NULL
) {
1552 fprintf(stderr
, tr(290, "Syntax is: remove mailbox ...\n"));
1557 fmt
= tr(287, "Remove \"%s\" (y/n) ? ");
1558 fmt_len
= strlen(fmt
);
1560 if ((name
= expand(*args
)) == NULL
)
1563 if (!strcmp(name
, mailname
)) {
1564 fprintf(stderr
, tr(286, "Cannot remove current mailbox \"%s\".\n"),
1570 size_t vl
= strlen(name
) + fmt_len
+1;
1571 char *vb
= ac_alloc(vl
);
1573 snprintf(vb
, vl
, fmt
, name
);
1574 asw
= getapproval(vb
, TRU1
);
1580 switch (which_protocol(name
)) {
1582 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1588 fprintf(stderr
, tr(288, "Cannot remove POP3 mailbox \"%s\".\n"),name
);
1593 if (imap_remove(name
) != OKAY
)
1598 if (maildir_remove(name
) != OKAY
)
1602 fprintf(stderr
, tr(289, "Unknown protocol in \"%s\". Not removed.\n"),
1607 } while (*++args
!= NULL
);
1616 char **args
= v
, *old
, *new;
1617 enum protocol oldp
, newp
;
1623 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1624 fprintf(stderr
, "Syntax: rename old new\n");
1628 if ((old
= expand(args
[0])) == NULL
)
1630 oldp
= which_protocol(old
);
1631 if ((new = expand(args
[1])) == NULL
)
1633 newp
= which_protocol(new);
1635 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1636 fprintf(stderr
, tr(291, "Cannot rename current mailbox \"%s\".\n"), old
);
1639 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1640 fprintf(stderr
, tr(292, "Can only rename folders of same type.\n"));
1646 if (newp
== PROTO_POP3
)
1650 if (link(old
, new) == -1) {
1664 } else if (unlink(old
) == -1) {
1670 if (rename(old
, new) == -1) {
1677 fprintf(stderr
, tr(293, "Cannot rename POP3 mailboxes.\n"));
1682 if (imap_rename(old
, new) != OKAY
)
1688 fprintf(stderr
, tr(294,
1689 "Unknown protocol in \"%s\" and \"%s\". Not renamed.\n"), old
, new);
1698 /* vim:set fenc=utf-8:s-it-mode */