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

Revision 12455, 44.2 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 * post.c -- enter messages into the mail transport system
4 *
5 * $Id: post.c,v 1.1.1.1 1999-02-07 18:14:16 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <fcntl.h>
10#include <h/signals.h>
11#include <h/addrsbr.h>
12#include <h/aliasbr.h>
13#include <h/dropsbr.h>
14#include <h/mime.h>
15
16#include <zotnet/tws/tws.h>
17#include <zotnet/mts/mts.h>
18
19#include <errno.h>
20#include <setjmp.h>
21#include <signal.h>
22
23#ifdef MMDFMTS
24# include <mts/mmdf/util.h>
25# include <mts/mmdf/mmdf.h>
26#endif
27
28/*
29 * Currently smtp and sendmail use
30 * the same interface for posting.
31 */
32#ifdef SMTPMTS
33# define SENDMTS
34#endif
35
36#ifdef SENDMTS
37# include <mts/smtp/smtp.h>
38#endif
39
40#ifndef MMDFMTS
41# define uptolow(c) ((isalpha(c) && isupper (c)) ? tolower (c) : (c))
42#endif
43
44#define FCCS            10      /* max number of fccs allowed */
45
46static struct swit switches[] = {
47#define ALIASW                    0
48    { "alias aliasfile", 0 },
49#define CHKSW                     1
50    { "check", -5 },                    /* interface from whom */
51#define NCHKSW                    2
52    { "nocheck", -7 },                  /* interface from whom */
53#define DEBUGSW                   3
54    { "debug", -5 },
55#define DISTSW                    4
56    { "dist", -4 },                     /* interface from dist */
57#define FILTSW                    5
58    { "filter filterfile", 0 },
59#define NFILTSW                   6
60    { "nofilter", 0 },
61#define FRMTSW                    7
62    { "format", 0 },
63#define NFRMTSW                   8
64    { "noformat", 0 },
65#define LIBSW                     9
66    { "library directory", -7 },        /* interface from send, whom */
67#define MIMESW                   10
68    { "mime", 0 },
69#define NMIMESW                  11
70    { "nomime", 0 },
71#define MSGDSW                   12
72    { "msgid", 0 },
73#define NMSGDSW                  13
74    { "nomsgid", 0 },
75#define VERBSW                   14
76    { "verbose", 0 },
77#define NVERBSW                  15
78    { "noverbose", 0 },
79#define WATCSW                   16
80    { "watch", 0 },
81#define NWATCSW                  17
82    { "nowatch", 0 },
83#define WHOMSW                   18
84    { "whom", -4 },                     /* interface from whom */
85#define WIDTHSW                  19
86    { "width columns", 0 },
87#define VERSIONSW                20
88    { "version", 0 },
89#define HELPSW                   21
90    { "help", 4 },
91#define BITSTUFFSW               22
92    { "dashstuffing", -12 },            /* should we dashstuff BCC messages? */
93#define NBITSTUFFSW              23
94    { "nodashstuffing", -14 },
95#define MAILSW                   24
96    { "mail", -4 },                     /* specify MAIL smtp mode */
97#define SAMLSW                   25
98    { "saml", -4 },                     /* specify SAML smtp mode */
99#define SENDSW                   26
100    { "send", -4 },                     /* specify SEND smtp mode */
101#define SOMLSW                   27
102    { "soml", -4 },                     /* specify SOML smtp mode */
103#define ANNOSW                   28
104    { "idanno number", -6 },            /* interface from send    */
105#define DLVRSW                   29
106    { "deliver address-list", -7 },
107#define CLIESW                   30
108    { "client host", -6 },
109#define SERVSW                   31
110    { "server host", -6 },              /* specify alternate SMTP server */
111#define SNOOPSW                  32
112    { "snoop", -5 },                    /* snoop the SMTP transaction */
113#define FILLSW                   33
114    { "fill-in file", -7 },
115#define FILLUSW                  34
116    { "fill-up", -7 },
117#define PARTSW                   35
118    { "partno", -6 },
119#define QUEUESW                  36
120    { "queued", -6 },
121    { NULL, 0 }
122};
123
124
125struct headers {
126    char *value;
127    unsigned int flags;
128    unsigned int set;
129};
130
131/*
132 * flags for headers->flags
133 */
134#define HNOP  0x0000            /* just used to keep .set around          */
135#define HBAD  0x0001            /* bad header - don't let it through      */
136#define HADR  0x0002            /* header has an address field            */
137#define HSUB  0x0004            /* Subject: header                        */
138#define HTRY  0x0008            /* try to send to addrs on header         */
139#define HBCC  0x0010            /* don't output this header               */
140#define HMNG  0x0020            /* munge this header                      */
141#define HNGR  0x0040            /* no groups allowed in this header       */
142#define HFCC  0x0080            /* FCC: type header                       */
143#define HNIL  0x0100            /* okay for this header not to have addrs */
144#define HIGN  0x0200            /* ignore this header                     */
145#define HDCC  0x0400            /* another undocumented feature           */
146
147/*
148 * flags for headers->set
149 */
150#define MFRM  0x0001            /* we've seen a From:        */
151#define MDAT  0x0002            /* we've seen a Date:        */
152#define MRFM  0x0004            /* we've seen a Resent-From: */
153#define MVIS  0x0008            /* we've seen sighted addrs  */
154#define MINV  0x0010            /* we've seen blind addrs    */
155
156
157static struct headers NHeaders[] = {
158    { "Return-Path", HBAD,                0 },
159    { "Received",    HBAD,                0 },
160    { "Reply-To",    HADR|HNGR,           0 },
161    { "From",        HADR|HNGR,           MFRM },
162    { "Sender",      HADR|HBAD,           0 },
163    { "Date",        HBAD,                0 },
164    { "Subject",     HSUB,                0 },
165    { "To",          HADR|HTRY,           MVIS },
166    { "cc",          HADR|HTRY,           MVIS },
167    { "Bcc",         HADR|HTRY|HBCC|HNIL, MINV },
168    { "Dcc",         HADR|HTRY|HDCC|HNIL, MVIS },       /* sorta cc & bcc combined */
169    { "Message-ID",  HBAD,                0 },
170    { "Fcc",         HFCC,                0 },
171    { NULL,          0,                   0 }
172};
173
174static struct headers RHeaders[] = {
175    { "Resent-Reply-To",   HADR|HNGR,           0 },
176    { "Resent-From",       HADR|HNGR,           MRFM },
177    { "Resent-Sender",     HADR|HBAD,           0 },
178    { "Resent-Date",       HBAD,                0 },
179    { "Resent-Subject",    HSUB,                0 },
180    { "Resent-To",         HADR|HTRY,           MVIS },
181    { "Resent-cc",         HADR|HTRY,           MVIS },
182    { "Resent-Bcc",        HADR|HTRY|HBCC,      MINV },
183    { "Resent-Message-ID", HBAD,                0 },
184    { "Resent-Fcc",        HFCC,                0 },
185    { "Reply-To",          HADR,                0 },
186    { "From",              HADR|HNGR,           MFRM },
187#ifdef MMDFI
188    { "Sender",            HADR|HNGR|HMNG,      0 },
189#else
190    { "Sender",            HADR|HNGR,           0 },
191#endif
192    { "Date",              HNOP,                MDAT },
193    { "To",                HADR|HNIL,           0 },
194    { "cc",                HADR|HNIL,           0 },
195    { "Bcc",               HADR|HTRY|HBCC|HNIL, 0 },
196    { "Fcc",               HIGN,                0 },
197    { NULL,                0,                   0 }
198};
199
200static short fccind = 0;        /* index into fccfold[] */
201static short outputlinelen = OUTPUTLINELEN;
202
203static int pfd = NOTOK;         /* fd to write annotation list to        */
204static uid_t myuid= -1;         /* my user id                            */
205static gid_t mygid= -1;         /* my group id                           */
206static int recipients = 0;      /* how many people will get a copy       */
207static int unkadr = 0;          /* how many of those were unknown        */
208static int badadr = 0;          /* number of bad addrs                   */
209static int badmsg = 0;          /* message has bad semantics             */
210static int verbose = 0;         /* spell it out                          */
211static int format = 1;          /* format addresses                      */
212static int mime = 0;            /* use MIME-style encapsulations for Bcc */
213static int msgid = 0;           /* add msgid                             */
214static int debug = 0;           /* debugging post                        */
215static int watch = 0;           /* watch the delivery process            */
216static int whomsw = 0;          /* we are whom not post                  */
217static int checksw = 0;         /* whom -check                           */
218static int linepos=0;           /* putadr()'s position on the line       */
219static int nameoutput=0;        /* putadr() has output header name       */
220
221static unsigned msgflags = 0;   /* what we've seen */
222
223#define NORMAL 0
224#define RESENT 1
225static int msgstate = NORMAL;
226
227static time_t tclock = 0;       /* the time we started (more or less) */
228
229static SIGNAL_HANDLER hstat, istat, qstat, tstat;
230
231static char tmpfil[BUFSIZ];
232static char bccfil[BUFSIZ];
233
234static char from[BUFSIZ];       /* my network address            */
235static char signature[BUFSIZ];  /* my signature                  */
236static char *filter = NULL;     /* the filter for BCC'ing        */
237static char *subject = NULL;    /* the subject field for BCC'ing */
238static char *fccfold[FCCS];     /* foldernames for FCC'ing       */
239
240static struct headers  *hdrtab; /* table for the message we're doing */
241
242static struct mailname localaddrs={NULL};       /* local addrs     */
243static struct mailname netaddrs={NULL};         /* network addrs   */
244static struct mailname uuaddrs={NULL};          /* uucp addrs      */
245static struct mailname tmpaddrs={NULL};         /* temporary queue */
246
247#ifdef MMDFMTS
248static char *submitmode = "m";          /* deliver to mailbox only    */
249static char submitopts[6] = "vl";       /* initial options for submit */
250#endif /* MMDFMTS */
251
252#ifdef SENDMTS
253static int snoop      = 0;
254static int smtpmode   = S_MAIL;
255static char *clientsw = NULL;
256static char *serversw = NULL;
257
258extern struct smtp sm_reply;
259#endif /* SENDMTS */
260
261static char prefix[] = "----- =_aaaaaaaaaa";
262
263static int fill_up = 0;
264static char *fill_in = NULL;
265static char *partno = NULL;
266static int queued = 0;
267
268/*
269 * static prototypes
270 */
271static void putfmt (char *, char *, FILE *);
272static void start_headers (void);
273static void finish_headers (FILE *);
274static int get_header (char *, struct headers *);
275static int putadr (char *, char *, struct mailname *, FILE *, unsigned int);
276static void putgrp (char *, char *, FILE *, unsigned int);
277static int insert (struct mailname *);
278static void pl (void);
279static void anno (void);
280static int annoaux (struct mailname *);
281static void insert_fcc (struct headers *, char *);
282static void make_bcc_file (int);
283static void verify_all_addresses (int);
284static void chkadr (void);
285static void sigon (void);
286static void sigoff (void);
287static void p_refile (char *);
288static void fcc (char *, char *);
289static void die (char *, char *, ...);
290static void post (char *, int, int);
291static void do_text (char *file, int fd);
292static void do_an_address (struct mailname *, int);
293static void do_addresses (int, int);
294static int find_prefix (void);
295
296
297int
298main (int argc, char **argv)
299{
300    int state, compnum, dashstuff = 0;
301    char *cp, *msg = NULL, **argp, **arguments;
302    char buf[BUFSIZ], name[NAMESZ];
303    FILE *in, *out;
304
305#ifdef LOCALE
306    setlocale(LC_ALL, "");
307#endif
308    invo_name = r1bindex (argv[0], '/');
309
310    /* foil search of user profile/context */
311    if (context_foil (NULL) == -1)
312        done (1);
313
314    mts_init (invo_name);
315    arguments = getarguments (invo_name, argc, argv, 0);
316    argp = arguments;
317
318#if defined(MMDFMTS) && defined(MMDFII)
319    mmdf_init (invo_name);
320#endif /* MMDFMTS and MMDFII */
321
322    while ((cp = *argp++)) {
323        if (*cp == '-') {
324            switch (smatch (++cp, switches)) {
325                case AMBIGSW:
326                    ambigsw (cp, switches);
327                    done (1);
328                case UNKWNSW:
329                    adios (NULL, "-%s unknown", cp);
330
331                case HELPSW:
332                    snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
333                    print_help (buf, switches, 0);
334                    done (1);
335                case VERSIONSW:
336                    print_version(invo_name);
337                    done (1);
338
339                case LIBSW:
340                    if (!(cp = *argp++) || *cp == '-')
341                        adios (NULL, "missing argument to %s", argp[-2]);
342                    /* create a minimal context */
343                    if (context_foil (cp) == -1)
344                        done (1);
345                    continue;
346
347                case ALIASW:
348                    if (!(cp = *argp++) || *cp == '-')
349                        adios (NULL, "missing argument to %s", argp[-2]);
350                    if ((state = alias (cp)) != AK_OK)
351                        adios (NULL, "aliasing error in %s - %s",
352                                cp, akerror (state));
353                    continue;
354
355                case CHKSW:
356                    checksw++;
357                    continue;
358                case NCHKSW:
359                    checksw = 0;
360                    continue;
361
362                case DEBUGSW:
363                    debug++;
364                    continue;
365
366                case DISTSW:
367                    msgstate = RESENT;
368                    continue;
369
370                case FILTSW:
371                    if (!(filter = *argp++) || *filter == '-')
372                        adios (NULL, "missing argument to %s", argp[-2]);
373                    mime = 0;
374                    continue;
375                case NFILTSW:
376                    filter = NULL;
377                    continue;
378               
379                case FRMTSW:
380                    format++;
381                    continue;
382                case NFRMTSW:
383                    format = 0;
384                    continue;
385
386                case BITSTUFFSW:
387                    dashstuff = 1;
388                    continue;
389                case NBITSTUFFSW:
390                    dashstuff = -1;
391                    continue;
392
393                case MIMESW:
394                    mime++;
395                    filter = NULL;
396                    continue;
397                case NMIMESW:
398                    mime = 0;
399                    continue;
400
401                case MSGDSW:
402                    msgid++;
403                    continue;
404                case NMSGDSW:
405                    msgid = 0;
406                    continue;
407
408                case VERBSW:
409                    verbose++;
410                    continue;
411                case NVERBSW:
412                    verbose = 0;
413                    continue;
414
415                case WATCSW:
416                    watch++;
417                    continue;
418                case NWATCSW:
419                    watch = 0;
420                    continue;
421
422                case WHOMSW:
423                    whomsw++;
424                    continue;
425
426                case WIDTHSW:
427                    if (!(cp = *argp++) || *cp == '-')
428                        adios (NULL, "missing argument to %s", argp[-2]);
429                    if ((outputlinelen = atoi (cp)) < 10)
430                        adios (NULL, "impossible width %d", outputlinelen);
431                    continue;
432
433                case ANNOSW:
434                    if (!(cp = *argp++) || *cp == '-')
435                        adios (NULL, "missing argument to %s", argp[-2]);
436                    if ((pfd = atoi (cp)) <= 2)
437                        adios (NULL, "bad argument %s %s", argp[-2], cp);
438                    continue;
439
440#ifdef MMDFMTS
441                case MAILSW:
442                    submitmode = "m";
443                    continue;
444                case SOMLSW:    /* for right now, sigh... */
445                case SAMLSW:
446                    submitmode = "b";
447                    continue;
448                case SENDSW:
449                    submitmode = "y";
450                    continue;
451#endif /* MMDFMTS */
452
453                case DLVRSW:
454                    if (!(cp = *argp++) || *cp == '-')
455                        adios (NULL, "missing argument to %s", argp[-2]);
456                    continue;
457
458#ifndef SENDMTS
459                case CLIESW:
460                case SERVSW:
461                    if (!(cp = *argp++) || *cp == '-')
462                        adios (NULL, "missing argument to %s", argp[-2]);
463                    continue;
464
465                case SNOOPSW:
466                    continue;
467#else /* SENDMTS */
468                case MAILSW:
469                    smtpmode = S_MAIL;
470                    continue;
471                case SAMLSW:
472                    smtpmode = S_SAML;
473                    continue;
474                case SOMLSW:
475                    smtpmode = S_SOML;
476                    continue;
477                case SENDSW:
478                    smtpmode = S_SEND;
479                    continue;
480                case CLIESW:
481                    if (!(clientsw = *argp++) || *clientsw == '-')
482                        adios (NULL, "missing argument to %s", argp[-2]);
483                    continue;
484                case SERVSW:
485                    if (!(serversw = *argp++) || *serversw == '-')
486                        adios (NULL, "missing argument to %s", argp[-2]);
487                    continue;
488                case SNOOPSW:
489                    snoop++;
490                    continue;
491#endif /* SENDMTS */
492
493                case FILLSW:
494                    if (!(fill_in = *argp++) || *fill_in == '-')
495                        adios (NULL, "missing argument to %s", argp[-2]);
496                    continue;
497                case FILLUSW:
498                    fill_up++;
499                    continue;
500                case PARTSW:
501                    if (!(partno = *argp++) || *partno == '-')
502                        adios (NULL, "missing argument to %s", argp[-2]);
503                    continue;
504
505                case QUEUESW:
506                    queued++;
507                    continue;
508            }
509        }
510        if (msg)
511            adios (NULL, "only one message at a time!");
512        else
513            msg = cp;
514    }
515
516    alias (AliasFile);
517
518    if (!msg)
519        adios (NULL, "usage: %s [switches] file", invo_name);
520
521    if (outputlinelen < 10)
522        adios (NULL, "impossible width %d", outputlinelen);
523
524    if ((in = fopen (msg, "r")) == NULL)
525        adios (msg, "unable to open");
526
527    start_headers ();
528    if (debug) {
529        verbose++;
530        discard (out = stdout); /* XXX: reference discard() to help loader */
531    } else {
532        if (whomsw) {
533            if ((out = fopen (fill_in ? fill_in : "/dev/null", "w")) == NULL)
534                adios ("/dev/null", "unable to open");
535        } else {
536            strncpy (tmpfil, m_scratch ("", m_maildir (invo_name)),
537                sizeof(tmpfil));
538            if ((out = fopen (tmpfil, "w")) == NULL) {
539                strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
540                if ((out = fopen (tmpfil, "w")) == NULL)
541                    adios (tmpfil, "unable to create");
542            }
543            chmod (tmpfil, 0600);
544        }
545    }
546
547    hdrtab = msgstate == NORMAL ? NHeaders : RHeaders;
548
549    for (compnum = 1, state = FLD;;) {
550        switch (state = m_getfld (state, name, buf, sizeof(buf), in)) {
551            case FLD:
552            case FLDEOF:
553            case FLDPLUS:
554                compnum++;
555                cp = add (buf, NULL);
556                while (state == FLDPLUS) {
557                    state = m_getfld (state, name, buf, sizeof(buf), in);
558                    cp = add (buf, cp);
559                }
560                putfmt (name, cp, out);
561                free (cp);
562                if (state != FLDEOF)
563                    continue;
564                finish_headers (out);
565                break;
566
567            case BODY:
568            case BODYEOF:
569                finish_headers (out);
570                if (whomsw && !fill_in)
571                    break;
572                fprintf (out, "\n%s", buf);
573                while (state == BODY) {
574                    state = m_getfld (state, name, buf, sizeof(buf), in);
575                    fputs (buf, out);
576                }
577                break;
578
579            case FILEEOF:
580                finish_headers (out);
581                break;
582
583            case LENERR:
584            case FMTERR:
585                adios (NULL, "message format error in component #%d", compnum);
586
587            default:
588                adios (NULL, "getfld() returned %d", state);
589        }
590        break;
591    }
592
593    if (pfd != NOTOK)
594        anno ();
595    fclose (in);
596
597    if (debug) {
598        pl ();
599        done (0);
600    } else {
601        fclose (out);
602    }
603
604    /* If we are doing a "whom" check */
605    if (whomsw) {
606        if (!fill_up)
607            verify_all_addresses (1);
608        done (0);
609    }
610
611#ifdef MMDFMTS
612    strcat (submitopts, submitmode);
613    if (watch)
614        strcat (submitopts, "nw");
615#endif /* MMDFMTS */
616
617    if (msgflags & MINV) {
618        make_bcc_file (dashstuff);
619        if (msgflags & MVIS) {
620            verify_all_addresses (verbose);
621            post (tmpfil, 0, verbose);
622        }
623        post (bccfil, 1, verbose);
624        unlink (bccfil);
625    } else {
626        post (tmpfil, 0, isatty (1));
627    }
628
629    p_refile (tmpfil);
630    unlink (tmpfil);
631
632    if (verbose)
633        printf (partno ? "Partial Message #%s Processed\n" : "Message Processed\n",
634                partno);
635    done (0);
636}
637
638
639/*
640 * DRAFT GENERATION
641 */
642
643static void
644putfmt (char *name, char *str, FILE *out)
645{
646    int count, grp, i, keep;
647    char *cp, *pp, *qp;
648    char namep[BUFSIZ];
649    struct mailname *mp, *np;
650    struct headers *hdr;
651
652    while (*str == ' ' || *str == '\t')
653        str++;
654
655    if (msgstate == NORMAL && uprf (name, "resent")) {
656        advise (NULL, "illegal header line -- %s:", name);
657        badmsg++;
658        return;
659    }
660
661    if ((i = get_header (name, hdrtab)) == NOTOK) {
662        fprintf (out, "%s: %s", name, str);
663        return;
664    }
665
666    hdr = &hdrtab[i];
667    if (hdr->flags & HIGN) {
668        if (fill_in)
669            fprintf (out, "%s: %s", name, str);
670        return;
671    }
672    if (hdr->flags & HBAD) {
673        if (fill_in)
674            fprintf (out, "%s: %s", name, str);
675        else {
676            advise (NULL, "illegal header line -- %s:", name);
677            badmsg++;
678        }
679        return;
680    }
681    msgflags |= (hdr->set & ~(MVIS | MINV));
682
683    if (hdr->flags & HSUB)
684        subject = subject ? add (str, add ("\t", subject)) : getcpy (str);
685    if (hdr->flags & HFCC) {
686        if (fill_in) {
687            fprintf (out, "%s: %s", name, str);
688            return;
689        }
690
691        if ((cp = strrchr(str, '\n')))
692            *cp = 0;
693        for (cp = pp = str; cp = strchr(pp, ','); pp = cp) {
694            *cp++ = 0;
695            insert_fcc (hdr, pp);
696        }
697        insert_fcc (hdr, pp);
698        return;
699    }
700
701    if (!(hdr->flags & HADR)) {
702        fprintf (out, "%s: %s", name, str);
703        return;
704    }
705
706    tmpaddrs.m_next = NULL;
707    for (count = 0; cp = getname (str); count++)
708        if ((mp = getm (cp, NULL, 0, AD_HOST, NULL))) {
709            if (tmpaddrs.m_next)
710                np->m_next = mp;
711            else
712                tmpaddrs.m_next = mp;
713            np = mp;
714        }
715        else
716            if (hdr->flags & HTRY)
717                badadr++;
718            else
719                badmsg++;
720
721    if (count < 1) {
722        if (hdr->flags & HNIL)
723            fprintf (out, "%s: %s", name, str);
724        else {
725#ifdef notdef
726            advise (NULL, "%s: field requires at least one address", name);
727            badmsg++;
728#endif /* notdef */
729        }
730        return;
731    }
732
733    nameoutput = linepos = 0;
734    snprintf (namep, sizeof(namep), "%s%s",
735                !fill_in && (hdr->flags & HMNG) ? "Original-" : "", name);
736
737    for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np)
738        if (mp->m_nohost) {     /* also used to test (hdr->flags & HTRY) */
739            pp = akvalue (mp->m_mbox);
740            qp = akvisible () ? mp->m_mbox : "";
741            np = mp;
742            if (np->m_gname)
743                putgrp (namep, np->m_gname, out, hdr->flags);
744            while ((cp = getname (pp))) {
745                if (!(mp = getm (cp, NULL, 0, AD_HOST, NULL))) {
746                    badadr++;
747                    continue;
748                }
749                if (hdr->flags & HBCC)
750                    mp->m_bcc++;
751                if (np->m_ingrp)
752                    mp->m_ingrp = np->m_ingrp;
753                else
754                    if (mp->m_gname)
755                        putgrp (namep, mp->m_gname, out, hdr->flags);
756                if (mp->m_ingrp)
757                    grp++;
758                if (putadr (namep, qp, mp, out, hdr->flags))
759                    msgflags |= (hdr->set & (MVIS | MINV));
760                else
761                    mnfree (mp);
762            }
763            mp = np;
764            np = np->m_next;
765            mnfree (mp);
766        }
767        else {
768            if (hdr->flags & HBCC)
769                mp->m_bcc++;
770            if (mp->m_gname)
771                putgrp (namep, mp->m_gname, out, hdr->flags);
772            if (mp->m_ingrp)
773                grp++;
774            keep = putadr (namep, "", mp, out, hdr->flags);
775            np = mp->m_next;
776            if (keep) {
777                mp->m_next = NULL;
778                msgflags |= (hdr->set & (MVIS | MINV));
779            }
780            else
781                mnfree (mp);
782        }
783
784    if (grp > 0 && (hdr->flags & HNGR)) {
785        advise (NULL, "%s: field does not allow groups", name);
786        badmsg++;
787    }
788    if (linepos) {
789        if (fill_in && grp > 0)
790            putc (';', out);
791        putc ('\n', out);
792    }
793}
794
795
796static void
797start_headers (void)
798{
799    char  *cp;
800    char myhost[BUFSIZ], sigbuf[BUFSIZ];
801    struct mailname *mp;
802
803    myuid = getuid ();
804    mygid = getgid ();
805    time (&tclock);
806
807    strncpy (from, adrsprintf (NULL, NULL), sizeof(from));
808    strncpy (myhost, LocalName (), sizeof(myhost));
809
810    for (cp = myhost; *cp; cp++)
811        *cp = uptolow (*cp);
812
813    if ((cp = getfullname ()) && *cp) {
814        strncpy (sigbuf, cp, sizeof(sigbuf));
815        snprintf (signature, sizeof(signature), "%s <%s>",
816                sigbuf, adrsprintf (NULL, NULL));
817        if ((cp = getname (signature)) == NULL)
818            adios (NULL, "getname () failed -- you lose extraordinarily big");
819        if ((mp = getm (cp, NULL, 0, AD_HOST, NULL)) == NULL)
820            adios (NULL, "bad signature '%s'", sigbuf);
821        mnfree (mp);
822        while (getname (""))
823            continue;
824    } else {
825        strncpy (signature, adrsprintf (NULL, NULL), sizeof(signature));
826    }
827}
828
829
830/*
831 * Now that we've outputted the header fields in the draft
832 * message, we will now output any remaining header fields
833 * that we need to add/create.
834 */
835
836static void
837finish_headers (FILE *out)
838{
839    switch (msgstate) {
840        case NORMAL:
841            if (whomsw && !fill_up)
842                break;
843
844            fprintf (out, "Date: %s\n", dtime (&tclock, 0));
845            if (msgid)
846                fprintf (out, "Message-ID: <%d.%ld@%s>\n",
847                        (int) getpid (), tclock, LocalName ());
848            if (msgflags & MFRM)
849                fprintf (out, "Sender: %s\n", from);
850            else
851                fprintf (out, "From: %s\n", signature);
852            if (whomsw)
853                break;
854
855            if (!(msgflags & MVIS))
856                fprintf (out, "Bcc: Blind Distribution List: ;\n");
857            break;
858
859        case RESENT:
860            if (!(msgflags & MDAT)) {
861                advise (NULL, "message has no Date: header");
862                badmsg++;
863            }
864            if (!(msgflags & MFRM)) {
865                advise (NULL, "message has no From: header");
866                badmsg++;
867            }
868            if (whomsw && !fill_up)
869                break;
870
871#ifdef MMDFI                    /* sigh */
872            fprintf (out, "Sender: %s\n", from);
873#endif /* MMDFI */
874
875            fprintf (out, "Resent-Date: %s\n", dtime (&tclock, 0));
876            if (msgid)
877                fprintf (out, "Resent-Message-ID: <%d.%ld@%s>\n",
878                        (int) getpid (), tclock, LocalName ());
879            if (msgflags & MRFM)
880                fprintf (out, "Resent-Sender: %s\n", from);
881            else
882                fprintf (out, "Resent-From: %s\n", signature);
883            if (whomsw)
884                break;
885            if (!(msgflags & MVIS))
886                fprintf (out, "Resent-Bcc: Blind Re-Distribution List: ;\n");
887            break;
888    }
889
890    if (badmsg)
891        adios (NULL, "re-format message and try again");
892    if (!recipients)
893        adios (NULL, "no addressees");
894}
895
896
897static int
898get_header (char *header, struct headers *table)
899{
900    struct headers *h;
901
902    for (h = table; h->value; h++)
903        if (!strcasecmp (header, h->value))
904            return (h - table);
905
906    return NOTOK;
907}
908
909
910static int
911putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flags)
912{
913    int len;
914    char *cp;
915    char buffer[BUFSIZ];
916
917    if (mp->m_mbox == NULL || ((flags & HTRY) && !insert (mp)))
918        return 0;
919    if (!fill_in && (flags & (HBCC | HDCC)) || mp->m_ingrp)
920        return 1;
921
922    if (!nameoutput) {
923        fprintf (out, "%s: ", name);
924        linepos += (nameoutput = strlen (name) + 2);
925    }
926
927    if (*aka && mp->m_type != UUCPHOST && !mp->m_pers)
928        mp->m_pers = getcpy (aka);
929    if (format) {
930        if (mp->m_gname && !fill_in) {
931            snprintf (buffer, sizeof(buffer), "%s;", mp->m_gname);
932            cp = buffer;
933        } else {
934            cp = adrformat (mp);
935        }
936    } else {
937        cp = mp->m_text;
938    }
939    len = strlen (cp);
940
941    if (linepos != nameoutput)
942        if (len + linepos + 2 > outputlinelen)
943            fprintf (out, ",\n%*s", linepos = nameoutput, "");
944        else {
945            fputs (", ", out);
946            linepos += 2;
947        }
948
949    fputs (cp, out);
950    linepos += len;
951
952    return (flags & HTRY);
953}
954
955
956static void
957putgrp (char *name, char *group, FILE *out, unsigned int flags)
958{
959    int len;
960    char *cp;
961
962    if (!fill_in && (flags & HBCC))
963        return;
964
965    if (!nameoutput) {
966        fprintf (out, "%s: ", name);
967        linepos += (nameoutput = strlen (name) + 2);
968        if (fill_in)
969            linepos -= strlen (group);
970    }
971
972    cp = fill_in ? group : concat (group, ";", NULL);
973    len = strlen (cp);
974
975    if (linepos > nameoutput)
976        if (len + linepos + 2 > outputlinelen) {
977            fprintf (out, ",\n%*s", nameoutput, "");
978            linepos = nameoutput;
979        }
980        else {
981            fputs (", ", out);
982            linepos += 2;
983        }
984
985    fputs (cp, out);
986    linepos += len;
987}
988
989
990static int
991insert (struct mailname *np)
992{
993    struct mailname *mp;
994
995    if (np->m_mbox == NULL)
996        return 0;
997
998    for (mp = np->m_type == LOCALHOST ? &localaddrs
999            : np->m_type == UUCPHOST ? &uuaddrs
1000            : &netaddrs;
1001            mp->m_next;
1002            mp = mp->m_next)
1003        if (!strcasecmp (np->m_host, mp->m_next->m_host)
1004                && !strcasecmp (np->m_mbox, mp->m_next->m_mbox)
1005                && np->m_bcc == mp->m_next->m_bcc)
1006            return 0;
1007
1008    mp->m_next = np;
1009    recipients++;
1010    return 1;
1011}
1012
1013
1014static void
1015pl (void)
1016{
1017    int i;
1018    struct mailname *mp;
1019
1020    printf ("-------\n\t-- Addresses --\nlocal:\t");
1021    for (mp = localaddrs.m_next; mp; mp = mp->m_next)
1022        printf ("%s%s%s", mp->m_mbox,
1023                mp->m_bcc ? "[BCC]" : "",
1024                mp->m_next ? ",\n\t" : "");
1025
1026    printf ("\nnet:\t");
1027    for (mp = netaddrs.m_next; mp; mp = mp->m_next)
1028        printf ("%s%s@%s%s%s", mp->m_path ? mp->m_path : "",
1029                mp->m_mbox, mp->m_host,
1030                mp->m_bcc ? "[BCC]" : "",
1031                mp->m_next ? ",\n\t" : "");
1032
1033    printf ("\nuucp:\t");
1034    for (mp = uuaddrs.m_next; mp; mp = mp->m_next)
1035        printf ("%s!%s%s%s", mp->m_host, mp->m_mbox,
1036                mp->m_bcc ? "[BCC]" : "",
1037                mp->m_next ? ",\n\t" : "");
1038
1039    printf ("\n\t-- Folder Copies --\nfcc:\t");
1040    for (i = 0; i < fccind; i++)
1041        printf ("%s%s", fccfold[i], i + 1 < fccind ? ",\n\t" : "");
1042    printf ("\n");
1043}
1044
1045
1046static void
1047anno (void)
1048{
1049    struct mailname *mp;
1050
1051    for (mp = localaddrs.m_next; mp; mp = mp->m_next)
1052        if (annoaux (mp) == NOTOK)
1053            goto oops;
1054
1055    for (mp = netaddrs.m_next; mp; mp = mp->m_next)
1056        if (annoaux (mp) == NOTOK)
1057            goto oops;
1058
1059    for (mp = uuaddrs.m_next; mp; mp = mp->m_next)
1060        if (annoaux (mp) == NOTOK)
1061            break;
1062
1063oops: ;
1064    close (pfd);
1065    pfd = NOTOK;
1066}
1067
1068
1069static int
1070annoaux (struct mailname *mp)
1071{
1072    int i;
1073    char buffer[BUFSIZ];
1074
1075    snprintf (buffer, sizeof(buffer), "%s\n", adrformat (mp));
1076    i = strlen (buffer);
1077
1078    return (write (pfd, buffer, i) == i ? OK : NOTOK);
1079}
1080
1081
1082static void
1083insert_fcc (struct headers *hdr, char *pp)
1084{
1085    char *cp;
1086
1087    for (cp = pp; isspace (*cp); cp++)
1088        continue;
1089    for (pp += strlen (pp) - 1; pp > cp && isspace (*pp); pp--)
1090        continue;
1091    if (pp >= cp)
1092        *++pp = 0;
1093    if (*cp == 0)
1094        return;
1095
1096    if (fccind >= FCCS)
1097        adios (NULL, "too many %ss", hdr->value);
1098    fccfold[fccind++] = getcpy (cp);
1099}
1100
1101/*
1102 * BCC GENERATION
1103 */
1104
1105static void
1106make_bcc_file (int dashstuff)
1107{
1108    int fd, i;
1109    pid_t child_id;
1110    char *vec[6];
1111    FILE *out;
1112
1113    strncpy (bccfil, m_tmpfil ("bccs"), sizeof(bccfil));
1114    if ((out = fopen (bccfil, "w")) == NULL)
1115        adios (bccfil, "unable to create");
1116    chmod (bccfil, 0600);
1117
1118    fprintf (out, "Date: %s\n", dtime (&tclock, 0));
1119    if (msgid)
1120        fprintf (out, "Message-ID: <%d.%ld@%s>\n",
1121                (int) getpid (), tclock, LocalName ());
1122    fprintf (out, "From: %s\n", signature);
1123    if (subject)
1124        fprintf (out, "Subject: %s", subject);
1125    fprintf (out, "BCC:\n");
1126
1127    /*
1128     * Use MIME encapsulation for Bcc messages
1129     */
1130    if (mime) {
1131        char *cp;
1132
1133        /*
1134         * Check if any lines in the message clash with the
1135         * prefix for the MIME multipart separator.  If there
1136         * is a clash, increment one of the letters in the
1137         * prefix and check again.
1138         */
1139        if ((cp = strchr(prefix, 'a')) == NULL)
1140            adios (NULL, "lost prefix start");
1141        while (find_prefix () == NOTOK) {
1142            if (*cp < 'z')
1143                (*cp)++;
1144            else
1145                if (*++cp == 0)
1146                    adios (NULL, "can't find a unique delimiter string");
1147                else
1148                    (*cp)++;
1149        }
1150
1151        fprintf (out, "%s: %s\n%s: multipart/digest; boundary=\"",
1152                 VRSN_FIELD, VRSN_VALUE, TYPE_FIELD);
1153        fprintf (out, "%s\"\n\n--%s\n\n", prefix, prefix);
1154    } else {
1155        fprintf (out, "\n------- Blind-Carbon-Copy\n\n");
1156    }
1157
1158    fflush (out);
1159
1160    /*
1161     * Do mhl filtering of Bcc messages instead
1162     * of MIME encapsulation.
1163     */
1164    if (filter != NULL) {
1165        vec[0] = r1bindex (mhlproc, '/');
1166
1167        for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
1168            sleep (5);
1169        switch (child_id) {
1170            case NOTOK:
1171                adios ("fork", "unable to");
1172
1173            case OK:
1174                dup2 (fileno (out), 1);
1175
1176                i = 1;
1177                vec[i++] = "-forward";
1178                vec[i++] = "-form";
1179                vec[i++] = filter;
1180                vec[i++] = tmpfil;
1181
1182                /* was the flag -[no]dashstuffing specified? */
1183                if (dashstuff > 0)
1184                    vec[i++] = "-dashstuffing";
1185                else if (dashstuff < 0)
1186                    vec[i++] = "-nodashstuffing";
1187                vec[i] = NULL;
1188
1189                execvp (mhlproc, vec);
1190                fprintf (stderr, "unable to exec ");
1191                perror (mhlproc);
1192                _exit (-1);
1193
1194            default:
1195                pidXwait (child_id, mhlproc);
1196                break;
1197        }
1198    } else {
1199        if ((fd = open (tmpfil, O_RDONLY)) == NOTOK)
1200            adios (tmpfil, "unable to re-open");
1201
1202        /*
1203         * If using MIME encapsulation, or if the -nodashstuffing
1204         * flag was given, then just copy message.  Else do
1205         * RFC934 quoting (dashstuffing).
1206         */
1207        if (mime || dashstuff < 0)
1208            cpydata (fd, fileno (out), tmpfil, bccfil);
1209        else
1210            cpydgst (fd, fileno (out), tmpfil, bccfil);
1211        close (fd);
1212    }
1213
1214    fseek (out, 0L, SEEK_END);
1215    if (mime)
1216        fprintf (out, "\n--%s--\n", prefix);
1217    else
1218        fprintf (out, "\n------- End of Blind-Carbon-Copy\n");
1219    fclose (out);
1220}
1221
1222
1223/*
1224 * Scan message to check if any lines clash with
1225 * the prefix of the MIME multipart separator.
1226 */
1227
1228static int
1229find_prefix (void)
1230{
1231    int len, result;
1232    char buffer[BUFSIZ];
1233    FILE *in;
1234
1235    if ((in = fopen (tmpfil, "r")) == NULL)
1236        adios (tmpfil, "unable to re-open");
1237
1238    len = strlen (prefix);
1239
1240    result = OK;
1241    while (fgets (buffer, sizeof(buffer) - 1, in))
1242        if (buffer[0] == '-' && buffer[1] == '-') {
1243            char *cp;
1244
1245            for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
1246                if (!isspace (*cp))
1247                    break;
1248            *++cp = '\0';
1249            if (strcmp (buffer + 2, prefix) == 0) {
1250                result = NOTOK;
1251                break;
1252            }
1253        }
1254
1255    fclose (in);
1256    return result;
1257}
1258
1259
1260#define plural(x) (x == 1 ? "" : "s")
1261
1262static void
1263chkadr (void)
1264{
1265    if (badadr && unkadr)
1266        die (NULL, "%d address%s unparsable, %d addressee%s undeliverable",
1267                badadr, plural (badadr), unkadr, plural (badadr));
1268    if (badadr)
1269        die (NULL, "%d address%s unparsable", badadr, plural (badadr));
1270    if (unkadr)
1271        die (NULL, "%d addressee%s undeliverable", unkadr, plural (unkadr));
1272}
1273
1274
1275static void
1276do_addresses (int bccque, int talk)
1277{
1278    int retval;
1279    int state;
1280    struct mailname *lp;
1281
1282    state = 0;
1283    for (lp = localaddrs.m_next; lp; lp = lp->m_next)
1284        if (lp->m_bcc ? bccque : !bccque) {
1285            if (talk && !state)
1286                printf ("  -- Local Recipients --\n");
1287            do_an_address (lp, talk);
1288            state++;
1289        }
1290
1291    state = 0;
1292    for (lp = uuaddrs.m_next; lp; lp = lp->m_next)
1293        if (lp->m_bcc ? bccque : !bccque) {
1294            if (talk && !state)
1295                printf ("  -- UUCP Recipients --\n");
1296            do_an_address (lp, talk);
1297            state++;
1298        }
1299
1300    state = 0;
1301    for (lp = netaddrs.m_next; lp; lp = lp->m_next)
1302        if (lp->m_bcc ? bccque : !bccque) {
1303            if (talk && !state)
1304                printf ("  -- Network Recipients --\n");
1305            do_an_address (lp, talk);
1306            state++;
1307        }
1308
1309    chkadr ();
1310
1311#ifdef MMDFMTS
1312    if (rp_isbad (retval = mm_waend ()))
1313        die (NULL, "problem ending addresses [%s]\n", rp_valstr (retval));
1314#endif /* MMDFMTS */
1315
1316#ifdef SENDMTS
1317    if (rp_isbad (retval = sm_waend ()))
1318        die (NULL, "problem ending addresses; %s", rp_string (retval));
1319#endif /* SENDMTS */
1320}
1321
1322
1323/*
1324 * MTS-SPECIFIC INTERACTION
1325 */
1326
1327
1328/*
1329 * SENDMAIL/SMTP routines
1330 */
1331
1332#ifdef SENDMTS
1333
1334static void
1335post (char *file, int bccque, int talk)
1336{
1337    int fd, onex;
1338    int retval;
1339
1340    onex = !(msgflags & MINV) || bccque;
1341    if (verbose) {
1342        if (msgflags & MINV)
1343            printf (" -- Posting for %s Recipients --\n",
1344                    bccque ? "Blind" : "Sighted");
1345        else
1346            printf (" -- Posting for All Recipients --\n");
1347    }
1348
1349    sigon ();
1350
1351    if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose,
1352                                    snoop, onex, queued))
1353            || rp_isbad (retval = sm_winit (smtpmode, from)))
1354        die (NULL, "problem initializing server; %s", rp_string (retval));
1355
1356    do_addresses (bccque, talk && verbose);
1357    if ((fd = open (file, O_RDONLY)) == NOTOK)
1358        die (file, "unable to re-open");
1359    do_text (file, fd);
1360    close (fd);
1361    fflush (stdout);
1362
1363    sm_end (onex ? OK : DONE);
1364    sigoff ();
1365
1366    if (verbose) {
1367        if (msgflags & MINV)
1368            printf (" -- %s Recipient Copies Posted --\n",
1369                    bccque ? "Blind" : "Sighted");
1370        else
1371            printf (" -- Recipient Copies Posted --\n");
1372    }
1373
1374    fflush (stdout);
1375}
1376
1377
1378/* Address Verification */
1379
1380static void
1381verify_all_addresses (int talk)
1382{
1383    int retval;
1384    struct mailname *lp;
1385
1386    sigon ();
1387
1388    if (!whomsw || checksw)
1389        if (rp_isbad (retval = sm_init (clientsw, serversw, 0, 0, snoop, 0, 0))
1390                || rp_isbad (retval = sm_winit (smtpmode, from)))
1391            die (NULL, "problem initializing server; %s", rp_string (retval));
1392
1393    if (talk && !whomsw)
1394        printf (" -- Address Verification --\n");
1395    if (talk && localaddrs.m_next)
1396        printf ("  -- Local Recipients --\n");
1397    for (lp = localaddrs.m_next; lp; lp = lp->m_next)
1398        do_an_address (lp, talk);
1399
1400    if (talk && uuaddrs.m_next)
1401        printf ("  -- UUCP Recipients --\n");
1402    for (lp = uuaddrs.m_next; lp; lp = lp->m_next)
1403        do_an_address (lp, talk);
1404
1405    if (talk && netaddrs.m_next)
1406        printf ("  -- Network Recipients --\n");
1407    for (lp = netaddrs.m_next; lp; lp = lp->m_next)
1408        do_an_address (lp, talk);
1409
1410    chkadr ();
1411    if (talk && !whomsw)
1412        printf (" -- Address Verification Successful --\n");
1413
1414    if (!whomsw || checksw)
1415        sm_end (DONE);
1416
1417    fflush (stdout);
1418    sigoff ();
1419}
1420
1421
1422static void
1423do_an_address (struct mailname *lp, int talk)
1424{
1425    int retval;
1426    char *mbox, *host;
1427    char addr[BUFSIZ];
1428
1429    switch (lp->m_type) {
1430        case LOCALHOST:
1431            mbox = lp->m_mbox;
1432            host = lp->m_host;
1433            strncpy (addr, mbox, sizeof(addr));
1434            break;
1435
1436        case UUCPHOST:
1437            mbox = auxformat (lp, 0);
1438            host = NULL;
1439            snprintf (addr, sizeof(addr), "%s!%s", lp->m_host, lp->m_mbox);
1440            break;
1441
1442        default:                /* let SendMail decide if the host is bad  */
1443            mbox = lp->m_mbox;
1444            host = lp->m_host;
1445            snprintf (addr, sizeof(addr), "%s at %s", mbox, host);
1446            break;
1447    }
1448
1449    if (talk)
1450        printf ("  %s%s", addr, whomsw && lp->m_bcc ? "[BCC]" : "");
1451
1452    if (whomsw && !checksw) {
1453        putchar ('\n');
1454        return;
1455    }
1456    if (talk)
1457        printf (": ");
1458    fflush (stdout);
1459
1460    switch (retval = sm_wadr (mbox, host,
1461                         lp->m_type != UUCPHOST ? lp->m_path : NULL)) {
1462        case RP_OK:
1463            if (talk)
1464                printf ("address ok\n");
1465            break;
1466
1467        case RP_NO:
1468        case RP_USER:
1469            if (!talk)
1470                fprintf (stderr, "  %s: ", addr);
1471            fprintf (talk ? stdout : stderr, "loses; %s\n",
1472                        rp_string (retval));
1473            unkadr++;
1474            break;
1475
1476        default:
1477            if (!talk)
1478                fprintf (stderr, "  %s: ", addr);
1479            die (NULL, "unexpected response; %s", rp_string (retval));
1480    }
1481
1482    fflush (stdout);
1483}
1484
1485
1486static void
1487do_text (char *file, int fd)
1488{
1489    int retval, state;
1490    char buf[BUFSIZ];
1491
1492    lseek (fd, (off_t) 0, SEEK_SET);
1493
1494    while ((state = read (fd, buf, sizeof(buf))) > 0) {
1495        if (rp_isbad (retval = sm_wtxt (buf, state)))
1496            die (NULL, "problem writing text; %s\n", rp_string (retval));
1497    }
1498
1499    if (state == NOTOK)
1500        die (file, "problem reading from");
1501
1502    switch (retval = sm_wtend ()) {
1503        case RP_OK:
1504            break;
1505
1506        case RP_NO:
1507        case RP_NDEL:
1508            die (NULL, "posting failed; %s", rp_string (retval));
1509
1510        default:
1511            die (NULL, "unexpected response; %s", rp_string (retval));
1512    }
1513}
1514
1515#endif /* SENDMTS */
1516
1517/*
1518 * MMDF routines
1519 */
1520
1521#ifdef MMDFMTS
1522
1523static void
1524post (char *file, int bccque, int talk)
1525{
1526    int fd, onex;
1527    int retval;
1528#ifdef RP_NS
1529    int len;
1530    struct rp_bufstruct reply;
1531#endif /* RP_NS */
1532
1533    onex = !(msgflags & MINV) || bccque;
1534    if (verbose) {
1535        if (msgflags & MINV)
1536            printf (" -- Posting for %s Recipients --\n",
1537                    bccque ? "Blind" : "Sighted");
1538        else
1539            printf (" -- Posting for All Recipients --\n");
1540    }
1541
1542    sigon ();
1543
1544    if (rp_isbad (retval = mm_init ())
1545            || rp_isbad (retval = mm_sbinit ())
1546            || rp_isbad (retval = mm_winit (NULL, submitopts, from)))
1547        die (NULL, "problem initializing MMDF system [%s]",
1548                rp_valstr (retval));
1549#ifdef RP_NS
1550        if (rp_isbad (retval = mm_rrply (&reply, &len)))
1551            die (NULL, "problem with sender address [%s]",
1552                    rp_valstr (retval));
1553#endif /* RP_NS */
1554
1555    do_addresses (bccque, talk && verbose);
1556    if ((fd = open (file, O_RDONLY)) == NOTOK)
1557        die (file, "unable to re-open");
1558    do_text (file, fd);
1559    close (fd);
1560    fflush (stdout);
1561
1562    mm_sbend ();
1563    mm_end (OK);
1564    sigoff ();
1565
1566    if (verbose)
1567        if (msgflags & MINV)
1568            printf (" -- %s Recipient Copies Posted --\n",
1569                    bccque ? "Blind" : "Sighted");
1570        else
1571            printf (" -- Recipient Copies Posted --\n");
1572    fflush (stdout);
1573}
1574
1575
1576/* Address Verification */
1577
1578static void
1579verify_all_addresses (int talk)
1580{
1581    int retval;
1582    struct mailname *lp;
1583
1584#ifdef RP_NS
1585    int len;
1586    struct rp_bufstruct reply;
1587#endif /* RP_NS */
1588
1589    sigon ();
1590
1591    if (!whomsw || checksw) {
1592        if (rp_isbad (retval = mm_init ())
1593                || rp_isbad (retval = mm_sbinit ())
1594                || rp_isbad (retval = mm_winit (NULL, submitopts, from)))
1595            die (NULL, "problem initializing MMDF system [%s]",
1596                    rp_valstr (retval));
1597#ifdef RP_NS
1598        if (rp_isbad (retval = mm_rrply (&reply, &len)))
1599            die (NULL, "problem with sender address [%s]", rp_valstr (retval));
1600#endif /* RP_NS */
1601    }
1602
1603    if (talk && !whomsw)
1604        printf (" -- Address Verification --\n");
1605    if (talk && localaddrs.m_next)
1606        printf ("  -- Local Recipients --\n");
1607    for (lp = localaddrs.m_next; lp; lp = lp->m_next)
1608        do_an_address (lp, talk);
1609
1610    if (talk && uuaddrs.m_next)
1611        printf ("  -- UUCP Recipients --\n");
1612    for (lp = uuaddrs.m_next; lp; lp = lp->m_next)
1613        do_an_address (lp, talk);
1614
1615    if (talk && netaddrs.m_next)
1616        printf ("  -- Network Recipients --\n");
1617    for (lp = netaddrs.m_next; lp; lp = lp->m_next)
1618        do_an_address (lp, talk);
1619
1620    chkadr ();
1621    if (talk && !whomsw)
1622        printf (" -- Address Verification Successful --\n");
1623
1624    if (!whomsw || checksw)
1625        mm_end (NOTOK);
1626
1627    fflush (stdout);
1628    sigoff ();
1629}
1630
1631
1632static void
1633do_an_address (struct mailname *lp, int talk)
1634{
1635    int len, retval;
1636    char *mbox, *host, *text, *path;
1637    char addr[BUFSIZ];
1638    struct rp_bufstruct reply;
1639
1640    switch (lp->m_type) {
1641        case LOCALHOST:
1642            mbox = lp->m_mbox;
1643            host = LocalName ();
1644            strncpy (addr, mbox, sizeof(addr));
1645            break;
1646
1647        case UUCPHOST:
1648            fprintf (talk ? stdout : stderr, "  %s!%s: %s\n",
1649                lp->m_host, lp->m_mbox, "not supported; UUCP address");
1650            unkadr++;
1651            fflush (stdout);
1652            return;
1653
1654        default:                /* let MMDF decide if the host is bad */
1655            mbox = lp->m_mbox;
1656            host = lp->m_host;
1657            snprintf (addr, sizeof(addr), "%s at %s", mbox, host);
1658            break;
1659    }
1660
1661    if (talk)
1662        printf ("  %s%s", addr, whomsw && lp->m_bcc ? "[BCC]" : "");
1663
1664    if (whomsw && !checksw) {
1665        putchar ('\n');
1666        return;
1667    }
1668    if (talk)
1669        printf (": ");
1670    fflush (stdout);
1671
1672#ifdef MMDFII
1673    if (lp->m_path)
1674        path = concat (lp->m_path, mbox, "@", host, NULL);
1675    else
1676#endif /* MMDFII */
1677        path = NULL;
1678    if (rp_isbad (retval = mm_wadr (path ? NULL : host, path ? path : mbox))
1679            || rp_isbad (retval = mm_rrply (&reply, &len)))
1680        die (NULL, "problem submitting address [%s]", rp_valstr (retval));
1681
1682    switch (rp_gval (reply.rp_val)) {
1683        case RP_AOK:
1684            if (talk)
1685                printf ("address ok\n");
1686            fflush (stdout);
1687            return;
1688
1689#ifdef RP_DOK
1690        case RP_DOK:
1691            if (talk)
1692                printf ("nameserver timeout - queued for checking\n");
1693            fflush (stdout);
1694            return;
1695#endif /* RP_DOK */
1696
1697        case RP_NO:
1698            text = "you lose";
1699            break;
1700
1701#ifdef RP_NS
1702        case RP_NS:
1703            text = "temporary nameserver failure";
1704            break;
1705
1706#endif /* RP_NS */
1707
1708        case RP_USER:
1709        case RP_NDEL:
1710            text = "not deliverable";
1711            break;
1712
1713        case RP_AGN:
1714            text = "try again later";
1715            break;
1716
1717        case RP_NOOP:
1718            text = "nothing done";
1719            break;
1720
1721        default:
1722            if (!talk)
1723                fprintf (stderr, "  %s: ", addr);
1724            text = "unexpected response";
1725            die (NULL, "%s;\n    [%s] -- %s", text,
1726                    rp_valstr (reply.rp_val), reply.rp_line);
1727    }
1728
1729    if (!talk)
1730        fprintf (stderr, "  %s: ", addr);
1731    fprintf (talk ? stdout : stderr, "%s;\n    %s\n", text, reply.rp_line);
1732    unkadr++;
1733
1734    fflush (stdout);
1735}
1736
1737
1738static void
1739do_text (char *file, int fd)
1740{
1741    int retval, state;
1742    char buf[BUFSIZ];
1743    struct rp_bufstruct reply;
1744
1745    lseek (fd, (off_t) 0, SEEK_SET);
1746
1747    while ((state = read (fd, buf, sizeof(buf))) > 0) {
1748        if (rp_isbad (mm_wtxt (buf, state)))
1749            die (NULL, "problem writing text [%s]\n", rp_valstr (retval));
1750    }
1751
1752    if (state == NOTOK)
1753        die (file, "problem reading from");
1754
1755    if (rp_isbad (retval = mm_wtend ()))
1756        die (NULL, "problem ending text [%s]\n", rp_valstr (retval));
1757
1758    if (rp_isbad (retval = mm_rrply (&reply, &state)))
1759        die (NULL, "problem getting submission status [%s]\n",
1760                rp_valstr (retval));
1761
1762    switch (rp_gval (reply.rp_val)) {
1763        case RP_OK:
1764        case RP_MOK:
1765            break;
1766
1767        case RP_NO:
1768            die (NULL, "you lose; %s", reply.rp_line);
1769
1770        case RP_NDEL:
1771            die (NULL, "no delivery occurred; %s", reply.rp_line);
1772
1773        case RP_AGN:
1774            die (NULL, "try again later; %s", reply.rp_line);
1775
1776        case RP_NOOP:
1777            die (NULL, "nothing done; %s", reply.rp_line);
1778
1779        default:
1780            die (NULL, "unexpected response;\n\t[%s] -- %s",
1781                    rp_valstr (reply.rp_val), reply.rp_line);
1782    }
1783}
1784
1785#endif /* MMDFMTS */
1786
1787
1788/*
1789 * SIGNAL HANDLING
1790 */
1791
1792static RETSIGTYPE
1793sigser (int i)
1794{
1795#ifndef RELIABLE_SIGNALS
1796    SIGNAL (i, SIG_IGN);
1797#endif
1798
1799    unlink (tmpfil);
1800    if (msgflags & MINV)
1801        unlink (bccfil);
1802
1803#ifdef MMDFMTS
1804    if (!whomsw || checksw)
1805        mm_end (NOTOK);
1806#endif /* MMDFMTS */
1807
1808#ifdef SENDMTS
1809    if (!whomsw || checksw)
1810        sm_end (NOTOK);
1811#endif /* SENDMTS */
1812
1813    done (1);
1814}
1815
1816
1817static void
1818sigon (void)
1819{
1820    if (debug)
1821        return;
1822
1823    hstat = SIGNAL2 (SIGHUP, sigser);
1824    istat = SIGNAL2 (SIGINT, sigser);
1825    qstat = SIGNAL2 (SIGQUIT, sigser);
1826    tstat = SIGNAL2 (SIGTERM, sigser);
1827}
1828
1829
1830static void
1831sigoff (void)
1832{
1833    if (debug)
1834        return;
1835
1836    SIGNAL (SIGHUP, hstat);
1837    SIGNAL (SIGINT, istat);
1838    SIGNAL (SIGQUIT, qstat);
1839    SIGNAL (SIGTERM, tstat);
1840}
1841
1842/*
1843 * FCC INTERACTION
1844 */
1845
1846static void
1847p_refile (char *file)
1848{
1849    int i;
1850
1851    if (fccind == 0)
1852        return;
1853
1854    if (verbose)
1855        printf (" -- Filing Folder Copies --\n");
1856    for (i = 0; i < fccind; i++)
1857        fcc (file, fccfold[i]);
1858    if (verbose)
1859        printf (" -- Folder Copies Filed --\n");
1860}
1861
1862
1863/*
1864 * Call the `fileproc' to add the file to the folder.
1865 */
1866
1867static void
1868fcc (char *file, char *folder)
1869{
1870    pid_t child_id;
1871    int i, status;
1872    char fold[BUFSIZ];
1873
1874    if (verbose)
1875        printf ("  %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", folder);
1876    fflush (stdout);
1877
1878    for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
1879        sleep (5);
1880
1881    switch (child_id) {
1882        case NOTOK:
1883            if (!verbose)
1884                fprintf (stderr, "  %sFcc %s: ",
1885                        msgstate == RESENT ? "Resent-" : "", folder);
1886            fprintf (verbose ? stdout : stderr, "no forks, so not ok\n");
1887            break;
1888
1889        case OK:
1890            /* see if we need to add `+' */
1891            snprintf (fold, sizeof(fold), "%s%s",
1892                    *folder == '+' || *folder == '@' ? "" : "+", folder);
1893
1894            /* now exec the fileproc */
1895            execlp (fileproc, r1bindex (fileproc, '/'),
1896                    "-link", "-file", file, fold, NULL);
1897            _exit (-1);
1898
1899        default:
1900            if ((status = pidwait (child_id, OK))) {
1901                if (!verbose)
1902                    fprintf (stderr, "  %sFcc %s: ",
1903                            msgstate == RESENT ? "Resent-" : "", folder);
1904                pidstatus (status, verbose ? stdout : stderr, NULL);
1905            } else {
1906                if (verbose)
1907                    printf ("folder ok\n");
1908            }
1909    }
1910
1911    fflush (stdout);
1912}
1913
1914/*
1915 * TERMINATION
1916 */
1917
1918static void
1919die (char *what, char *fmt, ...)
1920{
1921    va_list ap;
1922
1923    unlink (tmpfil);
1924    if (msgflags & MINV)
1925        unlink (bccfil);
1926
1927#ifdef MMDFMTS
1928    if (!whomsw || checksw)
1929        mm_end (NOTOK);
1930#endif /* MMDFMTS */
1931
1932#ifdef SENDMTS
1933    if (!whomsw || checksw)
1934        sm_end (NOTOK);
1935#endif /* SENDMTS */
1936
1937    va_start(ap, fmt);
1938    advertise (what, NULL, fmt, ap);
1939    va_end(ap);
1940    done (1);
1941}
1942
1943
1944#ifdef MMDFMTS
1945/*
1946 * err_abrt() is used by the mm_ routines
1947 *       do not, under *ANY* circumstances, remove it from post,
1948 *       or you will lose *BIG*
1949 */
1950
1951void
1952err_abrt (int code, char *fmt, ...)
1953{
1954    char buffer[BUFSIZ];
1955    va_list ap;
1956
1957    snprintf (buffer, sizeof(buffer), "[%s]", rp_valstr (code));
1958
1959    va_start(ap, fmt);
1960    advertise (buffer, NULL, fmt, ap);
1961    va_end(ap);
1962
1963    done (1);
1964}
1965#endif /* MMDFMTS */
Note: See TracBrowser for help on using the repository browser.