2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
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
42 static char sccsid
[] = "@(#)cmd3.c 2.87 (gritter) 10/1/08";
54 * Mail -- a mail program
56 * Still more user commands.
59 static int bangexp(char **str
, size_t *size
);
60 static void make_ref_and_cs(struct message
*mp
, struct header
*head
);
61 static int (*respond_or_Respond(int c
))(int *, int);
62 static int respond_internal(int *msgvec
, int recipient_record
);
63 static char *reedit(char *subj
);
64 static char *fwdedit(char *subj
);
65 static void onpipe(int signo
);
66 static void asort(char **list
);
67 static int diction(const void *a
, const void *b
);
68 static int file1(char *name
);
69 static int shellecho(const char *cp
);
70 static int Respond_internal(int *msgvec
, int recipient_record
);
71 static int resend1(void *v
, int add_resent
);
72 static void list_shortcuts(void);
73 static enum okay
delete_shortcut(const char *str
);
74 static float huge(void);
77 * Process a shell escape by saving signals, ignoring signals,
84 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
89 cmd
= smalloc(cmdsize
= strlen(str
) + 1);
91 if (bangexp(&cmd
, &cmdsize
) < 0)
93 if ((shell
= value("SHELL")) == NULL
)
95 run_command(shell
, 0, -1, -1, "-c", cmd
, NULL
);
96 safe_signal(SIGINT
, sigint
);
103 * Fork an interactive shell.
109 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
113 if ((shell
= value("SHELL")) == NULL
)
115 run_command(shell
, 0, -1, -1, NULL
, NULL
, NULL
);
116 safe_signal(SIGINT
, sigint
);
122 * Expand the shell escape by expanding unescaped !'s into the
123 * last issued command where possible.
126 static char *lastbang
;
127 static size_t lastbangsize
;
130 bangexp(char **str
, size_t *size
)
134 int dobang
= value("bang") != NULL
;
135 size_t sz
, i
, j
, bangbufsize
;
137 bangbuf
= smalloc(bangbufsize
= *size
);
141 if ((*str
)[i
] == '!') {
142 sz
= strlen(lastbang
);
143 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
145 strcpy(&bangbuf
[j
], lastbang
);
151 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
156 bangbuf
[j
++] = (*str
)[i
++];
160 printf("!%s\n", bangbuf
);
165 *str
= srealloc(*str
, *size
= sz
+ 1);
166 strcpy(*str
, bangbuf
);
167 if (sz
>= lastbangsize
)
168 lastbang
= srealloc(lastbang
, lastbangsize
= sz
+ 1);
169 strcpy(lastbang
, bangbuf
);
179 /* Very ugly, but take care for compiler supported string lengths :( */
184 "type <message list> type messages\n"
185 "next goto and type next message\n"
186 "from <message list> give head lines of messages\n"
187 "headers print out active message headers\n"
188 "delete <message list> delete messages\n"
189 "undelete <message list> undelete messages\n");
191 "save <message list> folder append messages to folder and mark as saved\n"
192 "copy <message list> folder append messages to folder without marking them\n"
193 "write <message list> file append message texts to file, save attachments\n"
194 "preserve <message list> keep incoming messages in mailbox even if saved\n"
195 "Reply <message list> reply to message senders\n"
196 "reply <message list> reply to message senders and all recipients\n");
198 "mail addresses mail to specific recipients\n"
199 "file folder change to another folder\n"
200 "quit quit and apply changes to folder\n"
201 "xit quit and discard changes made to folder\n"
203 "cd <directory> chdir to directory or home if none given\n"
204 "list list names of all available commands\n");
206 "\nA <message list> consists of integers, ranges of same, or other criteria\n"
207 "separated by spaces. If omitted, %s uses the last message typed.\n",
213 * Change user's working directory.
221 if (*arglist
== NULL
)
224 if ((cp
= expand(*arglist
)) == NULL
)
234 make_ref_and_cs(struct message
*mp
, struct header
*head
)
236 char *oldref
, *oldmsgid
, *newref
, *cp
;
241 oldref
= hfield("references", mp
);
242 oldmsgid
= hfield("message-id", mp
);
243 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
249 reflen
+= strlen(oldref
) + 2;
251 reflen
+= strlen(oldmsgid
);
252 newref
= ac_alloc(reflen
);
254 strcpy(newref
, oldref
);
256 strcat(newref
, ", ");
257 strcat(newref
, oldmsgid
);
260 strcpy(newref
, oldmsgid
);
261 n
= extract(newref
, GREF
);
264 * Limit the references to 21 entries.
266 while (n
->n_flink
!= NULL
)
268 for (i
= 1; i
< 21; i
++) {
269 if (n
->n_blink
!= NULL
)
276 if (value("reply-in-same-charset") != NULL
&&
277 (cp
= hfield("content-type", mp
)) != NULL
)
278 head
->h_charset
= mime_getparam("charset", cp
);
282 (*respond_or_Respond(int c
))(int *, int)
286 opt
+= (value("Replyall") != NULL
);
287 opt
+= (value("flipr") != NULL
);
288 return ((opt
== 1) ^ (c
== 'R')) ? Respond_internal
: respond_internal
;
294 return (respond_or_Respond('r'))((int *)v
, 0);
300 return respond_internal((int *)v
, 0);
304 respondsender(void *v
)
306 return Respond_internal((int *)v
, 0);
312 return (respond_or_Respond('r'))((int *)v
, 1);
318 return respond_internal((int *)v
, 1);
322 followupsender(void *v
)
324 return Respond_internal((int *)v
, 1);
328 * Reply to a list of messages. Extract each name from the
329 * message header and send them off to mail1()
332 respond_internal(int *msgvec
, int recipient_record
)
337 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
338 struct name
*np
= NULL
;
341 memset(&head
, 0, sizeof head
);
342 if (msgvec
[1] != 0) {
343 printf(catgets(catd
, CATSET
, 37,
344 "Sorry, can't reply to multiple messages at once\n"));
347 mp
= &message
[msgvec
[0] - 1];
350 if ((rcv
= hfield("reply-to", mp
)) == NULL
)
351 if ((rcv
= hfield("from", mp
)) == NULL
)
354 np
= sextract(rcv
, GTO
|gf
);
355 if (! value("recipients-in-cc") && (cp
= hfield("to", mp
)) != NULL
)
356 np
= cat(np
, sextract(cp
, GTO
|gf
));
359 * Delete my name from the reply list,
360 * and with it, all my alternate names.
362 np
= delete_alternates(np
);
364 np
= sextract(rcv
, GTO
|gf
);
366 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
367 head
.h_subject
= hfield("subj", mp
);
368 head
.h_subject
= reedit(head
.h_subject
);
371 if (value("recipients-in-cc") && (cp
= hfield("to", mp
)) != NULL
)
372 np
= sextract(cp
, GCC
|gf
);
373 if ((cp
= hfield("cc", mp
)) != NULL
)
374 np
= cat(np
, sextract(cp
, GCC
|gf
));
376 head
.h_cc
= elide(delete_alternates(np
));
377 make_ref_and_cs(mp
, &head
);
378 Eflag
= value("skipemptybody") != NULL
;
379 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
380 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
381 mp
->m_flag
|= MANSWER
|MANSWERED
;
386 * Modify the subject we are replying to to begin with Re: if
387 * it does not already.
395 if (subj
== NULL
|| *subj
== '\0')
399 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
400 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
401 (out
.s
[1] == 'e' || out
.s
[1] == 'E') &&
404 newsubj
= salloc(out
.l
+ 5);
405 strcpy(newsubj
, "Re: ");
406 strcpy(newsubj
+ 4, out
.s
);
411 * Forward a message to a new recipient, in the sense of RFC 2822.
414 forward1(char *str
, int recipient_record
)
421 int forward_as_attachment
;
423 forward_as_attachment
= value("forward-as-attachment") != NULL
;
424 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
425 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
426 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
430 *msgvec
= first(0, MMNORM
);
434 printf("No messages to forward.\n");
439 if (f
&& getmsglist(str
, msgvec
, 0) < 0)
444 printf("No applicable messages.\n");
447 if (msgvec
[1] != 0) {
448 printf("Cannot forward multiple messages at once\n");
451 memset(&head
, 0, sizeof head
);
452 if ((head
.h_to
= sextract(recipient
,
453 GTO
| (value("fullnames") ? GFULL
: GSKIN
))) == NULL
)
455 mp
= &message
[*msgvec
- 1];
456 if (forward_as_attachment
) {
457 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
458 head
.h_attach
->a_msgno
= *msgvec
;
463 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
464 head
.h_subject
= hfield("subj", mp
);
465 head
.h_subject
= fwdedit(head
.h_subject
);
466 Eflag
= value("skipemptybody") != NULL
;
467 mail1(&head
, 1, forward_as_attachment
? NULL
: mp
,
468 NULL
, recipient_record
, 1, 0, Eflag
);
473 * Modify the subject we are replying to to begin with Fwd:.
481 if (subj
== NULL
|| *subj
== '\0')
485 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
486 newsubj
= salloc(strlen(out
.s
) + 6);
487 strcpy(newsubj
, "Fwd: ");
488 strcpy(&newsubj
[5], out
.s
);
494 * The 'forward' command.
499 return forward1(v
, 0);
503 * Similar to forward, saving the message in a file named after the
509 return forward1(v
, 1);
513 * Preserve the named messages, so that they will be sent
514 * back to the system mailbox.
524 printf(catgets(catd
, CATSET
, 39,
525 "Cannot \"preserve\" in edit mode\n"));
528 for (ip
= msgvec
; *ip
!= 0; ip
++) {
530 mp
= &message
[mesg
-1];
531 mp
->m_flag
|= MPRESERVE
;
535 * This is now Austin Group Request XCU #20.
543 * Mark all given messages as unread.
551 for (ip
= msgvec
; *ip
!= 0; ip
++) {
552 setdot(&message
[*ip
-1]);
553 dot
->m_flag
&= ~(MREAD
|MTOUCH
);
554 dot
->m_flag
|= MSTATUS
;
555 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
556 imap_unread(&message
[*ip
-1], *ip
);
558 * The "unread" command is not part of POSIX mailx.
566 * Mark all given messages as read.
574 for (ip
= msgvec
; *ip
; ip
++) {
575 setdot(&message
[*ip
-1]);
576 touch(&message
[*ip
-1]);
582 * Print the size of each message.
591 for (ip
= msgvec
; *ip
!= 0; ip
++) {
593 mp
= &message
[mesg
-1];
594 printf("%d: ", mesg
);
595 if (mp
->m_xlines
> 0)
596 printf("%ld", mp
->m_xlines
);
599 printf("/%lu\n", (unsigned long)mp
->m_xsize
);
605 * Quit quickly. If we are sourcing, just pop the input level
606 * by returning an error.
619 static sigjmp_buf pipejmp
;
626 siglongjmp(pipejmp
, 1);
630 * Set or display a variable value. Syntax is similar to that
642 int bsdset
= value("bsdcompat") != NULL
|| value("bsdset") != NULL
;
644 if (*arglist
== NULL
) {
645 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
646 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
649 ap
= (char **)salloc(s
* sizeof *ap
);
650 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
651 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
655 if (is_a_tty
[0] && is_a_tty
[1] && (cp
= value("crt")) != NULL
) {
656 if (s
> (*cp
== '\0' ? screensize() : atoi(cp
)) + 3) {
658 /* TODO should be below the Popen?
659 * TODO Problem: Popen doesn't encapsulate it,
660 * TODO may leave child run if fdopen() fails!
661 * TODO even more such stuff in this file! */
662 if (sigsetjmp(pipejmp
, 1))
664 if ((obuf
= Popen(cp
, "w", NULL
, 1)) == NULL
) {
668 safe_signal(SIGPIPE
, onpipe
);
671 for (p
= ap
; *p
!= NULL
; p
++) {
673 fprintf(obuf
, "%s\t%s\n", *p
, value(*p
));
675 if ((cp
= value(*p
)) != NULL
&& *cp
)
676 fprintf(obuf
, "%s=\"%s\"\n",
679 fprintf(obuf
, "%s\n", *p
);
683 if (obuf
!= stdout
) {
684 safe_signal(SIGPIPE
, SIG_IGN
);
686 safe_signal(SIGPIPE
, dflpipe
);
691 for (ap
= arglist
; *ap
!= NULL
; ap
++) {
694 varbuf
= ac_alloc(strlen(*ap
) + 1);
697 while (*cp
!= '=' && *cp
!= '\0')
704 if (equal(varbuf
, "")) {
705 printf(catgets(catd
, CATSET
, 41,
706 "Non-null variable name required\n"));
711 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
712 errs
+= unset_internal(&varbuf
[2]);
721 * Unset a bunch of variable values.
730 for (ap
= (char **)v
; *ap
!= NULL
; ap
++)
731 errs
+= unset_internal(*ap
);
736 * Put add users to a group.
742 struct grouphead
*gh
;
746 char **ap
, *gname
, **p
;
749 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
750 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
753 ap
= (char **)salloc(s
* sizeof *ap
);
754 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
755 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
759 for (p
= ap
; *p
!= NULL
; p
++)
763 if (argv
[1] == NULL
) {
769 if ((gh
= findgroup(gname
)) == NULL
) {
770 gh
= (struct grouphead
*)scalloc(1, sizeof *gh
);
771 gh
->g_name
= vcopy(gname
);
773 gh
->g_link
= groups
[h
];
778 * Insert names from the command list into the group.
779 * Who cares if there are duplicates? They get tossed
783 for (ap
= argv
+1; *ap
!= NULL
; ap
++) {
784 gp
= (struct group
*)scalloc(1, sizeof *gp
);
785 gp
->ge_name
= vcopy(*ap
);
786 gp
->ge_link
= gh
->g_list
;
793 * Delete the passed groups.
801 printf(catgets(catd
, CATSET
, 209,
802 "Must specify alias or group to remove\n"));
807 while (*++argv
!= NULL
);
812 * Sort the passed string vecotor into ascending dictionary
820 for (ap
= list
; *ap
!= NULL
; ap
++)
824 qsort(list
, ap
-list
, sizeof(*list
), diction
);
828 * Do a dictionary order comparison of the arguments from
832 diction(const void *a
, const void *b
)
834 return(strcmp(*(char **)a
, *(char **)b
));
838 * Change to another file. With no argument, print information about
846 if (argv
[0] == NULL
) {
850 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
860 fprintf(stderr
, "Cannot change folder from within a hook.\n");
863 i
= setfile(name
, 0);
866 callhook(mailname
, 0);
867 if (i
> 0 && value("emptystart") == NULL
)
869 announce(value("bsdcompat") != NULL
|| value("bsdannounce") != NULL
);
874 shellecho(const char *cp
)
914 while (n
-- && octalchar(cp
[1]&0377)) {
929 * Expand file names like echo
939 for (ap
= argv
; *ap
!= NULL
; ap
++) {
941 if ((cp
= expand(cp
)) != NULL
) {
944 cflag
|= shellecho(cp
);
955 return (respond_or_Respond('R'))((int *)v
, 0);
961 return (respond_or_Respond('R'))((int *)v
, 1);
965 * Reply to a series of messages by simply mailing to the senders
966 * and not messing around with the To: and Cc: lists as in normal
970 Respond_internal(int *msgvec
, int recipient_record
)
975 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
979 memset(&head
, 0, sizeof head
);
980 for (ap
= msgvec
; *ap
!= 0; ap
++) {
981 mp
= &message
[*ap
- 1];
984 if ((cp
= hfield("reply-to", mp
)) == NULL
)
985 if ((cp
= hfield("from", mp
)) == NULL
)
987 head
.h_to
= cat(head
.h_to
, sextract(cp
, GTO
|gf
));
989 if (head
.h_to
== NULL
)
991 mp
= &message
[msgvec
[0] - 1];
992 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
993 head
.h_subject
= hfield("subj", mp
);
994 head
.h_subject
= reedit(head
.h_subject
);
995 make_ref_and_cs(mp
, &head
);
996 Eflag
= value("skipemptybody") != NULL
;
997 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
998 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
999 mp
->m_flag
|= MANSWER
|MANSWERED
;
1004 * Conditional commands. These allow one to parameterize one's
1005 * .mailrc and do some things if sending, others if receiving.
1014 printf(catgets(catd
, CATSET
, 42, "Illegal nested \"if\"\n"));
1033 printf(catgets(catd
, CATSET
, 43,
1034 "Unrecognized if-keyword: \"%s\"\n"), cp
);
1041 * Implement 'else'. This is pretty simple -- we just
1042 * flip over the conditional flag.
1052 printf(catgets(catd
, CATSET
, 44,
1053 "\"Else\" without matching \"if\"\n"));
1069 printf(catgets(catd
, CATSET
, 45,
1070 "Mail's idea of conditions is screwed up\n"));
1078 * End of if statement. Just set cond back to anything.
1087 printf(catgets(catd
, CATSET
, 46,
1088 "\"Endif\" without matching \"if\"\n"));
1096 * Set the list of alternate names.
1101 char **namelist
= v
;
1103 char **ap
, **ap2
, *cp
;
1105 c
= argcount(namelist
) + 1;
1109 for (ap
= altnames
; *ap
; ap
++)
1116 altnames
= scalloc(c
, sizeof (char *));
1117 for (ap
= namelist
, ap2
= altnames
; *ap
; ap
++, ap2
++) {
1118 cp
= scalloc(strlen(*ap
) + 1, sizeof (char));
1127 * Do the real work of resending.
1130 resend1(void *v
, int add_resent
)
1135 int f
, *ip
, *msgvec
;
1139 msgvec
= (int *)salloc((msgCount
+ 2) * sizeof *msgvec
);
1140 name
= laststring(str
, &f
, 1);
1142 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
1146 *msgvec
= first(0, MMNORM
);
1150 puts(catgets(catd
, CATSET
, 48,
1151 "No applicable messages."));
1155 } else if (getmsglist(str
, msgvec
, 0) < 0)
1160 printf("No applicable messages.\n");
1163 sn
= nalloc(name
, GTO
);
1165 for (ip
= msgvec
; *ip
&& ip
- msgvec
< msgCount
; ip
++) {
1166 if (resend_msg(&message
[*ip
- 1], to
, add_resent
) != OKAY
)
1173 * Resend a message list to a third person.
1178 return resend1(v
, 1);
1182 * Resend a message list to a third person without adding headers.
1187 return resend1(v
, 0);
1191 * 'newmail' or 'inc' command: Check for new mail without writing old
1201 if ((mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1202 (val
= setfile(mailname
, 1)) == 0) {
1204 setdot(&message
[mdot
- 1]);
1210 list_shortcuts(void)
1214 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1215 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
1221 char **args
= (char **)v
;
1224 if (args
[0] == NULL
) {
1228 if (args
[1] == NULL
) {
1229 fprintf(stderr
, catgets(catd
, CATSET
, 220,
1230 "expansion name for shortcut missing\n"));
1233 if (args
[2] != NULL
) {
1234 fprintf(stderr
, catgets(catd
, CATSET
, 221,
1235 "too many arguments\n"));
1238 if ((s
= get_shortcut(args
[0])) != NULL
) {
1240 s
->sh_long
= sstrdup(args
[1]);
1242 s
= scalloc(1, sizeof *s
);
1243 s
->sh_short
= sstrdup(args
[0]);
1244 s
->sh_long
= sstrdup(args
[1]);
1245 s
->sh_next
= shortcuts
;
1252 get_shortcut(const char *str
)
1256 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1257 if (strcmp(str
, s
->sh_short
) == 0)
1263 delete_shortcut(const char *str
)
1265 struct shortcut
*sp
, *sq
;
1267 for (sp
= shortcuts
, sq
= NULL
; sp
; sq
= sp
, sp
= sp
->sh_next
) {
1268 if (strcmp(sp
->sh_short
, str
) == 0) {
1272 sq
->sh_next
= sp
->sh_next
;
1273 if (sp
== shortcuts
)
1274 shortcuts
= sp
->sh_next
;
1285 char **args
= (char **)v
;
1288 if (args
[0] == NULL
) {
1289 fprintf(stderr
, catgets(catd
, CATSET
, 222,
1290 "need shortcut names to remove\n"));
1293 while (*args
!= NULL
) {
1294 if (delete_shortcut(*args
) != OKAY
) {
1296 fprintf(stderr
, catgets(catd
, CATSET
, 223,
1297 "%s: no such shortcut\n"), *args
);
1305 struct oldaccount
*ac_next
; /* next account in list */
1306 char *ac_name
; /* name of account */
1307 char **ac_vars
; /* variables to set */
1310 static struct oldaccount
*oldaccounts
;
1313 get_oldaccount(const char *name
)
1315 struct oldaccount
*a
;
1317 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1318 if (a
->ac_name
&& strcmp(name
, a
->ac_name
) == 0)
1326 char **args
= (char **)v
;
1327 struct oldaccount
*a
;
1329 int i
, mc
, oqf
, nqf
;
1332 if (args
[0] == NULL
) {
1333 if ((fp
= Ftemp(&cp
, "Ra", "w+", 0600, 1)) == NULL
) {
1339 mc
= listaccounts(fp
);
1340 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1344 fprintf(fp
, "%s:\n", a
->ac_name
);
1345 for (i
= 0; a
->ac_vars
[i
]; i
++)
1346 fprintf(fp
, "\t%s\n", a
->ac_vars
[i
]);
1353 if (args
[1] && args
[1][0] == '{' && args
[1][1] == '\0') {
1354 if (args
[2] != NULL
) {
1355 fprintf(stderr
, "Syntax is: account <name> {\n");
1358 if ((a
= get_oldaccount(args
[0])) != NULL
)
1360 return define1(args
[0], 1);
1362 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
1363 oqf
= savequitflags();
1364 if ((a
= get_oldaccount(args
[0])) == NULL
) {
1366 a
= scalloc(1, sizeof *a
);
1367 a
->ac_next
= oldaccounts
;
1370 if ((i
= callaccount(args
[0])) != CBAD
)
1372 printf("Account %s does not exist.\n", args
[0]);
1377 delaccount(args
[0]);
1378 a
->ac_name
= sstrdup(args
[0]);
1379 for (i
= 1; args
[i
]; i
++);
1380 a
->ac_vars
= scalloc(i
, sizeof *a
->ac_vars
);
1381 for (i
= 0; args
[i
+1]; i
++)
1382 a
->ac_vars
[i
] = sstrdup(args
[i
+1]);
1384 unset_allow_undefined
= 1;
1386 unset_allow_undefined
= 0;
1387 setf
: if (!starting
) {
1388 nqf
= savequitflags();
1389 restorequitflags(oqf
);
1391 restorequitflags(nqf
);
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
;
1421 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1422 m
= &message
[*ip
-1];
1424 if (m
->m_flag
& (MFLAG
|MFLAGGED
)) {
1425 m
->m_flag
&= ~(MFLAG
|MFLAGGED
);
1426 m
->m_flag
|= MUNFLAG
;
1439 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1440 m
= &message
[*ip
-1];
1442 if ((m
->m_flag
& (MANSWER
|MANSWERED
)) == 0)
1443 m
->m_flag
|= MANSWER
|MANSWERED
;
1449 cunanswered(void *v
)
1455 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1456 m
= &message
[*ip
-1];
1458 if (m
->m_flag
& (MANSWER
|MANSWERED
)) {
1459 m
->m_flag
&= ~(MANSWER
|MANSWERED
);
1460 m
->m_flag
|= MUNANSWER
;
1473 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1474 m
= &message
[*ip
-1];
1476 if ((m
->m_flag
& (MDRAFT
|MDRAFTED
)) == 0)
1477 m
->m_flag
|= MDRAFT
|MDRAFTED
;
1489 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1490 m
= &message
[*ip
-1];
1492 if (m
->m_flag
& (MDRAFT
|MDRAFTED
)) {
1493 m
->m_flag
&= ~(MDRAFT
|MDRAFTED
);
1494 m
->m_flag
|= MUNDRAFT
;
1505 * This is not perfect, but correct for machines with a 32-bit
1506 * IEEE float and a 32-bit unsigned long, and does at least not
1507 * produce SIGFPE on the Cray Y-MP.
1514 u
.l
= 0xff800000; /* -inf */
1516 #elif defined (INFINITY)
1518 #elif defined (HUGE_VALF)
1520 #elif defined (FLT_MAX)
1534 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1535 m
= &message
[*ip
-1];
1537 m
->m_score
= huge();
1549 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1550 m
= &message
[*ip
-1];
1551 m
->m_flag
&= ~MKILL
;
1562 int f
, *msgvec
, *ip
;
1566 msgvec
= salloc((msgCount
+2) * sizeof *msgvec
);
1567 if ((sscore
= laststring(str
, &f
, 0)) == NULL
) {
1568 fprintf(stderr
, "No score given.\n");
1571 nscore
= strtod(sscore
, &xp
);
1573 fprintf(stderr
, "Invalid score: \"%s\"\n", sscore
);
1576 if (nscore
> FLT_MAX
)
1578 else if (nscore
< -FLT_MAX
)
1581 *msgvec
= first(0, MMNORM
);
1585 fprintf(stderr
, "No messages to score.\n");
1589 } else if (getmsglist(str
, msgvec
, 0) < 0)
1594 fprintf(stderr
, "No applicable messages.\n");
1597 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
1598 m
= &message
[*ip
-1];
1599 if (m
->m_score
!= huge()) {
1600 m
->m_score
+= nscore
;
1603 else if (m
->m_score
> 0)
1604 m
->m_flag
&= ~MKILL
;
1605 if (m
->m_score
>= 0)
1618 switch (mb
.mb_type
) {
1639 if (*args
== NULL
) {
1640 fprintf(stderr
, "Syntax is: remove mailbox ...\n");
1644 if ((name
= expand(*args
)) == NULL
)
1646 if (strcmp(name
, mailname
) == 0) {
1648 "Cannot remove current mailbox \"%s\".\n",
1653 snprintf(vb
, sizeof vb
, "Remove \"%s\" (y/n) ? ", name
);
1656 switch (which_protocol(name
)) {
1658 if (unlink(name
) < 0) { /* do not handle .gz .bz2 */
1664 fprintf(stderr
, "Cannot remove POP3 mailbox \"%s\".\n",
1669 if (imap_remove(name
) != OKAY
)
1673 if (maildir_remove(name
) != OKAY
)
1678 "Unknown protocol in \"%s\". Not removed.\n",
1689 char **args
= v
, *old
, *new;
1690 enum protocol oldp
, newp
;
1693 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1694 fprintf(stderr
, "Syntax: rename old new\n");
1697 old
= expand(args
[0]);
1698 oldp
= which_protocol(old
);
1699 new = expand(args
[1]);
1700 newp
= which_protocol(new);
1701 if (strcmp(old
, mailname
) == 0 || strcmp(new, mailname
) == 0) {
1702 fprintf(stderr
, "Cannot rename current mailbox \"%s\".\n", old
);
1705 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1706 fprintf(stderr
, "Can only rename folders of same type.\n");
1709 if (newp
== PROTO_POP3
)
1713 if (link(old
, new) < 0) {
1727 } else if (unlink(old
) < 0) {
1733 if (rename(old
, new) < 0) {
1739 nopop3
: fprintf(stderr
, "Cannot rename POP3 mailboxes.\n");
1743 if (imap_rename(old
, new) != OKAY
)
1747 fprintf(stderr
, "Unknown protocol in \"%s\" and \"%s\". "
1748 "Not renamed.\n", old
, new);