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 #pragma ident "%Z%%M% %I% %E% SMI" 42 43 #include "rcv.h" 44 #include <locale.h> 45 46 /* 47 * mailx -- a modified version of a University of California at Berkeley 48 * mail program 49 * 50 * Still more user commands. 51 */ 52 53 static int bangexp(char *str); 54 static int diction(const void *a, const void *b); 55 static char *getfilename(char *name, int *aedit); 56 static int resp1(int *msgvec, int useauthor); 57 static int Resp1(int *msgvec, int useauthor); 58 static char *reedit(char *subj); 59 static int shell1(char *str); 60 static void sort(char **list); 61 static char *replyto(struct message *mp, char **f); 62 static int reply2sender(void); 63 64 static char prevfile[PATHSIZE]; 65 static char origprevfile[PATHSIZE]; 66 static char lastbang[BUFSIZ]; 67 68 /* 69 * Process a shell escape by saving signals, ignoring signals, 70 * and forking a sh -c 71 */ 72 73 int 74 shell(char *str) 75 { 76 shell1(str); 77 printf("!\n"); 78 return(0); 79 } 80 81 static int 82 shell1(char *str) 83 { 84 void (*sig[2])(int); 85 register int t; 86 register pid_t p; 87 char *Shell; 88 char cmd[BUFSIZ]; 89 90 nstrcpy(cmd, sizeof (cmd), str); 91 if (bangexp(cmd) < 0) 92 return(-1); 93 if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0') 94 Shell = SHELL; 95 for (t = SIGINT; t <= SIGQUIT; t++) 96 sig[t-SIGINT] = sigset(t, SIG_IGN); 97 p = vfork(); 98 if (p == 0) { 99 setuid(getuid()); 100 sigchild(); 101 for (t = SIGINT; t <= SIGQUIT; t++) 102 if (sig[t-SIGINT] != SIG_IGN) 103 sigsys(t, SIG_DFL); 104 execlp(Shell, Shell, "-c", cmd, (char *)0); 105 perror(Shell); 106 _exit(1); 107 } 108 while (wait(0) != p) 109 ; 110 if (p == (pid_t)-1) 111 perror("fork"); 112 for (t = SIGINT; t <= SIGQUIT; t++) 113 sigset(t, sig[t-SIGINT]); 114 return(0); 115 } 116 117 /* 118 * Fork an interactive shell. 119 */ 120 121 int 122 #ifdef __cplusplus 123 dosh(char *) 124 #else 125 /* ARGSUSED */ 126 dosh(char *s) 127 #endif 128 { 129 void (*sig[2])(int); 130 register int t; 131 register pid_t p; 132 char *Shell; 133 134 if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0') 135 Shell = SHELL; 136 for (t = SIGINT; t <= SIGQUIT; t++) 137 sig[t-SIGINT] = sigset(t, SIG_IGN); 138 p = vfork(); 139 if (p == 0) { 140 setuid(getuid()); 141 sigchild(); 142 for (t = SIGINT; t <= SIGQUIT; t++) 143 if (sig[t-SIGINT] != SIG_IGN) 144 sigset(t, SIG_DFL); 145 execlp(Shell, Shell, (char *)0); 146 perror(Shell); 147 _exit(1); 148 } 149 while (wait(0) != p) 150 ; 151 if (p == (pid_t)-1) 152 perror("fork"); 153 for (t = SIGINT; t <= SIGQUIT; t++) 154 sigset(t, sig[t-SIGINT]); 155 putchar('\n'); 156 return(0); 157 } 158 159 /* 160 * Expand the shell escape by expanding unescaped !'s into the 161 * last issued command where possible. 162 */ 163 static int 164 bangexp(char *str) 165 { 166 char bangbuf[BUFSIZ]; 167 register char *cp, *cp2; 168 register int n; 169 int changed = 0; 170 int bangit = (value("bang")!=NOSTR); 171 172 cp = str; 173 cp2 = bangbuf; 174 n = BUFSIZ; 175 while (*cp) { 176 if (*cp=='!' && bangit) { 177 if (n < (int)strlen(lastbang)) { 178 overf: 179 printf(gettext("Command buffer overflow\n")); 180 return(-1); 181 } 182 changed++; 183 strcpy(cp2, lastbang); 184 cp2 += strlen(lastbang); 185 n -= strlen(lastbang); 186 cp++; 187 continue; 188 } 189 if (*cp == '\\' && cp[1] == '!') { 190 if (--n <= 1) 191 goto overf; 192 *cp2++ = '!'; 193 cp += 2; 194 changed++; 195 } 196 if (--n <= 1) 197 goto overf; 198 *cp2++ = *cp++; 199 } 200 *cp2 = 0; 201 if (changed) { 202 printf("!%s\n", bangbuf); 203 fflush(stdout); 204 } 205 nstrcpy(str, BUFSIZ, bangbuf); 206 nstrcpy(lastbang, sizeof (lastbang), bangbuf); 207 return(0); 208 } 209 210 /* 211 * Print out a nice help message from some file or another. 212 */ 213 214 int 215 help(void) 216 { 217 int c; 218 register FILE *f; 219 220 if ((f = fopen(HELPFILE, "r")) == NULL) { 221 printf(gettext("No help just now.\n")); 222 return(1); 223 } 224 while ((c = getc(f)) != EOF) 225 putchar(c); 226 fclose(f); 227 return(0); 228 } 229 230 /* 231 * Change user's working directory. 232 */ 233 234 int 235 schdir(char *str) 236 { 237 register char *cp; 238 char cwd[PATHSIZE], file[PATHSIZE]; 239 static char efile[PATHSIZE]; 240 241 for (cp = str; *cp == ' '; cp++) 242 ; 243 if (*cp == '\0') 244 cp = homedir; 245 else 246 if ((cp = expand(cp)) == NOSTR) 247 return(1); 248 if (editfile != NOSTR && (*editfile != '/' || mailname[0] != '/')) { 249 if (getcwd(cwd, (int)sizeof (cwd)) == 0) { 250 fprintf(stderr, 251 gettext("Can't get current directory: %s\n"), cwd); 252 return(1); 253 } 254 } 255 if (chdir(cp) < 0) { 256 perror(cp); 257 return(1); 258 } 259 /* 260 * Convert previously relative names to absolute names. 261 */ 262 if (editfile != NOSTR && *editfile != '/') { 263 snprintf(file, sizeof (file), "%s/%s", cwd, editfile); 264 nstrcpy(efile, sizeof (efile), file); 265 editfile = efile; 266 } 267 if (mailname[0] != '/') { 268 snprintf(file, sizeof (file), "%s/%s", cwd, mailname); 269 nstrcpy(mailname, PATHSIZE, file); 270 } 271 return(0); 272 } 273 274 /* 275 * Two versions of reply. Reply to all names in message or reply 276 * to only sender of message, depending on setting of "replyall". 277 */ 278 279 int 280 respond(int *msgvec) 281 { 282 if (reply2sender()) 283 return(resp1(msgvec, 0)); 284 else 285 return(Resp1(msgvec, 0)); 286 } 287 288 int 289 followup(int *msgvec) 290 { 291 if (reply2sender()) 292 return(resp1(msgvec, 1)); 293 else 294 return(Resp1(msgvec, 1)); 295 } 296 297 int 298 replyall(int *msgvec) 299 { 300 return(resp1(msgvec, 0)); 301 } 302 303 static int 304 resp1(int *msgvec, int useauthor) 305 { 306 struct message *mp; 307 char *cp, *buf, *rcv, *skin_rcv, *reply2, **ap, *returnaddr; 308 struct name *np; 309 struct header head; 310 char mylocalname[BUFSIZ], mydomname[BUFSIZ]; 311 312 if (msgvec[1] != 0) { 313 printf(gettext( 314 "Sorry, can't reply to multiple messages at once\n")); 315 return(1); 316 } 317 snprintf(mydomname, sizeof (mydomname), "%s@%s", myname, domain); 318 snprintf(mylocalname, sizeof (mylocalname), "%s@%s", myname, host); 319 returnaddr = value("returnaddr"); 320 321 mp = &message[msgvec[0] - 1]; 322 dot = mp; 323 reply2 = replyto(mp, &rcv); 324 cp = skin(hfield("to", mp, addto)); 325 if (cp != NOSTR) { 326 buf = (char *)salloc(strlen(reply2) + strlen(cp) + 2); 327 strcpy(buf, reply2); 328 strcat(buf, " "); 329 strcat(buf, cp); 330 } else 331 buf = reply2; 332 np = elide(extract(buf, GTO)); 333 #ifdef OPTIM 334 /* rcv = netrename(rcv); */ 335 #endif /* OPTIM */ 336 /* 337 * Delete my name from the reply list, 338 * and with it, all my alternate names. 339 */ 340 skin_rcv = skin(rcv); 341 mapf(np, skin_rcv); 342 np = delname(np, myname); 343 np = delname(np, mylocalname); 344 np = delname(np, mydomname); 345 if (returnaddr && *returnaddr) 346 np = delname(np, returnaddr); 347 if (altnames != 0) 348 for (ap = altnames; *ap; ap++) 349 np = delname(np, *ap); 350 head.h_seq = 1; 351 cp = detract(np, 0); 352 if (cp == NOSTR) { 353 if (reply2) 354 cp = unuucp(reply2); 355 else 356 cp = unuucp(rcv); 357 } 358 head.h_to = cp; 359 head.h_subject = hfield("subject", mp, addone); 360 if (head.h_subject == NOSTR) 361 head.h_subject = hfield("subj", mp, addone); 362 head.h_subject = reedit(head.h_subject); 363 head.h_cc = NOSTR; 364 cp = skin(hfield("cc", mp, addto)); 365 if (cp != NOSTR) { 366 np = elide(extract(cp, GCC)); 367 mapf(np, skin_rcv); 368 np = delname(np, myname); 369 np = delname(np, mylocalname); 370 np = delname(np, mydomname); 371 if (returnaddr && *returnaddr) 372 np = delname(np, returnaddr); 373 np = delname(np, skin_rcv); 374 if (altnames != 0) 375 for (ap = altnames; *ap; ap++) 376 np = delname(np, *ap); 377 head.h_cc = detract(np, 0); 378 } 379 head.h_bcc = NOSTR; 380 head.h_defopt = NOSTR; 381 head.h_others = NOSTRPTR; 382 mail1(&head, useauthor, useauthor ? rcv : NOSTR); 383 return(0); 384 } 385 386 void 387 getrecf(char *buf, char *recfile, int useauthor, int sz_recfile) 388 { 389 register char *bp, *cp; 390 register char *recf = recfile; 391 register int folderize; 392 char fldr[BUFSIZ]; 393 394 folderize = (value("outfolder")!=NOSTR && getfold(fldr) == 0); 395 396 if (useauthor) { 397 if (folderize) 398 *recf++ = '+'; 399 if (debug) fprintf(stderr, "buf='%s'\n", buf); 400 for (bp=skin(buf), cp=recf; *bp && !any(*bp, ", "); bp++) { 401 if (*bp=='!') 402 cp = recf; 403 else 404 *cp++ = *bp; 405 406 if (cp >= &recfile[sz_recfile - 1]) { 407 printf(gettext("File name buffer overflow\n")); 408 break; 409 } 410 } 411 *cp = '\0'; 412 if (cp==recf) 413 *recfile = '\0'; 414 /* now strip off any Internet host names */ 415 if ((cp = strchr(recf, '%')) == NOSTR) 416 cp = strchr(recf, '@'); 417 if (cp != NOSTR) 418 *cp = '\0'; 419 } else { 420 if (cp = value("record")) { 421 int sz = PATHSIZE; 422 if (folderize && *cp!='+' && *cp!='/' 423 && *safeexpand(cp)!='/') { 424 *recf++ = '+'; 425 sz--; 426 } 427 nstrcpy(recf, sz, cp); 428 } else 429 *recf = '\0'; 430 } 431 if (debug) fprintf(stderr, "recfile='%s'\n", recfile); 432 } 433 434 /* 435 * Modify the subject we are replying to to begin with Re: if 436 * it does not already. 437 */ 438 439 static char * 440 reedit(char *subj) 441 { 442 char sbuf[10]; 443 register char *newsubj; 444 445 if (subj == NOSTR) 446 return(NOSTR); 447 strncpy(sbuf, subj, 3); 448 sbuf[3] = 0; 449 if (icequal(sbuf, "re:")) 450 return(subj); 451 newsubj = (char *)salloc((unsigned)(strlen(subj) + 5)); 452 sprintf(newsubj, "Re: %s", subj); 453 return(newsubj); 454 } 455 456 /* 457 * Preserve the named messages, so that they will be sent 458 * back to the system mailbox. 459 */ 460 461 int 462 preserve(int *msgvec) 463 { 464 register struct message *mp; 465 register int *ip, mesg; 466 467 if (edit) { 468 printf(gettext("Cannot \"preserve\" in edit mode\n")); 469 return(1); 470 } 471 for (ip = msgvec; *ip != NULL; ip++) { 472 mesg = *ip; 473 mp = &message[mesg-1]; 474 mp->m_flag |= MPRESERVE; 475 mp->m_flag &= ~MBOX; 476 dot = mp; 477 } 478 return(0); 479 } 480 481 /* 482 * Mark all given messages as unread. 483 */ 484 int 485 unread(int msgvec[]) 486 { 487 register int *ip; 488 489 for (ip = msgvec; *ip != NULL; ip++) { 490 dot = &message[*ip-1]; 491 dot->m_flag &= ~(MREAD|MTOUCH); 492 dot->m_flag |= MSTATUS; 493 } 494 return(0); 495 } 496 497 /* 498 * Print the size of each message. 499 */ 500 501 int 502 messize(int *msgvec) 503 { 504 register struct message *mp; 505 register int *ip, mesg; 506 507 for (ip = msgvec; *ip != NULL; ip++) { 508 mesg = *ip; 509 mp = &message[mesg-1]; 510 dot = mp; 511 printf("%d: %ld\n", mesg, mp->m_size); 512 } 513 return(0); 514 } 515 516 /* 517 * Quit quickly. If we are sourcing, just pop the input level 518 * by returning an error. 519 */ 520 521 int 522 rexit(int e) 523 { 524 if (sourcing) 525 return(1); 526 if (Tflag != NOSTR) 527 close(creat(Tflag, TEMPPERM)); 528 if (!edit) 529 Verhogen(); 530 exit(e ? e : rpterr); 531 /* NOTREACHED */ 532 return (0); /* shut up lint and CC */ 533 } 534 535 /* 536 * Set or display a variable value. Syntax is similar to that 537 * of csh. 538 */ 539 540 int 541 set(char **arglist) 542 { 543 register struct var *vp; 544 register char *cp, *cp2; 545 char varbuf[BUFSIZ], **ap, **p; 546 int errs, h, s; 547 548 if (argcount(arglist) == 0) { 549 for (h = 0, s = 1; h < HSHSIZE; h++) 550 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) 551 s++; 552 ap = (char **) salloc(s * sizeof *ap); 553 for (h = 0, p = ap; h < HSHSIZE; h++) 554 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) 555 *p++ = vp->v_name; 556 *p = NOSTR; 557 sort(ap); 558 for (p = ap; *p != NOSTR; p++) 559 if (((cp = value(*p)) != 0) && *cp) 560 printf("%s=\"%s\"\n", *p, cp); 561 else 562 printf("%s\n", *p); 563 return(0); 564 } 565 errs = 0; 566 for (ap = arglist; *ap != NOSTR; ap++) { 567 cp = *ap; 568 cp2 = varbuf; 569 while (*cp != '=' && *cp != '\0') 570 *cp2++ = *cp++; 571 *cp2 = '\0'; 572 if (*cp == '\0') 573 cp = ""; 574 else 575 cp++; 576 if (equal(varbuf, "")) { 577 printf(gettext("Non-null variable name required\n")); 578 errs++; 579 continue; 580 } 581 assign(varbuf, cp); 582 } 583 return(errs); 584 } 585 586 /* 587 * Unset a bunch of variable values. 588 */ 589 590 int 591 unset(char **arglist) 592 { 593 register int errs; 594 register char **ap; 595 596 errs = 0; 597 for (ap = arglist; *ap != NOSTR; ap++) 598 errs += deassign(*ap); 599 return(errs); 600 } 601 602 /* 603 * Add users to a group. 604 */ 605 606 int 607 group(char **argv) 608 { 609 register struct grouphead *gh; 610 register struct mgroup *gp; 611 register int h; 612 int s; 613 char **ap, *gname, **p; 614 615 if (argcount(argv) == 0) { 616 for (h = 0, s = 1; h < HSHSIZE; h++) 617 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) 618 s++; 619 ap = (char **) salloc(s * sizeof *ap); 620 for (h = 0, p = ap; h < HSHSIZE; h++) 621 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) 622 *p++ = gh->g_name; 623 *p = NOSTR; 624 sort(ap); 625 for (p = ap; *p != NOSTR; p++) 626 printgroup(*p); 627 return(0); 628 } 629 if (argcount(argv) == 1) { 630 printgroup(*argv); 631 return(0); 632 } 633 gname = *argv; 634 h = hash(gname); 635 if ((gh = findgroup(gname)) == NOGRP) { 636 if ((gh = (struct grouphead *) 637 calloc(sizeof (*gh), 1)) == NULL) { 638 panic("Failed to allocate memory for group"); 639 } 640 gh->g_name = vcopy(gname); 641 gh->g_list = NOGE; 642 gh->g_link = groups[h]; 643 groups[h] = gh; 644 } 645 646 /* 647 * Insert names from the command list into the group. 648 * Who cares if there are duplicates? They get tossed 649 * later anyway. 650 */ 651 652 for (ap = argv+1; *ap != NOSTR; ap++) { 653 if ((gp = (struct mgroup *) 654 calloc(sizeof (*gp), 1)) == NULL) { 655 panic("Failed to allocate memory for group"); 656 } 657 gp->ge_name = vcopy(*ap); 658 gp->ge_link = gh->g_list; 659 gh->g_list = gp; 660 } 661 return(0); 662 } 663 664 /* 665 * Remove users from a group. 666 */ 667 668 int 669 ungroup(char **argv) 670 { 671 register struct grouphead *gh, **ghp; 672 register struct mgroup *gp, *gpnext; 673 register int h; 674 char **ap, *gname; 675 676 if (argcount(argv) == 0) { 677 printf("Must specify alias or group to remove\n"); 678 return(1); 679 } 680 681 /* 682 * Remove names on the command list from the group list. 683 */ 684 685 for (ap = argv; *ap != NOSTR; ap++) { 686 gname = *ap; 687 h = hash(gname); 688 for (ghp = &groups[h]; *ghp != NOGRP; ghp = &((*ghp)->g_link)) { 689 gh = *ghp; 690 if (equal(gh->g_name, gname)) { 691 /* remove from list */ 692 *ghp = gh->g_link; 693 /* free each member of gorup */ 694 for (gp = gh->g_list; gp != NOGE; gp = gpnext) { 695 gpnext = gp->ge_link; 696 vfree(gp->ge_name); 697 free(gp); 698 } 699 vfree(gh->g_name); 700 free(gh); 701 break; 702 } 703 } 704 } 705 return(0); 706 } 707 708 /* 709 * Sort the passed string vecotor into ascending dictionary 710 * order. 711 */ 712 713 static void 714 sort(char **list) 715 { 716 register char **ap; 717 718 for (ap = list; *ap != NOSTR; ap++) 719 ; 720 if (ap-list < 2) 721 return; 722 qsort((char *) list, (unsigned) (ap-list), sizeof *list, diction); 723 } 724 725 /* 726 * Do a dictionary order comparison of the arguments from 727 * qsort. 728 */ 729 static int 730 diction(const void *a, const void *b) 731 { 732 return(strcmp(*(char **)a, *(char **)b)); 733 } 734 735 /* 736 * The do nothing command for comments. 737 */ 738 739 int 740 #ifdef __cplusplus 741 null(char *) 742 #else 743 /* ARGSUSED */ 744 null(char *s) 745 #endif 746 { 747 return(0); 748 } 749 750 /* 751 * Print out the current edit file, if we are editing. 752 * Otherwise, print the name of the person who's mail 753 * we are reading. 754 */ 755 int 756 file(char **argv) 757 { 758 register char *cp; 759 int editing, mdot; 760 761 if (argv[0] == NOSTR) { 762 mdot = newfileinfo(1); 763 dot = &message[mdot - 1]; 764 return(0); 765 } 766 767 /* 768 * Acker's! Must switch to the new file. 769 * We use a funny interpretation -- 770 * # -- gets the previous file 771 * % -- gets the invoker's post office box 772 * %user -- gets someone else's post office box 773 * & -- gets invoker's mbox file 774 * string -- reads the given file 775 */ 776 777 cp = getfilename(argv[0], &editing); 778 if (cp == NOSTR) 779 return(-1); 780 if (setfile(cp, editing)) { 781 nstrcpy(origname, PATHSIZE, origprevfile); 782 return(-1); 783 } 784 mdot = newfileinfo(1); 785 dot = &message[mdot - 1]; 786 return(0); 787 } 788 789 /* 790 * Evaluate the string given as a new mailbox name. 791 * Ultimately, we want this to support a number of meta characters. 792 * Possibly: 793 * % -- for my system mail box 794 * %user -- for user's system mail box 795 * # -- for previous file 796 * & -- get's invoker's mbox file 797 * file name -- for any other file 798 */ 799 800 static char * 801 getfilename(char *name, int *aedit) 802 { 803 register char *cp; 804 char savename[BUFSIZ]; 805 char oldmailname[BUFSIZ]; 806 char tmp[BUFSIZ]; 807 808 /* 809 * Assume we will be in "edit file" mode, until 810 * proven wrong. 811 */ 812 *aedit = 1; 813 switch (*name) { 814 case '%': 815 *aedit = 0; 816 nstrcpy(prevfile, sizeof (prevfile), editfile); 817 nstrcpy(origprevfile, sizeof (origprevfile), origname); 818 if (name[1] != 0) { 819 nstrcpy(oldmailname, sizeof (oldmailname), mailname); 820 findmail(name+1); 821 cp = savestr(mailname); 822 nstrcpy(origname, PATHSIZE, cp); 823 nstrcpy(mailname, PATHSIZE, oldmailname); 824 return(cp); 825 } 826 nstrcpy(oldmailname, sizeof (oldmailname), mailname); 827 findmail(NULL); 828 cp = savestr(mailname); 829 nstrcpy(mailname, PATHSIZE, oldmailname); 830 nstrcpy(origname, PATHSIZE, cp); 831 return(cp); 832 833 case '#': 834 if (name[1] != 0) 835 goto regular; 836 if (prevfile[0] == 0) { 837 printf(gettext("No previous file\n")); 838 return(NOSTR); 839 } 840 cp = savestr(prevfile); 841 nstrcpy(prevfile, sizeof (prevfile), editfile); 842 nstrcpy(tmp, sizeof (tmp), origname); 843 nstrcpy(origname, PATHSIZE, origprevfile); 844 nstrcpy(origprevfile, sizeof (origprevfile), tmp); 845 return(cp); 846 847 case '&': 848 nstrcpy(prevfile, sizeof (prevfile), editfile); 849 nstrcpy(origprevfile, sizeof (origprevfile), origname); 850 if (name[1] == 0) { 851 cp=Getf("MBOX"); 852 nstrcpy(origname, PATHSIZE, cp); 853 return(cp); 854 } 855 /* Fall into . . . */ 856 857 default: 858 regular: 859 nstrcpy(prevfile, sizeof (prevfile), editfile); 860 nstrcpy(origprevfile, sizeof (origprevfile), origname); 861 cp = safeexpand(name); 862 nstrcpy(origname, PATHSIZE, cp); 863 if (cp[0] != '/') { 864 name = getcwd(NOSTR, PATHSIZE); 865 nstrcat(name, PATHSIZE, "/"); 866 nstrcat(name, PATHSIZE, cp); 867 cp = name; 868 } 869 return(cp); 870 } 871 } 872 873 /* 874 * Expand file names like echo 875 */ 876 877 int 878 echo(register char **argv) 879 { 880 register char *cp; 881 int neednl = 0; 882 883 while (*argv != NOSTR) { 884 cp = *argv++; 885 if ((cp = expand(cp)) != NOSTR) { 886 neednl++; 887 printf("%s", cp); 888 if (*argv!=NOSTR) 889 putchar(' '); 890 } 891 } 892 if (neednl) 893 putchar('\n'); 894 return(0); 895 } 896 897 /* 898 * Reply to a series of messages by simply mailing to the senders 899 * and not messing around with the To: and Cc: lists as in normal 900 * reply. 901 */ 902 903 int 904 Respond(int *msgvec) 905 { 906 if (reply2sender()) 907 return(Resp1(msgvec, 0)); 908 else 909 return(resp1(msgvec, 0)); 910 } 911 912 int 913 Followup(int *msgvec) 914 { 915 if (reply2sender()) 916 return(Resp1(msgvec, 1)); 917 else 918 return(resp1(msgvec, 1)); 919 } 920 921 int 922 replysender(int *msgvec) 923 { 924 return(Resp1(msgvec, 0)); 925 } 926 927 static int 928 Resp1(int *msgvec, int useauthor) 929 { 930 struct header head; 931 struct message *mp; 932 register int s, *ap; 933 register char *cp, *cp2, *subject; 934 935 for (s = 0, ap = msgvec; *ap != 0; ap++) { 936 mp = &message[*ap - 1]; 937 dot = mp; 938 cp = replyto(mp, NOSTRPTR); 939 s += strlen(cp) + 1; 940 } 941 if (s == 0) 942 return(0); 943 cp = (char *)salloc(s + 2); 944 head.h_to = cp; 945 for (ap = msgvec; *ap != 0; ap++) { 946 mp = &message[*ap - 1]; 947 cp2 = replyto(mp, NOSTRPTR); 948 cp = copy(cp2, cp); 949 *cp++ = ' '; 950 } 951 *--cp = 0; 952 mp = &message[msgvec[0] - 1]; 953 subject = hfield("subject", mp, addone); 954 head.h_seq = 1; 955 if (subject == NOSTR) 956 subject = hfield("subj", mp, addone); 957 head.h_subject = reedit(subject); 958 if (subject != NOSTR) 959 head.h_seq++; 960 head.h_cc = NOSTR; 961 head.h_bcc = NOSTR; 962 head.h_defopt = NOSTR; 963 head.h_others = NOSTRPTR; 964 mail1(&head, useauthor, NOSTR); 965 return(0); 966 } 967 968 /* 969 * Conditional commands. These allow one to parameterize one's 970 * .mailrc and do some things if sending, others if receiving. 971 */ 972 973 int 974 ifcmd(char **argv) 975 { 976 register char *cp; 977 978 if (cond != CANY) { 979 printf(gettext("Illegal nested \"if\"\n")); 980 return(1); 981 } 982 cond = CANY; 983 cp = argv[0]; 984 switch (*cp) { 985 case 'r': case 'R': 986 cond = CRCV; 987 break; 988 989 case 's': case 'S': 990 cond = CSEND; 991 break; 992 993 case 't': case 'T': 994 cond = CTTY; 995 break; 996 997 default: 998 printf(gettext("Unrecognized if-keyword: \"%s\"\n"), cp); 999 return(1); 1000 } 1001 return(0); 1002 } 1003 1004 /* 1005 * Implement 'else'. This is pretty simple -- we just 1006 * flip over the conditional flag. 1007 */ 1008 1009 int 1010 elsecmd(void) 1011 { 1012 1013 switch (cond) { 1014 case CANY: 1015 printf(gettext("\"Else\" without matching \"if\"\n")); 1016 return(1); 1017 1018 case CSEND: 1019 cond = CRCV; 1020 break; 1021 1022 case CRCV: 1023 cond = CSEND; 1024 break; 1025 1026 case CTTY: 1027 cond = CNOTTY; 1028 break; 1029 1030 case CNOTTY: 1031 cond = CTTY; 1032 break; 1033 1034 default: 1035 printf(gettext("invalid condition encountered\n")); 1036 cond = CANY; 1037 break; 1038 } 1039 return(0); 1040 } 1041 1042 /* 1043 * End of if statement. Just set cond back to anything. 1044 */ 1045 1046 int 1047 endifcmd(void) 1048 { 1049 1050 if (cond == CANY) { 1051 printf(gettext("\"Endif\" without matching \"if\"\n")); 1052 return(1); 1053 } 1054 cond = CANY; 1055 return(0); 1056 } 1057 1058 /* 1059 * Set the list of alternate names. 1060 */ 1061 int 1062 alternates(char **namelist) 1063 { 1064 register int c; 1065 register char **ap, **ap2, *cp; 1066 1067 c = argcount(namelist) + 1; 1068 if (c == 1) { 1069 if (altnames == 0) 1070 return(0); 1071 for (ap = altnames; *ap; ap++) 1072 printf("%s ", *ap); 1073 printf("\n"); 1074 return (0); 1075 } 1076 if (altnames != 0) 1077 free((char *)altnames); 1078 if ((altnames = (char **) 1079 calloc((unsigned)c, sizeof (char *))) == NULL) 1080 panic("Failed to allocate memory"); 1081 for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) { 1082 if ((cp = (char *) 1083 calloc((unsigned)strlen(*ap) + 1, sizeof (char))) == NULL) 1084 panic("Failed to allocate memory"); 1085 strcpy(cp, *ap); 1086 *ap2 = cp; 1087 } 1088 *ap2 = 0; 1089 return(0); 1090 } 1091 1092 /* 1093 * Figure out who to reply to. 1094 * Return the real sender in *f. 1095 */ 1096 static char * 1097 replyto(struct message *mp, char **f) 1098 { 1099 char *r, *rf; 1100 1101 if ((rf = skin(hfield("from", mp, addto)))==NOSTR) 1102 rf = skin(addto(NOSTR, nameof(mp))); 1103 if ((r = skin(hfield("reply-to", mp, addto)))==NOSTR) 1104 r = rf; 1105 if (f) 1106 *f = rf; 1107 return (r); 1108 } 1109 1110 /* 1111 * reply2sender - determine whether a "reply" command should reply to the 1112 * sender of the messages, or to all the recipients of the 1113 * message. 1114 * 1115 * With the advent of POSIX.2 compliance, this has become 1116 * a bit more complicated, and so should be done in one 1117 * place, for all to use. 1118 */ 1119 1120 static int 1121 reply2sender (void) 1122 { 1123 register int rep = (value("replyall") != NOSTR); 1124 register int flp = (value("flipr") != NOSTR); 1125 1126 return((rep && !flp)|| (!rep && flp)); 1127 } 1128