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' || op
[1] != '=' || op
[2] != '\0')
1114 /* A null value is treated as the empty string */
1117 if (strcmp(v
, argv
[2]))
1122 csp
->c_go
= ((op
[0] == '=') ^ (v
== NULL
));
1129 fprintf(stderr
, tr(43, "Unrecognized if-keyword: \"%s\"\n"), cp
);
1147 if (_cond_stack
== NULL
|| _cond_stack
->c_else
) {
1148 fprintf(stderr
, tr(44, "\"else\" without matching \"if\"\n"));
1151 _cond_stack
->c_go
= !_cond_stack
->c_go
;
1152 _cond_stack
->c_else
= TRU1
;
1162 struct cond_stack
*csp
;
1167 if ((csp
= _cond_stack
) == NULL
) {
1168 fprintf(stderr
, tr(46, "\"endif\" without matching \"if\"\n"));
1171 _cond_stack
= csp
->c_outer
;
1180 condstack_isskip(void)
1185 rv
= (_cond_stack
!= NULL
&& (_cond_stack
->c_noop
|| !_cond_stack
->c_go
));
1191 condstack_release(void)
1203 condstack_take(void *self
)
1205 struct cond_stack
*csp
;
1209 if (!(rv
= ((csp
= _cond_stack
) == NULL
)))
1211 _cond_stack
= csp
->c_outer
;
1213 } while ((csp
= _cond_stack
) != NULL
);
1221 c_alternates(void *v
)
1224 char **namelist
= v
, **ap
, **ap2
, *cp
;
1227 l
= argcount(namelist
) + 1;
1229 if (altnames
== NULL
)
1231 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1237 if (altnames
!= NULL
) {
1238 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1242 altnames
= smalloc(l
* sizeof(char*));
1243 for (ap
= namelist
, ap2
= altnames
; *ap
!= NULL
; ++ap
, ++ap2
) {
1244 l
= strlen(*ap
) + 1;
1264 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1266 (val
= setfile(mailname
, 1)) == 0) {
1268 setdot(message
+ mdot
- 1);
1282 if (args
[0] == NULL
) {
1289 if (args
[1] == NULL
) {
1290 fprintf(stderr
, tr(220, "expansion name for shortcut missing\n"));
1293 if (args
[2] != NULL
) {
1294 fprintf(stderr
, tr(221, "too many arguments\n"));
1298 if ((s
= get_shortcut(args
[0])) != NULL
) {
1300 s
->sh_long
= sstrdup(args
[1]);
1302 s
= scalloc(1, sizeof *s
);
1303 s
->sh_short
= sstrdup(args
[0]);
1304 s
->sh_long
= sstrdup(args
[1]);
1305 s
->sh_next
= shortcuts
;
1314 FL
struct shortcut
*
1315 get_shortcut(char const *str
)
1320 for (s
= shortcuts
; s
!= NULL
; s
= s
->sh_next
)
1321 if (!strcmp(str
, s
->sh_short
))
1328 c_unshortcut(void *v
)
1334 if (args
[0] == NULL
) {
1335 fprintf(stderr
, tr(222, "need shortcut names to remove\n"));
1340 while (*args
!= NULL
) {
1341 if (delete_shortcut(*args
) != OKAY
) {
1343 fprintf(stderr
, tr(223, "%s: no such shortcut\n"), *args
);
1356 int *msgvec
= v
, *ip
;
1359 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1360 m
= message
+ *ip
- 1;
1362 if (!(m
->m_flag
& (MFLAG
| MFLAGGED
)))
1363 m
->m_flag
|= MFLAG
| MFLAGGED
;
1373 int *msgvec
= v
, *ip
;
1376 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1377 m
= message
+ *ip
- 1;
1379 if (m
->m_flag
& (MFLAG
| MFLAGGED
)) {
1380 m
->m_flag
&= ~(MFLAG
| MFLAGGED
);
1381 m
->m_flag
|= MUNFLAG
;
1392 int *msgvec
= v
, *ip
;
1395 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1396 m
= message
+ *ip
- 1;
1398 if (!(m
->m_flag
& (MANSWER
| MANSWERED
)))
1399 m
->m_flag
|= MANSWER
| MANSWERED
;
1406 c_unanswered(void *v
)
1409 int *msgvec
= v
, *ip
;
1412 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1413 m
= message
+ *ip
- 1;
1415 if (m
->m_flag
& (MANSWER
| MANSWERED
)) {
1416 m
->m_flag
&= ~(MANSWER
| MANSWERED
);
1417 m
->m_flag
|= MUNANSWER
;
1428 int *msgvec
= v
, *ip
;
1431 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1432 m
= message
+ *ip
- 1;
1434 if (!(m
->m_flag
& (MDRAFT
| MDRAFTED
)))
1435 m
->m_flag
|= MDRAFT
| MDRAFTED
;
1445 int *msgvec
= v
, *ip
;
1448 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1449 m
= message
+ *ip
- 1;
1451 if (m
->m_flag
& (MDRAFT
| MDRAFTED
)) {
1452 m
->m_flag
&= ~(MDRAFT
| MDRAFTED
);
1453 m
->m_flag
|= MUNDRAFT
;
1467 switch (mb
.mb_type
) {
1472 rv
= c_cmdnotsupp(NULL
);
1479 rv
= c_cmdnotsupp(NULL
);
1494 char **args
= v
, *name
;
1498 if (*args
== NULL
) {
1499 fprintf(stderr
, tr(290, "Syntax is: remove mailbox ...\n"));
1504 fmt
= tr(287, "Remove \"%s\" (y/n) ? ");
1505 fmt_len
= strlen(fmt
);
1507 if ((name
= expand(*args
)) == NULL
)
1510 if (!strcmp(name
, mailname
)) {
1511 fprintf(stderr
, tr(286, "Cannot remove current mailbox \"%s\".\n"),
1517 size_t vl
= strlen(name
) + fmt_len
+1;
1518 char *vb
= ac_alloc(vl
);
1520 snprintf(vb
, vl
, fmt
, name
);
1521 asw
= getapproval(vb
, TRU1
);
1527 switch (which_protocol(name
)) {
1529 if (unlink(name
) == -1) { /* TODO do not handle .gz .bz2 .xz.. */
1535 fprintf(stderr
, tr(288, "Cannot remove POP3 mailbox \"%s\".\n"),name
);
1540 if (imap_remove(name
) != OKAY
)
1545 if (maildir_remove(name
) != OKAY
)
1549 fprintf(stderr
, tr(289, "Unknown protocol in \"%s\". Not removed.\n"),
1554 } while (*++args
!= NULL
);
1563 char **args
= v
, *old
, *new;
1564 enum protocol oldp
, newp
;
1570 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1571 fprintf(stderr
, "Syntax: rename old new\n");
1575 if ((old
= expand(args
[0])) == NULL
)
1577 oldp
= which_protocol(old
);
1578 if ((new = expand(args
[1])) == NULL
)
1580 newp
= which_protocol(new);
1582 if (!strcmp(old
, mailname
) || !strcmp(new, mailname
)) {
1583 fprintf(stderr
, tr(291, "Cannot rename current mailbox \"%s\".\n"), old
);
1586 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1587 fprintf(stderr
, tr(292, "Can only rename folders of same type.\n"));
1593 if (newp
== PROTO_POP3
)
1597 if (link(old
, new) == -1) {
1611 } else if (unlink(old
) == -1) {
1617 if (rename(old
, new) == -1) {
1624 fprintf(stderr
, tr(293, "Cannot rename POP3 mailboxes.\n"));
1629 if (imap_rename(old
, new) != OKAY
)
1635 fprintf(stderr
, tr(294,
1636 "Unknown protocol in \"%s\" and \"%s\". Not renamed.\n"), old
, new);
1646 c_urlenc(void *v
) /* XXX IDNA?? */
1651 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1652 char *in
= *ap
, *out
= urlxenc(in
);
1654 printf(" in: <%s> (%" ZFMT
" bytes)\nout: <%s> (%" ZFMT
" bytes)\n",
1655 in
, strlen(in
), out
, strlen(out
));
1662 c_urldec(void *v
) /* XXX IDNA?? */
1667 for (ap
= v
; *ap
!= NULL
; ++ap
) {
1668 char *in
= *ap
, *out
= urlxdec(in
);
1670 printf(" in: <%s> (%" ZFMT
" bytes)\nout: <%s> (%" ZFMT
" bytes)\n",
1671 in
, strlen(in
), out
, strlen(out
));
1677 /* vim:set fenc=utf-8:s-it-mode */