2 * S-nail - 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
48 * Mail -- a mail program
50 * Still more user commands.
53 static int bangexp(char **str
, size_t *size
);
54 static void make_ref_and_cs(struct message
*mp
, struct header
*head
);
55 static int (*respond_or_Respond(int c
))(int *, int);
56 static int respond_internal(int *msgvec
, int recipient_record
);
57 static char *reedit(char *subj
);
58 static char *fwdedit(char *subj
);
59 static void onpipe(int signo
);
60 static void asort(char **list
);
61 static int diction(const void *a
, const void *b
);
62 static int file1(char *name
);
63 static int shellecho(const char *cp
);
64 static int Respond_internal(int *msgvec
, int recipient_record
);
65 static int resend1(void *v
, int add_resent
);
66 static void list_shortcuts(void);
67 static enum okay
delete_shortcut(const char *str
);
68 static float huge(void);
71 * Process a shell escape by saving signals, ignoring signals,
78 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
83 cmd
= smalloc(cmdsize
= strlen(str
) + 1);
85 if (bangexp(&cmd
, &cmdsize
) < 0)
87 if ((shell
= value("SHELL")) == NULL
)
89 run_command(shell
, 0, -1, -1, "-c", cmd
, NULL
);
90 safe_signal(SIGINT
, sigint
);
97 * Fork an interactive shell.
103 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
107 if ((shell
= value("SHELL")) == NULL
)
109 run_command(shell
, 0, -1, -1, NULL
, NULL
, NULL
);
110 safe_signal(SIGINT
, sigint
);
116 * Expand the shell escape by expanding unescaped !'s into the
117 * last issued command where possible.
120 static char *lastbang
;
121 static size_t lastbangsize
;
124 bangexp(char **str
, size_t *size
)
128 int dobang
= value("bang") != NULL
;
129 size_t sz
, i
, j
, bangbufsize
;
131 bangbuf
= smalloc(bangbufsize
= *size
);
135 if ((*str
)[i
] == '!') {
136 sz
= strlen(lastbang
);
137 bangbuf
= srealloc(bangbuf
, bangbufsize
+= sz
);
139 strcpy(&bangbuf
[j
], lastbang
);
145 if ((*str
)[i
] == '\\' && (*str
)[i
+ 1] == '!') {
150 bangbuf
[j
++] = (*str
)[i
++];
154 printf("!%s\n", bangbuf
);
159 *str
= srealloc(*str
, *size
= sz
+ 1);
160 strcpy(*str
, bangbuf
);
161 if (sz
>= lastbangsize
)
162 lastbang
= srealloc(lastbang
, lastbangsize
= sz
+ 1);
163 strcpy(lastbang
, bangbuf
);
173 /* Very ugly, but take care for compiler supported string lengths :( */
178 "type <message list> type messages\n"
179 "next goto and type next message\n"
180 "from <message list> give head lines of messages\n"
181 "headers print out active message headers\n"
182 "delete <message list> delete messages\n"
183 "undelete <message list> undelete messages\n");
185 "save <message list> folder append messages to folder and mark as saved\n"
186 "copy <message list> folder append messages to folder without marking them\n"
187 "write <message list> file append message texts to file, save attachments\n"
188 "preserve <message list> keep incoming messages in mailbox even if saved\n"
189 "Reply <message list> reply to message senders\n"
190 "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 "\nA <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",
207 * Change user's working directory.
215 if (*arglist
== NULL
)
218 if ((cp
= file_expand(*arglist
)) == NULL
)
228 make_ref_and_cs(struct message
*mp
, struct header
*head
)
230 char *oldref
, *oldmsgid
, *newref
, *cp
;
235 oldref
= hfield1("references", mp
);
236 oldmsgid
= hfield1("message-id", mp
);
237 if (oldmsgid
== NULL
|| *oldmsgid
== '\0') {
243 reflen
+= strlen(oldref
) + 2;
245 reflen
+= strlen(oldmsgid
);
246 newref
= ac_alloc(reflen
);
248 strcpy(newref
, oldref
);
250 strcat(newref
, ", ");
251 strcat(newref
, oldmsgid
);
254 strcpy(newref
, oldmsgid
);
255 n
= extract(newref
, GREF
);
258 * Limit the references to 21 entries.
260 while (n
->n_flink
!= NULL
)
262 for (i
= 1; i
< 21; i
++) {
263 if (n
->n_blink
!= NULL
)
270 if (value("reply-in-same-charset") != NULL
&&
271 (cp
= hfield1("content-type", mp
)) != NULL
)
272 head
->h_charset
= mime_getparam("charset", cp
);
276 (*respond_or_Respond(int c
))(int *, int)
280 opt
+= (value("Replyall") != NULL
);
281 opt
+= (value("flipr") != NULL
);
282 return ((opt
== 1) ^ (c
== 'R')) ? Respond_internal
: respond_internal
;
288 return (respond_or_Respond('r'))((int *)v
, 0);
294 return respond_internal((int *)v
, 0);
298 respondsender(void *v
)
300 return Respond_internal((int *)v
, 0);
306 return (respond_or_Respond('r'))((int *)v
, 1);
312 return respond_internal((int *)v
, 1);
316 followupsender(void *v
)
318 return Respond_internal((int *)v
, 1);
322 * Reply to a list of messages. Extract each name from the
323 * message header and send them off to mail1()
326 respond_internal(int *msgvec
, int recipient_record
)
331 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
332 struct name
*np
= NULL
;
335 memset(&head
, 0, sizeof head
);
336 if (msgvec
[1] != 0) {
337 printf(catgets(catd
, CATSET
, 37,
338 "Sorry, can't reply to multiple messages at once\n"));
341 mp
= &message
[msgvec
[0] - 1];
344 if ((rcv
= hfield1("reply-to", mp
)) == NULL
)
345 if ((rcv
= hfield1("from", mp
)) == NULL
)
348 np
= sextract(rcv
, GTO
|gf
);
349 if (! value("recipients-in-cc") && (cp
= hfield1("to", mp
)) != NULL
)
350 np
= cat(np
, sextract(cp
, GTO
|gf
));
353 * Delete my name from the reply list,
354 * and with it, all my alternate names.
356 np
= delete_alternates(np
);
358 np
= sextract(rcv
, GTO
|gf
);
360 head
.h_subject
= hfield1("subject", mp
);
361 head
.h_subject
= reedit(head
.h_subject
);
364 if (value("recipients-in-cc") && (cp
= hfield1("to", mp
)) != NULL
)
365 np
= sextract(cp
, GCC
|gf
);
366 if ((cp
= hfield1("cc", mp
)) != NULL
)
367 np
= cat(np
, sextract(cp
, GCC
|gf
));
369 head
.h_cc
= elide(delete_alternates(np
));
370 make_ref_and_cs(mp
, &head
);
371 Eflag
= value("skipemptybody") != NULL
;
372 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
373 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
374 mp
->m_flag
|= MANSWER
|MANSWERED
;
379 * Modify the subject we are replying to to begin with Re: if
380 * it does not already.
388 if (subj
== NULL
|| *subj
== '\0')
392 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
393 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
394 (out
.s
[1] == 'e' || out
.s
[1] == 'E') &&
397 newsubj
= salloc(out
.l
+ 5);
398 strcpy(newsubj
, "Re: ");
399 strcpy(newsubj
+ 4, out
.s
);
404 * Forward a message to a new recipient, in the sense of RFC 2822.
407 forward1(char *str
, int recipient_record
)
414 int forward_as_attachment
;
416 forward_as_attachment
= value("forward-as-attachment") != NULL
;
417 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
418 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
419 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
423 *msgvec
= first(0, MMNORM
);
427 printf("No messages to forward.\n");
432 if (f
&& getmsglist(str
, msgvec
, 0) < 0)
437 printf("No applicable messages.\n");
440 if (msgvec
[1] != 0) {
441 printf("Cannot forward multiple messages at once\n");
444 memset(&head
, 0, sizeof head
);
445 if ((head
.h_to
= sextract(recipient
,
446 GTO
| (value("fullnames") ? GFULL
: GSKIN
))) == NULL
)
448 mp
= &message
[*msgvec
- 1];
449 if (forward_as_attachment
) {
450 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
451 head
.h_attach
->a_msgno
= *msgvec
;
456 head
.h_subject
= hfield1("subject", mp
);
457 head
.h_subject
= fwdedit(head
.h_subject
);
458 Eflag
= value("skipemptybody") != NULL
;
459 mail1(&head
, 1, forward_as_attachment
? NULL
: mp
,
460 NULL
, recipient_record
, 1, 0, Eflag
);
465 * Modify the subject we are replying to to begin with Fwd:.
473 if (subj
== NULL
|| *subj
== '\0')
477 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
478 newsubj
= salloc(strlen(out
.s
) + 6);
479 strcpy(newsubj
, "Fwd: ");
480 strcpy(&newsubj
[5], out
.s
);
486 * The 'forward' command.
491 return forward1(v
, 0);
495 * Similar to forward, saving the message in a file named after the
501 return forward1(v
, 1);
505 * Preserve the named messages, so that they will be sent
506 * back to the system mailbox.
516 printf(catgets(catd
, CATSET
, 39,
517 "Cannot \"preserve\" in edit mode\n"));
520 for (ip
= msgvec
; *ip
!= 0; ip
++) {
522 mp
= &message
[mesg
-1];
523 mp
->m_flag
|= MPRESERVE
;
527 * This is now Austin Group Request XCU #20.
535 * Mark all given messages as unread.
543 for (ip
= msgvec
; *ip
!= 0; ip
++) {
544 setdot(&message
[*ip
-1]);
545 dot
->m_flag
&= ~(MREAD
|MTOUCH
);
546 dot
->m_flag
|= MSTATUS
;
547 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
548 imap_unread(&message
[*ip
-1], *ip
);
550 * The "unread" command is not part of POSIX mailx.
558 * Mark all given messages as read.
566 for (ip
= msgvec
; *ip
; ip
++) {
567 setdot(&message
[*ip
-1]);
568 touch(&message
[*ip
-1]);
574 * Print the size of each message.
583 for (ip
= msgvec
; *ip
!= 0; ip
++) {
585 mp
= &message
[mesg
-1];
586 printf("%d: ", mesg
);
587 if (mp
->m_xlines
> 0)
588 printf("%ld", mp
->m_xlines
);
591 printf("/%lu\n", (unsigned long)mp
->m_xsize
);
597 * Quit quickly. If we are sourcing, just pop the input level
598 * by returning an error.
611 static sigjmp_buf pipejmp
;
618 siglongjmp(pipejmp
, 1);
622 * Set or display a variable value. Syntax is similar to that
633 FILE *volatile obuf
= stdout
;
634 int volatile bsdset
= (value("bsdcompat") != NULL
||
635 value("bsdset") != NULL
);
637 if (*arglist
== NULL
) {
638 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
639 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
642 ap
= (char **)salloc(s
* sizeof *ap
);
643 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
644 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
648 if (is_a_tty
[0] && is_a_tty
[1] && (cp
= value("crt")) != NULL
) {
649 if (s
> (*cp
== '\0' ? screensize() : atoi(cp
)) + 3) {
651 /* TODO should be below the Popen?
652 * TODO Problem: Popen doesn't encapsulate it,
653 * TODO may leave child run if fdopen() fails!
654 * TODO even more such stuff in this file! */
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 (strcmp(varbuf
, "") == 0) {
698 printf(tr(41, "Non-null variable name required\n"));
703 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
704 errs
+= unset_internal(&varbuf
[2]);
713 * Unset a bunch of variable values.
722 for (ap
= (char **)v
; *ap
!= NULL
; ap
++)
723 errs
+= unset_internal(*ap
);
728 * Put add users to a group.
734 struct grouphead
*gh
;
738 char **ap
, *gname
, **p
;
741 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
742 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
745 ap
= (char **)salloc(s
* sizeof *ap
);
746 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
747 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
751 for (p
= ap
; *p
!= NULL
; p
++)
755 if (argv
[1] == NULL
) {
761 if ((gh
= findgroup(gname
)) == NULL
) {
762 gh
= (struct grouphead
*)scalloc(1, sizeof *gh
);
763 gh
->g_name
= vcopy(gname
);
765 gh
->g_link
= groups
[h
];
770 * Insert names from the command list into the group.
771 * Who cares if there are duplicates? They get tossed
775 for (ap
= argv
+1; *ap
!= NULL
; ap
++) {
776 gp
= (struct group
*)scalloc(1, sizeof *gp
);
777 gp
->ge_name
= vcopy(*ap
);
778 gp
->ge_link
= gh
->g_list
;
785 * Delete the passed groups.
793 printf(catgets(catd
, CATSET
, 209,
794 "Must specify alias or group to remove\n"));
799 while (*++argv
!= NULL
);
804 * Sort the passed string vecotor into ascending dictionary
812 for (ap
= list
; *ap
!= NULL
; ap
++)
816 qsort(list
, ap
-list
, sizeof(*list
), diction
);
820 * Do a dictionary order comparison of the arguments from
824 diction(const void *a
, const void *b
)
826 return(strcmp(*(char **)a
, *(char **)b
));
830 * Change to another file. With no argument, print information about
838 if (argv
[0] == NULL
) {
842 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
852 fprintf(stderr
, "Cannot change folder from within a hook.\n");
855 i
= setfile(name
, 0);
858 callhook(mailname
, 0);
859 if (i
> 0 && value("emptystart") == NULL
)
861 announce(value("bsdcompat") != NULL
|| value("bsdannounce") != NULL
);
866 shellecho(const char *cp
)
906 while (n
-- && octalchar(cp
[1]&0377)) {
921 * Expand file names like echo
931 for (ap
= argv
; *ap
!= NULL
; ap
++) {
933 if ((cp
= expand(cp
)) != NULL
) {
936 cflag
|= shellecho(cp
);
947 return (respond_or_Respond('R'))((int *)v
, 0);
953 return (respond_or_Respond('R'))((int *)v
, 1);
957 * Reply to a series of messages by simply mailing to the senders
958 * and not messing around with the To: and Cc: lists as in normal
962 Respond_internal(int *msgvec
, int recipient_record
)
967 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
971 memset(&head
, 0, sizeof head
);
972 for (ap
= msgvec
; *ap
!= 0; ap
++) {
973 mp
= &message
[*ap
- 1];
976 if ((cp
= hfield1("reply-to", mp
)) == NULL
)
977 if ((cp
= hfield1("from", mp
)) == NULL
)
979 head
.h_to
= cat(head
.h_to
, sextract(cp
, GTO
|gf
));
981 if (head
.h_to
== NULL
)
983 mp
= &message
[msgvec
[0] - 1];
984 head
.h_subject
= hfield1("subject", mp
);
985 head
.h_subject
= reedit(head
.h_subject
);
986 make_ref_and_cs(mp
, &head
);
987 Eflag
= value("skipemptybody") != NULL
;
988 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
989 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
990 mp
->m_flag
|= MANSWER
|MANSWERED
;
995 * Conditional commands. These allow one to parameterize one's
996 * .mailrc and do some things if sending, others if receiving.
1005 printf(catgets(catd
, CATSET
, 42, "Illegal nested \"if\"\n"));
1024 printf(catgets(catd
, CATSET
, 43,
1025 "Unrecognized if-keyword: \"%s\"\n"), cp
);
1032 * Implement 'else'. This is pretty simple -- we just
1033 * flip over the conditional flag.
1043 printf(catgets(catd
, CATSET
, 44,
1044 "\"Else\" without matching \"if\"\n"));
1060 printf(catgets(catd
, CATSET
, 45,
1061 "Mail's idea of conditions is screwed up\n"));
1069 * 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
1192 if ((mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1193 (val
= setfile(mailname
, 1)) == 0) {
1195 setdot(&message
[mdot
- 1]);
1201 list_shortcuts(void)
1205 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1206 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
1212 char **args
= (char **)v
;
1215 if (args
[0] == NULL
) {
1219 if (args
[1] == NULL
) {
1220 fprintf(stderr
, catgets(catd
, CATSET
, 220,
1221 "expansion name for shortcut missing\n"));
1224 if (args
[2] != NULL
) {
1225 fprintf(stderr
, catgets(catd
, CATSET
, 221,
1226 "too many arguments\n"));
1229 if ((s
= get_shortcut(args
[0])) != NULL
) {
1231 s
->sh_long
= sstrdup(args
[1]);
1233 s
= scalloc(1, sizeof *s
);
1234 s
->sh_short
= sstrdup(args
[0]);
1235 s
->sh_long
= sstrdup(args
[1]);
1236 s
->sh_next
= shortcuts
;
1243 get_shortcut(const char *str
)
1247 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1248 if (strcmp(str
, s
->sh_short
) == 0)
1254 delete_shortcut(const char *str
)
1256 struct shortcut
*sp
, *sq
;
1258 for (sp
= shortcuts
, sq
= NULL
; sp
; sq
= sp
, sp
= sp
->sh_next
) {
1259 if (strcmp(sp
->sh_short
, str
) == 0) {
1263 sq
->sh_next
= sp
->sh_next
;
1264 if (sp
== shortcuts
)
1265 shortcuts
= sp
->sh_next
;
1276 char **args
= (char **)v
;
1279 if (args
[0] == NULL
) {
1280 fprintf(stderr
, catgets(catd
, CATSET
, 222,
1281 "need shortcut names to remove\n"));
1284 while (*args
!= NULL
) {
1285 if (delete_shortcut(*args
) != OKAY
) {
1287 fprintf(stderr
, catgets(catd
, CATSET
, 223,
1288 "%s: no such shortcut\n"), *args
);
1296 struct oldaccount
*ac_next
; /* next account in list */
1297 char *ac_name
; /* name of account */
1298 char **ac_vars
; /* variables to set */
1301 static struct oldaccount
*oldaccounts
;
1304 get_oldaccount(const char *name
)
1306 struct oldaccount
*a
;
1308 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1309 if (a
->ac_name
&& strcmp(name
, a
->ac_name
) == 0)
1317 char **args
= (char **)v
;
1318 struct oldaccount
*a
;
1320 int i
, mc
, oqf
, nqf
;
1323 if (args
[0] == NULL
) {
1324 if ((fp
= Ftemp(&cp
, "Ra", "w+", 0600, 1)) == NULL
) {
1330 mc
= listaccounts(fp
);
1331 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1335 fprintf(fp
, "%s:\n", a
->ac_name
);
1336 for (i
= 0; a
->ac_vars
[i
]; i
++)
1337 fprintf(fp
, "\t%s\n", a
->ac_vars
[i
]);
1344 if (args
[1] && args
[1][0] == '{' && args
[1][1] == '\0') {
1345 if (args
[2] != NULL
) {
1346 fprintf(stderr
, "Syntax is: account <name> {\n");
1349 if ((a
= get_oldaccount(args
[0])) != NULL
)
1351 return define1(args
[0], 1);
1353 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
1354 oqf
= savequitflags();
1355 if ((a
= get_oldaccount(args
[0])) == NULL
) {
1357 a
= scalloc(1, sizeof *a
);
1358 a
->ac_next
= oldaccounts
;
1361 if ((i
= callaccount(args
[0])) != CBAD
)
1363 printf("Account %s does not exist.\n", args
[0]);
1368 delaccount(args
[0]);
1369 a
->ac_name
= sstrdup(args
[0]);
1370 for (i
= 1; args
[i
]; i
++);
1371 a
->ac_vars
= scalloc(i
, sizeof *a
->ac_vars
);
1372 for (i
= 0; args
[i
+1]; i
++)
1373 a
->ac_vars
[i
] = sstrdup(args
[i
+1]);
1375 unset_allow_undefined
= 1;
1377 unset_allow_undefined
= 0;
1378 setf
: if (!starting
) {
1379 nqf
= savequitflags();
1380 restorequitflags(oqf
);
1382 restorequitflags(nqf
);
1396 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1397 m
= &message
[*ip
-1];
1399 if ((m
->m_flag
& (MFLAG
|MFLAGGED
)) == 0)
1400 m
->m_flag
|= MFLAG
|MFLAGGED
;
1412 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1413 m
= &message
[*ip
-1];
1415 if (m
->m_flag
& (MFLAG
|MFLAGGED
)) {
1416 m
->m_flag
&= ~(MFLAG
|MFLAGGED
);
1417 m
->m_flag
|= MUNFLAG
;
1430 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1431 m
= &message
[*ip
-1];
1433 if ((m
->m_flag
& (MANSWER
|MANSWERED
)) == 0)
1434 m
->m_flag
|= MANSWER
|MANSWERED
;
1440 cunanswered(void *v
)
1446 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1447 m
= &message
[*ip
-1];
1449 if (m
->m_flag
& (MANSWER
|MANSWERED
)) {
1450 m
->m_flag
&= ~(MANSWER
|MANSWERED
);
1451 m
->m_flag
|= MUNANSWER
;
1464 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1465 m
= &message
[*ip
-1];
1467 if ((m
->m_flag
& (MDRAFT
|MDRAFTED
)) == 0)
1468 m
->m_flag
|= MDRAFT
|MDRAFTED
;
1480 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1481 m
= &message
[*ip
-1];
1483 if (m
->m_flag
& (MDRAFT
|MDRAFTED
)) {
1484 m
->m_flag
&= ~(MDRAFT
|MDRAFTED
);
1485 m
->m_flag
|= MUNDRAFT
;
1496 * This is not perfect, but correct for machines with a 32-bit
1497 * IEEE float and a 32-bit unsigned long, and does at least not
1498 * produce SIGFPE on the Cray Y-MP.
1505 u
.l
= 0xff800000; /* -inf */
1507 #elif defined (INFINITY)
1509 #elif defined (HUGE_VALF)
1511 #elif defined (FLT_MAX)
1525 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1526 m
= &message
[*ip
-1];
1528 m
->m_score
= huge();
1540 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1541 m
= &message
[*ip
-1];
1542 m
->m_flag
&= ~MKILL
;
1553 int f
, *msgvec
, *ip
;
1557 msgvec
= salloc((msgCount
+2) * sizeof *msgvec
);
1558 if ((sscore
= laststring(str
, &f
, 0)) == NULL
) {
1559 fprintf(stderr
, "No score given.\n");
1562 nscore
= strtod(sscore
, &xp
);
1564 fprintf(stderr
, "Invalid score: \"%s\"\n", sscore
);
1567 if (nscore
> FLT_MAX
)
1569 else if (nscore
< -FLT_MAX
)
1572 *msgvec
= first(0, MMNORM
);
1576 fprintf(stderr
, "No messages to score.\n");
1580 } else if (getmsglist(str
, msgvec
, 0) < 0)
1585 fprintf(stderr
, "No applicable messages.\n");
1588 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
1589 m
= &message
[*ip
-1];
1590 if (m
->m_score
!= huge()) {
1591 m
->m_score
+= nscore
;
1594 else if (m
->m_score
> 0)
1595 m
->m_flag
&= ~MKILL
;
1596 if (m
->m_score
>= 0)
1609 switch (mb
.mb_type
) {
1630 if (*args
== NULL
) {
1631 fprintf(stderr
, "Syntax is: remove mailbox ...\n");
1635 if ((name
= expand(*args
)) == NULL
)
1637 if (strcmp(name
, mailname
) == 0) {
1639 "Cannot remove current mailbox \"%s\".\n",
1644 snprintf(vb
, sizeof vb
, "Remove \"%s\" (y/n) ? ", name
);
1647 switch (which_protocol(name
)) {
1649 if (unlink(name
) < 0) { /* do not handle .gz .bz2 */
1655 fprintf(stderr
, "Cannot remove POP3 mailbox \"%s\".\n",
1660 if (imap_remove(name
) != OKAY
)
1664 if (maildir_remove(name
) != OKAY
)
1669 "Unknown protocol in \"%s\". Not removed.\n",
1680 char **args
= v
, *old
, *new;
1681 enum protocol oldp
, newp
;
1684 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1685 fprintf(stderr
, "Syntax: rename old new\n");
1688 old
= expand(args
[0]);
1689 oldp
= which_protocol(old
);
1690 new = expand(args
[1]);
1691 newp
= which_protocol(new);
1692 if (strcmp(old
, mailname
) == 0 || strcmp(new, mailname
) == 0) {
1693 fprintf(stderr
, "Cannot rename current mailbox \"%s\".\n", old
);
1696 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1697 fprintf(stderr
, "Can only rename folders of same type.\n");
1700 if (newp
== PROTO_POP3
)
1704 if (link(old
, new) < 0) {
1718 } else if (unlink(old
) < 0) {
1724 if (rename(old
, new) < 0) {
1730 nopop3
: fprintf(stderr
, "Cannot rename POP3 mailboxes.\n");
1734 if (imap_rename(old
, new) != OKAY
)
1738 fprintf(stderr
, "Unknown protocol in \"%s\" and \"%s\". "
1739 "Not renamed.\n", old
, new);