1 /* 2 * CDDL HEADER START 3 * 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. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * University Copyright- Copyright (c) 1982, 1986, 1988 33 * The Regents of the University of California 34 * All Rights Reserved 35 * 36 * University Acknowledgment- Portions of this document are derived from 37 * software developed by the University of California, Berkeley, and its 38 * contributors. 39 */ 40 41 #include "rcv.h" 42 #include <locale.h> 43 44 /* 45 * mailx -- a modified version of a University of California at Berkeley 46 * mail program 47 * 48 * Still more user commands. 49 */ 50 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); 61 62 static char prevfile[PATHSIZE]; 63 static char origprevfile[PATHSIZE]; 64 static char lastbang[BUFSIZ]; 65 66 /* 67 * Process a shell escape by saving signals, ignoring signals, 68 * and forking a sh -c 69 */ 70 71 int 72 shell(char *str) 73 { 74 shell1(str); 75 printf("!\n"); 76 return(0); 77 } 78 79 static int 80 shell1(char *str) 81 { 82 void (*sig[2])(int); 83 register int t; 84 register pid_t p; 85 char *Shell; 86 char cmd[BUFSIZ]; 87 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); 105 } 106 while (wait(0) != p) 107 ; 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); 113 } 114 115 /* 116 * Fork an interactive shell. 117 */ 118 119 int 120 #ifdef __cplusplus 121 dosh(char *) 122 #else 123 /* ARGSUSED */ 124 dosh(char *s) 125 #endif 126 { 127 void (*sig[2])(int); 128 register int t; 129 register pid_t p; 130 char *Shell; 131 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); 146 } 147 while (wait(0) != p) 148 ; 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); 155 } 156 157 /* 158 * Expand the shell escape by expanding unescaped !'s into the 159 * last issued command where possible. 160 */ 161 static int 162 bangexp(char *str) 163 { 164 char bangbuf[BUFSIZ]; 165 register char *cp, *cp2; 166 register int n; 167 int changed = 0; 168 int bangit = (value("bang")!=NOSTR); 169 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); 179 } 180 changed++; 181 strcpy(cp2, lastbang); 182 cp2 += strlen(lastbang); 183 n -= strlen(lastbang); 184 cp++; 185 continue; 186 } 187 if (*cp == '\\' && cp[1] == '!') { 188 if (--n <= 1) 189 goto overf; 190 *cp2++ = '!'; 191 cp += 2; 192 changed++; 193 } 194 if (--n <= 1) 195 goto overf; 196 *cp2++ = *cp++; 197 } 198 *cp2 = 0; 199 if (changed) { 200 printf("!%s\n", bangbuf); 201 fflush(stdout); 202 } 203 nstrcpy(str, BUFSIZ, bangbuf); 204 nstrcpy(lastbang, sizeof (lastbang), bangbuf); 205 return(0); 206 } 207 208 /* 209 * Print out a nice help message from some file or another. 210 */ 211 212 int 213 help(void) 214 { 215 int c; 216 register FILE *f; 217 218 if ((f = fopen(HELPFILE, "r")) == NULL) { 219 printf(gettext("No help just now.\n")); 220 return(1); 221 } 222 while ((c = getc(f)) != EOF) 223 putchar(c); 224 fclose(f); 225 return(0); 226 } 227 228 /* 229 * Change user's working directory. 230 */ 231 232 int 233 schdir(char *str) 234 { 235 register char *cp; 236 char cwd[PATHSIZE], file[PATHSIZE]; 237 static char efile[PATHSIZE]; 238 239 for (cp = str; *cp == ' '; cp++) 240 ; 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); 251 } 252 } 253 if (chdir(cp) < 0) { 254 perror(cp); 255 return(1); 256 } 257 /* 258 * Convert previously relative names to absolute names. 259 */ 260 if (editfile != NOSTR && *editfile != '/') { 261 snprintf(file, sizeof (file), "%s/%s", cwd, editfile); 262 nstrcpy(efile, sizeof (efile), file); 263 editfile = efile; 264 } 265 if (mailname[0] != '/') { 266 snprintf(file, sizeof (file), "%s/%s", cwd, mailname); 267 nstrcpy(mailname, PATHSIZE, file); 268 } 269 return(0); 270 } 271 272 /* 273 * Two versions of reply. Reply to all names in message or reply 274 * to only sender of message, depending on setting of "replyall". 275 */ 276 277 int 278 respond(int *msgvec) 279 { 280 if (reply2sender()) 281 return(resp1(msgvec, 0)); 282 else 283 return(Resp1(msgvec, 0)); 284 } 285 286 int 287 followup(int *msgvec) 288 { 289 if (reply2sender()) 290 return(resp1(msgvec, 1)); 291 else 292 return(Resp1(msgvec, 1)); 293 } 294 295 int 296 replyall(int *msgvec) 297 { 298 return(resp1(msgvec, 0)); 299 } 300 301 static int 302 resp1(int *msgvec, int useauthor) 303 { 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]; 309 310 if (msgvec[1] != 0) { 311 printf(gettext( 312 "Sorry, can't reply to multiple messages at once\n")); 313 return(1); 314 } 315 snprintf(mydomname, sizeof (mydomname), "%s@%s", myname, domain); 316 snprintf(mylocalname, sizeof (mylocalname), "%s@%s", myname, host); 317 returnaddr = value("returnaddr"); 318 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 */ 334 /* 335 * Delete my name from the reply list, 336 * and with it, all my alternate names. 337 */ 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); 355 } 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); 376 } 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); 382 } 383 384 void 385 getrecf(char *buf, char *recfile, int useauthor, int sz_recfile) 386 { 387 register char *bp, *cp; 388 register char *recf = recfile; 389 register int folderize; 390 char fldr[BUFSIZ]; 391 392 folderize = (value("outfolder")!=NOSTR && getfold(fldr) == 0); 393 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; 403 404 if (cp >= &recfile[sz_recfile - 1]) { 405 printf(gettext("File name buffer overflow\n")); 406 break; 407 } 408 } 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--; 424 } 425 nstrcpy(recf, sz, cp); 426 } else 427 *recf = '\0'; 428 } 429 if (debug) fprintf(stderr, "recfile='%s'\n", recfile); 430 } 431 432 /* 433 * Modify the subject we are replying to to begin with Re: if 434 * it does not already. 435 */ 436 437 static char * 438 reedit(char *subj) 439 { 440 char sbuf[10]; 441 register char *newsubj; 442 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); 452 } 453 454 /* 455 * Preserve the named messages, so that they will be sent 456 * back to the system mailbox. 457 */ 458 459 int 460 preserve(int *msgvec) 461 { 462 register struct message *mp; 463 register int *ip, mesg; 464 465 if (edit) { 466 printf(gettext("Cannot \"preserve\" in edit mode\n")); 467 return(1); 468 } 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; 475 } 476 return(0); 477 } 478 479 /* 480 * Mark all given messages as unread. 481 */ 482 int 483 unread(int msgvec[]) 484 { 485 register int *ip; 486 487 for (ip = msgvec; *ip != NULL; ip++) { 488 dot = &message[*ip-1]; 489 dot->m_flag &= ~(MREAD|MTOUCH); 490 dot->m_flag |= MSTATUS; 491 } 492 return(0); 493 } 494 495 /* 496 * Print the size of each message. 497 */ 498 499 int 500 messize(int *msgvec) 501 { 502 register struct message *mp; 503 register int *ip, mesg; 504 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); 510 } 511 return(0); 512 } 513 514 /* 515 * Quit quickly. If we are sourcing, just pop the input level 516 * by returning an error. 517 */ 518 519 int 520 rexit(int e) 521 { 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 */ 531 } 532 533 /* 534 * Set or display a variable value. Syntax is similar to that 535 * of csh. 536 */ 537 538 int 539 set(char **arglist) 540 { 541 register struct var *vp; 542 register char *cp, *cp2; 543 char varbuf[BUFSIZ], **ap, **p; 544 int errs, h, s; 545 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); 562 } 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; 578 } 579 assign(varbuf, cp); 580 } 581 return(errs); 582 } 583 584 /* 585 * Unset a bunch of variable values. 586 */ 587 588 int 589 unset(char **arglist) 590 { 591 register int errs; 592 register char **ap; 593 594 errs = 0; 595 for (ap = arglist; *ap != NOSTR; ap++) 596 errs += deassign(*ap); 597 return(errs); 598 } 599 600 /* 601 * Add users to a group. 602 */ 603 604 int 605 group(char **argv) 606 { 607 register struct grouphead *gh; 608 register struct mgroup *gp; 609 register int h; 610 int s; 611 char **ap, *gname, **p; 612 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); 626 } 627 if (argcount(argv) == 1) { 628 printgroup(*argv); 629 return(0); 630 } 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"); 637 } 638 gh->g_name = vcopy(gname); 639 gh->g_list = NOGE; 640 gh->g_link = groups[h]; 641 groups[h] = gh; 642 } 643 644 /* 645 * Insert names from the command list into the group. 646 * Who cares if there are duplicates? They get tossed 647 * later anyway. 648 */ 649 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"); 654 } 655 gp->ge_name = vcopy(*ap); 656 gp->ge_link = gh->g_list; 657 gh->g_list = gp; 658 } 659 return(0); 660 } 661 662 /* 663 * Remove users from a group. 664 */ 665 666 int 667 ungroup(char **argv) 668 { 669 register struct grouphead *gh, **ghp; 670 register struct mgroup *gp, *gpnext; 671 register int h; 672 char **ap, *gname; 673 674 if (argcount(argv) == 0) { 675 printf("Must specify alias or group to remove\n"); 676 return(1); 677 } 678 679 /* 680 * Remove names on the command list from the group list. 681 */ 682 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); 696 } 697 vfree(gh->g_name); 698 free(gh); 699 break; 700 } 701 } 702 } 703 return(0); 704 } 705 706 /* 707 * Sort the passed string vecotor into ascending dictionary 708 * order. 709 */ 710 711 static void 712 sort(char **list) 713 { 714 register char **ap; 715 716 for (ap = list; *ap != NOSTR; ap++) 717 ; 718 if (ap-list < 2) 719 return; 720 qsort((char *) list, (unsigned) (ap-list), sizeof *list, diction); 721 } 722 723 /* 724 * Do a dictionary order comparison of the arguments from 725 * qsort. 726 */ 727 static int 728 diction(const void *a, const void *b) 729 { 730 return(strcmp(*(char **)a, *(char **)b)); 731 } 732 733 /* 734 * The do nothing command for comments. 735 */ 736 737 int 738 #ifdef __cplusplus 739 null(char *) 740 #else 741 /* ARGSUSED */ 742 null(char *s) 743 #endif 744 { 745 return(0); 746 } 747 748 /* 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. 752 */ 753 int 754 file(char **argv) 755 { 756 register char *cp; 757 int editing, mdot; 758 759 if (argv[0] == NOSTR) { 760 mdot = newfileinfo(1); 761 dot = &message[mdot - 1]; 762 return(0); 763 } 764 765 /* 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 773 */ 774 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); 781 } 782 mdot = newfileinfo(1); 783 dot = &message[mdot - 1]; 784 return(0); 785 } 786 787 /* 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 796 */ 797 798 static char * 799 getfilename(char *name, int *aedit) 800 { 801 register char *cp; 802 char savename[BUFSIZ]; 803 char oldmailname[BUFSIZ]; 804 char tmp[BUFSIZ]; 805 806 /* 807 * Assume we will be in "edit file" mode, until 808 * proven wrong. 809 */ 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); 823 } 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); 830 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); 837 } 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); 844 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); 852 } 853 /* FALLTHROUGH */ 854 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; 866 } 867 return(cp); 868 } 869 } 870 871 /* 872 * Expand file names like echo 873 */ 874 875 int 876 echo(register char **argv) 877 { 878 register char *cp; 879 int neednl = 0; 880 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(' '); 888 } 889 } 890 if (neednl) 891 putchar('\n'); 892 return(0); 893 } 894 895 /* 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. 899 */ 900 901 int 902 Respond(int *msgvec) 903 { 904 if (reply2sender()) 905 return(Resp1(msgvec, 0)); 906 else 907 return(resp1(msgvec, 0)); 908 } 909 910 int 911 Followup(int *msgvec) 912 { 913 if (reply2sender()) 914 return(Resp1(msgvec, 1)); 915 else 916 return(resp1(msgvec, 1)); 917 } 918 919 int 920 replysender(int *msgvec) 921 { 922 return(Resp1(msgvec, 0)); 923 } 924 925 static int 926 Resp1(int *msgvec, int useauthor) 927 { 928 struct header head; 929 struct message *mp; 930 register int s, *ap; 931 register char *cp, *cp2, *subject; 932 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; 938 } 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++ = ' '; 948 } 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); 964 } 965 966 /* 967 * Conditional commands. These allow one to parameterize one's 968 * .mailrc and do some things if sending, others if receiving. 969 */ 970 971 int 972 ifcmd(char **argv) 973 { 974 register char *cp; 975 976 if (cond != CANY) { 977 printf(gettext("Illegal nested \"if\"\n")); 978 return(1); 979 } 980 cond = CANY; 981 cp = argv[0]; 982 switch (*cp) { 983 case 'r': case 'R': 984 cond = CRCV; 985 break; 986 987 case 's': case 'S': 988 cond = CSEND; 989 break; 990 991 case 't': case 'T': 992 cond = CTTY; 993 break; 994 995 default: 996 printf(gettext("Unrecognized if-keyword: \"%s\"\n"), cp); 997 return(1); 998 } 999 return(0); 1000 } 1001 1002 /* 1003 * Implement 'else'. This is pretty simple -- we just 1004 * flip over the conditional flag. 1005 */ 1006 1007 int 1008 elsecmd(void) 1009 { 1010 1011 switch (cond) { 1012 case CANY: 1013 printf(gettext("\"Else\" without matching \"if\"\n")); 1014 return(1); 1015 1016 case CSEND: 1017 cond = CRCV; 1018 break; 1019 1020 case CRCV: 1021 cond = CSEND; 1022 break; 1023 1024 case CTTY: 1025 cond = CNOTTY; 1026 break; 1027 1028 case CNOTTY: 1029 cond = CTTY; 1030 break; 1031 1032 default: 1033 printf(gettext("invalid condition encountered\n")); 1034 cond = CANY; 1035 break; 1036 } 1037 return(0); 1038 } 1039 1040 /* 1041 * End of if statement. Just set cond back to anything. 1042 */ 1043 1044 int 1045 endifcmd(void) 1046 { 1047 1048 if (cond == CANY) { 1049 printf(gettext("\"Endif\" without matching \"if\"\n")); 1050 return(1); 1051 } 1052 cond = CANY; 1053 return(0); 1054 } 1055 1056 /* 1057 * Set the list of alternate names. 1058 */ 1059 int 1060 alternates(char **namelist) 1061 { 1062 register int c; 1063 register char **ap, **ap2, *cp; 1064 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); 1073 } 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; 1085 } 1086 *ap2 = 0; 1087 return(0); 1088 } 1089 1090 /* 1091 * Figure out who to reply to. 1092 * Return the real sender in *f. 1093 */ 1094 static char * 1095 replyto(struct message *mp, char **f) 1096 { 1097 char *r, *rf; 1098 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); 1106 } 1107 1108 /* 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. 1112 * 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. 1116 */ 1117 1118 static int 1119 reply2sender (void) 1120 { 1121 register int rep = (value("replyall") != NOSTR); 1122 register int flp = (value("flipr") != NOSTR); 1123 1124 return((rep && !flp)|| (!rep && flp)); 1125 } 1126