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