source: trunk/third/nmh/uip/forw.c @ 12455

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