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
= expand(*arglist
)) == NULL
)
228 make_ref_and_cs(struct message
*mp
, struct header
*head
)
230 char *oldref
, *oldmsgid
, *newref
, *cp
;
235 oldref
= hfield("references", mp
);
236 oldmsgid
= hfield("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
= hfield("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
= hfield("reply-to", mp
)) == NULL
)
345 if ((rcv
= hfield("from", mp
)) == NULL
)
348 np
= sextract(rcv
, GTO
|gf
);
349 if (! value("recipients-in-cc") && (cp
= hfield("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 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
361 head
.h_subject
= hfield("subj", mp
);
362 head
.h_subject
= reedit(head
.h_subject
);
365 if (value("recipients-in-cc") && (cp
= hfield("to", mp
)) != NULL
)
366 np
= sextract(cp
, GCC
|gf
);
367 if ((cp
= hfield("cc", mp
)) != NULL
)
368 np
= cat(np
, sextract(cp
, GCC
|gf
));
370 head
.h_cc
= elide(delete_alternates(np
));
371 make_ref_and_cs(mp
, &head
);
372 Eflag
= value("skipemptybody") != NULL
;
373 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
374 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
375 mp
->m_flag
|= MANSWER
|MANSWERED
;
380 * Modify the subject we are replying to to begin with Re: if
381 * it does not already.
389 if (subj
== NULL
|| *subj
== '\0')
393 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
394 if ((out
.s
[0] == 'r' || out
.s
[0] == 'R') &&
395 (out
.s
[1] == 'e' || out
.s
[1] == 'E') &&
398 newsubj
= salloc(out
.l
+ 5);
399 strcpy(newsubj
, "Re: ");
400 strcpy(newsubj
+ 4, out
.s
);
405 * Forward a message to a new recipient, in the sense of RFC 2822.
408 forward1(char *str
, int recipient_record
)
415 int forward_as_attachment
;
417 forward_as_attachment
= value("forward-as-attachment") != NULL
;
418 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
419 if ((recipient
= laststring(str
, &f
, 0)) == NULL
) {
420 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
424 *msgvec
= first(0, MMNORM
);
428 printf("No messages to forward.\n");
433 if (f
&& getmsglist(str
, msgvec
, 0) < 0)
438 printf("No applicable messages.\n");
441 if (msgvec
[1] != 0) {
442 printf("Cannot forward multiple messages at once\n");
445 memset(&head
, 0, sizeof head
);
446 if ((head
.h_to
= sextract(recipient
,
447 GTO
| (value("fullnames") ? GFULL
: GSKIN
))) == NULL
)
449 mp
= &message
[*msgvec
- 1];
450 if (forward_as_attachment
) {
451 head
.h_attach
= csalloc(1, sizeof *head
.h_attach
);
452 head
.h_attach
->a_msgno
= *msgvec
;
457 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
458 head
.h_subject
= hfield("subj", mp
);
459 head
.h_subject
= fwdedit(head
.h_subject
);
460 Eflag
= value("skipemptybody") != NULL
;
461 mail1(&head
, 1, forward_as_attachment
? NULL
: mp
,
462 NULL
, recipient_record
, 1, 0, Eflag
);
467 * Modify the subject we are replying to to begin with Fwd:.
475 if (subj
== NULL
|| *subj
== '\0')
479 mime_fromhdr(&in
, &out
, TD_ISPR
|TD_ICONV
);
480 newsubj
= salloc(strlen(out
.s
) + 6);
481 strcpy(newsubj
, "Fwd: ");
482 strcpy(&newsubj
[5], out
.s
);
488 * The 'forward' command.
493 return forward1(v
, 0);
497 * Similar to forward, saving the message in a file named after the
503 return forward1(v
, 1);
507 * Preserve the named messages, so that they will be sent
508 * back to the system mailbox.
518 printf(catgets(catd
, CATSET
, 39,
519 "Cannot \"preserve\" in edit mode\n"));
522 for (ip
= msgvec
; *ip
!= 0; ip
++) {
524 mp
= &message
[mesg
-1];
525 mp
->m_flag
|= MPRESERVE
;
529 * This is now Austin Group Request XCU #20.
537 * Mark all given messages as unread.
545 for (ip
= msgvec
; *ip
!= 0; ip
++) {
546 setdot(&message
[*ip
-1]);
547 dot
->m_flag
&= ~(MREAD
|MTOUCH
);
548 dot
->m_flag
|= MSTATUS
;
549 if (mb
.mb_type
== MB_IMAP
|| mb
.mb_type
== MB_CACHE
)
550 imap_unread(&message
[*ip
-1], *ip
);
552 * The "unread" command is not part of POSIX mailx.
560 * Mark all given messages as read.
568 for (ip
= msgvec
; *ip
; ip
++) {
569 setdot(&message
[*ip
-1]);
570 touch(&message
[*ip
-1]);
576 * Print the size of each message.
585 for (ip
= msgvec
; *ip
!= 0; ip
++) {
587 mp
= &message
[mesg
-1];
588 printf("%d: ", mesg
);
589 if (mp
->m_xlines
> 0)
590 printf("%ld", mp
->m_xlines
);
593 printf("/%lu\n", (unsigned long)mp
->m_xsize
);
599 * Quit quickly. If we are sourcing, just pop the input level
600 * by returning an error.
613 static sigjmp_buf pipejmp
;
620 siglongjmp(pipejmp
, 1);
624 * Set or display a variable value. Syntax is similar to that
636 int bsdset
= value("bsdcompat") != NULL
|| value("bsdset") != NULL
;
638 if (*arglist
== NULL
) {
639 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
640 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
643 ap
= (char **)salloc(s
* sizeof *ap
);
644 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
645 for (vp
= variables
[h
]; vp
!= NULL
; vp
= vp
->v_link
)
649 if (is_a_tty
[0] && is_a_tty
[1] && (cp
= value("crt")) != NULL
) {
650 if (s
> (*cp
== '\0' ? screensize() : atoi(cp
)) + 3) {
652 /* TODO should be below the Popen?
653 * TODO Problem: Popen doesn't encapsulate it,
654 * TODO may leave child run if fdopen() fails!
655 * TODO even more such stuff in this file! */
656 if (sigsetjmp(pipejmp
, 1))
658 if ((obuf
= Popen(cp
, "w", NULL
, 1)) == NULL
) {
662 safe_signal(SIGPIPE
, onpipe
);
665 for (p
= ap
; *p
!= NULL
; p
++) {
667 fprintf(obuf
, "%s\t%s\n", *p
, value(*p
));
669 if ((cp
= value(*p
)) != NULL
&& *cp
)
670 fprintf(obuf
, "%s=\"%s\"\n",
673 fprintf(obuf
, "%s\n", *p
);
677 if (obuf
!= stdout
) {
678 safe_signal(SIGPIPE
, SIG_IGN
);
680 safe_signal(SIGPIPE
, dflpipe
);
685 for (ap
= arglist
; *ap
!= NULL
; ap
++) {
688 varbuf
= ac_alloc(strlen(*ap
) + 1);
691 while (*cp
!= '=' && *cp
!= '\0')
698 if (equal(varbuf
, "")) {
699 printf(catgets(catd
, CATSET
, 41,
700 "Non-null variable name required\n"));
705 if (varbuf
[0] == 'n' && varbuf
[1] == 'o')
706 errs
+= unset_internal(&varbuf
[2]);
715 * Unset a bunch of variable values.
724 for (ap
= (char **)v
; *ap
!= NULL
; ap
++)
725 errs
+= unset_internal(*ap
);
730 * Put add users to a group.
736 struct grouphead
*gh
;
740 char **ap
, *gname
, **p
;
743 for (h
= 0, s
= 1; h
< HSHSIZE
; h
++)
744 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
747 ap
= (char **)salloc(s
* sizeof *ap
);
748 for (h
= 0, p
= ap
; h
< HSHSIZE
; h
++)
749 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
)
753 for (p
= ap
; *p
!= NULL
; p
++)
757 if (argv
[1] == NULL
) {
763 if ((gh
= findgroup(gname
)) == NULL
) {
764 gh
= (struct grouphead
*)scalloc(1, sizeof *gh
);
765 gh
->g_name
= vcopy(gname
);
767 gh
->g_link
= groups
[h
];
772 * Insert names from the command list into the group.
773 * Who cares if there are duplicates? They get tossed
777 for (ap
= argv
+1; *ap
!= NULL
; ap
++) {
778 gp
= (struct group
*)scalloc(1, sizeof *gp
);
779 gp
->ge_name
= vcopy(*ap
);
780 gp
->ge_link
= gh
->g_list
;
787 * Delete the passed groups.
795 printf(catgets(catd
, CATSET
, 209,
796 "Must specify alias or group to remove\n"));
801 while (*++argv
!= NULL
);
806 * Sort the passed string vecotor into ascending dictionary
814 for (ap
= list
; *ap
!= NULL
; ap
++)
818 qsort(list
, ap
-list
, sizeof(*list
), diction
);
822 * Do a dictionary order comparison of the arguments from
826 diction(const void *a
, const void *b
)
828 return(strcmp(*(char **)a
, *(char **)b
));
832 * Change to another file. With no argument, print information about
840 if (argv
[0] == NULL
) {
844 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
854 fprintf(stderr
, "Cannot change folder from within a hook.\n");
857 i
= setfile(name
, 0);
860 callhook(mailname
, 0);
861 if (i
> 0 && value("emptystart") == NULL
)
863 announce(value("bsdcompat") != NULL
|| value("bsdannounce") != NULL
);
868 shellecho(const char *cp
)
908 while (n
-- && octalchar(cp
[1]&0377)) {
923 * Expand file names like echo
933 for (ap
= argv
; *ap
!= NULL
; ap
++) {
935 if ((cp
= expand(cp
)) != NULL
) {
938 cflag
|= shellecho(cp
);
949 return (respond_or_Respond('R'))((int *)v
, 0);
955 return (respond_or_Respond('R'))((int *)v
, 1);
959 * Reply to a series of messages by simply mailing to the senders
960 * and not messing around with the To: and Cc: lists as in normal
964 Respond_internal(int *msgvec
, int recipient_record
)
969 enum gfield gf
= value("fullnames") ? GFULL
: GSKIN
;
973 memset(&head
, 0, sizeof head
);
974 for (ap
= msgvec
; *ap
!= 0; ap
++) {
975 mp
= &message
[*ap
- 1];
978 if ((cp
= hfield("reply-to", mp
)) == NULL
)
979 if ((cp
= hfield("from", mp
)) == NULL
)
981 head
.h_to
= cat(head
.h_to
, sextract(cp
, GTO
|gf
));
983 if (head
.h_to
== NULL
)
985 mp
= &message
[msgvec
[0] - 1];
986 if ((head
.h_subject
= hfield("subject", mp
)) == NULL
)
987 head
.h_subject
= hfield("subj", mp
);
988 head
.h_subject
= reedit(head
.h_subject
);
989 make_ref_and_cs(mp
, &head
);
990 Eflag
= value("skipemptybody") != NULL
;
991 if (mail1(&head
, 1, mp
, NULL
, recipient_record
, 0, 0, Eflag
) == OKAY
&&
992 value("markanswered") && (mp
->m_flag
& MANSWERED
) == 0)
993 mp
->m_flag
|= MANSWER
|MANSWERED
;
998 * Conditional commands. These allow one to parameterize one's
999 * .mailrc and do some things if sending, others if receiving.
1008 printf(catgets(catd
, CATSET
, 42, "Illegal nested \"if\"\n"));
1027 printf(catgets(catd
, CATSET
, 43,
1028 "Unrecognized if-keyword: \"%s\"\n"), cp
);
1035 * Implement 'else'. This is pretty simple -- we just
1036 * flip over the conditional flag.
1046 printf(catgets(catd
, CATSET
, 44,
1047 "\"Else\" without matching \"if\"\n"));
1063 printf(catgets(catd
, CATSET
, 45,
1064 "Mail's idea of conditions is screwed up\n"));
1072 * End of if statement. Just set cond back to anything.
1081 printf(catgets(catd
, CATSET
, 46,
1082 "\"Endif\" without matching \"if\"\n"));
1090 * Set the list of alternate names.
1095 char **namelist
= v
;
1097 char **ap
, **ap2
, *cp
;
1099 c
= argcount(namelist
) + 1;
1103 for (ap
= altnames
; *ap
; ap
++)
1110 altnames
= scalloc(c
, sizeof (char *));
1111 for (ap
= namelist
, ap2
= altnames
; *ap
; ap
++, ap2
++) {
1112 cp
= scalloc(strlen(*ap
) + 1, sizeof (char));
1121 * Do the real work of resending.
1124 resend1(void *v
, int add_resent
)
1129 int f
, *ip
, *msgvec
;
1133 msgvec
= (int *)salloc((msgCount
+ 2) * sizeof *msgvec
);
1134 name
= laststring(str
, &f
, 1);
1136 puts(catgets(catd
, CATSET
, 47, "No recipient specified."));
1140 *msgvec
= first(0, MMNORM
);
1144 puts(catgets(catd
, CATSET
, 48,
1145 "No applicable messages."));
1149 } else if (getmsglist(str
, msgvec
, 0) < 0)
1154 printf("No applicable messages.\n");
1157 sn
= nalloc(name
, GTO
);
1159 for (ip
= msgvec
; *ip
&& ip
- msgvec
< msgCount
; ip
++) {
1160 if (resend_msg(&message
[*ip
- 1], to
, add_resent
) != OKAY
)
1167 * Resend a message list to a third person.
1172 return resend1(v
, 1);
1176 * Resend a message list to a third person without adding headers.
1181 return resend1(v
, 0);
1185 * 'newmail' or 'inc' command: Check for new mail without writing old
1195 if ((mb
.mb_type
!= MB_IMAP
|| imap_newmail(1)) &&
1196 (val
= setfile(mailname
, 1)) == 0) {
1198 setdot(&message
[mdot
- 1]);
1204 list_shortcuts(void)
1208 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1209 printf("%s=%s\n", s
->sh_short
, s
->sh_long
);
1215 char **args
= (char **)v
;
1218 if (args
[0] == NULL
) {
1222 if (args
[1] == NULL
) {
1223 fprintf(stderr
, catgets(catd
, CATSET
, 220,
1224 "expansion name for shortcut missing\n"));
1227 if (args
[2] != NULL
) {
1228 fprintf(stderr
, catgets(catd
, CATSET
, 221,
1229 "too many arguments\n"));
1232 if ((s
= get_shortcut(args
[0])) != NULL
) {
1234 s
->sh_long
= sstrdup(args
[1]);
1236 s
= scalloc(1, sizeof *s
);
1237 s
->sh_short
= sstrdup(args
[0]);
1238 s
->sh_long
= sstrdup(args
[1]);
1239 s
->sh_next
= shortcuts
;
1246 get_shortcut(const char *str
)
1250 for (s
= shortcuts
; s
; s
= s
->sh_next
)
1251 if (strcmp(str
, s
->sh_short
) == 0)
1257 delete_shortcut(const char *str
)
1259 struct shortcut
*sp
, *sq
;
1261 for (sp
= shortcuts
, sq
= NULL
; sp
; sq
= sp
, sp
= sp
->sh_next
) {
1262 if (strcmp(sp
->sh_short
, str
) == 0) {
1266 sq
->sh_next
= sp
->sh_next
;
1267 if (sp
== shortcuts
)
1268 shortcuts
= sp
->sh_next
;
1279 char **args
= (char **)v
;
1282 if (args
[0] == NULL
) {
1283 fprintf(stderr
, catgets(catd
, CATSET
, 222,
1284 "need shortcut names to remove\n"));
1287 while (*args
!= NULL
) {
1288 if (delete_shortcut(*args
) != OKAY
) {
1290 fprintf(stderr
, catgets(catd
, CATSET
, 223,
1291 "%s: no such shortcut\n"), *args
);
1299 struct oldaccount
*ac_next
; /* next account in list */
1300 char *ac_name
; /* name of account */
1301 char **ac_vars
; /* variables to set */
1304 static struct oldaccount
*oldaccounts
;
1307 get_oldaccount(const char *name
)
1309 struct oldaccount
*a
;
1311 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1312 if (a
->ac_name
&& strcmp(name
, a
->ac_name
) == 0)
1320 char **args
= (char **)v
;
1321 struct oldaccount
*a
;
1323 int i
, mc
, oqf
, nqf
;
1326 if (args
[0] == NULL
) {
1327 if ((fp
= Ftemp(&cp
, "Ra", "w+", 0600, 1)) == NULL
) {
1333 mc
= listaccounts(fp
);
1334 for (a
= oldaccounts
; a
; a
= a
->ac_next
)
1338 fprintf(fp
, "%s:\n", a
->ac_name
);
1339 for (i
= 0; a
->ac_vars
[i
]; i
++)
1340 fprintf(fp
, "\t%s\n", a
->ac_vars
[i
]);
1347 if (args
[1] && args
[1][0] == '{' && args
[1][1] == '\0') {
1348 if (args
[2] != NULL
) {
1349 fprintf(stderr
, "Syntax is: account <name> {\n");
1352 if ((a
= get_oldaccount(args
[0])) != NULL
)
1354 return define1(args
[0], 1);
1356 strncpy(mboxname
, expand("&"), sizeof mboxname
)[sizeof mboxname
-1]='\0';
1357 oqf
= savequitflags();
1358 if ((a
= get_oldaccount(args
[0])) == NULL
) {
1360 a
= scalloc(1, sizeof *a
);
1361 a
->ac_next
= oldaccounts
;
1364 if ((i
= callaccount(args
[0])) != CBAD
)
1366 printf("Account %s does not exist.\n", args
[0]);
1371 delaccount(args
[0]);
1372 a
->ac_name
= sstrdup(args
[0]);
1373 for (i
= 1; args
[i
]; i
++);
1374 a
->ac_vars
= scalloc(i
, sizeof *a
->ac_vars
);
1375 for (i
= 0; args
[i
+1]; i
++)
1376 a
->ac_vars
[i
] = sstrdup(args
[i
+1]);
1378 unset_allow_undefined
= 1;
1380 unset_allow_undefined
= 0;
1381 setf
: if (!starting
) {
1382 nqf
= savequitflags();
1383 restorequitflags(oqf
);
1385 restorequitflags(nqf
);
1399 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1400 m
= &message
[*ip
-1];
1402 if ((m
->m_flag
& (MFLAG
|MFLAGGED
)) == 0)
1403 m
->m_flag
|= MFLAG
|MFLAGGED
;
1415 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1416 m
= &message
[*ip
-1];
1418 if (m
->m_flag
& (MFLAG
|MFLAGGED
)) {
1419 m
->m_flag
&= ~(MFLAG
|MFLAGGED
);
1420 m
->m_flag
|= MUNFLAG
;
1433 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1434 m
= &message
[*ip
-1];
1436 if ((m
->m_flag
& (MANSWER
|MANSWERED
)) == 0)
1437 m
->m_flag
|= MANSWER
|MANSWERED
;
1443 cunanswered(void *v
)
1449 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1450 m
= &message
[*ip
-1];
1452 if (m
->m_flag
& (MANSWER
|MANSWERED
)) {
1453 m
->m_flag
&= ~(MANSWER
|MANSWERED
);
1454 m
->m_flag
|= MUNANSWER
;
1467 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1468 m
= &message
[*ip
-1];
1470 if ((m
->m_flag
& (MDRAFT
|MDRAFTED
)) == 0)
1471 m
->m_flag
|= MDRAFT
|MDRAFTED
;
1483 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1484 m
= &message
[*ip
-1];
1486 if (m
->m_flag
& (MDRAFT
|MDRAFTED
)) {
1487 m
->m_flag
&= ~(MDRAFT
|MDRAFTED
);
1488 m
->m_flag
|= MUNDRAFT
;
1499 * This is not perfect, but correct for machines with a 32-bit
1500 * IEEE float and a 32-bit unsigned long, and does at least not
1501 * produce SIGFPE on the Cray Y-MP.
1508 u
.l
= 0xff800000; /* -inf */
1510 #elif defined (INFINITY)
1512 #elif defined (HUGE_VALF)
1514 #elif defined (FLT_MAX)
1528 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1529 m
= &message
[*ip
-1];
1531 m
->m_score
= huge();
1543 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1544 m
= &message
[*ip
-1];
1545 m
->m_flag
&= ~MKILL
;
1556 int f
, *msgvec
, *ip
;
1560 msgvec
= salloc((msgCount
+2) * sizeof *msgvec
);
1561 if ((sscore
= laststring(str
, &f
, 0)) == NULL
) {
1562 fprintf(stderr
, "No score given.\n");
1565 nscore
= strtod(sscore
, &xp
);
1567 fprintf(stderr
, "Invalid score: \"%s\"\n", sscore
);
1570 if (nscore
> FLT_MAX
)
1572 else if (nscore
< -FLT_MAX
)
1575 *msgvec
= first(0, MMNORM
);
1579 fprintf(stderr
, "No messages to score.\n");
1583 } else if (getmsglist(str
, msgvec
, 0) < 0)
1588 fprintf(stderr
, "No applicable messages.\n");
1591 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
1592 m
= &message
[*ip
-1];
1593 if (m
->m_score
!= huge()) {
1594 m
->m_score
+= nscore
;
1597 else if (m
->m_score
> 0)
1598 m
->m_flag
&= ~MKILL
;
1599 if (m
->m_score
>= 0)
1612 switch (mb
.mb_type
) {
1633 if (*args
== NULL
) {
1634 fprintf(stderr
, "Syntax is: remove mailbox ...\n");
1638 if ((name
= expand(*args
)) == NULL
)
1640 if (strcmp(name
, mailname
) == 0) {
1642 "Cannot remove current mailbox \"%s\".\n",
1647 snprintf(vb
, sizeof vb
, "Remove \"%s\" (y/n) ? ", name
);
1650 switch (which_protocol(name
)) {
1652 if (unlink(name
) < 0) { /* do not handle .gz .bz2 */
1658 fprintf(stderr
, "Cannot remove POP3 mailbox \"%s\".\n",
1663 if (imap_remove(name
) != OKAY
)
1667 if (maildir_remove(name
) != OKAY
)
1672 "Unknown protocol in \"%s\". Not removed.\n",
1683 char **args
= v
, *old
, *new;
1684 enum protocol oldp
, newp
;
1687 if (args
[0] == NULL
|| args
[1] == NULL
|| args
[2] != NULL
) {
1688 fprintf(stderr
, "Syntax: rename old new\n");
1691 old
= expand(args
[0]);
1692 oldp
= which_protocol(old
);
1693 new = expand(args
[1]);
1694 newp
= which_protocol(new);
1695 if (strcmp(old
, mailname
) == 0 || strcmp(new, mailname
) == 0) {
1696 fprintf(stderr
, "Cannot rename current mailbox \"%s\".\n", old
);
1699 if ((oldp
== PROTO_IMAP
|| newp
== PROTO_IMAP
) && oldp
!= newp
) {
1700 fprintf(stderr
, "Can only rename folders of same type.\n");
1703 if (newp
== PROTO_POP3
)
1707 if (link(old
, new) < 0) {
1721 } else if (unlink(old
) < 0) {
1727 if (rename(old
, new) < 0) {
1733 nopop3
: fprintf(stderr
, "Cannot rename POP3 mailboxes.\n");
1737 if (imap_rename(old
, new) != OKAY
)
1741 fprintf(stderr
, "Unknown protocol in \"%s\" and \"%s\". "
1742 "Not renamed.\n", old
, new);