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.
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 static char sccsid
[] = "@(#)cmd3.c 2.87 (gritter) 10/1/08";
55 * Mail -- a mail program
57 * Still more user commands.
60 static int bangexp(char **str
, size_t *size
);
61 static void make_ref_and_cs(struct message
*mp
, struct header
*head
);
62 static int (*respond_or_Respond(int c
))(int *, int);
63 static int respond_internal(int *msgvec
, int recipient_record
);
64 static char *reedit(char *subj
);
65 static char *fwdedit(char *subj
);
66 static void onpipe(int signo
);
67 static void asort(char **list
);
68 static int diction(const void *a
, const void *b
);
69 static int file1(char *name
);
70 static int shellecho(const char *cp
);
71 static int Respond_internal(int *msgvec
, int recipient_record
);
72 static int resend1(void *v
, int add_resent
);
73 static void list_shortcuts(void);
74 static enum okay
delete_shortcut(const char *str
);
75 static float huge(void);
78 * Process a shell escape by saving signals, ignoring signals,
85 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
90 cmd
= smalloc(cmdsize
= strlen(str
) + 1);
92 if (bangexp(&cmd
, &cmdsize
) < 0)
94 if ((shell
= value("SHELL")) == NULL
)
96 run_command(shell
, 0, -1, -1, "-c", cmd
, NULL
);
97 safe_signal(SIGINT
, sigint
);
104 * Fork an interactive shell.
110 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
);
178 const char *helptext
=
180 type <message list> type messages\n\
181 next goto and type next message\n\
182 from <message list> give head lines of messages\n\
183 headers print out active message headers\n\
184 delete <message list> delete messages\n\
185 undelete <message list> undelete messages\n\
186 save <message list> folder append messages to folder and mark as saved\n\
187 copy <message list> folder append messages to folder without marking them\n\
188 write <message list> file append message texts to file, save attachments\n\
189 preserve <message list> keep incoming messages in mailbox even if saved\n\
190 Reply <message list> reply to message senders\n\
191 reply <message list> reply to message senders and all recipients\n\
192 mail addresses mail to specific recipients\n\
193 file folder change to another folder\n\
194 quit quit and apply changes to folder\n\
195 xit quit and discard changes made to folder\n\
197 cd <directory> chdir to directory or home if none given\n\
198 list list names of all available commands\n\
200 A <message list> consists of integers, ranges of same, or other criteria\n\
201 separated by spaces. If omitted, %s uses the last message typed.\n";
203 fprintf(stdout
, helptext
, progname
, progname
);
208 * Change user's working directory.
216 if (*arglist
== NULL
)
219 if ((cp
= expand(*arglist
)) == NULL
)
229 make_ref_and_cs(struct message
*mp
, struct header
*head
)
231 char *oldref
, *oldmsgid
, *newref
, *cp
;
236 oldref
= hfield("references", mp
);
237 oldmsgid
= hfield("message-id", mp
);
238 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
244 reflen
+= strlen(oldref
) + 2;
246 reflen
+= strlen(oldmsgid
);
247 newref
= ac_alloc(reflen
);
249 strcpy(newref
, oldref
);
251 strcat(newref
, ", ");
252 strcat(newref
, oldmsgid
);
255 strcpy(newref
, oldmsgid
);
256 n
= extract(newref
, GREF
);
259 * Limit the references to 21 entries.
261 while (n
->n_flink
!= NULL
)
263 for (i
= 1; i
< 21; i
++) {
264 if (n
->n_blink
!= NULL
)
271 if (value("reply-in-same-charset") != NULL
&&
272 (cp
= hfield("content-type", mp
)) != NULL
)
273 head
->h_charset
= mime_getparam("charset", cp
);
277 (*respond_or_Respond(int c
))(int *, int)
281 opt
+= (value("Replyall") != NULL
);
282 opt
+= (value("flipr") != NULL
);
283 return ((opt
== 1) ^ (c
== 'R')) ? Respond_internal
: respond_internal
;
289 return (respond_or_Respond('r'))((int *)v
, 0);
295 return respond_internal((int *)v
, 0);
299 respondsender(void *v
)
301 return Respond_internal((int *)v
, 0);
307 return (respond_or_Respond('r'))((int *)v
, 1);
313 return respond_internal((int *)v
, 1);
317 followupsender(void *v
)
319 return Respond_internal((int *)v
, 1);
323 * Reply to a list of messages. Extract each name from the
324 * message header and send them off to mail1()
327 respond_internal(int *msgvec
, int recipient_record
)
332 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
333 struct name
*np
= NULL
;
336 memset(&head
, 0, sizeof head
);
337 if (msgvec
[1] != 0) {
338 printf(catgets(catd
, CATSET
, 37,
339 "Sorry, can't reply to multiple messages at once\n"));
342 mp
= &message
[msgvec
[0] - 1];
345 if ((rcv
= hfield("reply-to", mp
)) == NULL
)
346 if ((rcv
= hfield("from", mp
)) == NULL
)
349 np
= sextract(rcv
, GTO
|gf
);
350 if (! value("recipients-in-cc") && (cp
= hfield("to", mp
)) != NULL
)
351 np
= cat(np
, sextract(cp
, GTO
|gf
));
354 * Delete my name from the reply list,
355 * and with it, all my alternate names.
357 np
= delete_alternates(np
);
359 np
= sextract(rcv
, GTO
|gf
);
361 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
362 head
.h_subject
= hfield("subj", mp
);
363 head
.h_subject
= reedit(head
.h_subject
);
366 if (value("recipients-in-cc") && (cp
= hfield("to", mp
)) != NULL
)
367 np
= sextract(cp
, GCC
|gf
);
368 if ((cp
= hfield("cc", mp
)) != NULL
)
369 np
= cat(np
, sextract(cp
, GCC
|gf
));
371 head
.h_cc
= elide(delete_alternates(np
));
372 make_ref_and_cs(mp
, &head
);
373 Eflag
= value("skipemptybody") != NULL
;
374 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
375 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
376 mp
->m_flag
|= MANSWER
|MANSWERED
;
381 * Modify the subject we are replying to to begin with Re: if
382 * it does not already.
390 if (subj
== NULL
|| *subj
== '\0')
394 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
395 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
396 (out
.s
[1] == 'e' || out
.s
[1] == 'E') &&
399 newsubj
= salloc(out
.l
+ 5);
400 strcpy(newsubj
, "Re: ");
401 strcpy(newsubj
+ 4, out
.s
);
406 * Forward a message to a new recipient, in the sense of RFC 2822.
409 forward1(char *str
, int recipient_record
)
416 int forward_as_attachment
;
418 forward_as_attachment
= value("forward-as-attachment") != NULL
;
419 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
420 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
421 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
425 *msgvec
= first(0, MMNORM
);
429 printf("No messages to forward.\n");
434 if (f
&& getmsglist(str
, msgvec
, 0) < 0)
439 printf("No applicable messages.\n");
442 if (msgvec
[1] != 0) {
443 printf("Cannot forward multiple messages at once\n");
446 memset(&head
, 0, sizeof head
);
447 if ((head
.h_to
= sextract(recipient
,
448 GTO
| (value("fullnames") ? GFULL
: GSKIN
))) == NULL
)
450 mp
= &message
[*msgvec
- 1];
451 if (forward_as_attachment
) {
452 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
453 head
.h_attach
->a_msgno
= *msgvec
;
458 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
459 head
.h_subject
= hfield("subj", mp
);
460 head
.h_subject
= fwdedit(head
.h_subject
);
461 Eflag
= value("skipemptybody") != NULL
;
462 mail1(&head
, 1, forward_as_attachment
? NULL
: mp
,
463 NULL
, recipient_record
, 1, 0, Eflag
);
468 * Modify the subject we are replying to to begin with Fwd:.
476 if (subj
== NULL
|| *subj
== '\0')
480 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
481 newsubj
= salloc(strlen(out
.s
) + 6);
482 strcpy(newsubj
, "Fwd: ");
483 strcpy(&newsubj
[5], out
.s
);
489 * The 'forward' command.
494 return forward1(v
, 0);
498 * Similar to forward, saving the message in a file named after the
504 return forward1(v
, 1);
508 * Preserve the named messages, so that they will be sent
509 * back to the system mailbox.
519 printf(catgets(catd
, CATSET
, 39,
520 "Cannot \"preserve\" in edit mode\n"));
523 for (ip
= msgvec
; *ip
!= 0; ip
++) {
525 mp
= &message
[mesg
-1];
526 mp
->m_flag
|= MPRESERVE
;
530 * This is now Austin Group Request XCU #20.
538 * Mark all given messages as unread.
546 for (ip
= msgvec
; *ip
!= 0; ip
++) {
547 setdot(&message
[*ip
-1]);
548 dot
->m_flag
&= ~(MREAD
|MTOUCH
);
549 dot
->m_flag
|= MSTATUS
;
550 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
551 imap_unread(&message
[*ip
-1], *ip
);
553 * The "unread" command is not part of POSIX mailx.
561 * Mark all given messages as read.
569 for (ip
= msgvec
; *ip
; ip
++) {
570 setdot(&message
[*ip
-1]);
571 touch(&message
[*ip
-1]);
577 * Print the size of each message.
586 for (ip
= msgvec
; *ip
!= 0; ip
++) {
588 mp
= &message
[mesg
-1];
589 printf("%d: ", mesg
);
590 if (mp
->m_xlines
> 0)
591 printf("%ld", mp
->m_xlines
);
594 printf("/%lu\n", (unsigned long)mp
->m_xsize
);
600 * Quit quickly. If we are sourcing, just pop the input level
601 * by returning an error.
613 static sigjmp_buf pipejmp
;
619 siglongjmp(pipejmp
, 1);
623 * Set or display a variable value. Syntax is similar to that
635 int bsdset
= value("bsdcompat") != NULL
|| value("bsdset") != NULL
;
641 if (*arglist
== NULL
) {
642 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
643 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
646 ap
= (char **)salloc(s
* sizeof *ap
);
647 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
648 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
652 if (is_a_tty
[0] && is_a_tty
[1] && (cp
= value("crt")) != NULL
) {
653 if (s
> (*cp
== '\0' ? screensize() : atoi(cp
)) + 3) {
655 if (sigsetjmp(pipejmp
, 1))
657 if ((obuf
= Popen(cp
, "w", NULL
, 1)) == NULL
) {
661 safe_signal(SIGPIPE
, onpipe
);
664 for (p
= ap
; *p
!= NULL
; p
++) {
666 fprintf(obuf
, "%s\t%s\n", *p
, value(*p
));
668 if ((cp
= value(*p
)) != NULL
&& *cp
)
669 fprintf(obuf
, "%s=\"%s\"\n",
672 fprintf(obuf
, "%s\n", *p
);
676 if (obuf
!= stdout
) {
677 safe_signal(SIGPIPE
, SIG_IGN
);
679 safe_signal(SIGPIPE
, dflpipe
);
684 for (ap
= arglist
; *ap
!= NULL
; ap
++) {
687 varbuf
= ac_alloc(strlen(*ap
) + 1);
690 while (*cp
!= '=' && *cp
!= '\0')
697 if (equal(varbuf
, "")) {
698 printf(catgets(catd
, CATSET
, 41,
699 "Non-null variable name required\n"));
704 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
705 errs
+= unset_internal(&varbuf
[2]);
714 * Unset a bunch of variable values.
723 for (ap
= (char **)v
; *ap
!= NULL
; ap
++)
724 errs
+= unset_internal(*ap
);
729 * Put add users to a group.
735 struct grouphead
*gh
;
739 char **ap
, *gname
, **p
;
742 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
743 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
746 ap
= (char **)salloc(s
* sizeof *ap
);
747 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
748 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
752 for (p
= ap
; *p
!= NULL
; p
++)
756 if (argv
[1] == NULL
) {
762 if ((gh
= findgroup(gname
)) == NULL
) {
763 gh
= (struct grouphead
*)scalloc(1, sizeof *gh
);
764 gh
->g_name
= vcopy(gname
);
766 gh
->g_link
= groups
[h
];
771 * Insert names from the command list into the group.
772 * Who cares if there are duplicates? They get tossed
776 for (ap
= argv
+1; *ap
!= NULL
; ap
++) {
777 gp
= (struct group
*)scalloc(1, sizeof *gp
);
778 gp
->ge_name
= vcopy(*ap
);
779 gp
->ge_link
= gh
->g_list
;
786 * Delete the passed groups.
794 printf(catgets(catd
, CATSET
, 209,
795 "Must specify alias or group to remove\n"));
800 while (*++argv
!= NULL
);
805 * Sort the passed string vecotor into ascending dictionary
813 for (ap
= list
; *ap
!= NULL
; ap
++)
817 qsort(list
, ap
-list
, sizeof(*list
), diction
);
821 * Do a dictionary order comparison of the arguments from
825 diction(const void *a
, const void *b
)
827 return(strcmp(*(char **)a
, *(char **)b
));
831 * Change to another file. With no argument, print information about
839 if (argv
[0] == NULL
) {
843 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
853 fprintf(stderr
, "Cannot change folder from within a hook.\n");
856 i
= setfile(name
, 0);
859 callhook(mailname
, 0);
860 if (i
> 0 && value("emptystart") == NULL
)
862 announce(value("bsdcompat") != NULL
|| value("bsdannounce") != NULL
);
867 shellecho(const char *cp
)
907 while (n
-- && octalchar(cp
[1]&0377)) {
922 * Expand file names like echo
932 for (ap
= argv
; *ap
!= NULL
; ap
++) {
934 if ((cp
= expand(cp
)) != NULL
) {
937 cflag
|= shellecho(cp
);
948 return (respond_or_Respond('R'))((int *)v
, 0);
954 return (respond_or_Respond('R'))((int *)v
, 1);
958 * Reply to a series of messages by simply mailing to the senders
959 * and not messing around with the To: and Cc: lists as in normal
963 Respond_internal(int *msgvec
, int recipient_record
)
968 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
972 memset(&head
, 0, sizeof head
);
973 for (ap
= msgvec
; *ap
!= 0; ap
++) {
974 mp
= &message
[*ap
- 1];
977 if ((cp
= hfield("reply-to", mp
)) == NULL
)
978 if ((cp
= hfield("from", mp
)) == NULL
)
980 head
.h_to
= cat(head
.h_to
, sextract(cp
, GTO
|gf
));
982 if (head
.h_to
== NULL
)
984 mp
= &message
[msgvec
[0] - 1];
985 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
986 head
.h_subject
= hfield("subj", mp
);
987 head
.h_subject
= reedit(head
.h_subject
);
988 make_ref_and_cs(mp
, &head
);
989 Eflag
= value("skipemptybody") != NULL
;
990 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
991 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
992 mp
->m_flag
|= MANSWER
|MANSWERED
;
997 * Conditional commands. These allow one to parameterize one's
998 * .mailrc and do some things if sending, others if receiving.
1007 printf(catgets(catd
, CATSET
, 42, "Illegal nested \"if\"\n"));
1026 printf(catgets(catd
, CATSET
, 43,
1027 "Unrecognized if-keyword: \"%s\"\n"), cp
);
1034 * Implement 'else'. This is pretty simple -- we just
1035 * flip over the conditional flag.
1044 printf(catgets(catd
, CATSET
, 44,
1045 "\"Else\" without matching \"if\"\n"));
1061 printf(catgets(catd
, CATSET
, 45,
1062 "Mail's idea of conditions is screwed up\n"));
1070 * End of if statement. Just set cond back to anything.
1078 printf(catgets(catd
, CATSET
, 46,
1079 "\"Endif\" without matching \"if\"\n"));
1087 * Set the list of alternate names.
1092 char **namelist
= v
;
1094 char **ap
, **ap2
, *cp
;
1096 c
= argcount(namelist
) + 1;
1100 for (ap
= altnames
; *ap
; ap
++)
1107 altnames
= scalloc(c
, sizeof (char *));
1108 for (ap
= namelist
, ap2
= altnames
; *ap
; ap
++, ap2
++) {
1109 cp
= scalloc(strlen(*ap
) + 1, sizeof (char));
1118 * Do the real work of resending.
1121 resend1(void *v
, int add_resent
)
1126 int f
, *ip
, *msgvec
;
1130 msgvec
= (int *)salloc((msgCount
+ 2) * sizeof *msgvec
);
1131 name
= laststring(str
, &f
, 1);
1133 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
1137 *msgvec
= first(0, MMNORM
);
1141 puts(catgets(catd
, CATSET
, 48,
1142 "No applicable messages."));
1146 } else if (getmsglist(str
, msgvec
, 0) < 0)
1151 printf("No applicable messages.\n");
1154 sn
= nalloc(name
, GTO
);
1156 for (ip
= msgvec
; *ip
&& ip
- msgvec
< msgCount
; ip
++) {
1157 if (resend_msg(&message
[*ip
- 1], to
, add_resent
) != OKAY
)
1164 * Resend a message list to a third person.
1169 return resend1(v
, 1);
1173 * Resend a message list to a third person without adding headers.
1178 return resend1(v
, 0);
1182 * 'newmail' or 'inc' command: Check for new mail without writing old
1191 if ((mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1192 (val
= setfile(mailname
, 1)) == 0) {
1194 setdot(&message
[mdot
- 1]);
1200 list_shortcuts(void)
1204 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1205 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
1211 char **args
= (char **)v
;
1214 if (args
[0] == NULL
) {
1218 if (args
[1] == NULL
) {
1219 fprintf(stderr
, catgets(catd
, CATSET
, 220,
1220 "expansion name for shortcut missing\n"));
1223 if (args
[2] != NULL
) {
1224 fprintf(stderr
, catgets(catd
, CATSET
, 221,
1225 "too many arguments\n"));
1228 if ((s
= get_shortcut(args
[0])) != NULL
) {
1230 s
->sh_long
= sstrdup(args
[1]);
1232 s
= scalloc(1, sizeof *s
);
1233 s
->sh_short
= sstrdup(args
[0]);
1234 s
->sh_long
= sstrdup(args
[1]);
1235 s
->sh_next
= shortcuts
;
1242 get_shortcut(const char *str
)
1246 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1247 if (strcmp(str
, s
->sh_short
) == 0)
1253 delete_shortcut(const char *str
)
1255 struct shortcut
*sp
, *sq
;
1257 for (sp
= shortcuts
, sq
= NULL
; sp
; sq
= sp
, sp
= sp
->sh_next
) {
1258 if (strcmp(sp
->sh_short
, str
) == 0) {
1262 sq
->sh_next
= sp
->sh_next
;
1263 if (sp
== shortcuts
)
1264 shortcuts
= sp
->sh_next
;
1275 char **args
= (char **)v
;
1278 if (args
[0] == NULL
) {
1279 fprintf(stderr
, catgets(catd
, CATSET
, 222,
1280 "need shortcut names to remove\n"));
1283 while (*args
!= NULL
) {
1284 if (delete_shortcut(*args
) != OKAY
) {
1286 fprintf(stderr
, catgets(catd
, CATSET
, 223,
1287 "%s: no such shortcut\n"), *args
);
1295 struct oldaccount
*ac_next
; /* next account in list */
1296 char *ac_name
; /* name of account */
1297 char **ac_vars
; /* variables to set */
1300 static struct oldaccount
*oldaccounts
;
1303 get_oldaccount(const char *name
)
1305 struct oldaccount
*a
;
1307 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1308 if (a
->ac_name
&& strcmp(name
, a
->ac_name
) == 0)
1316 char **args
= (char **)v
;
1317 struct oldaccount
*a
;
1319 int i
, mc
, oqf
, nqf
;
1322 if (args
[0] == NULL
) {
1323 if ((fp
= Ftemp(&cp
, "Ra", "w+", 0600, 1)) == NULL
) {
1329 mc
= listaccounts(fp
);
1330 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1334 fprintf(fp
, "%s:\n", a
->ac_name
);
1335 for (i
= 0; a
->ac_vars
[i
]; i
++)
1336 fprintf(fp
, "\t%s\n", a
->ac_vars
[i
]);
1343 if (args
[1] && args
[1][0] == '{' && args
[1][1] == '\0') {
1344 if (args
[2] != NULL
) {
1345 fprintf(stderr
, "Syntax is: account <name> {\n");
1348 if ((a
= get_oldaccount(args
[0])) != NULL
)
1350 return define1(args
[0], 1);
1352 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
1353 oqf
= savequitflags();
1354 if ((a
= get_oldaccount(args
[0])) == NULL
) {
1356 a
= scalloc(1, sizeof *a
);
1357 a
->ac_next
= oldaccounts
;
1360 if ((i
= callaccount(args
[0])) != CBAD
)
1362 printf("Account %s does not exist.\n", args
[0]);
1367 delaccount(args
[0]);
1368 a
->ac_name
= sstrdup(args
[0]);
1369 for (i
= 1; args
[i
]; i
++);
1370 a
->ac_vars
= scalloc(i
, sizeof *a
->ac_vars
);
1371 for (i
= 0; args
[i
+1]; i
++)
1372 a
->ac_vars
[i
] = sstrdup(args
[i
+1]);
1374 unset_allow_undefined
= 1;
1376 unset_allow_undefined
= 0;
1377 setf
: if (!starting
) {
1378 nqf
= savequitflags();
1379 restorequitflags(oqf
);
1381 restorequitflags(nqf
);
1395 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1396 m
= &message
[*ip
-1];
1398 if ((m
->m_flag
& (MFLAG
|MFLAGGED
)) == 0)
1399 m
->m_flag
|= MFLAG
|MFLAGGED
;
1411 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1412 m
= &message
[*ip
-1];
1414 if (m
->m_flag
& (MFLAG
|MFLAGGED
)) {
1415 m
->m_flag
&= ~(MFLAG
|MFLAGGED
);
1416 m
->m_flag
|= MUNFLAG
;
1429 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1430 m
= &message
[*ip
-1];
1432 if ((m
->m_flag
& (MANSWER
|MANSWERED
)) == 0)
1433 m
->m_flag
|= MANSWER
|MANSWERED
;
1439 cunanswered(void *v
)
1445 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1446 m
= &message
[*ip
-1];
1448 if (m
->m_flag
& (MANSWER
|MANSWERED
)) {
1449 m
->m_flag
&= ~(MANSWER
|MANSWERED
);
1450 m
->m_flag
|= MUNANSWER
;
1463 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1464 m
= &message
[*ip
-1];
1466 if ((m
->m_flag
& (MDRAFT
|MDRAFTED
)) == 0)
1467 m
->m_flag
|= MDRAFT
|MDRAFTED
;
1479 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1480 m
= &message
[*ip
-1];
1482 if (m
->m_flag
& (MDRAFT
|MDRAFTED
)) {
1483 m
->m_flag
&= ~(MDRAFT
|MDRAFTED
);
1484 m
->m_flag
|= MUNDRAFT
;
1495 * This is not perfect, but correct for machines with a 32-bit
1496 * IEEE float and a 32-bit unsigned long, and does at least not
1497 * produce SIGFPE on the Cray Y-MP.
1504 u
.l
= 0xff800000; /* -inf */
1506 #elif defined (INFINITY)
1508 #elif defined (HUGE_VALF)
1510 #elif defined (FLT_MAX)
1524 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1525 m
= &message
[*ip
-1];
1527 m
->m_score
= huge();
1539 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1540 m
= &message
[*ip
-1];
1541 m
->m_flag
&= ~MKILL
;
1552 int f
, *msgvec
, *ip
;
1556 msgvec
= salloc((msgCount
+2) * sizeof *msgvec
);
1557 if ((sscore
= laststring(str
, &f
, 0)) == NULL
) {
1558 fprintf(stderr
, "No score given.\n");
1561 nscore
= strtod(sscore
, &xp
);
1563 fprintf(stderr
, "Invalid score: \"%s\"\n", sscore
);
1566 if (nscore
> FLT_MAX
)
1568 else if (nscore
< -FLT_MAX
)
1571 *msgvec
= first(0, MMNORM
);
1575 fprintf(stderr
, "No messages to score.\n");
1579 } else if (getmsglist(str
, msgvec
, 0) < 0)
1584 fprintf(stderr
, "No applicable messages.\n");
1587 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
1588 m
= &message
[*ip
-1];
1589 if (m
->m_score
!= huge()) {
1590 m
->m_score
+= nscore
;
1593 else if (m
->m_score
> 0)
1594 m
->m_flag
&= ~MKILL
;
1595 if (m
->m_score
>= 0)
1606 switch (mb
.mb_type
) {
1627 if (*args
== NULL
) {
1628 fprintf(stderr
, "Syntax is: remove mailbox ...\n");
1632 if ((name
= expand(*args
)) == NULL
)
1634 if (strcmp(name
, mailname
) == 0) {
1636 "Cannot remove current mailbox \"%s\".\n",
1641 snprintf(vb
, sizeof vb
, "Remove \"%s\" (y/n) ? ", name
);
1644 switch (which_protocol(name
)) {
1646 if (unlink(name
) < 0) { /* do not handle .gz .bz2 */
1652 fprintf(stderr
, "Cannot remove POP3 mailbox \"%s\".\n",
1657 if (imap_remove(name
) != OKAY
)
1661 if (maildir_remove(name
) != OKAY
)
1666 "Unknown protocol in \"%s\". Not removed.\n",
1677 char **args
= v
, *old
, *new;
1678 enum protocol oldp
, newp
;
1681 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1682 fprintf(stderr
, "Syntax: rename old new\n");
1685 old
= expand(args
[0]);
1686 oldp
= which_protocol(old
);
1687 new = expand(args
[1]);
1688 newp
= which_protocol(new);
1689 if (strcmp(old
, mailname
) == 0 || strcmp(new, mailname
) == 0) {
1690 fprintf(stderr
, "Cannot rename current mailbox \"%s\".\n", old
);
1693 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1694 fprintf(stderr
, "Can only rename folders of same type.\n");
1697 if (newp
== PROTO_POP3
)
1701 if (link(old
, new) < 0) {
1715 } else if (unlink(old
) < 0) {
1721 if (rename(old
, new) < 0) {
1727 nopop3
: fprintf(stderr
, "Cannot rename POP3 mailboxes.\n");
1731 if (imap_rename(old
, new) != OKAY
)
1735 fprintf(stderr
, "Unknown protocol in \"%s\" and \"%s\". "
1736 "Not renamed.\n", old
, new);