1: /* whatnowsbr.c - the WhatNow shell */ 2: 3: #include "../h/mh.h" 4: #include <stdio.h> 5: #include <signal.h> 6: #include <sys/types.h> 7: #include <sys/stat.h> 8: 9: /* */ 10: 11: static struct swit whatnowswitches[] = { 12: #define DFOLDSW 0 13: "draftfolder +folder", 0, 14: #define DMSGSW 1 15: "draftmessage msg", 0, 16: #define NDFLDSW 2 17: "nodraftfolder", 0, 18: 19: #define EDITRSW 3 20: "editor editor", 0, 21: #define NEDITSW 4 22: "noedit", 0, 23: 24: #define PRMPTSW 5 25: "prompt string", 4, 26: 27: #define HELPSW 6 28: "help", 4, 29: 30: NULL, NULL 31: }; 32: 33: /* */ 34: 35: static struct swit aleqs[] = { 36: #define DISPSW 0 37: "display [<switches>]", 0, 38: #define EDITSW 1 39: "edit [<editor> <switches>]", 0, 40: #define LISTSW 2 41: "list [<switches>]", 0, 42: #define PUSHSW 3 43: "push [<switches>]", 0, 44: #define QUITSW 4 45: "quit [-delete]", 0, 46: #define REFILEOPT 5 47: "refile [<switches>] +folder", 0, 48: #define SENDSW 6 49: "send [<switches>]", 0, 50: #define WHOMSW 7 51: "whom [<switches>]", 0, 52: 53: NULL, NULL 54: }; 55: 56: /* */ 57: 58: static char *myprompt = "\nWhat now? "; 59: 60: /* */ 61: 62: /* ARGSUSED */ 63: 64: int WhatNow (argc, argv) 65: int argc; 66: char **argv; 67: { 68: int isdf = 0, 69: nedit = 0, 70: use = 0; 71: char *cp, 72: *dfolder = NULL, 73: *dmsg = NULL, 74: *ed = NULL, 75: *drft = NULL, 76: *msgnam = NULL, 77: buf[100], 78: prompt[BUFSIZ], 79: **ap, 80: **argp, 81: *arguments[MAXARGS]; 82: struct stat st; 83: 84: invo_name = r1bindex (argv[0], '/'); 85: if ((cp = m_find (invo_name)) != NULL) { 86: ap = brkstring (cp = getcpy (cp), " ", "\n"); 87: ap = copyip (ap, arguments); 88: } 89: else 90: ap = arguments; 91: (void) copyip (argv + 1, ap); 92: argp = arguments; 93: 94: /* */ 95: 96: while (cp = *argp++) { 97: if (*cp == '-') 98: switch (smatch (++cp, whatnowswitches)) { 99: case AMBIGSW: 100: ambigsw (cp, whatnowswitches); 101: done (1); 102: case UNKWNSW: 103: adios (NULLCP, "-%s unknown", cp); 104: case HELPSW: 105: (void) sprintf (buf, "%s [switches] [file]", invo_name); 106: help (buf, whatnowswitches); 107: done (1); 108: 109: case DFOLDSW: 110: if (dfolder) 111: adios (NULLCP, "only one draft folder at a time!"); 112: if (!(cp = *argp++) || *cp == '-') 113: adios (NULLCP, "missing argument to %s", argp[-2]); 114: dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, 115: *cp != '@' ? TFOLDER : TSUBCWF); 116: continue; 117: case DMSGSW: 118: if (dmsg) 119: adios (NULLCP, "only one draft message at a time!"); 120: if (!(dmsg = *argp++) || *dmsg == '-') 121: adios (NULLCP, "missing argument to %s", argp[-2]); 122: continue; 123: case NDFLDSW: 124: dfolder = NULL; 125: isdf = NOTOK; 126: continue; 127: 128: case EDITRSW: 129: if (!(ed = *argp++) || *ed == '-') 130: adios (NULLCP, "missing argument to %s", argp[-2]); 131: nedit = 0; 132: continue; 133: case NEDITSW: 134: nedit++; 135: continue; 136: 137: case PRMPTSW: 138: if (!(myprompt = *argp++) || *myprompt == '-') 139: adios (NULLCP, "missing argument to %s", argp[-2]); 140: continue; 141: } 142: if (drft) 143: adios (NULLCP, "only one draft at a time!"); 144: else 145: drft = cp; 146: } 147: 148: /* */ 149: 150: if (drft == NULL && (drft = getenv ("mhdraft")) == NULL || *drft == NULL) 151: drft = getcpy (m_draft (dfolder, dmsg, 1, &isdf)); 152: msgnam = (cp = getenv ("mhaltmsg")) && *cp ? getcpy (cp) : NULLCP; 153: if (ed == NULL && ((ed = getenv ("mheditor")) == NULL || *ed == NULL)) 154: ed = NULL, nedit++; 155: if ((cp = getenv ("mhuse")) && *cp) 156: use = atoi (cp); 157: if (!nedit 158: && editfile (&ed, NULLVP, drft, use, NULLMP, msgnam, NULLCP) < 0) 159: done (1); 160: 161: /* */ 162: 163: (void) sprintf (prompt, myprompt, invo_name); 164: for (;;) { 165: if (!(argp = getans (prompt, aleqs))) { 166: (void) unlink (LINK); 167: done (1); 168: } 169: switch (smatch (*argp, aleqs)) { 170: case DISPSW: 171: if (msgnam) 172: (void) showfile (++argp, msgnam); 173: else 174: advise (NULLCP, "no alternate message to display"); 175: break; 176: 177: case EDITSW: 178: if (*++argp) 179: ed = *argp++; 180: if (editfile (&ed, argp, drft, NOUSE, NULLMP, msgnam, NULLCP) 181: == NOTOK) 182: done (1); 183: break; 184: 185: case LISTSW: 186: (void) showfile (++argp, drft); 187: break; 188: 189: case WHOMSW: 190: (void) whomfile (++argp, drft); 191: break; 192: 193: case QUITSW: 194: if (*++argp && (*argp[0] == 'd' || 195: ((*argp)[0] == '-' && (*argp)[1] == 'd'))) { 196: if (unlink (drft) == NOTOK) 197: adios (drft, "unable to unlink"); 198: } 199: else 200: if (stat (drft, &st) != NOTOK) 201: advise (NULLCP, "draft left on %s", drft); 202: done (1); 203: 204: case PUSHSW: 205: sendfile (++argp, drft, 1); 206: done (1); 207: 208: case SENDSW: 209: sendfile (++argp, drft, 0); 210: break; 211: 212: case REFILEOPT: 213: if (refile (++argp, drft) == 0) 214: done (0); 215: break; 216: 217: default: 218: advise (NULLCP, "say what?"); 219: break; 220: } 221: } 222: } 223: 224: /* EDIT */ 225: 226: static int reedit = 0; 227: static char *edsave = NULL; 228: 229: 230: /* ARGSUSED */ 231: 232: static int editfile (ed, arg, file, use, mp, altmsg, cwd) 233: register struct msgs *mp; 234: register char **ed, 235: **arg, 236: *file, 237: *altmsg, 238: *cwd; 239: register int use; 240: { 241: int pid, 242: status; 243: register int vecp; 244: register char *cp; 245: char altpath[BUFSIZ], 246: linkpath[BUFSIZ], 247: *vec[MAXARGS]; 248: struct stat st; 249: #ifdef BSD42 250: int slinked; 251: #endif BSD42 252: 253: if (!reedit) { /* set initial editor */ 254: if (*ed == NULL && (*ed = m_find ("editor")) == NULL) 255: *ed = sysed; 256: } 257: else 258: if (!*ed) { /* no explicit editor */ 259: *ed = edsave; 260: if ((cp = r1bindex (*ed, '/')) == NULL) 261: cp = *ed; 262: cp = concat (cp, "-next", NULLCP); 263: if ((cp = m_find (cp)) != NULL) 264: *ed = cp; 265: } 266: 267: if (altmsg) { 268: if (mp == NULL || *altmsg == '/' || cwd == NULL) 269: (void) strcpy (altpath, altmsg); 270: else 271: (void) sprintf (altpath, "%s/%s", mp -> foldpath, altmsg); 272: if (cwd == NULL) 273: (void) strcpy (linkpath, LINK); 274: else 275: (void) sprintf (linkpath, "%s/%s", cwd, LINK); 276: } 277: 278: if (altmsg) { 279: (void) unlink (linkpath); 280: #ifdef BSD42 281: if (link (altpath, linkpath) == NOTOK) { 282: (void) symlink (altpath, linkpath); 283: slinked = 1; 284: } 285: else 286: slinked = 0; 287: #else not BSD42 288: (void) link (altpath, linkpath); 289: #endif not BSD42 290: } 291: 292: m_update (); 293: (void) fflush (stdout); 294: 295: switch (pid = vfork ()) { 296: case NOTOK: 297: advise ("fork", "unable to"); 298: status = NOTOK; 299: break; 300: 301: case OK: 302: if (cwd) 303: (void) chdir (cwd); 304: if (altmsg) { 305: if (mp) 306: (void) putenv ("mhfolder", mp -> foldpath); 307: (void) putenv ("editalt", altpath); 308: } 309: 310: vecp = 0; 311: vec[vecp++] = r1bindex (*ed, '/'); 312: if (arg) 313: while (*arg) 314: vec[vecp++] = *arg++; 315: vec[vecp++] = file; 316: vec[vecp] = NULL; 317: 318: execvp (*ed, vec); 319: fprintf (stderr, "unable to exec "); 320: perror (*ed); 321: _exit (-1); 322: 323: default: 324: if (status = pidwait (pid, NOTOK)) { 325: if (((status & 0xff00) != 0xff00) 326: && (!reedit || (status & 0x00ff))) 327: if (!use && (status & 0xff00)) { 328: (void) unlink (file); 329: advise (NULLCP, "problems with edit--%s deleted", file); 330: } 331: else 332: advise (NULLCP, "problems with edit--%s preserved", 333: file); 334: status = -2; 335: break; 336: } 337: 338: reedit++; 339: #ifdef BSD42 340: if (altmsg 341: && mp 342: && (!mp -> msgflags & READONLY) 343: && (slinked 344: ? lstat (linkpath, &st) != NOTOK 345: && (st.st_mode & S_IFMT) == S_IFREG 346: && copyf (linkpath, altpath) == NOTOK 347: : stat (linkpath, &st) != NOTOK 348: && st.st_nlink == 1 349: && (unlink (altpath) == NOTOK 350: || link (linkpath, altpath) == NOTOK))) 351: advise (linkpath, "unable to update %s from", altmsg); 352: #else not BSD42 353: if (altmsg 354: && mp 355: && (!mp -> msgflags & READONLY) 356: && stat (linkpath, &st) != NOTOK 357: && st.st_nlink == 1 358: && (unlink (altpath) == NOTOK 359: || link (linkpath, altpath) == NOTOK)) 360: advise (linkpath, "unable to update %s from", altmsg); 361: #endif not BSD42 362: } 363: 364: edsave = getcpy (*ed); 365: *ed = NULL; 366: if (altmsg) 367: (void) unlink (linkpath); 368: 369: return status; 370: } 371: 372: /* */ 373: 374: #ifdef BSD42 375: static int copyf (ifile, ofile) 376: register char *ifile, 377: *ofile; 378: { 379: register int i; 380: int in, 381: out; 382: char buffer[BUFSIZ]; 383: 384: if ((in = open (ifile, 0)) == NOTOK) 385: return NOTOK; 386: if ((out = open (ofile, 1)) == NOTOK || ftruncate (out, 0) == NOTOK) { 387: if (out != NOTOK) { 388: admonish (ofile, "unable to truncate"); 389: (void) close (out); 390: } 391: (void) close (in); 392: return NOTOK; 393: } 394: 395: while ((i = read (in, buffer, sizeof buffer)) > OK) 396: if (write (out, buffer, i) != i) { 397: advise (ofile, "may have damaged"); 398: i = NOTOK; 399: break; 400: } 401: 402: (void) close (in); 403: (void) close (out); 404: 405: return i; 406: } 407: #endif BSD42 408: 409: /* SEND */ 410: 411: static sendfile (arg, file, pushsw) 412: register char **arg, 413: *file; 414: int pushsw; 415: { 416: register int child_id, 417: i, 418: vecp; 419: char *cp, 420: *sp, 421: *vec[MAXARGS]; 422: 423: if (strcmp (sp = r1bindex (sendproc, '/'), "send") == 0) { 424: cp = invo_name; 425: sendit (invo_name = sp, arg, file, pushsw); 426: invo_name = cp; 427: return; 428: } 429: 430: m_update (); 431: (void) fflush (stdout); 432: 433: for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++) 434: sleep (5); 435: switch (child_id) { 436: case NOTOK: 437: advise (NULLCP, "unable to fork, so sending directly..."); 438: case OK: 439: vecp = 0; 440: vec[vecp++] = invo_name; 441: if (pushsw) 442: vec[vecp++] = "-push"; 443: if (arg) 444: while (*arg) 445: vec[vecp++] = *arg++; 446: vec[vecp++] = file; 447: vec[vecp] = NULL; 448: 449: execvp (sendproc, vec); 450: fprintf (stderr, "unable to exec "); 451: perror (sendproc); 452: _exit (-1); 453: 454: default: 455: if (pidwait (child_id, OK) == 0) 456: done (0); 457: return; 458: } 459: } 460: 461: /* */ 462: 463: static struct swit sendswitches[] = { 464: #define ALIASW 0 465: "alias aliasfile", 0, 466: 467: #define DEBUGSW 1 468: "debug", -5, 469: 470: #define ENCRSW 2 471: "encrypt", 472: #ifndef TMA 473: -7, 474: #else TMA 475: 0, 476: #endif TMA 477: #define NENCRSW 3 478: "noencrypt", 479: #ifndef TMA 480: -9, 481: #else TMA 482: 0, 483: #endif TMA 484: 485: #define FILTSW 4 486: "filter filterfile", 0, 487: #define NFILTSW 5 488: "nofilter", 0, 489: 490: #define FRMTSW 6 491: "format", 0, 492: #define NFRMTSW 7 493: "noformat", 0, 494: 495: #define FORWSW 8 496: "forward", 0, 497: #define NFORWSW 9 498: "noforward", 0, 499: 500: #define MSGDSW 10 501: "msgid", 0, 502: #define NMSGDSW 11 503: "nomsgid", 0, 504: 505: #define SPSHSW 12 506: "push", 0, 507: #define NSPSHSW 13 508: "nopush", 0, 509: 510: #define UNIQSW 14 511: "unique", -6, 512: #define NUNIQSW 15 513: "nounique", -8, 514: 515: #define VERBSW 16 516: "verbose", 0, 517: #define NVERBSW 17 518: "noverbose", 0, 519: 520: #define WATCSW 18 521: "watch", 0, 522: #define NWATCSW 19 523: "nowatch", 0, 524: 525: #define WIDTHSW 20 526: "width columns", 0, 527: 528: #define SHELPSW 21 529: "help", 4, 530: 531: #define MAILSW 22 532: "mail", -4, 533: #define SAMLSW 23 534: "saml", -4, 535: #define SSNDSW 24 536: "send", -4, 537: #define SOMLSW 25 538: "soml", -4, 539: 540: #define CLIESW 26 541: "client host", -6, 542: #define SERVSW 27 543: "server host", -6, 544: #define SNOOPSW 28 545: "snoop", -5, 546: 547: #define SDRFSW 29 548: "draftfolder +folder", -6, 549: #define SDRMSW 30 550: "draftmessage msg", -6, 551: #define SNDRFSW 31 552: "nodraftfolder", -3, 553: 554: NULL, NULL 555: }; 556: 557: /* */ 558: 559: extern int debugsw; /* from sendsbr.c */ 560: extern int forwsw; 561: extern int inplace; 562: extern int pushsw; 563: extern int unique; 564: 565: extern char *altmsg; /* .. */ 566: extern char *annotext; 567: extern char *distfile; 568: 569: /* */ 570: 571: static sendit (sp, arg, file, pushed) 572: register char *sp, 573: **arg, 574: *file; 575: int pushed; 576: { 577: int distsw = 0, 578: vecp = 1; 579: char *cp, 580: buf[100], 581: **ap, 582: **argp, 583: *arguments[MAXARGS], 584: *vec[MAXARGS]; 585: struct stat st; 586: #ifdef UCI 587: FILE *fp; 588: #endif UCI 589: 590: if (arg) 591: (void) copyip (arg, vec); 592: if ((cp = m_find (sp)) != NULL) { 593: ap = brkstring (cp = getcpy (cp), " ", "\n"); 594: ap = copyip (ap, arguments); 595: } 596: else 597: ap = arguments; 598: if (arg) 599: (void) copyip (vec, ap); 600: argp = arguments; 601: 602: debugsw = 0, forwsw = 1, inplace = 0, unique = 0; 603: altmsg = annotext = distfile = NULL; 604: vec[vecp++] = "-library"; 605: vec[vecp++] = getcpy (m_maildir ("")); 606: 607: /* */ 608: 609: while (cp = *argp++) { 610: if (*cp == '-') 611: switch (smatch (++cp, sendswitches)) { 612: case AMBIGSW: 613: ambigsw (cp, sendswitches); 614: return; 615: case UNKWNSW: 616: advise (NULLCP, "-%s unknown\n", cp); 617: return; 618: case SHELPSW: 619: (void) sprintf (buf, "%s [switches]", sp); 620: help (buf, sendswitches); 621: return; 622: 623: case SPSHSW: 624: pushed++; 625: continue; 626: case NSPSHSW: 627: pushed = 0; 628: continue; 629: 630: case UNIQSW: 631: unique++; 632: continue; 633: case NUNIQSW: 634: unique = 0; 635: continue; 636: case FORWSW: 637: forwsw++; 638: continue; 639: case NFORWSW: 640: forwsw = 0; 641: continue; 642: 643: case DEBUGSW: 644: debugsw++; /* fall */ 645: case NFILTSW: 646: case FRMTSW: 647: case NFRMTSW: 648: case MSGDSW: 649: case NMSGDSW: 650: case VERBSW: 651: case NVERBSW: 652: case WATCSW: 653: case NWATCSW: 654: case MAILSW: 655: case SAMLSW: 656: case SSNDSW: 657: case SOMLSW: 658: case ENCRSW: 659: case NENCRSW: 660: case SNOOPSW: 661: vec[vecp++] = --cp; 662: continue; 663: 664: case ALIASW: 665: case FILTSW: 666: case WIDTHSW: 667: case CLIESW: 668: case SERVSW: 669: vec[vecp++] = --cp; 670: if (!(cp = *argp++) || *cp == '-') { 671: advise (NULLCP, "missing argument to %s", argp[-2]); 672: return; 673: } 674: vec[vecp++] = cp; 675: continue; 676: 677: case SDRFSW: 678: case SDRMSW: 679: if (!(cp = *argp++) || *cp == '-') { 680: advise (NULLCP, "missing argument to %s", argp[-2]); 681: return; 682: } 683: case SNDRFSW: 684: continue; 685: } 686: advise (NULLCP, "usage: %s [switches]", sp); 687: return; 688: } 689: 690: /* */ 691: 692: #ifdef TMA 693: if ((cp = getenv ("KDS")) == NULL || *cp == NULL) 694: if ((cp = m_find ("kdsproc")) && *cp) 695: (void) putenv ("KDS", cp); 696: if ((cp = getenv ("TMADB")) == NULL || *cp == NULL) 697: if ((cp = m_find ("tmadb")) && *cp) 698: (void) putenv ("TMADB", m_maildir (cp)); 699: #endif TMA 700: 701: if ((cp = getenv ("SIGNATURE")) == NULL || *cp == NULL) 702: if ((cp = m_find ("signature")) && *cp) 703: (void) putenv ("SIGNATURE", cp); 704: #ifdef UCI 705: else { 706: (void) sprintf (buf, "%s/.signature", mypath); 707: if ((fp = fopen (buf, "r")) != NULL 708: && fgets (buf, sizeof buf, fp) != NULL) { 709: (void) fclose (fp); 710: if (cp = index (buf, '\n')) 711: *cp = NULL; 712: (void) putenv ("SIGNATURE", buf); 713: } 714: } 715: #endif UCI 716: 717: if ((annotext = getenv ("mhannotate")) == NULL || *annotext == NULL) 718: annotext = NULL; 719: if ((altmsg = getenv ("mhaltmsg")) == NULL || *altmsg == NULL) 720: altmsg = NULL; 721: if (annotext && ((cp = getenv ("mhinplace")) != NULL && *cp != NULL)) 722: inplace = atoi (cp); 723: 724: if ((cp = getenv ("mhdist")) 725: && *cp 726: && (distsw = atoi (cp)) 727: && altmsg) { 728: vec[vecp++] = "-dist"; 729: distfile = getcpy (m_scratch (altmsg, invo_name)); 730: if (link (altmsg, distfile) == NOTOK) 731: adios (distfile, "unable to link %s to", altmsg); 732: } 733: else 734: distfile = NULL; 735: 736: if (altmsg == NULL || stat (altmsg, &st) == NOTOK) 737: st.st_mtime = 0, st.st_dev = 0, st.st_ino = 0; 738: if (pushsw = pushed) 739: push (); 740: 741: vec[0] = r1bindex (postproc, '/'); 742: closefds (3); 743: 744: if (sendsbr (vec, vecp, file, &st) == OK) 745: done (0); 746: } 747: 748: /* WHOM */ 749: 750: static int whomfile (arg, file) 751: register char **arg, 752: *file; 753: { 754: int pid; 755: register int vecp; 756: char *vec[MAXARGS]; 757: 758: m_update (); 759: (void) fflush (stdout); 760: 761: switch (pid = vfork ()) { 762: case NOTOK: 763: advise ("fork", "unable to"); 764: return 1; 765: 766: case OK: 767: vecp = 0; 768: vec[vecp++] = r1bindex (whomproc, '/'); 769: vec[vecp++] = file; 770: if (arg) 771: while (*arg) 772: vec[vecp++] = *arg++; 773: vec[vecp] = NULL; 774: 775: execvp (whomproc, vec); 776: fprintf (stderr, "unable to exec "); 777: perror (whomproc); 778: _exit (-1); /* NOTREACHED */ 779: 780: default: 781: return (pidwait (pid, NOTOK) & 0377 ? 1 : 0); 782: } 783: }