Annotation of src/usr.bin/mail/cmd3.c, Revision 1.18
1.18 ! millert 1: /* $OpenBSD: cmd3.c,v 1.17 2001/11/21 15:26:39 millert Exp $ */
1.5 millert 2: /* $NetBSD: cmd3.c,v 1.8 1997/07/09 05:29:49 mikel Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
1.17 millert 39: static const char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95";
1.2 deraadt 40: #else
1.18 ! millert 41: static const char rcsid[] = "$OpenBSD: cmd3.c,v 1.17 2001/11/21 15:26:39 millert Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include "extern.h"
47:
48: /*
49: * Mail -- a mail program
50: *
51: * Still more user commands.
52: */
1.17 millert 53: static int diction(const void *, const void *);
1.1 deraadt 54:
55: /*
56: * Process a shell escape by saving signals, ignoring signals,
57: * and forking a sh -c
58: */
59: int
1.17 millert 60: shell(void *v)
1.1 deraadt 61: {
1.2 deraadt 62: char *str = v;
1.1 deraadt 63: char *shell;
64: char cmd[BUFSIZ];
1.16 millert 65: struct sigaction oact;
66: sigset_t oset;
1.1 deraadt 67:
1.16 millert 68: (void)ignoresig(SIGINT, &oact, &oset);
69: (void)strlcpy(cmd, str, sizeof(cmd));
1.8 millert 70: if (bangexp(cmd, sizeof(cmd)) < 0)
1.5 millert 71: return(1);
1.14 millert 72: shell = value("SHELL");
1.15 millert 73: (void)run_command(shell, 0, 0, -1, "-c", cmd, NULL);
1.16 millert 74: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
75: (void)sigaction(SIGINT, &oact, NULL);
1.5 millert 76: puts("!");
77: return(0);
1.1 deraadt 78: }
79:
80: /*
81: * Fork an interactive shell.
82: */
83: /*ARGSUSED*/
84: int
1.17 millert 85: dosh(void *v)
1.1 deraadt 86: {
87: char *shell;
1.16 millert 88: struct sigaction oact;
89: sigset_t oset;
1.1 deraadt 90:
1.14 millert 91: shell = value("SHELL");
1.16 millert 92: (void)ignoresig(SIGINT, &oact, &oset);
1.15 millert 93: (void)run_command(shell, 0, 0, -1, NULL, NULL, NULL);
1.16 millert 94: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
95: (void)sigaction(SIGINT, &oact, NULL);
1.1 deraadt 96: putchar('\n');
1.5 millert 97: return(0);
1.1 deraadt 98: }
99:
100: /*
101: * Expand the shell escape by expanding unescaped !'s into the
102: * last issued command where possible.
103: */
104: int
1.17 millert 105: bangexp(char *str, size_t strsize)
1.1 deraadt 106: {
107: char bangbuf[BUFSIZ];
1.8 millert 108: static char lastbang[BUFSIZ];
1.10 millert 109: char *cp, *cp2;
110: int n, changed = 0;
1.1 deraadt 111:
112: cp = str;
113: cp2 = bangbuf;
114: n = BUFSIZ;
115: while (*cp) {
116: if (*cp == '!') {
117: if (n < strlen(lastbang)) {
118: overf:
1.5 millert 119: puts("Command buffer overflow");
1.1 deraadt 120: return(-1);
121: }
122: changed++;
1.17 millert 123: strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf));
1.1 deraadt 124: cp2 += strlen(lastbang);
125: n -= strlen(lastbang);
126: cp++;
127: continue;
128: }
129: if (*cp == '\\' && cp[1] == '!') {
130: if (--n <= 1)
131: goto overf;
132: *cp2++ = '!';
133: cp += 2;
134: changed++;
135: }
136: if (--n <= 1)
137: goto overf;
138: *cp2++ = *cp++;
139: }
140: *cp2 = 0;
141: if (changed) {
1.8 millert 142: (void)printf("!%s\n", bangbuf);
143: (void)fflush(stdout);
1.1 deraadt 144: }
1.17 millert 145: (void)strlcpy(str, bangbuf, strsize);
146: (void)strlcpy(lastbang, bangbuf, sizeof(lastbang));
1.1 deraadt 147: return(0);
148: }
149:
150: /*
151: * Print out a nice help message from some file or another.
152: */
153: int
1.17 millert 154: help(void *v)
1.1 deraadt 155: {
156:
1.14 millert 157: (void)run_command(value("PAGER"), 0, -1, -1, _PATH_HELP, NULL);
1.1 deraadt 158: return(0);
159: }
160:
161: /*
162: * Change user's working directory.
163: */
164: int
1.17 millert 165: schdir(void *v)
1.1 deraadt 166: {
1.2 deraadt 167: char **arglist = v;
1.1 deraadt 168: char *cp;
169:
1.13 millert 170: if (*arglist == NULL) {
171: if (homedir == NULL)
172: return(1);
1.1 deraadt 173: cp = homedir;
1.13 millert 174: } else {
1.7 millert 175: if ((cp = expand(*arglist)) == NULL)
1.1 deraadt 176: return(1);
1.13 millert 177: }
1.1 deraadt 178: if (chdir(cp) < 0) {
1.12 millert 179: warn("%s", cp);
1.1 deraadt 180: return(1);
181: }
1.5 millert 182: return(0);
1.1 deraadt 183: }
184:
185: int
1.17 millert 186: respond(void *v)
1.1 deraadt 187: {
1.2 deraadt 188: int *msgvec = v;
1.17 millert 189:
1.7 millert 190: if (value("Replyall") == NULL)
1.5 millert 191: return(_respond(msgvec));
1.1 deraadt 192: else
1.5 millert 193: return(_Respond(msgvec));
1.1 deraadt 194: }
195:
196: /*
197: * Reply to a list of messages. Extract each name from the
198: * message header and send them off to mail1()
199: */
200: int
201: _respond(msgvec)
202: int *msgvec;
203: {
204: struct message *mp;
205: char *cp, *rcv, *replyto;
206: char **ap;
207: struct name *np;
208: struct header head;
209:
210: if (msgvec[1] != 0) {
1.5 millert 211: puts("Sorry, can't reply to multiple messages at once");
1.1 deraadt 212: return(1);
213: }
214: mp = &message[msgvec[0] - 1];
215: touch(mp);
216: dot = mp;
1.7 millert 217: if ((rcv = skin(hfield("from", mp))) == NULL)
1.1 deraadt 218: rcv = skin(nameof(mp, 1));
1.7 millert 219: if ((replyto = skin(hfield("reply-to", mp))) != NULL)
1.1 deraadt 220: np = extract(replyto, GTO);
1.7 millert 221: else if ((cp = skin(hfield("to", mp))) != NULL)
1.1 deraadt 222: np = extract(cp, GTO);
223: else
1.17 millert 224: np = NULL;
1.1 deraadt 225: np = elide(np);
226: /*
227: * Delete my name from the reply list,
228: * and with it, all my alternate names.
229: */
230: np = delname(np, myname);
231: if (altnames)
232: for (ap = altnames; *ap; ap++)
233: np = delname(np, *ap);
1.17 millert 234: if (np != NULL && replyto == NULL)
1.1 deraadt 235: np = cat(np, extract(rcv, GTO));
1.17 millert 236: else if (np == NULL) {
1.7 millert 237: if (replyto != NULL)
1.5 millert 238: puts("Empty reply-to field -- replying to author");
1.1 deraadt 239: np = extract(rcv, GTO);
240: }
241: head.h_to = np;
1.7 millert 242: if ((head.h_subject = hfield("subject", mp)) == NULL)
1.1 deraadt 243: head.h_subject = hfield("subj", mp);
244: head.h_subject = reedit(head.h_subject);
1.7 millert 245: if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) {
1.1 deraadt 246: np = elide(extract(cp, GCC));
247: np = delname(np, myname);
248: if (altnames != 0)
249: for (ap = altnames; *ap; ap++)
250: np = delname(np, *ap);
251: head.h_cc = np;
252: } else
1.17 millert 253: head.h_cc = NULL;
254: head.h_bcc = NULL;
255: head.h_smopts = NULL;
1.1 deraadt 256: mail1(&head, 1);
257: return(0);
258: }
259:
260: /*
261: * Modify the subject we are replying to to begin with Re: if
262: * it does not already.
263: */
264: char *
1.17 millert 265: reedit(char *subj)
1.1 deraadt 266: {
267: char *newsubj;
1.18 ! millert 268: size_t len;
1.1 deraadt 269:
1.7 millert 270: if (subj == NULL)
271: return(NULL);
1.1 deraadt 272: if ((subj[0] == 'r' || subj[0] == 'R') &&
273: (subj[1] == 'e' || subj[1] == 'E') &&
274: subj[2] == ':')
1.5 millert 275: return(subj);
1.18 ! millert 276: len = strlen(subj) + 5;
! 277: newsubj = salloc(len);
! 278: strlcpy(newsubj, "Re: ", len);
! 279: strlcat(newsubj, subj, len);
1.5 millert 280: return(newsubj);
1.1 deraadt 281: }
282:
283: /*
1.14 millert 284: * Mark new the named messages, so that they will be left in the system
285: * mailbox as unread.
286: */
287: int
1.17 millert 288: marknew(void *v)
1.14 millert 289: {
290: int *msgvec = v;
291: int *ip;
292:
293: for (ip = msgvec; *ip != NULL; ip++) {
294: dot = &message[*ip-1];
295: dot->m_flag &= ~(MBOX|MREAD|MTOUCH);
296: dot->m_flag |= MNEW|MSTATUS;
297: }
298: return(0);
299: }
300:
301: /*
1.1 deraadt 302: * Preserve the named messages, so that they will be sent
303: * back to the system mailbox.
304: */
305: int
1.17 millert 306: preserve(void *v)
1.1 deraadt 307: {
1.2 deraadt 308: int *msgvec = v;
1.10 millert 309: int *ip, mesg;
310: struct message *mp;
1.1 deraadt 311:
312: if (edit) {
1.5 millert 313: puts("Cannot \"preserve\" in edit mode");
1.1 deraadt 314: return(1);
315: }
316: for (ip = msgvec; *ip != NULL; ip++) {
317: mesg = *ip;
318: mp = &message[mesg-1];
319: mp->m_flag |= MPRESERVE;
320: mp->m_flag &= ~MBOX;
321: dot = mp;
322: }
323: return(0);
324: }
325:
326: /*
327: * Mark all given messages as unread.
328: */
329: int
1.17 millert 330: unread(void *v)
1.1 deraadt 331: {
1.14 millert 332: int *msgvec = v;
1.10 millert 333: int *ip;
1.1 deraadt 334:
335: for (ip = msgvec; *ip != NULL; ip++) {
336: dot = &message[*ip-1];
337: dot->m_flag &= ~(MREAD|MTOUCH);
338: dot->m_flag |= MSTATUS;
339: }
340: return(0);
341: }
342:
343: /*
344: * Print the size of each message.
345: */
346: int
1.17 millert 347: messize(void *v)
1.1 deraadt 348: {
1.2 deraadt 349: int *msgvec = v;
1.10 millert 350: struct message *mp;
351: int *ip, mesg;
1.1 deraadt 352:
353: for (ip = msgvec; *ip != NULL; ip++) {
354: mesg = *ip;
355: mp = &message[mesg-1];
1.3 millert 356: printf("%d: %d/%d\n", mesg, mp->m_lines, mp->m_size);
1.1 deraadt 357: }
358: return(0);
359: }
360:
361: /*
362: * Quit quickly. If we are sourcing, just pop the input level
363: * by returning an error.
364: */
365: int
1.17 millert 366: rexit(void *v)
1.1 deraadt 367: {
1.17 millert 368:
1.1 deraadt 369: if (sourcing)
370: return(1);
1.2 deraadt 371: exit(0);
1.1 deraadt 372: /*NOTREACHED*/
373: }
374:
375: /*
376: * Set or display a variable value. Syntax is similar to that
377: * of csh.
378: */
379: int
1.17 millert 380: set(void *v)
1.1 deraadt 381: {
1.2 deraadt 382: char **arglist = v;
1.10 millert 383: struct var *vp;
384: char *cp, *cp2;
1.1 deraadt 385: char varbuf[BUFSIZ], **ap, **p;
386: int errs, h, s;
387:
1.7 millert 388: if (*arglist == NULL) {
1.1 deraadt 389: for (h = 0, s = 1; h < HSHSIZE; h++)
1.17 millert 390: for (vp = variables[h]; vp != NULL; vp = vp->v_link)
1.1 deraadt 391: s++;
1.6 millert 392: ap = (char **)salloc(s * sizeof(*ap));
1.1 deraadt 393: for (h = 0, p = ap; h < HSHSIZE; h++)
1.17 millert 394: for (vp = variables[h]; vp != NULL; vp = vp->v_link)
1.1 deraadt 395: *p++ = vp->v_name;
1.7 millert 396: *p = NULL;
1.1 deraadt 397: sort(ap);
1.7 millert 398: for (p = ap; *p != NULL; p++)
1.1 deraadt 399: printf("%s\t%s\n", *p, value(*p));
400: return(0);
401: }
402: errs = 0;
1.7 millert 403: for (ap = arglist; *ap != NULL; ap++) {
1.1 deraadt 404: cp = *ap;
405: cp2 = varbuf;
406: while (*cp != '=' && *cp != '\0')
407: *cp2++ = *cp++;
408: *cp2 = '\0';
409: if (*cp == '\0')
410: cp = "";
411: else
412: cp++;
413: if (equal(varbuf, "")) {
1.5 millert 414: puts("Non-null variable name required");
1.1 deraadt 415: errs++;
416: continue;
417: }
418: assign(varbuf, cp);
419: }
420: return(errs);
421: }
422:
423: /*
424: * Unset a bunch of variable values.
425: */
426: int
1.17 millert 427: unset(void *v)
1.1 deraadt 428: {
1.2 deraadt 429: char **arglist = v;
1.10 millert 430: struct var *vp, *vp2;
1.1 deraadt 431: int errs, h;
432: char **ap;
433:
434: errs = 0;
1.7 millert 435: for (ap = arglist; *ap != NULL; ap++) {
1.17 millert 436: if ((vp2 = lookup(*ap)) == NULL) {
1.1 deraadt 437: if (!sourcing) {
438: printf("\"%s\": undefined variable\n", *ap);
439: errs++;
440: }
441: continue;
442: }
443: h = hash(*ap);
444: if (vp2 == variables[h]) {
445: variables[h] = variables[h]->v_link;
446: vfree(vp2->v_name);
447: vfree(vp2->v_value);
1.6 millert 448: (void)free(vp2);
1.1 deraadt 449: continue;
450: }
451: for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
452: ;
453: vp->v_link = vp2->v_link;
454: vfree(vp2->v_name);
455: vfree(vp2->v_value);
1.6 millert 456: (void)free(vp2);
1.1 deraadt 457: }
458: return(errs);
459: }
460:
461: /*
462: * Put add users to a group.
463: */
464: int
1.17 millert 465: group(void *v)
1.1 deraadt 466: {
1.2 deraadt 467: char **argv = v;
1.10 millert 468: struct grouphead *gh;
469: struct group *gp;
1.1 deraadt 470: char **ap, *gname, **p;
1.10 millert 471: int h, s;
1.1 deraadt 472:
1.7 millert 473: if (*argv == NULL) {
1.1 deraadt 474: for (h = 0, s = 1; h < HSHSIZE; h++)
1.17 millert 475: for (gh = groups[h]; gh != NULL; gh = gh->g_link)
1.1 deraadt 476: s++;
1.6 millert 477: ap = (char **)salloc(s * sizeof(*ap));
1.1 deraadt 478: for (h = 0, p = ap; h < HSHSIZE; h++)
1.17 millert 479: for (gh = groups[h]; gh != NULL; gh = gh->g_link)
1.1 deraadt 480: *p++ = gh->g_name;
1.7 millert 481: *p = NULL;
1.1 deraadt 482: sort(ap);
1.7 millert 483: for (p = ap; *p != NULL; p++)
1.1 deraadt 484: printgroup(*p);
485: return(0);
486: }
1.7 millert 487: if (argv[1] == NULL) {
1.1 deraadt 488: printgroup(*argv);
489: return(0);
490: }
491: gname = *argv;
492: h = hash(gname);
1.17 millert 493: if ((gh = findgroup(gname)) == NULL) {
1.18 ! millert 494: if ((gh = (struct grouphead *)calloc(sizeof(*gh), 1)) == NULL)
! 495: errx(1, "Out of memory");
1.1 deraadt 496: gh->g_name = vcopy(gname);
1.17 millert 497: gh->g_list = NULL;
1.1 deraadt 498: gh->g_link = groups[h];
499: groups[h] = gh;
500: }
501:
502: /*
503: * Insert names from the command list into the group.
504: * Who cares if there are duplicates? They get tossed
505: * later anyway.
506: */
507:
1.7 millert 508: for (ap = argv+1; *ap != NULL; ap++) {
1.18 ! millert 509: if ((gp = (struct group *)calloc(sizeof(*gp), 1)) == NULL)
! 510: errx(1, "Out of memory");
1.1 deraadt 511: gp->ge_name = vcopy(*ap);
512: gp->ge_link = gh->g_list;
513: gh->g_list = gp;
514: }
515: return(0);
516: }
517:
518: /*
519: * Sort the passed string vecotor into ascending dictionary
520: * order.
521: */
522: void
1.17 millert 523: sort(char **list)
1.1 deraadt 524: {
1.10 millert 525: char **ap;
1.1 deraadt 526:
1.7 millert 527: for (ap = list; *ap != NULL; ap++)
1.1 deraadt 528: ;
529: if (ap-list < 2)
530: return;
531: qsort(list, ap-list, sizeof(*list), diction);
532: }
533:
534: /*
535: * Do a dictionary order comparison of the arguments from
536: * qsort.
537: */
1.2 deraadt 538: static int
1.17 millert 539: diction(const void *a, const void *b)
1.1 deraadt 540: {
1.17 millert 541:
1.1 deraadt 542: return(strcmp(*(char **)a, *(char **)b));
543: }
544:
545: /*
546: * The do nothing command for comments.
547: */
548: /*ARGSUSED*/
549: int
1.17 millert 550: null(void *v)
1.1 deraadt 551: {
1.17 millert 552:
1.5 millert 553: return(0);
1.1 deraadt 554: }
555:
556: /*
557: * Change to another file. With no argument, print information about
558: * the current file.
559: */
560: int
1.17 millert 561: file(void *v)
1.1 deraadt 562: {
1.2 deraadt 563: char **argv = v;
1.1 deraadt 564:
1.7 millert 565: if (argv[0] == NULL) {
1.5 millert 566: newfileinfo(0);
1.11 millert 567: clearnew();
1.5 millert 568: return(0);
1.1 deraadt 569: }
570: if (setfile(*argv) < 0)
1.5 millert 571: return(1);
1.1 deraadt 572: announce();
1.5 millert 573: return(0);
1.1 deraadt 574: }
575:
576: /*
577: * Expand file names like echo
578: */
579: int
1.17 millert 580: echo(void *v)
1.1 deraadt 581: {
1.2 deraadt 582: char **argv = v;
1.10 millert 583: char **ap, *cp;
1.1 deraadt 584:
1.7 millert 585: for (ap = argv; *ap != NULL; ap++) {
1.1 deraadt 586: cp = *ap;
1.7 millert 587: if ((cp = expand(cp)) != NULL) {
1.1 deraadt 588: if (ap != argv)
589: putchar(' ');
1.5 millert 590: fputs(cp, stdout);
1.1 deraadt 591: }
592: }
593: putchar('\n');
1.5 millert 594: return(0);
1.1 deraadt 595: }
596:
597: int
1.17 millert 598: Respond(void *v)
1.1 deraadt 599: {
1.2 deraadt 600: int *msgvec = v;
1.17 millert 601:
1.7 millert 602: if (value("Replyall") == NULL)
1.5 millert 603: return(_Respond(msgvec));
1.1 deraadt 604: else
1.5 millert 605: return(_respond(msgvec));
1.1 deraadt 606: }
607:
608: /*
609: * Reply to a series of messages by simply mailing to the senders
610: * and not messing around with the To: and Cc: lists as in normal
611: * reply.
612: */
613: int
1.17 millert 614: _Respond(int *msgvec)
1.1 deraadt 615: {
616: struct header head;
617: struct message *mp;
1.10 millert 618: int *ap;
619: char *cp;
1.1 deraadt 620:
1.17 millert 621: head.h_to = NULL;
1.1 deraadt 622: for (ap = msgvec; *ap != 0; ap++) {
623: mp = &message[*ap - 1];
624: touch(mp);
625: dot = mp;
1.7 millert 626: if ((cp = skin(hfield("from", mp))) == NULL)
1.1 deraadt 627: cp = skin(nameof(mp, 2));
628: head.h_to = cat(head.h_to, extract(cp, GTO));
629: }
1.17 millert 630: if (head.h_to == NULL)
1.5 millert 631: return(0);
1.1 deraadt 632: mp = &message[msgvec[0] - 1];
1.7 millert 633: if ((head.h_subject = hfield("subject", mp)) == NULL)
1.1 deraadt 634: head.h_subject = hfield("subj", mp);
635: head.h_subject = reedit(head.h_subject);
1.17 millert 636: head.h_cc = NULL;
637: head.h_bcc = NULL;
638: head.h_smopts = NULL;
1.1 deraadt 639: mail1(&head, 1);
1.5 millert 640: return(0);
1.1 deraadt 641: }
642:
643: /*
644: * Conditional commands. These allow one to parameterize one's
645: * .mailrc and do some things if sending, others if receiving.
646: */
647: int
1.17 millert 648: ifcmd(void *v)
1.1 deraadt 649: {
1.2 deraadt 650: char **argv = v;
1.10 millert 651: char *cp;
1.1 deraadt 652:
653: if (cond != CANY) {
1.5 millert 654: puts("Illegal nested \"if\"");
1.1 deraadt 655: return(1);
656: }
657: cond = CANY;
658: cp = argv[0];
659: switch (*cp) {
660: case 'r': case 'R':
661: cond = CRCV;
662: break;
663:
664: case 's': case 'S':
665: cond = CSEND;
666: break;
667:
668: default:
669: printf("Unrecognized if-keyword: \"%s\"\n", cp);
670: return(1);
671: }
672: return(0);
673: }
674:
675: /*
676: * Implement 'else'. This is pretty simple -- we just
677: * flip over the conditional flag.
678: */
679: int
1.17 millert 680: elsecmd(void *v)
1.1 deraadt 681: {
682:
683: switch (cond) {
684: case CANY:
1.5 millert 685: puts("\"Else\" without matching \"if\"");
1.1 deraadt 686: return(1);
687:
688: case CSEND:
689: cond = CRCV;
690: break;
691:
692: case CRCV:
693: cond = CSEND;
694: break;
695:
696: default:
1.5 millert 697: puts("mail's idea of conditions is screwed up");
1.1 deraadt 698: cond = CANY;
699: break;
700: }
701: return(0);
702: }
703:
704: /*
705: * End of if statement. Just set cond back to anything.
706: */
707: int
1.17 millert 708: endifcmd(void *v)
1.1 deraadt 709: {
710:
711: if (cond == CANY) {
1.5 millert 712: puts("\"Endif\" without matching \"if\"");
1.1 deraadt 713: return(1);
714: }
715: cond = CANY;
716: return(0);
717: }
718:
719: /*
720: * Set the list of alternate names.
721: */
722: int
1.17 millert 723: alternates(void *v)
1.1 deraadt 724: {
1.2 deraadt 725: char **namelist = v;
1.18 ! millert 726: char **ap, **ap2;
1.10 millert 727: int c;
1.1 deraadt 728:
729: c = argcount(namelist) + 1;
730: if (c == 1) {
731: if (altnames == 0)
732: return(0);
733: for (ap = altnames; *ap; ap++)
734: printf("%s ", *ap);
1.5 millert 735: putchar('\n');
1.1 deraadt 736: return(0);
737: }
738: if (altnames != 0)
1.6 millert 739: (void)free(altnames);
1.18 ! millert 740: if ((altnames = (char **)calloc(c, sizeof(char *))) == NULL)
! 741: errx(1, "Out of memory");
1.1 deraadt 742: for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
1.18 ! millert 743: if ((*ap2 = strdup(*ap)) == NULL)
! 744: errx(1, "Out of memory");
1.1 deraadt 745: }
746: *ap2 = 0;
747: return(0);
748: }