9393 mailx: this statement may fall through
[unleashed.git] / usr / src / cmd / mailx / cmd3.c
blob9407090ed15e8964a58fa00ce50e84e7615ed640
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
24 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
41 #include "rcv.h"
42 #include <locale.h>
45 * mailx -- a modified version of a University of California at Berkeley
46 * mail program
48 * Still more user commands.
51 static int bangexp(char *str);
52 static int diction(const void *a, const void *b);
53 static char *getfilename(char *name, int *aedit);
54 static int resp1(int *msgvec, int useauthor);
55 static int Resp1(int *msgvec, int useauthor);
56 static char *reedit(char *subj);
57 static int shell1(char *str);
58 static void sort(char **list);
59 static char *replyto(struct message *mp, char **f);
60 static int reply2sender(void);
62 static char prevfile[PATHSIZE];
63 static char origprevfile[PATHSIZE];
64 static char lastbang[BUFSIZ];
67 * Process a shell escape by saving signals, ignoring signals,
68 * and forking a sh -c
71 int
72 shell(char *str)
74 shell1(str);
75 printf("!\n");
76 return(0);
79 static int
80 shell1(char *str)
82 void (*sig[2])(int);
83 register int t;
84 register pid_t p;
85 char *Shell;
86 char cmd[BUFSIZ];
88 nstrcpy(cmd, sizeof (cmd), str);
89 if (bangexp(cmd) < 0)
90 return(-1);
91 if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
92 Shell = SHELL;
93 for (t = SIGINT; t <= SIGQUIT; t++)
94 sig[t-SIGINT] = sigset(t, SIG_IGN);
95 p = vfork();
96 if (p == 0) {
97 setuid(getuid());
98 sigchild();
99 for (t = SIGINT; t <= SIGQUIT; t++)
100 if (sig[t-SIGINT] != SIG_IGN)
101 sigsys(t, SIG_DFL);
102 execlp(Shell, Shell, "-c", cmd, (char *)0);
103 perror(Shell);
104 _exit(1);
106 while (wait(0) != p)
108 if (p == (pid_t)-1)
109 perror("fork");
110 for (t = SIGINT; t <= SIGQUIT; t++)
111 sigset(t, sig[t-SIGINT]);
112 return(0);
116 * Fork an interactive shell.
119 int
120 #ifdef __cplusplus
121 dosh(char *)
122 #else
123 /* ARGSUSED */
124 dosh(char *s)
125 #endif
127 void (*sig[2])(int);
128 register int t;
129 register pid_t p;
130 char *Shell;
132 if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
133 Shell = SHELL;
134 for (t = SIGINT; t <= SIGQUIT; t++)
135 sig[t-SIGINT] = sigset(t, SIG_IGN);
136 p = vfork();
137 if (p == 0) {
138 setuid(getuid());
139 sigchild();
140 for (t = SIGINT; t <= SIGQUIT; t++)
141 if (sig[t-SIGINT] != SIG_IGN)
142 sigset(t, SIG_DFL);
143 execlp(Shell, Shell, (char *)0);
144 perror(Shell);
145 _exit(1);
147 while (wait(0) != p)
149 if (p == (pid_t)-1)
150 perror("fork");
151 for (t = SIGINT; t <= SIGQUIT; t++)
152 sigset(t, sig[t-SIGINT]);
153 putchar('\n');
154 return(0);
158 * Expand the shell escape by expanding unescaped !'s into the
159 * last issued command where possible.
161 static int
162 bangexp(char *str)
164 char bangbuf[BUFSIZ];
165 register char *cp, *cp2;
166 register int n;
167 int changed = 0;
168 int bangit = (value("bang")!=NOSTR);
170 cp = str;
171 cp2 = bangbuf;
172 n = BUFSIZ;
173 while (*cp) {
174 if (*cp=='!' && bangit) {
175 if (n < (int)strlen(lastbang)) {
176 overf:
177 printf(gettext("Command buffer overflow\n"));
178 return(-1);
180 changed++;
181 strcpy(cp2, lastbang);
182 cp2 += strlen(lastbang);
183 n -= strlen(lastbang);
184 cp++;
185 continue;
187 if (*cp == '\\' && cp[1] == '!') {
188 if (--n <= 1)
189 goto overf;
190 *cp2++ = '!';
191 cp += 2;
192 changed++;
194 if (--n <= 1)
195 goto overf;
196 *cp2++ = *cp++;
198 *cp2 = 0;
199 if (changed) {
200 printf("!%s\n", bangbuf);
201 fflush(stdout);
203 nstrcpy(str, BUFSIZ, bangbuf);
204 nstrcpy(lastbang, sizeof (lastbang), bangbuf);
205 return(0);
209 * Print out a nice help message from some file or another.
212 int
213 help(void)
215 int c;
216 register FILE *f;
218 if ((f = fopen(HELPFILE, "r")) == NULL) {
219 printf(gettext("No help just now.\n"));
220 return(1);
222 while ((c = getc(f)) != EOF)
223 putchar(c);
224 fclose(f);
225 return(0);
229 * Change user's working directory.
232 int
233 schdir(char *str)
235 register char *cp;
236 char cwd[PATHSIZE], file[PATHSIZE];
237 static char efile[PATHSIZE];
239 for (cp = str; *cp == ' '; cp++)
241 if (*cp == '\0')
242 cp = homedir;
243 else
244 if ((cp = expand(cp)) == NOSTR)
245 return(1);
246 if (editfile != NOSTR && (*editfile != '/' || mailname[0] != '/')) {
247 if (getcwd(cwd, (int)sizeof (cwd)) == 0) {
248 fprintf(stderr,
249 gettext("Can't get current directory: %s\n"), cwd);
250 return(1);
253 if (chdir(cp) < 0) {
254 perror(cp);
255 return(1);
258 * Convert previously relative names to absolute names.
260 if (editfile != NOSTR && *editfile != '/') {
261 snprintf(file, sizeof (file), "%s/%s", cwd, editfile);
262 nstrcpy(efile, sizeof (efile), file);
263 editfile = efile;
265 if (mailname[0] != '/') {
266 snprintf(file, sizeof (file), "%s/%s", cwd, mailname);
267 nstrcpy(mailname, PATHSIZE, file);
269 return(0);
273 * Two versions of reply. Reply to all names in message or reply
274 * to only sender of message, depending on setting of "replyall".
277 int
278 respond(int *msgvec)
280 if (reply2sender())
281 return(resp1(msgvec, 0));
282 else
283 return(Resp1(msgvec, 0));
286 int
287 followup(int *msgvec)
289 if (reply2sender())
290 return(resp1(msgvec, 1));
291 else
292 return(Resp1(msgvec, 1));
295 int
296 replyall(int *msgvec)
298 return(resp1(msgvec, 0));
301 static int
302 resp1(int *msgvec, int useauthor)
304 struct message *mp;
305 char *cp, *buf, *rcv, *skin_rcv, *reply2, **ap, *returnaddr;
306 struct name *np;
307 struct header head;
308 char mylocalname[BUFSIZ], mydomname[BUFSIZ];
310 if (msgvec[1] != 0) {
311 printf(gettext(
312 "Sorry, can't reply to multiple messages at once\n"));
313 return(1);
315 snprintf(mydomname, sizeof (mydomname), "%s@%s", myname, domain);
316 snprintf(mylocalname, sizeof (mylocalname), "%s@%s", myname, host);
317 returnaddr = value("returnaddr");
319 mp = &message[msgvec[0] - 1];
320 dot = mp;
321 reply2 = replyto(mp, &rcv);
322 cp = skin(hfield("to", mp, addto));
323 if (cp != NOSTR) {
324 buf = (char *)salloc(strlen(reply2) + strlen(cp) + 2);
325 strcpy(buf, reply2);
326 strcat(buf, " ");
327 strcat(buf, cp);
328 } else
329 buf = reply2;
330 np = elide(extract(buf, GTO));
331 #ifdef OPTIM
332 /* rcv = netrename(rcv); */
333 #endif /* OPTIM */
335 * Delete my name from the reply list,
336 * and with it, all my alternate names.
338 skin_rcv = skin(rcv);
339 mapf(np, skin_rcv);
340 np = delname(np, myname);
341 np = delname(np, mylocalname);
342 np = delname(np, mydomname);
343 if (returnaddr && *returnaddr)
344 np = delname(np, returnaddr);
345 if (altnames != 0)
346 for (ap = altnames; *ap; ap++)
347 np = delname(np, *ap);
348 head.h_seq = 1;
349 cp = detract(np, 0);
350 if (cp == NOSTR) {
351 if (reply2)
352 cp = unuucp(reply2);
353 else
354 cp = unuucp(rcv);
356 head.h_to = cp;
357 head.h_subject = hfield("subject", mp, addone);
358 if (head.h_subject == NOSTR)
359 head.h_subject = hfield("subj", mp, addone);
360 head.h_subject = reedit(head.h_subject);
361 head.h_cc = NOSTR;
362 cp = skin(hfield("cc", mp, addto));
363 if (cp != NOSTR) {
364 np = elide(extract(cp, GCC));
365 mapf(np, skin_rcv);
366 np = delname(np, myname);
367 np = delname(np, mylocalname);
368 np = delname(np, mydomname);
369 if (returnaddr && *returnaddr)
370 np = delname(np, returnaddr);
371 np = delname(np, skin_rcv);
372 if (altnames != 0)
373 for (ap = altnames; *ap; ap++)
374 np = delname(np, *ap);
375 head.h_cc = detract(np, 0);
377 head.h_bcc = NOSTR;
378 head.h_defopt = NOSTR;
379 head.h_others = NOSTRPTR;
380 mail1(&head, useauthor, useauthor ? rcv : NOSTR);
381 return(0);
384 void
385 getrecf(char *buf, char *recfile, int useauthor, int sz_recfile)
387 register char *bp, *cp;
388 register char *recf = recfile;
389 register int folderize;
390 char fldr[BUFSIZ];
392 folderize = (value("outfolder")!=NOSTR && getfold(fldr) == 0);
394 if (useauthor) {
395 if (folderize)
396 *recf++ = '+';
397 if (debug) fprintf(stderr, "buf='%s'\n", buf);
398 for (bp=skin(buf), cp=recf; *bp && !any(*bp, ", "); bp++) {
399 if (*bp=='!')
400 cp = recf;
401 else
402 *cp++ = *bp;
404 if (cp >= &recfile[sz_recfile - 1]) {
405 printf(gettext("File name buffer overflow\n"));
406 break;
409 *cp = '\0';
410 if (cp==recf)
411 *recfile = '\0';
412 /* now strip off any Internet host names */
413 if ((cp = strchr(recf, '%')) == NOSTR)
414 cp = strchr(recf, '@');
415 if (cp != NOSTR)
416 *cp = '\0';
417 } else {
418 if (cp = value("record")) {
419 int sz = PATHSIZE;
420 if (folderize && *cp!='+' && *cp!='/'
421 && *safeexpand(cp)!='/') {
422 *recf++ = '+';
423 sz--;
425 nstrcpy(recf, sz, cp);
426 } else
427 *recf = '\0';
429 if (debug) fprintf(stderr, "recfile='%s'\n", recfile);
433 * Modify the subject we are replying to to begin with Re: if
434 * it does not already.
437 static char *
438 reedit(char *subj)
440 char sbuf[10];
441 register char *newsubj;
443 if (subj == NOSTR)
444 return(NOSTR);
445 strncpy(sbuf, subj, 3);
446 sbuf[3] = 0;
447 if (icequal(sbuf, "re:"))
448 return(subj);
449 newsubj = (char *)salloc((unsigned)(strlen(subj) + 5));
450 sprintf(newsubj, "Re: %s", subj);
451 return(newsubj);
455 * Preserve the named messages, so that they will be sent
456 * back to the system mailbox.
459 int
460 preserve(int *msgvec)
462 register struct message *mp;
463 register int *ip, mesg;
465 if (edit) {
466 printf(gettext("Cannot \"preserve\" in edit mode\n"));
467 return(1);
469 for (ip = msgvec; *ip != NULL; ip++) {
470 mesg = *ip;
471 mp = &message[mesg-1];
472 mp->m_flag |= MPRESERVE;
473 mp->m_flag &= ~MBOX;
474 dot = mp;
476 return(0);
480 * Mark all given messages as unread.
482 int
483 unread(int msgvec[])
485 register int *ip;
487 for (ip = msgvec; *ip != NULL; ip++) {
488 dot = &message[*ip-1];
489 dot->m_flag &= ~(MREAD|MTOUCH);
490 dot->m_flag |= MSTATUS;
492 return(0);
496 * Print the size of each message.
499 int
500 messize(int *msgvec)
502 register struct message *mp;
503 register int *ip, mesg;
505 for (ip = msgvec; *ip != NULL; ip++) {
506 mesg = *ip;
507 mp = &message[mesg-1];
508 dot = mp;
509 printf("%d: %ld\n", mesg, mp->m_size);
511 return(0);
515 * Quit quickly. If we are sourcing, just pop the input level
516 * by returning an error.
519 int
520 rexit(int e)
522 if (sourcing)
523 return(1);
524 if (Tflag != NOSTR)
525 close(creat(Tflag, TEMPPERM));
526 if (!edit)
527 Verhogen();
528 exit(e ? e : rpterr);
529 /* NOTREACHED */
530 return (0); /* shut up lint and CC */
534 * Set or display a variable value. Syntax is similar to that
535 * of csh.
538 int
539 set(char **arglist)
541 register struct var *vp;
542 register char *cp, *cp2;
543 char varbuf[BUFSIZ], **ap, **p;
544 int errs, h, s;
546 if (argcount(arglist) == 0) {
547 for (h = 0, s = 1; h < HSHSIZE; h++)
548 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
549 s++;
550 ap = (char **) salloc(s * sizeof *ap);
551 for (h = 0, p = ap; h < HSHSIZE; h++)
552 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
553 *p++ = vp->v_name;
554 *p = NOSTR;
555 sort(ap);
556 for (p = ap; *p != NOSTR; p++)
557 if (((cp = value(*p)) != 0) && *cp)
558 printf("%s=\"%s\"\n", *p, cp);
559 else
560 printf("%s\n", *p);
561 return(0);
563 errs = 0;
564 for (ap = arglist; *ap != NOSTR; ap++) {
565 cp = *ap;
566 cp2 = varbuf;
567 while (*cp != '=' && *cp != '\0')
568 *cp2++ = *cp++;
569 *cp2 = '\0';
570 if (*cp == '\0')
571 cp = "";
572 else
573 cp++;
574 if (equal(varbuf, "")) {
575 printf(gettext("Non-null variable name required\n"));
576 errs++;
577 continue;
579 assign(varbuf, cp);
581 return(errs);
585 * Unset a bunch of variable values.
588 int
589 unset(char **arglist)
591 register int errs;
592 register char **ap;
594 errs = 0;
595 for (ap = arglist; *ap != NOSTR; ap++)
596 errs += deassign(*ap);
597 return(errs);
601 * Add users to a group.
604 int
605 group(char **argv)
607 register struct grouphead *gh;
608 register struct mgroup *gp;
609 register int h;
610 int s;
611 char **ap, *gname, **p;
613 if (argcount(argv) == 0) {
614 for (h = 0, s = 1; h < HSHSIZE; h++)
615 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
616 s++;
617 ap = (char **) salloc(s * sizeof *ap);
618 for (h = 0, p = ap; h < HSHSIZE; h++)
619 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
620 *p++ = gh->g_name;
621 *p = NOSTR;
622 sort(ap);
623 for (p = ap; *p != NOSTR; p++)
624 printgroup(*p);
625 return(0);
627 if (argcount(argv) == 1) {
628 printgroup(*argv);
629 return(0);
631 gname = *argv;
632 h = hash(gname);
633 if ((gh = findgroup(gname)) == NOGRP) {
634 if ((gh = (struct grouphead *)
635 calloc(sizeof (*gh), 1)) == NULL) {
636 panic("Failed to allocate memory for group");
638 gh->g_name = vcopy(gname);
639 gh->g_list = NOGE;
640 gh->g_link = groups[h];
641 groups[h] = gh;
645 * Insert names from the command list into the group.
646 * Who cares if there are duplicates? They get tossed
647 * later anyway.
650 for (ap = argv+1; *ap != NOSTR; ap++) {
651 if ((gp = (struct mgroup *)
652 calloc(sizeof (*gp), 1)) == NULL) {
653 panic("Failed to allocate memory for group");
655 gp->ge_name = vcopy(*ap);
656 gp->ge_link = gh->g_list;
657 gh->g_list = gp;
659 return(0);
663 * Remove users from a group.
666 int
667 ungroup(char **argv)
669 register struct grouphead *gh, **ghp;
670 register struct mgroup *gp, *gpnext;
671 register int h;
672 char **ap, *gname;
674 if (argcount(argv) == 0) {
675 printf("Must specify alias or group to remove\n");
676 return(1);
680 * Remove names on the command list from the group list.
683 for (ap = argv; *ap != NOSTR; ap++) {
684 gname = *ap;
685 h = hash(gname);
686 for (ghp = &groups[h]; *ghp != NOGRP; ghp = &((*ghp)->g_link)) {
687 gh = *ghp;
688 if (equal(gh->g_name, gname)) {
689 /* remove from list */
690 *ghp = gh->g_link;
691 /* free each member of gorup */
692 for (gp = gh->g_list; gp != NOGE; gp = gpnext) {
693 gpnext = gp->ge_link;
694 vfree(gp->ge_name);
695 free(gp);
697 vfree(gh->g_name);
698 free(gh);
699 break;
703 return(0);
707 * Sort the passed string vecotor into ascending dictionary
708 * order.
711 static void
712 sort(char **list)
714 register char **ap;
716 for (ap = list; *ap != NOSTR; ap++)
718 if (ap-list < 2)
719 return;
720 qsort((char *) list, (unsigned) (ap-list), sizeof *list, diction);
724 * Do a dictionary order comparison of the arguments from
725 * qsort.
727 static int
728 diction(const void *a, const void *b)
730 return(strcmp(*(char **)a, *(char **)b));
734 * The do nothing command for comments.
737 int
738 #ifdef __cplusplus
739 null(char *)
740 #else
741 /* ARGSUSED */
742 null(char *s)
743 #endif
745 return(0);
749 * Print out the current edit file, if we are editing.
750 * Otherwise, print the name of the person who's mail
751 * we are reading.
753 int
754 file(char **argv)
756 register char *cp;
757 int editing, mdot;
759 if (argv[0] == NOSTR) {
760 mdot = newfileinfo(1);
761 dot = &message[mdot - 1];
762 return(0);
766 * Acker's! Must switch to the new file.
767 * We use a funny interpretation --
768 * # -- gets the previous file
769 * % -- gets the invoker's post office box
770 * %user -- gets someone else's post office box
771 * & -- gets invoker's mbox file
772 * string -- reads the given file
775 cp = getfilename(argv[0], &editing);
776 if (cp == NOSTR)
777 return(-1);
778 if (setfile(cp, editing)) {
779 nstrcpy(origname, PATHSIZE, origprevfile);
780 return(-1);
782 mdot = newfileinfo(1);
783 dot = &message[mdot - 1];
784 return(0);
788 * Evaluate the string given as a new mailbox name.
789 * Ultimately, we want this to support a number of meta characters.
790 * Possibly:
791 * % -- for my system mail box
792 * %user -- for user's system mail box
793 * # -- for previous file
794 * & -- get's invoker's mbox file
795 * file name -- for any other file
798 static char *
799 getfilename(char *name, int *aedit)
801 register char *cp;
802 char savename[BUFSIZ];
803 char oldmailname[BUFSIZ];
804 char tmp[BUFSIZ];
807 * Assume we will be in "edit file" mode, until
808 * proven wrong.
810 *aedit = 1;
811 switch (*name) {
812 case '%':
813 *aedit = 0;
814 nstrcpy(prevfile, sizeof (prevfile), editfile);
815 nstrcpy(origprevfile, sizeof (origprevfile), origname);
816 if (name[1] != 0) {
817 nstrcpy(oldmailname, sizeof (oldmailname), mailname);
818 findmail(name+1);
819 cp = savestr(mailname);
820 nstrcpy(origname, PATHSIZE, cp);
821 nstrcpy(mailname, PATHSIZE, oldmailname);
822 return(cp);
824 nstrcpy(oldmailname, sizeof (oldmailname), mailname);
825 findmail(NULL);
826 cp = savestr(mailname);
827 nstrcpy(mailname, PATHSIZE, oldmailname);
828 nstrcpy(origname, PATHSIZE, cp);
829 return(cp);
831 case '#':
832 if (name[1] != 0)
833 goto regular;
834 if (prevfile[0] == 0) {
835 printf(gettext("No previous file\n"));
836 return(NOSTR);
838 cp = savestr(prevfile);
839 nstrcpy(prevfile, sizeof (prevfile), editfile);
840 nstrcpy(tmp, sizeof (tmp), origname);
841 nstrcpy(origname, PATHSIZE, origprevfile);
842 nstrcpy(origprevfile, sizeof (origprevfile), tmp);
843 return(cp);
845 case '&':
846 nstrcpy(prevfile, sizeof (prevfile), editfile);
847 nstrcpy(origprevfile, sizeof (origprevfile), origname);
848 if (name[1] == 0) {
849 cp=Getf("MBOX");
850 nstrcpy(origname, PATHSIZE, cp);
851 return(cp);
853 /* FALLTHROUGH */
855 default:
856 regular:
857 nstrcpy(prevfile, sizeof (prevfile), editfile);
858 nstrcpy(origprevfile, sizeof (origprevfile), origname);
859 cp = safeexpand(name);
860 nstrcpy(origname, PATHSIZE, cp);
861 if (cp[0] != '/') {
862 name = getcwd(NOSTR, PATHSIZE);
863 nstrcat(name, PATHSIZE, "/");
864 nstrcat(name, PATHSIZE, cp);
865 cp = name;
867 return(cp);
872 * Expand file names like echo
875 int
876 echo(register char **argv)
878 register char *cp;
879 int neednl = 0;
881 while (*argv != NOSTR) {
882 cp = *argv++;
883 if ((cp = expand(cp)) != NOSTR) {
884 neednl++;
885 printf("%s", cp);
886 if (*argv!=NOSTR)
887 putchar(' ');
890 if (neednl)
891 putchar('\n');
892 return(0);
896 * Reply to a series of messages by simply mailing to the senders
897 * and not messing around with the To: and Cc: lists as in normal
898 * reply.
901 int
902 Respond(int *msgvec)
904 if (reply2sender())
905 return(Resp1(msgvec, 0));
906 else
907 return(resp1(msgvec, 0));
910 int
911 Followup(int *msgvec)
913 if (reply2sender())
914 return(Resp1(msgvec, 1));
915 else
916 return(resp1(msgvec, 1));
919 int
920 replysender(int *msgvec)
922 return(Resp1(msgvec, 0));
925 static int
926 Resp1(int *msgvec, int useauthor)
928 struct header head;
929 struct message *mp;
930 register int s, *ap;
931 register char *cp, *cp2, *subject;
933 for (s = 0, ap = msgvec; *ap != 0; ap++) {
934 mp = &message[*ap - 1];
935 dot = mp;
936 cp = replyto(mp, NOSTRPTR);
937 s += strlen(cp) + 1;
939 if (s == 0)
940 return(0);
941 cp = (char *)salloc(s + 2);
942 head.h_to = cp;
943 for (ap = msgvec; *ap != 0; ap++) {
944 mp = &message[*ap - 1];
945 cp2 = replyto(mp, NOSTRPTR);
946 cp = copy(cp2, cp);
947 *cp++ = ' ';
949 *--cp = 0;
950 mp = &message[msgvec[0] - 1];
951 subject = hfield("subject", mp, addone);
952 head.h_seq = 1;
953 if (subject == NOSTR)
954 subject = hfield("subj", mp, addone);
955 head.h_subject = reedit(subject);
956 if (subject != NOSTR)
957 head.h_seq++;
958 head.h_cc = NOSTR;
959 head.h_bcc = NOSTR;
960 head.h_defopt = NOSTR;
961 head.h_others = NOSTRPTR;
962 mail1(&head, useauthor, NOSTR);
963 return(0);
967 * Conditional commands. These allow one to parameterize one's
968 * .mailrc and do some things if sending, others if receiving.
971 int
972 ifcmd(char **argv)
974 register char *cp;
976 if (cond != CANY) {
977 printf(gettext("Illegal nested \"if\"\n"));
978 return(1);
980 cond = CANY;
981 cp = argv[0];
982 switch (*cp) {
983 case 'r': case 'R':
984 cond = CRCV;
985 break;
987 case 's': case 'S':
988 cond = CSEND;
989 break;
991 case 't': case 'T':
992 cond = CTTY;
993 break;
995 default:
996 printf(gettext("Unrecognized if-keyword: \"%s\"\n"), cp);
997 return(1);
999 return(0);
1003 * Implement 'else'. This is pretty simple -- we just
1004 * flip over the conditional flag.
1007 int
1008 elsecmd(void)
1011 switch (cond) {
1012 case CANY:
1013 printf(gettext("\"Else\" without matching \"if\"\n"));
1014 return(1);
1016 case CSEND:
1017 cond = CRCV;
1018 break;
1020 case CRCV:
1021 cond = CSEND;
1022 break;
1024 case CTTY:
1025 cond = CNOTTY;
1026 break;
1028 case CNOTTY:
1029 cond = CTTY;
1030 break;
1032 default:
1033 printf(gettext("invalid condition encountered\n"));
1034 cond = CANY;
1035 break;
1037 return(0);
1041 * End of if statement. Just set cond back to anything.
1044 int
1045 endifcmd(void)
1048 if (cond == CANY) {
1049 printf(gettext("\"Endif\" without matching \"if\"\n"));
1050 return(1);
1052 cond = CANY;
1053 return(0);
1057 * Set the list of alternate names.
1059 int
1060 alternates(char **namelist)
1062 register int c;
1063 register char **ap, **ap2, *cp;
1065 c = argcount(namelist) + 1;
1066 if (c == 1) {
1067 if (altnames == 0)
1068 return(0);
1069 for (ap = altnames; *ap; ap++)
1070 printf("%s ", *ap);
1071 printf("\n");
1072 return (0);
1074 if (altnames != 0)
1075 free((char *)altnames);
1076 if ((altnames = (char **)
1077 calloc((unsigned)c, sizeof (char *))) == NULL)
1078 panic("Failed to allocate memory");
1079 for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
1080 if ((cp = (char *)
1081 calloc((unsigned)strlen(*ap) + 1, sizeof (char))) == NULL)
1082 panic("Failed to allocate memory");
1083 strcpy(cp, *ap);
1084 *ap2 = cp;
1086 *ap2 = 0;
1087 return(0);
1091 * Figure out who to reply to.
1092 * Return the real sender in *f.
1094 static char *
1095 replyto(struct message *mp, char **f)
1097 char *r, *rf;
1099 if ((rf = skin(hfield("from", mp, addto)))==NOSTR)
1100 rf = skin(addto(NOSTR, nameof(mp)));
1101 if ((r = skin(hfield("reply-to", mp, addto)))==NOSTR)
1102 r = rf;
1103 if (f)
1104 *f = rf;
1105 return (r);
1109 * reply2sender - determine whether a "reply" command should reply to the
1110 * sender of the messages, or to all the recipients of the
1111 * message.
1113 * With the advent of POSIX.2 compliance, this has become
1114 * a bit more complicated, and so should be done in one
1115 * place, for all to use.
1118 static int
1119 reply2sender (void)
1121 register int rep = (value("replyall") != NOSTR);
1122 register int flp = (value("flipr") != NOSTR);
1124 return((rep && !flp)|| (!rep && flp));