1: /* forw.c - forward messages */ 2: 3: #include "../h/mh.h" 4: #include "../h/formatsbr.h" 5: #include "../zotnet/tws.h" 6: #include <stdio.h> 7: #include <sys/types.h> 8: #include <sys/stat.h> 9: 10: 11: #define IFMT "digest-issue-%s" 12: #define VFMT "digest-volume-%s" 13: 14: /* */ 15: 16: static struct swit switches[] = { 17: #define ANNOSW 0 18: "annotate", 0, 19: #define NANNOSW 1 20: "noannotate", 0, 21: 22: #define DFOLDSW 2 23: "draftfolder +folder", 0, 24: #define DMSGSW 3 25: "draftmessage msg", 0, 26: #define NDFLDSW 4 27: "nodraftfolder", 0, 28: 29: #define EDITRSW 5 30: "editor editor", 0, 31: #define NEDITSW 6 32: "noedit", 0, 33: 34: #define FILTSW 7 35: "filter filterfile", 0, 36: #define FORMSW 8 37: "form formfile", 0, 38: 39: #define FRMTSW 9 40: "format", 5, 41: #define NFRMTSW 10 42: "noformat", 7, 43: 44: #define INPLSW 11 45: "inplace", 0, 46: #define NINPLSW 12 47: "noinplace", 0, 48: 49: #define DGSTSW 13 50: "digest list", 0, 51: #define ISSUESW 14 52: "issue number", 0, 53: #define VOLUMSW 15 54: "volume number", 0, 55: 56: #define WHATSW 16 57: "whatnowproc program", 0, 58: #define NWHATSW 17 59: "nowhatnowproc", 0, 60: 61: #define HELPSW 18 62: "help", 4, 63: 64: #define FILESW 19 65: "file file", -4, /* interface from msh */ 66: 67: #ifdef MHE 68: #define BILDSW 20 69: "build", -5, /* interface from mhe */ 70: #endif MHE 71: 72: NULL, NULL 73: }; 74: 75: /* */ 76: 77: static struct swit aqrnl[] = { 78: #define NOSW 0 79: "quit", 0, 80: #define YESW 1 81: "replace", 0, 82: #define LISTDSW 2 83: "list", 0, 84: #define REFILSW 3 85: "refile +folder", 0, 86: #define NEWSW 4 87: "new", 0, 88: 89: NULL, NULL 90: }; 91: 92: 93: static struct swit aqrl[] = { 94: "quit", 0, 95: "replace", 0, 96: "list", 0, 97: "refile +folder", 0, 98: 99: NULL, NULL 100: }; 101: 102: /* */ 103: 104: static char drft[BUFSIZ]; 105: 106: static char delim3[] = 107: "\n------------------------------------------------------------\n\n"; 108: static char delim4[] = "\n------------------------------\n\n"; 109: 110: 111: static struct msgs *mp = NULL; /* used a lot */ 112: 113: 114: long lseek (), time (); 115: 116: /* */ 117: 118: /* ARGSUSED */ 119: 120: main (argc, argv) 121: int argc; 122: char *argv[]; 123: { 124: int msgp = 0, 125: anot = 0, 126: inplace = 0, 127: issue = 0, 128: volume = 0, 129: #ifdef MHE 130: buildsw = 0, 131: #endif MHE 132: nedit = 0, 133: nwhat = 0, 134: i, 135: in, 136: out, 137: isdf = 0, 138: msgnum; 139: char *cp, 140: *cwd, 141: *maildir, 142: *dfolder = NULL, 143: *dmsg = NULL, 144: *digest = NULL, 145: *ed = NULL, 146: *file = NULL, 147: *filter = NULL, 148: *folder = NULL, 149: *form = NULL, 150: buf[100], 151: value[10], 152: **ap, 153: **argp, 154: *arguments[MAXARGS], 155: *msgs[MAXARGS]; 156: struct stat st; 157: 158: invo_name = r1bindex (argv[0], '/'); 159: if ((cp = m_find (invo_name)) != NULL) { 160: ap = brkstring (cp = getcpy (cp), " ", "\n"); 161: ap = copyip (ap, arguments); 162: } 163: else 164: ap = arguments; 165: (void) copyip (argv + 1, ap); 166: argp = arguments; 167: 168: /* */ 169: 170: while (cp = *argp++) { 171: if (*cp == '-') 172: switch (smatch (++cp, switches)) { 173: case AMBIGSW: 174: ambigsw (cp, switches); 175: done (1); 176: case UNKWNSW: 177: adios (NULLCP, "-%s unknown", cp); 178: case HELPSW: 179: (void) sprintf (buf, "%s [+folder] [msgs] [switches]", 180: invo_name); 181: help (buf, switches); 182: done (1); 183: 184: case ANNOSW: 185: anot++; 186: continue; 187: case NANNOSW: 188: anot = 0; 189: continue; 190: 191: case EDITRSW: 192: if (!(ed = *argp++) || *ed == '-') 193: adios (NULLCP, "missing argument to %s", argp[-2]); 194: nedit = 0; 195: continue; 196: case NEDITSW: 197: nedit++; 198: continue; 199: 200: case WHATSW: 201: if (!(whatnowproc = *argp++) || *whatnowproc == '-') 202: adios (NULLCP, "missing argument to %s", argp[-2]); 203: nwhat = 0; 204: continue; 205: #ifdef MHE 206: case BILDSW: 207: buildsw++; /* fall... */ 208: #endif MHE 209: case NWHATSW: 210: nwhat++; 211: continue; 212: 213: case FILESW: 214: if (file) 215: adios (NULLCP, "only one file at a time!"); 216: if (!(cp = *argp++) || *cp == '-') 217: adios (NULLCP, "missing argument to %s", argp[-2]); 218: file = path (cp, TFILE); 219: continue; 220: case FILTSW: 221: if (!(cp = *argp++) || *cp == '-') 222: adios (NULLCP, "missing argument to %s", argp[-2]); 223: filter = getcpy (libpath (cp)); 224: continue; 225: case FORMSW: 226: if (!(form = *argp++) || *form == '-') 227: adios (NULLCP, "missing argument to %s", argp[-2]); 228: continue; 229: 230: case FRMTSW: 231: filter = getcpy (libpath (mhlforward)); 232: continue; 233: case NFRMTSW: 234: filter = NULL; 235: continue; 236: 237: case INPLSW: 238: inplace++; 239: continue; 240: case NINPLSW: 241: inplace = 0; 242: continue; 243: 244: case DGSTSW: 245: if (!(digest = *argp++) || *digest == '-') 246: adios (NULLCP, "missing argument to %s", argp[-2]); 247: continue; 248: case ISSUESW: 249: if (!(cp = *argp++) || *cp == '-') 250: adios (NULLCP, "missing argument to %s", argp[-2]); 251: if ((issue = atoi (cp)) < 1) 252: adios (NULLCP, "bad argument %s %s", argp[-2], cp); 253: continue; 254: case VOLUMSW: 255: if (!(cp = *argp++) || *cp == '-') 256: adios (NULLCP, "missing argument to %s", argp[-2]); 257: if ((volume = atoi (cp)) < 1) 258: adios (NULLCP, "bad argument %s %s", argp[-2], cp); 259: continue; 260: 261: case DFOLDSW: 262: if (dfolder) 263: adios (NULLCP, "only one draft folder at a time!"); 264: if (!(cp = *argp++) || *cp == '-') 265: adios (NULLCP, "missing argument to %s", argp[-2]); 266: dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, 267: *cp != '@' ? TFOLDER : TSUBCWF); 268: continue; 269: case DMSGSW: 270: if (dmsg) 271: adios (NULLCP, "only one draft message at a time!"); 272: if (!(dmsg = *argp++) || *dmsg == '-') 273: adios (NULLCP, "missing argument to %s", argp[-2]); 274: continue; 275: case NDFLDSW: 276: dfolder = NULL; 277: isdf = NOTOK; 278: continue; 279: } 280: if (*cp == '+' || *cp == '@') { 281: if (folder) 282: adios (NULLCP, "only one folder at a time!"); 283: else 284: folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); 285: } 286: else 287: msgs[msgp++] = cp; 288: } 289: 290: /* */ 291: 292: cwd = getcpy (pwd ()); 293: 294: if (!m_find ("path")) 295: free (path ("./", TFOLDER)); 296: if (file && (msgp || folder)) 297: adios (NULLCP, "can't mix files and folders/msgs"); 298: 299: try_it_again: ; 300: #ifndef MHE 301: (void) strcpy (drft, m_draft (dfolder, dmsg, NOUSE, &isdf)); 302: if (stat (drft, &st) != NOTOK) { 303: #else MHE 304: (void) strcpy (drft, buildsw ? m_maildir ("draft") 305: : m_draft (dfolder, NULLCP, NOUSE, &isdf)); 306: if (!buildsw && stat (drft, &st) != NOTOK) { 307: #endif MHE 308: printf ("Draft \"%s\" exists (%ld bytes).", drft, st.st_size); 309: for (i = LISTDSW; i != YESW;) { 310: if (!(argp = getans ("\nDisposition? ", isdf ? aqrnl : aqrl))) 311: done (1); 312: switch (i = smatch (*argp, isdf ? aqrnl : aqrl)) { 313: case NOSW: 314: done (0); 315: case NEWSW: 316: dmsg = NULL; 317: goto try_it_again; 318: case YESW: 319: break; 320: case LISTDSW: 321: (void) showfile (++argp, drft); 322: break; 323: case REFILSW: 324: if (refile (++argp, drft) == 0) 325: i = YESW; 326: break; 327: default: 328: advise (NULLCP, "say what?"); 329: break; 330: } 331: } 332: } 333: 334: /* */ 335: 336: if (file) { 337: anot = 0; 338: goto go_to_it; 339: } 340: 341: if (!msgp) 342: msgs[msgp++] = "cur"; 343: if (!folder) 344: folder = m_getfolder (); 345: maildir = m_maildir (folder); 346: 347: if (chdir (maildir) == NOTOK) 348: adios (maildir, "unable to change directory to"); 349: if (!(mp = m_gmsg (folder))) 350: adios (NULLCP, "unable to read folder %s", folder); 351: if (mp -> hghmsg == 0) 352: adios (NULLCP, "no messages in %s", folder); 353: 354: for (msgnum = 0; msgnum < msgp; msgnum++) 355: if (!m_convert (mp, msgs[msgnum])) 356: done (1); 357: m_setseq (mp); 358: 359: /* */ 360: 361: go_to_it: ; 362: if (filter && access (filter, 04) == NOTOK) 363: adios (filter, "unable to read"); 364: 365: if (digest) { 366: if (issue == 0) { 367: (void) sprintf (buf, IFMT, digest); 368: if (volume == 0 369: && (cp = m_find (buf)) 370: && ((issue = atoi (cp)) < 0)) 371: issue = 0; 372: issue++; 373: } 374: if (volume == 0) 375: (void) sprintf (buf, VFMT, digest); 376: if ((cp = m_find (buf)) == NULL || (volume = atoi (cp)) <= 0) 377: volume = 1; 378: if (!form) 379: form = digestcomps; 380: in = build_form (form, digest, volume, issue); 381: } 382: else 383: if (form) { 384: if ((in = open (libpath (form), 0)) == NOTOK) 385: adios (form, "unable to open form file"); 386: } 387: else { 388: if ((in = open (libpath (forwcomps), 0)) == NOTOK) 389: adios (forwcomps, "unable to open default components file"); 390: form = forwcomps; 391: } 392: 393: if ((out = creat (drft, m_gmprot ())) == NOTOK) 394: adios (drft, "unable to create"); 395: 396: cpydata (in, out, form, drft); 397: (void) close (in); 398: 399: /* */ 400: 401: if (file) { 402: if ((in = open (file, 0)) == NOTOK) 403: adios (file, "unable to open"); 404: cpydata (in, out, file, drft); 405: (void) close (in); 406: (void) close (out); 407: goto edit_it; 408: } 409: 410: if (filter) 411: mhl_draft (out, digest, drft, filter); 412: else 413: copy_draft (out, digest, drft); 414: (void) close (out); 415: 416: if (digest) { 417: (void) sprintf (buf, IFMT, digest); 418: (void) sprintf (value, "%d", issue); 419: m_replace (buf, getcpy (value)); 420: (void) sprintf (buf, VFMT, digest); 421: (void) sprintf (value, "%d", volume); 422: m_replace (buf, getcpy (value)); 423: } 424: 425: m_replace (pfolder, folder); 426: if (mp -> lowsel != mp -> curmsg) 427: m_setcur (mp, mp -> lowsel); 428: m_sync (mp); 429: m_update (); 430: 431: edit_it: ; 432: if (nwhat) 433: done (0); 434: (void) m_whatnow (ed, nedit, NOUSE, drft, NULLCP, 0, mp, 435: anot ? "Forwarded" : NULLCP, inplace, cwd); 436: done (1); 437: } 438: 439: /* */ 440: 441: static mhl_draft (out, digest, file, filter) 442: int out; 443: register char *digest, 444: *file, 445: *filter; 446: { 447: int i, 448: child_id, 449: msgnum, 450: pd[2]; 451: char *vec[MAXARGS]; 452: 453: if (pipe (pd) == NOTOK) 454: adios ("pipe", "unable to create"); 455: 456: vec[0] = r1bindex (mhlproc, '/'); 457: 458: for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++) 459: sleep (5); 460: switch (child_id) { 461: case NOTOK: 462: adios ("fork", "unable to"); 463: 464: case OK: 465: (void) close (pd[0]); 466: (void) dup2 (pd[1], 1); 467: (void) close (pd[1]); 468: 469: i = 1; 470: vec[i++] = "-forwall"; 471: vec[i++] = "-form"; 472: vec[i++] = filter; 473: if (digest) { 474: vec[i++] = "-digest"; 475: vec[i++] = digest; 476: } 477: if (mp -> numsel >= MAXARGS - i) 478: adios (NULLCP, "more than %d messages for %s exec", 479: vec[0], MAXARGS - i); 480: for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) 481: if (mp -> msgstats[msgnum] & SELECTED) 482: vec[i++] = getcpy (m_name (msgnum)); 483: vec[i] = NULL; 484: 485: execvp (mhlproc, vec); 486: fprintf (stderr, "unable to exec "); 487: perror (mhlproc); 488: _exit (-1); 489: 490: default: 491: (void) close (pd[1]); 492: cpydata (pd[0], out, vec[0], file); 493: (void) close (pd[0]); 494: (void) pidXwait (child_id, mhlproc); 495: break; 496: } 497: } 498: 499: /* */ 500: 501: static copy_draft (out, digest, file) 502: int out; 503: register char *digest, 504: *file; 505: { 506: int fd,i, 507: msgcnt, 508: msgnum; 509: register char *bp, 510: *msgnam; 511: char buffer[BUFSIZ]; 512: 513: msgcnt = 1; 514: for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) 515: if (mp -> msgstats[msgnum] & SELECTED) { 516: if (digest) 517: (void) strcpy (buffer, 518: msgnum == mp -> lowsel ? delim3 : delim4); 519: else { 520: (void) strcpy (bp = buffer, "\n-------"), bp += strlen (bp); 521: if (msgnum == mp -> lowsel) 522: (void) sprintf (bp, " Forwarded Message%s", 523: mp -> numsel > 1 ? "s" : ""); 524: else 525: (void) sprintf (bp, " Message %d", msgcnt); 526: bp += strlen (bp); 527: (void) strcpy (bp, "\n\n"); 528: } 529: (void) write (out, buffer, strlen (buffer)); 530: 531: if ((fd = open (msgnam = m_name (msgnum), 0)) == NOTOK) { 532: admonish (msgnam, "unable to read message"); 533: continue; 534: } 535: cpydgst (fd, out, msgnam, file); 536: (void) close (fd); 537: 538: msgcnt++; 539: } 540: 541: if (digest) 542: (void) strcpy (buffer, delim4); 543: else 544: (void) sprintf (buffer, "\n------- End of Forwarded Message%s\n\n", 545: mp -> numsel > 1 ? "s" : ""); 546: (void) write (out, buffer, strlen (buffer)); 547: 548: if (digest) { 549: (void) sprintf (buffer, "End of %s Digest\n", digest); 550: i = strlen (buffer); 551: for (bp = buffer + i; i > 1; i--) 552: *bp++ = '*'; 553: *bp++ = '\n'; 554: *bp = NULL; 555: (void) write (out, buffer, strlen (buffer)); 556: } 557: } 558: 559: /* */ 560: 561: static int build_form (form, digest, volume, issue) 562: register char *form, 563: *digest; 564: int volume, 565: issue; 566: { 567: int in; 568: int fmtsize; 569: register char *nfs; 570: char *line, 571: tmpfil[BUFSIZ]; 572: register FILE *tmp; 573: register struct comp *cptr; 574: struct format *fmt; 575: int dat[4]; 576: 577: nfs = new_fs (form, NULLCP, NULLCP); 578: fmtsize = strlen (nfs) + 256; 579: (void) fmt_compile (nfs, &fmt); 580: 581: FINDCOMP (cptr, "digest"); 582: if (cptr) 583: cptr->c_text = digest; 584: FINDCOMP (cptr, "date"); 585: if (cptr) 586: cptr->c_text = getcpy(dtimenow ()); 587: 588: dat[0] = issue; 589: dat[1] = volume; 590: dat[2] = 0; 591: dat[3] = fmtsize; 592: 593: (void) strcpy (tmpfil, m_tmpfil (invo_name)); 594: if ((tmp = fopen (tmpfil, "w+")) == NULL) 595: adios (tmpfil, "unable to create"); 596: (void) unlink (tmpfil); 597: if ((in = dup (fileno (tmp))) == NOTOK) 598: adios ("dup", "unable to"); 599: 600: if ((line = malloc ((unsigned) fmtsize)) == NULLCP) 601: adios (NULLCP, "unable to allocate format line storage"); 602: (void) fmtscan (fmt, line, fmtsize, dat); 603: (void) fputs (line, tmp); 604: (void) free (line); 605: if (fclose (tmp)) 606: adios (tmpfil, "error writing"); 607: 608: (void) lseek (in, 0L, 0); 609: return in; 610: }