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 - 2013 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
44 /* Modify subject we reply to to begin with Re: if it does not already */
45 static char * _reedit(char *subj
);
47 static int bangexp(char **str
, size_t *size
);
48 static void make_ref_and_cs(struct message
*mp
, struct header
*head
);
49 static int (* respond_or_Respond(int c
))(int *, int);
50 static int respond_internal(int *msgvec
, int recipient_record
);
51 static char * fwdedit(char *subj
);
52 static void asort(char **list
);
53 static int diction(const void *a
, const void *b
);
54 static int Respond_internal(int *msgvec
, int recipient_record
);
55 static int resend1(void *v
, int add_resent
);
56 static void list_shortcuts(void);
57 static enum okay
delete_shortcut(const char *str
);
65 if (subj
== NULL
|| *subj
== '\0')
70 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
72 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
73 (out
.s
[1] == 'e' || out
.s
[1] == 'E') &&
75 newsubj
= savestr(out
.s
);
78 newsubj
= salloc(out
.l
+ 5);
79 sstpcpy(sstpcpy(newsubj
, "Re: "), out
.s
);
87 * Process a shell escape by saving signals, ignoring signals,
96 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
98 cmd
= smalloc(cmdsize
= strlen(str
) + 1);
99 memcpy(cmd
, str
, cmdsize
);
100 if (bangexp(&cmd
, &cmdsize
) < 0)
102 if ((sh
= ok_vlook(SHELL
)) == NULL
)
104 run_command(sh
, 0, -1, -1, "-c", cmd
, NULL
);
105 safe_signal(SIGINT
, sigint
);
112 * Fork an interactive shell.
118 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
122 if ((sh
= ok_vlook(SHELL
)) == NULL
)
124 run_command(sh
, 0, -1, -1, NULL
, NULL
, NULL
);
125 safe_signal(SIGINT
, sigint
);
131 * Expand the shell escape by expanding unescaped !'s into the
132 * last issued command where possible.
135 static char *lastbang
;
136 static size_t lastbangsize
;
139 bangexp(char **str
, size_t *size
)
143 int dobang
= ok_blook(bang
);
144 size_t sz
, i
, j
, bangbufsize
;
146 bangbuf
= smalloc(bangbufsize
= *size
);
150 if ((*str
)[i
] == '!') {
151 sz
= strlen(lastbang
);
152 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
154 memcpy(bangbuf
+ j
, lastbang
, sz
+ 1);
160 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
165 bangbuf
[j
++] = (*str
)[i
++];
169 printf("!%s\n", bangbuf
);
174 *str
= srealloc(*str
, *size
= sz
);
175 memcpy(*str
, bangbuf
, sz
);
176 if (sz
> lastbangsize
)
177 lastbang
= srealloc(lastbang
, lastbangsize
= sz
);
178 memcpy(lastbang
, bangbuf
, sz
);
188 char *arg
= *(char**)v
;
191 #ifdef HAVE_DOCSTRINGS
192 ret
= ! print_comm_docstr(arg
);
194 fprintf(stderr
, tr(91, "Unknown command: `%s'\n"), arg
);
196 ret
= ccmdnotsupp(NULL
);
201 /* Very ugly, but take care for compiler supported string lengths :( */
202 printf(tr(295, "%s commands:\n"), progname
);
204 "type <message list> type messages\n"
205 "next goto and type next message\n"
206 "from <message list> give head lines of messages\n"
207 "headers print out active message headers\n"
208 "delete <message list> delete messages\n"
209 "undelete <message list> undelete messages\n"));
211 "save <message list> folder append messages to folder and mark as saved\n"
212 "copy <message list> folder append messages to folder without marking them\n"
213 "write <message list> file append message texts to file, save attachments\n"
214 "preserve <message list> keep incoming messages in mailbox even if saved\n"
215 "Reply <message list> reply to message senders\n"
216 "reply <message list> reply to message senders and all recipients\n"));
218 "mail addresses mail to specific recipients\n"
219 "file folder change to another folder\n"
220 "quit quit and apply changes to folder\n"
221 "xit quit and discard changes made to folder\n"
223 "cd <directory> chdir to directory or home if none given\n"
224 "list list names of all available commands\n"));
226 "\nA <message list> consists of integers, ranges of same, or other criteria\n"
227 "separated by spaces. If omitted, %s uses the last message typed.\n"),
237 char buf
[MAXPATHLEN
]; /* TODO getcwd(3) may return a larger value */
239 if (getcwd(buf
, sizeof buf
) != NULL
) {
255 if (*arglist
== NULL
)
257 else if ((cp
= file_expand(*arglist
)) == NULL
)
268 make_ref_and_cs(struct message
*mp
, struct header
*head
)
270 char *oldref
, *oldmsgid
, *newref
, *cp
;
271 size_t oldreflen
= 0, oldmsgidlen
= 0, reflen
;
275 oldref
= hfield1("references", mp
);
276 oldmsgid
= hfield1("message-id", mp
);
277 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
283 oldreflen
= strlen(oldref
);
284 reflen
+= oldreflen
+ 2;
287 oldmsgidlen
= strlen(oldmsgid
);
288 reflen
+= oldmsgidlen
;
291 newref
= ac_alloc(reflen
);
292 if (oldref
!= NULL
) {
293 memcpy(newref
, oldref
, oldreflen
+ 1);
294 if (oldmsgid
!= NULL
) {
295 newref
[oldreflen
++] = ',';
296 newref
[oldreflen
++] = ' ';
297 memcpy(newref
+ oldreflen
, oldmsgid
, oldmsgidlen
+ 1);
300 memcpy(newref
, oldmsgid
, oldmsgidlen
+ 1);
301 n
= extract(newref
, GREF
);
305 * Limit the references to 21 entries.
307 while (n
->n_flink
!= NULL
)
309 for (i
= 1; i
< 21; i
++) {
310 if (n
->n_blink
!= NULL
)
317 if (ok_blook(reply_in_same_charset
) &&
318 (cp
= hfield1("content-type", mp
)) != NULL
)
319 head
->h_charset
= mime_getparam("charset", cp
);
323 (*respond_or_Respond(int c
))(int *, int)
327 opt
+= ok_blook(Replyall
);
328 opt
+= ok_blook(flipr
);
329 return ((opt
== 1) ^ (c
== 'R')) ? Respond_internal
: respond_internal
;
335 return (respond_or_Respond('r'))((int *)v
, 0);
341 return respond_internal((int *)v
, 0);
345 respondsender(void *v
)
347 return Respond_internal((int *)v
, 0);
353 return (respond_or_Respond('r'))((int *)v
, 1);
359 return respond_internal((int *)v
, 1);
363 followupsender(void *v
)
365 return Respond_internal((int *)v
, 1);
369 * Reply to a single message. Extract each name from the
370 * message header and send them off to mail1()
373 respond_internal(int *msgvec
, int recipient_record
)
378 struct name
*np
= NULL
;
379 enum gfield gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
381 if (msgvec
[1] != 0) {
382 fprintf(stderr
, tr(37,
383 "Sorry, can't reply to multiple messages at once\n"));
386 mp
= &message
[msgvec
[0] - 1];
390 if ((rcv
= hfield1("reply-to", mp
)) == NULL
)
391 if ((rcv
= hfield1("from", mp
)) == NULL
)
394 np
= lextract(rcv
, GTO
|gf
);
395 if (!ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
396 np
= cat(np
, lextract(cp
, GTO
| gf
));
398 * Delete my name from the reply list,
399 * and with it, all my alternate names.
401 np
= elide(delete_alternates(np
));
403 np
= lextract(rcv
, GTO
| gf
);
405 memset(&head
, 0, sizeof head
);
407 head
.h_subject
= hfield1("subject", mp
);
408 head
.h_subject
= _reedit(head
.h_subject
);
411 if (ok_blook(recipients_in_cc
) && (cp
= hfield1("to", mp
)) != NULL
)
412 np
= lextract(cp
, GCC
| gf
);
413 if ((cp
= hfield1("cc", mp
)) != NULL
)
414 np
= cat(np
, lextract(cp
, GCC
| gf
));
416 head
.h_cc
= elide(delete_alternates(np
));
417 make_ref_and_cs(mp
, &head
);
419 if (ok_blook(quote_as_attachment
)) {
420 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
421 head
.h_attach
->a_msgno
= *msgvec
;
422 head
.h_attach
->a_content_description
= tr(512,
423 "Original message content");
426 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
427 ok_blook(markanswered
) &&
428 (mp
->m_flag
& MANSWERED
) == 0)
429 mp
->m_flag
|= MANSWER
| MANSWERED
;
434 * Forward a message to a new recipient, in the sense of RFC 2822.
437 forward1(char *str
, int recipient_record
)
443 bool_t f
, forward_as_attachment
;
445 forward_as_attachment
= ok_blook(forward_as_attachment
);
446 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
447 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
448 puts(tr(47, "No recipient specified."));
452 *msgvec
= first(0, MMNORM
);
456 printf("No messages to forward.\n");
460 } else if (getmsglist(str
, msgvec
, 0) < 0)
465 printf("No applicable messages.\n");
468 if (msgvec
[1] != 0) {
469 printf("Cannot forward multiple messages at once\n");
472 memset(&head
, 0, sizeof head
);
473 if ((head
.h_to
= lextract(recipient
,
474 GTO
| (ok_blook(fullnames
) ? GFULL
: GSKIN
))) == NULL
)
476 mp
= &message
[*msgvec
- 1];
477 if (forward_as_attachment
) {
478 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
479 head
.h_attach
->a_msgno
= *msgvec
;
480 head
.h_attach
->a_content_description
= "Forwarded message";
485 head
.h_subject
= hfield1("subject", mp
);
486 head
.h_subject
= fwdedit(head
.h_subject
);
487 mail1(&head
, 1, (forward_as_attachment
? NULL
: mp
),
488 NULL
, recipient_record
, 1);
493 * Modify the subject we are replying to to begin with Fwd:.
501 if (subj
== NULL
|| *subj
== '\0')
505 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
507 newsubj
= salloc(out
.l
+ 6);
508 memcpy(newsubj
, "Fwd: ", 5);
509 memcpy(newsubj
+ 5, out
.s
, out
.l
+ 1);
515 * The 'forward' command.
520 return forward1(v
, 0);
524 * Similar to forward, saving the message in a file named after the
530 return forward1(v
, 1);
534 * Preserve the named messages, so that they will be sent
535 * back to the system mailbox.
545 printf(tr(39, "Cannot \"preserve\" in edit mode\n"));
548 for (ip
= msgvec
; *ip
!= 0; ip
++) {
550 mp
= &message
[mesg
-1];
551 mp
->m_flag
|= MPRESERVE
;
555 * This is now Austin Group Request XCU #20.
557 did_print_dot
= TRU1
;
563 * Mark all given messages as unread.
571 for (ip
= msgvec
; *ip
!= 0; ip
++) {
572 setdot(&message
[*ip
-1]);
573 dot
->m_flag
&= ~(MREAD
|MTOUCH
);
574 dot
->m_flag
|= MSTATUS
;
576 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
577 imap_unread(&message
[*ip
-1], *ip
); /* TODO return? */
580 * The "unread" command is not part of POSIX mailx.
582 did_print_dot
= TRU1
;
588 * Mark all given messages as read.
596 for (ip
= msgvec
; *ip
; ip
++) {
597 setdot(&message
[*ip
-1]);
598 touch(&message
[*ip
-1]);
604 * Print the size of each message.
613 for (ip
= msgvec
; *ip
!= 0; ip
++) {
615 mp
= &message
[mesg
-1];
616 printf("%d: ", mesg
);
617 if (mp
->m_xlines
> 0)
618 printf("%ld", mp
->m_xlines
);
621 printf("/%lu\n", (unsigned long)mp
->m_xsize
);
627 * Quit quickly. If we are sourcing, just pop the input level
628 * by returning an error.
644 char **ap
= v
, *cp
, *cp2
, *varbuf
, c
;
652 for (; *ap
!= NULL
; ++ap
) {
654 cp2
= varbuf
= ac_alloc(strlen(cp
) + 1);
655 for (; (c
= *cp
) != '=' && c
!= '\0'; ++cp
)
664 tr(41, "Non-null variable name required\n"));
668 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
669 errs
+= _var_vokclear(&varbuf
[2]);
671 errs
+= _var_vokset(varbuf
, (uintptr_t)cp
);
680 * Unset a bunch of variable values.
689 for (ap
= (char**)v
; *ap
!= NULL
; ap
++)
690 errs
+= _var_vokclear(*ap
);
695 * Put add users to a group.
701 struct grouphead
*gh
;
705 char **ap
, *gname
, **p
;
708 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
709 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
712 ap
= (char **)salloc(s
* sizeof *ap
);
713 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
714 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
718 for (p
= ap
; *p
!= NULL
; p
++)
722 if (argv
[1] == NULL
) {
728 if ((gh
= findgroup(gname
)) == NULL
) {
729 gh
= (struct grouphead
*)scalloc(1, sizeof *gh
);
730 gh
->g_name
= sstrdup(gname
);
732 gh
->g_link
= groups
[h
];
737 * Insert names from the command list into the group.
738 * Who cares if there are duplicates? They get tossed
742 for (ap
= argv
+1; *ap
!= NULL
; ap
++) {
743 gp
= (struct group
*)scalloc(1, sizeof *gp
);
744 gp
->ge_name
= sstrdup(*ap
);
745 gp
->ge_link
= gh
->g_list
;
752 * Delete the passed groups.
760 fprintf(stderr
, tr(209, "Must specify alias to remove\n"));
765 while (*++argv
!= NULL
);
770 * Sort the passed string vecotor into ascending dictionary
778 for (ap
= list
; *ap
!= NULL
; ap
++)
782 qsort(list
, ap
-list
, sizeof(*list
), diction
);
786 * Do a dictionary order comparison of the arguments from
790 diction(const void *a
, const void *b
)
792 return(strcmp(*(char**)UNCONST(a
), *(char**)UNCONST(b
)));
796 * Change to another file. With no argument, print information about
811 fprintf(stderr
, tr(516,
812 "Cannot change folder from within a hook.\n"));
816 save_mbox_for_possible_quitstuff();
818 i
= setfile(*argv
, 0);
821 callhook(mailname
, 0);
822 if (i
> 0 && !ok_blook(emptystart
))
824 announce(ok_blook(bsdcompat
) || ok_blook(bsdannounce
));
829 * Expand file names like echo
834 char const **argv
= v
, **ap
, *cp
;
837 for (ap
= argv
; *ap
!= NULL
; ++ap
) {
839 if ((cp
= fexpand(cp
, FEXP_NSHORTCUT
)) != NULL
) {
843 while (*cp
!= '\0' &&
844 (c
= expand_shell_escape(&cp
, FAL0
))
847 /* \c ends overall processing */
860 return (respond_or_Respond('R'))((int *)v
, 0);
866 return (respond_or_Respond('R'))((int *)v
, 1);
870 * Reply to a series of messages by simply mailing to the senders
871 * and not messing around with the To: and Cc: lists as in normal
875 Respond_internal(int *msgvec
, int recipient_record
)
881 enum gfield gf
= ok_blook(fullnames
) ? GFULL
: GSKIN
;
883 memset(&head
, 0, sizeof head
);
885 for (ap
= msgvec
; *ap
!= 0; ap
++) {
886 mp
= &message
[*ap
- 1];
889 if ((cp
= hfield1("reply-to", mp
)) == NULL
)
890 if ((cp
= hfield1("from", mp
)) == NULL
)
892 head
.h_to
= cat(head
.h_to
, lextract(cp
, GTO
| gf
));
894 if (head
.h_to
== NULL
)
897 mp
= &message
[msgvec
[0] - 1];
898 head
.h_subject
= hfield1("subject", mp
);
899 head
.h_subject
= _reedit(head
.h_subject
);
900 make_ref_and_cs(mp
, &head
);
902 if (ok_blook(quote_as_attachment
)) {
903 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
904 head
.h_attach
->a_msgno
= *msgvec
;
905 head
.h_attach
->a_content_description
= tr(512,
906 "Original message content");
909 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0) == OKAY
&&
910 ok_blook(markanswered
) && (mp
->m_flag
& MANSWERED
) == 0)
911 mp
->m_flag
|= MANSWER
| MANSWERED
;
919 char **argv
= v
, *cp
, *op
;
921 if (cond_state
!= COND_ANY
) {
922 fprintf(stderr
, tr(42, "Illegal nested \"if\"\n"));
927 if (*cp
!= '$' && argv
[1] != NULL
) {
929 fprintf(stderr
, tr(528,
930 "Invalid conditional expression \"%s %s %s\"\n"),
931 argv
[0], (argv
[1] != NULL
? argv
[1] : ""),
932 (argv
[2] != NULL
? argv
[2] : ""));
933 cond_state
= COND_ANY
;
939 cond_state
= COND_NOEXEC
;
942 cond_state
= COND_EXEC
;
945 cond_state
= COND_RCV
;
948 cond_state
= COND_SEND
;
951 cond_state
= COND_TERM
;
954 /* Look up the value in question, we need it anyway */
957 /* Single argument, "implicit boolean" form? */
958 if ((op
= argv
[1]) == NULL
) {
959 cond_state
= (v
== NULL
) ? COND_NOEXEC
: COND_EXEC
;
963 /* Three argument comparison form? */
964 if (argv
[2] == NULL
||
965 op
[0] == '\0' || op
[1] != '=' || op
[2] != '\0')
967 /* A null value is treated as the empty string */
970 if (strcmp(v
, argv
[2]))
975 cond_state
= (((op
[0] == '!') ^ (v
== NULL
))
976 ? COND_NOEXEC
: COND_EXEC
);
983 fprintf(stderr
, tr(43, "Unrecognized if-keyword: \"%s\"\n"),
985 cond_state
= COND_ANY
;
999 switch (cond_state
) {
1001 fprintf(stderr
, tr(44, "\"Else\" without matching \"if\"\n"));
1004 cond_state
= COND_RCV
;
1007 cond_state
= COND_SEND
;
1010 cond_state
= COND_NOTERM
;
1013 cond_state
= COND_NOEXEC
;
1016 cond_state
= COND_EXEC
;
1019 fprintf(stderr
, tr(45,
1020 "Mail's idea of conditions is screwed up\n"));
1021 cond_state
= COND_ANY
;
1035 if (cond_state
== COND_ANY
) {
1036 fprintf(stderr
, tr(46, "\"Endif\" without matching \"if\"\n"));
1039 cond_state
= COND_ANY
;
1046 * Set the list of alternate names.
1052 char **namelist
= v
, **ap
, **ap2
, *cp
;
1054 l
= argcount(namelist
) + 1;
1057 if (altnames
== NULL
)
1059 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1065 if (altnames
!= NULL
) {
1066 for (ap
= altnames
; *ap
!= NULL
; ++ap
)
1070 altnames
= smalloc(l
* sizeof(char*));
1071 for (ap
= namelist
, ap2
= altnames
; *ap
; ++ap
, ++ap2
) {
1072 l
= strlen(*ap
) + 1;
1083 * Do the real work of resending.
1086 resend1(void *v
, int add_resent
)
1096 msgvec
= (int *)salloc((msgCount
+ 2) * sizeof *msgvec
);
1097 name
= laststring(str
, &f
, 1);
1099 puts(tr(47, "No recipient specified."));
1103 *msgvec
= first(0, MMNORM
);
1107 puts(tr(48, "No applicable messages."));
1111 } else if (getmsglist(str
, msgvec
, 0) < 0)
1116 printf("No applicable messages.\n");
1119 sn
= nalloc(name
, GTO
);
1120 to
= usermap(sn
, FAL0
);
1121 for (ip
= msgvec
; *ip
&& ip
- msgvec
< msgCount
; ip
++) {
1122 if (resend_msg(&message
[*ip
- 1], to
, add_resent
) != OKAY
)
1129 * Resend a message list to a third person.
1134 return resend1(v
, 1);
1138 * Resend a message list to a third person without adding headers.
1143 return resend1(v
, 0);
1147 * 'newmail' or 'inc' command: Check for new mail without writing old
1159 (mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1161 (val
= setfile(mailname
, 1)) == 0) {
1163 setdot(&message
[mdot
- 1]);
1169 list_shortcuts(void)
1173 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1174 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
1180 char **args
= (char **)v
;
1183 if (args
[0] == NULL
) {
1187 if (args
[1] == NULL
) {
1188 fprintf(stderr
, tr(220,
1189 "expansion name for shortcut missing\n"));
1192 if (args
[2] != NULL
) {
1193 fprintf(stderr
, tr(221, "too many arguments\n"));
1196 if ((s
= get_shortcut(args
[0])) != NULL
) {
1198 s
->sh_long
= sstrdup(args
[1]);
1200 s
= scalloc(1, sizeof *s
);
1201 s
->sh_short
= sstrdup(args
[0]);
1202 s
->sh_long
= sstrdup(args
[1]);
1203 s
->sh_next
= shortcuts
;
1209 FL
struct shortcut
*
1210 get_shortcut(const char *str
)
1214 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1215 if (strcmp(str
, s
->sh_short
) == 0)
1221 delete_shortcut(const char *str
)
1223 struct shortcut
*sp
, *sq
;
1225 for (sp
= shortcuts
, sq
= NULL
; sp
; sq
= sp
, sp
= sp
->sh_next
) {
1226 if (strcmp(sp
->sh_short
, str
) == 0) {
1230 sq
->sh_next
= sp
->sh_next
;
1231 if (sp
== shortcuts
)
1232 shortcuts
= sp
->sh_next
;
1243 char **args
= (char **)v
;
1246 if (args
[0] == NULL
) {
1247 fprintf(stderr
, tr(222, "need shortcut names to remove\n"));
1250 while (*args
!= NULL
) {
1251 if (delete_shortcut(*args
) != OKAY
) {
1253 fprintf(stderr
, tr(223, "%s: no such shortcut\n"),
1268 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1269 m
= &message
[*ip
-1];
1271 if ((m
->m_flag
& (MFLAG
|MFLAGGED
)) == 0)
1272 m
->m_flag
|= MFLAG
|MFLAGGED
;
1284 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1285 m
= &message
[*ip
-1];
1287 if (m
->m_flag
& (MFLAG
|MFLAGGED
)) {
1288 m
->m_flag
&= ~(MFLAG
|MFLAGGED
);
1289 m
->m_flag
|= MUNFLAG
;
1302 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1303 m
= &message
[*ip
-1];
1305 if ((m
->m_flag
& (MANSWER
|MANSWERED
)) == 0)
1306 m
->m_flag
|= MANSWER
|MANSWERED
;
1312 cunanswered(void *v
)
1318 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1319 m
= &message
[*ip
-1];
1321 if (m
->m_flag
& (MANSWER
|MANSWERED
)) {
1322 m
->m_flag
&= ~(MANSWER
|MANSWERED
);
1323 m
->m_flag
|= MUNANSWER
;
1336 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1337 m
= &message
[*ip
-1];
1339 if ((m
->m_flag
& (MDRAFT
|MDRAFTED
)) == 0)
1340 m
->m_flag
|= MDRAFT
|MDRAFTED
;
1352 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1353 m
= &message
[*ip
-1];
1355 if (m
->m_flag
& (MDRAFT
|MDRAFTED
)) {
1356 m
->m_flag
&= ~(MDRAFT
|MDRAFTED
);
1357 m
->m_flag
|= MUNDRAFT
;
1369 switch (mb
.mb_type
) {
1375 return (ccmdnotsupp(NULL
));
1382 return (ccmdnotsupp(NULL
));
1398 if (*args
== NULL
) {
1399 fprintf(stderr
, tr(290, "Syntax is: remove mailbox ...\n"));
1403 if ((name
= expand(*args
)) == NULL
)
1405 if (strcmp(name
, mailname
) == 0) {
1406 fprintf(stderr
, tr(286,
1407 "Cannot remove current mailbox \"%s\".\n"),
1412 snprintf(vb
, sizeof vb
, tr(287, "Remove \"%s\" (y/n) ? "),
1416 switch (which_protocol(name
)) {
1418 if (unlink(name
) < 0) { /* do not handle .gz .bz2 */
1424 fprintf(stderr
, tr(288,
1425 "Cannot remove POP3 mailbox \"%s\".\n"),
1431 if (imap_remove(name
) != OKAY
)
1436 if (maildir_remove(name
) != OKAY
)
1440 fprintf(stderr
, tr(289,
1441 "Unknown protocol in \"%s\". Not removed.\n"),
1452 char **args
= v
, *old
, *new;
1453 enum protocol oldp
, newp
;
1456 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1457 fprintf(stderr
, "Syntax: rename old new\n");
1461 if ((old
= expand(args
[0])) == NULL
)
1463 oldp
= which_protocol(old
);
1464 if ((new = expand(args
[1])) == NULL
)
1466 newp
= which_protocol(new);
1468 if (strcmp(old
, mailname
) == 0 || strcmp(new, mailname
) == 0) {
1469 fprintf(stderr
, tr(291,
1470 "Cannot rename current mailbox \"%s\".\n"), old
);
1473 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1474 fprintf(stderr
, tr(292,
1475 "Can only rename folders of same type.\n"));
1478 if (newp
== PROTO_POP3
)
1482 if (link(old
, new) < 0) {
1496 } else if (unlink(old
) < 0) {
1502 if (rename(old
, new) < 0) {
1508 nopop3
: fprintf(stderr
, tr(293, "Cannot rename POP3 mailboxes.\n"));
1513 if (imap_rename(old
, new) != OKAY
)
1519 fprintf(stderr
, tr(294,
1520 "Unknown protocol in \"%s\" and \"%s\". "
1521 "Not renamed.\n"), old
, new);