If heirloom shell is in /usr/lib/heirloom/5bin/sh, use it to run tests.
[mmh] / docs / historical / mh-6.8.5 / uip / post.c
1 /* post.c - enter messages into the transport system */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: post.c,v 2.26 1996/02/10 00:22:14 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include "../h/addrsbr.h"
8 #include "../h/aliasbr.h"
9 #include "../h/dropsbr.h"
10 #include "../zotnet/tws.h"
11 #ifndef MMDFMTS
12 #include <ctype.h>
13 #include <errno.h>
14 #include <setjmp.h>
15 #include <stdio.h>
16 #include <sys/types.h>
17 #else   /* MMDFMTS */
18 #include "../mts/mmdf/util.h"
19 #include "../mts/mmdf/mmdf.h"
20 #endif  /* MMDFMTS */
21 #include "../zotnet/mts.h"
22 #ifdef  MHMTS
23 #ifndef V7
24 #include <sys/ioctl.h>
25 #endif  /* not V7 */
26 #include <sys/stat.h>
27 #endif  /* MHMTS */
28 #ifdef  SENDMTS
29 #include "../mts/sendmail/smail.h"
30 #undef  MF
31 #endif  /* SENDMTS */
32 #include <signal.h>
33 #ifdef  MIME
34 #include "../h/mhn.h"
35 #endif  /* MIME */
36 #ifdef LOCALE
37 #include <locale.h>
38 #endif
39
40
41 #ifndef MMDFMTS
42 #define uptolow(c)      ((isalpha(c) && isupper (c)) ? tolower (c) : (c))
43 #endif  /* not MMDFMTS */
44
45 #define FCCS            10      /* max number of fccs allowed */
46
47 /* \f */
48
49 #ifndef MIME
50 #define MIMEminc(a)     (a)
51 #else
52 #define MIMEminc(a)     0
53 #endif
54
55 #ifndef TMA
56 #define TMAminc(a)      (a)
57 #else   /* TMA */
58 #define TMAminc(a)      0
59 #endif  /* TMA */
60
61 static struct swit switches[] = {
62 #define ALIASW  0
63     "alias aliasfile", 0,
64
65 #define CHKSW   1
66     "check", -1,                /* interface from whom */
67 #define NCHKSW  2
68     "nocheck", -3,              /* interface from whom */
69
70 #define DEBUGSW 3
71     "debug", -5,
72
73 #define DISTSW  4
74     "dist", -4,                 /* interface from dist */
75
76 #define ENCRSW  5
77     "encrypt", TMAminc (-7),
78 #define NENCRSW 6
79     "noencrypt", TMAminc (-9),
80
81 #define FILTSW  7
82     "filter filterfile", 0,
83 #define NFILTSW 8
84     "nofilter", 0,
85
86 #define FRMTSW  9
87     "format", 0,
88 #define NFRMTSW 10
89     "noformat", 0,
90
91 #define LIBSW   11              /* interface from send, whom */
92     "library directory", -7,
93
94 #define MIMESW  12
95     "mime", MIMEminc(-4),
96 #define NMIMESW 13
97     "nomime", MIMEminc(-6),
98
99 #define MSGDSW  14
100     "msgid", 0,
101 #define NMSGDSW 15
102     "nomsgid", 0,
103
104 #define VERBSW  16
105     "verbose", 0,
106 #define NVERBSW 17
107     "noverbose", 0,
108
109 #define WATCSW  18
110     "watch", 0,
111 #define NWATCSW 19
112     "nowatch", 0,
113
114 #define WHOMSW  20      /* interface from whom */
115     "whom", -4,         
116
117 #define WIDTHSW 21
118     "width columns", 0,
119
120 #define HELPSW  22
121     "help", 4,
122
123 #define MAILSW  23
124     "mail", -4,
125 #define SAMLSW  24
126     "saml", -4,
127 #define SENDSW  25
128     "send", -4,
129 #define SOMLSW  26
130     "soml", -4,
131
132 #define ANNOSW  27              /* interface from send */
133     "idanno number", -6,
134
135 #define DLVRSW  28
136     "deliver address-list", -7,
137
138 #define CLIESW  29
139     "client host", -6,
140 #define SERVSW  30
141     "server host", -6,
142 #define SNOOPSW 31
143     "snoop", -5,
144
145 #define FILLSW  32
146     "fill-in file", -7,
147 #define FILLUSW 33
148     "fill-up", -7,
149 #define PARTSW  34
150     "partno", -6,
151
152 #define QUEUESW 35
153     "queued", -6,
154
155 #define RECORSW 36
156     "record program", -6,
157 #define NRECOSW 37
158     "norecord", -8,
159
160     NULL, 0
161 };
162
163 /* \f */
164
165 struct headers {
166     char   *value;
167
168     unsigned int    flags;
169 #define HNOP    0x0000          /* just used to keep .set around */
170 #define HBAD    0x0001          /* bad header - don't let it through */
171 #define HADR    0x0002          /* header has an address field */
172 #define HSUB    0x0004          /* Subject: header */
173 #define HTRY    0x0008          /* try to send to addrs on header */
174 #define HBCC    0x0010          /* don't output this header */
175 #define HMNG    0x0020          /* munge this header */
176 #define HNGR    0x0040          /* no groups allowed in this header */
177 #define HFCC    0x0080          /* FCC: type header */
178 #define HNIL    0x0100          /* okay for this header not to have addrs */
179 #define HIGN    0x0200          /* ignore this header */
180 #define HDCC    0x0400          /* another undocumented feature */
181
182     unsigned int    set;
183 #define MFRM    0x0001          /* we've seen a From: */
184 #define MDAT    0x0002          /* we've seen a Date: */
185 #define MRFM    0x0004          /* we've seen a Resent-From: */
186 #define MVIS    0x0008          /* we've seen sighted addrs */
187 #define MINV    0x0010          /* we've seen blind addrs */
188 #define MRPY    0x0020          /* we've seen a Reply-to: */
189 };
190
191 /* \f */
192
193 static struct headers  NHeaders[] = {
194     "Return-Path", HBAD, 0,
195     "Received", HBAD, 0,
196     "Reply-To", HADR | HNGR, MRPY,
197     "From", HADR | HNGR, MFRM,
198     "Sender", HADR | HBAD, 0,
199     "Date", HBAD, 0,
200     "Subject", HSUB, 0,
201     "To", HADR | HTRY, MVIS,
202     "cc", HADR | HTRY, MVIS,
203     "Bcc", HADR | HTRY | HBCC | HNIL, MINV,
204     "Dcc", HADR | HTRY | HDCC | HNIL, MVIS,     /* sorta cc & bcc combined */
205     "Message-ID", HBAD, 0,
206     "Fcc", HFCC, 0,
207
208     NULL
209 };
210
211 static struct headers  RHeaders[] = {
212     "Resent-Reply-To", HADR | HNGR, MRPY,
213     "Resent-From", HADR | HNGR, MRFM,
214     "Resent-Sender", HADR | HBAD, 0,
215     "Resent-Date", HBAD, 0,
216     "Resent-Subject", HSUB, 0,
217     "Resent-To", HADR | HTRY, MVIS,
218     "Resent-cc", HADR | HTRY, MVIS,
219     "Resent-Bcc", HADR | HTRY | HBCC, MINV,
220     "Resent-Message-ID", HBAD, 0,
221     "Resent-Fcc", HFCC, 0,
222     "Reply-To", HADR, MRPY,
223     "From", HADR | HNGR, MFRM,
224 #ifdef  MMDFI
225     "Sender", HADR | HMNG | HNGR, 0,
226 #else   /* not MMFDI */
227     "Sender", HADR | HNGR, 0,
228 #endif  /* not MMDFI */
229     "Date", HNOP, MDAT,
230     "To", HADR | HNIL, 0,
231     "cc", HADR | HNIL, 0,
232     "Bcc", HADR | HTRY | HBCC | HNIL, 0,
233     "Fcc", HIGN, 0,
234
235     NULL
236 };
237
238 /* \f */
239
240
241 static short    fccind = 0;     /* index into fccfold[] */
242 static short    outputlinelen = OUTPUTLINELEN;
243
244 static int  pfd = NOTOK;        /* fd to write annotation list to */
245 static int  myuid= -1;          /* my user id */
246 static int  mygid= -1;          /* my group id */
247 static int  recipients = 0;     /* how many people will get a copy */
248 static int  unkadr = 0;         /* how many of those were unknown */
249 static int  badadr = 0;         /* number of bad addrs */
250 static int  badmsg = 0;         /* message has bad semantics */
251 static int  verbose = 0;        /* spell it out */
252 static int  format = 1;         /* format addresses */
253 static int  mime = 0;           /* use MIME-style encapsulations */
254 static int  msgid = 0;          /* add msgid */
255 static int  debug = 0;          /* debugging post */
256 static int  watch = 0;          /* watch the delivery process */
257 static int  whomsw = 0;         /* we are whom not post */
258 static int  checksw = 0;        /* whom -check */
259 static int  linepos=0;          /* putadr()'s position on the line */
260 static int  nameoutput=0;       /* putadr() has output header name */
261
262 static unsigned msgflags = 0;   /* what we've seen */
263
264 #define NORMAL 0
265 #define RESENT 1
266 static int msgstate = NORMAL;
267
268 static long tclock = 0L;                /* the time we started (more or less) */
269
270 static TYPESIG  (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
271
272 static char tmpfil[BUFSIZ];
273 static char bccfil[BUFSIZ];
274
275 static char from[BUFSIZ];       /* my network address */
276 static char signature[BUFSIZ];  /* my signature */
277 static char *filter = NULL;     /* the filter for BCC'ing */
278 static char *msgfrom = NULL;    /* the From: field for Bcc'ing */
279 static char *subject = NULL;    /* the subject field for BCC'ing */
280 static char *fccfold[FCCS];     /* foldernames for FCC'ing */
281
282 static struct headers  *hdrtab; /* table for the message we're doing */
283
284 static struct mailname localaddrs={NULL};       /* local addrs */
285 static struct mailname netaddrs={NULL};         /* network addrs */
286 static struct mailname uuaddrs={NULL};          /* uucp addrs */
287 static struct mailname tmpaddrs={NULL};         /* temporary queue */
288
289 /* \f */
290
291 #ifdef  MMDFMTS
292 static char *submitmode = "m";  /* deliver to mailbox only */
293 static char submitopts[6] = "vl";/* initial options for submit */
294 #endif  /* MMDFMTS */
295
296 #ifdef  MHMTS
297 static char *deliver = NULL;
298
299 extern char **environ;
300
301 TYPESIG sigser ();
302 #endif  /* MHMTS */
303
304 #ifdef  SENDMTS
305 static int smtpmode = S_MAIL;
306 static int snoop = 0;
307 static char *clientsw = NULL;
308 static char *serversw = NULL;
309
310 extern struct smtp  sm_reply;
311 #endif  /* SENDMTS */
312
313 #ifdef  TMA
314 #define post(a,b,c) \
315     if (encryptsw) postcipher ((a), (b), (c)); else postplain ((a), (b), (c))
316
317 #ifndef SENDMTS
318 #define tmasnoop        0
319 #else   /* SENDMTS */
320 #define tmasnoop        snoop
321 #endif  /* SENDMTS */
322 #endif  /* TMA */
323
324 static int  encryptsw = 0;      /* encrypt it */
325
326
327 #ifdef  BERK
328 #undef  WP
329 #endif
330
331 #ifdef MIME
332 static char     prefix[] = "----- =_aaaaaaaaaa";
333 static int      find_prefix();
334 #endif /* MIME */
335
336 static int      fill_up = 0;
337 static char    *fill_in = NULLCP;
338 static char    *partno = NULLCP;
339
340 static  int     queued = 0;
341
342 static  char   *record = NULLCP;
343
344 off_t   lseek ();
345 long    time ();
346
347 static  putfmt(), start_headers(), finish_headers(), putgrp(), pl();
348 static  anno(), make_bcc_file(), verify_all_addresses();
349 static  chkadr(), do_addresses(), do_text(), do_an_address(), sigon();
350 static  sigoff(), p_refile(), fcc(), die(), insert_fcc(), p_record ();
351 static int      get_header(), putadr(), insert(), annoaux();
352 #ifdef TMA
353 static  postplain();
354 #else
355 static  post();
356 #endif  /* !TMA */
357 /* \f   MAIN */
358
359 /* ARGSUSED */
360
361 main (argc, argv)
362 int     argc;
363 char   *argv[];
364 {
365     int     state,
366             compnum;
367     char   *cp,
368            *msg = NULL,
369           **argp = argv + 1,
370             buf[BUFSIZ],
371             name[NAMESZ];
372     FILE   *in,
373            *out;
374
375 #ifdef LOCALE
376         setlocale(LC_ALL, "");
377 #endif
378     invo_name = r1bindex (argv[0], '/');
379     m_foil (NULLCP);
380     mts_init (invo_name);
381 #ifdef  MMDFMTS
382 #ifdef  MMDFII
383     mmdf_init (invo_name);
384 #endif  /* MMDFII */
385 #endif  /* MMDFMTS */
386
387 /* \f */
388
389     while (cp = *argp++) {
390         if (*cp == '-')
391             switch (smatch (++cp, switches)) {
392                 case AMBIGSW: 
393                     ambigsw (cp, switches);
394                     done (1);
395                 case UNKWNSW: 
396                     adios (NULLCP, "-%s unknown", cp);
397                 case HELPSW: 
398                     (void) sprintf (buf, "%s [switches] file", invo_name);
399                     help (buf, switches);
400                     done (1);
401
402                 case LIBSW:
403                     if (!(cp = *argp++) || *cp == '-')
404                         adios (NULLCP, "missing argument to %s", argp[-2]);
405                     m_foil (cp);
406                     continue;
407
408                 case ALIASW: 
409                     if (!(cp = *argp++) || *cp == '-')
410                         adios (NULLCP, "missing argument to %s", argp[-2]);
411 #ifdef  MHMTS
412                     if (access (libpath (cp), 04) == NOTOK)
413                         adios (cp, "unable to read");
414 #endif  /* MHMTS */
415                     if ((state = alias (cp)) != AK_OK)
416                         adios (NULLCP, "aliasing error in %s - %s",
417                                 cp, akerror (state));
418                     continue;
419
420                 case CHKSW: 
421                     checksw++;
422                     continue;
423                 case NCHKSW: 
424                     checksw = 0;
425                     continue;
426
427                 case DEBUGSW: 
428                     debug++;
429                     continue;
430
431                 case DISTSW:
432                     msgstate = RESENT;
433                     continue;
434
435                 case FILTSW:
436                     if (!(filter = *argp++) || *filter == '-')
437                         adios (NULLCP, "missing argument to %s", argp[-2]);
438                     mime = 0;
439                     continue;
440                 case NFILTSW:
441                     filter = NULL;
442                     continue;
443                 
444                 case FRMTSW: 
445                     format++;
446                     continue;
447                 case NFRMTSW: 
448                     format = 0;
449                     continue;
450
451                 case MIMESW:
452 #ifdef  MIME
453                     mime++;
454                     filter = 0;
455 #endif
456                     continue;
457                 case NMIMESW: 
458                     mime = 0;
459                     continue;
460
461                 case MSGDSW: 
462                     msgid++;
463                     continue;
464                 case NMSGDSW: 
465                     msgid = 0;
466                     continue;
467
468                 case VERBSW: 
469                     verbose++;
470                     continue;
471                 case NVERBSW: 
472                     verbose = 0;
473                     continue;
474
475                 case WATCSW: 
476                     watch++;
477                     continue;
478                 case NWATCSW: 
479                     watch = 0;
480                     continue;
481
482                 case WHOMSW: 
483                     whomsw++;
484                     continue;
485
486                 case WIDTHSW: 
487                     if (!(cp = *argp++) || *cp == '-')
488                         adios (NULLCP, "missing argument to %s", argp[-2]);
489                     if ((outputlinelen = atoi (cp)) < 10)
490                         adios (NULLCP, "impossible width %d", outputlinelen);
491                     continue;
492
493                 case ENCRSW:
494                     encryptsw++;
495                     continue;
496                 case NENCRSW:
497                     encryptsw = 0;
498                     continue;
499
500                 case ANNOSW: 
501                     if (!(cp = *argp++) || *cp == '-')
502                         adios (NULLCP, "missing argument to %s", argp[-2]);
503                     if ((pfd = atoi (cp)) <= 2)
504                         adios (NULLCP, "bad argument %s %s", argp[-2], cp);
505                     continue;
506
507 #ifdef  MMDFMTS
508                 case MAILSW:
509                     submitmode = "m";
510                     continue;
511                 case SOMLSW:    /* for right now, sigh... */
512                 case SAMLSW:
513                     submitmode = "b";
514                     continue;
515                 case SENDSW:
516                     submitmode = "y";
517                     continue;
518 #endif  /* MMDFMTS */
519
520 #ifndef MHMTS
521                 case DLVRSW:
522                     if (!(cp = *argp++) || *cp == '-')
523                         adios (NULLCP, "missing argument to %s", argp[-2]);
524                     continue;
525 #else   /* MHMTS */
526                 case MAILSW:
527                 case SAMLSW:
528                 case SOMLSW:
529                 case SENDSW:
530                     continue;
531                 case DLVRSW: 
532                     if (!(deliver = *argp++) || *deliver == '-')
533                         adios (NULLCP, "missing argument to %s", argp[-2]);
534                     continue;
535 #endif  /* MHMTS */
536
537 #ifndef SENDMTS
538                 case CLIESW:
539                 case SERVSW:
540                     if (!(cp = *argp++) || *cp == '-')
541                         adios (NULLCP, "missing argument to %s", argp[-2]);
542                     continue;
543
544                 case SNOOPSW:
545                     continue;
546 #else   /* SENDMTS */
547                 case MAILSW:
548                     smtpmode = S_MAIL;
549                     continue;
550                 case SAMLSW:
551                     smtpmode = S_SAML;
552                     continue;
553                 case SOMLSW:
554                     smtpmode = S_SOML;
555                     continue;
556                 case SENDSW:
557                     smtpmode = S_SEND;
558                     continue;
559                 case CLIESW:
560                     if (!(clientsw = *argp++) || *clientsw == '-')
561                         adios (NULLCP, "missing argument to %s", argp[-2]);
562                     continue;
563                 case SERVSW:
564                     if (!(serversw = *argp++) || *serversw == '-')
565                         adios (NULLCP, "missing argument to %s", argp[-2]);
566                     continue;
567                 case SNOOPSW:
568                     snoop++;
569                     continue;
570 #endif  /* SENDMTS */
571
572                 case FILLSW:
573                     if (!(fill_in = *argp++) || *fill_in == '-')
574                         adios (NULLCP, "missing argument to %s", argp[-2]);
575                     continue;
576                 case FILLUSW:
577                     fill_up++;
578                     continue;
579                 case PARTSW:
580                     if (!(partno = *argp++) || *partno == '-')
581                         adios (NULLCP, "missing argument to %s", argp[-2]);
582                     continue;
583
584                 case QUEUESW:
585                     queued++;
586                     continue;
587
588                 case RECORSW:
589                     if (!(record = *argp++) || *record == '-')
590                         adios (NULLCP, "missing argument to %s", argp[-2]);
591                     continue;
592                 case NRECOSW:
593                     record = NULLCP;
594                     continue;
595             }
596         if (msg)
597             adios (NULLCP, "only one message at a time!");
598         else
599             msg = cp;
600     }
601
602     (void) alias (AliasFile);
603
604 /* \f */
605
606     if (!msg)
607         adios (NULLCP, "usage: %s [switches] file", invo_name);
608
609     if (outputlinelen < 10)
610         adios (NULLCP, "impossible width %d", outputlinelen);
611
612 #ifdef  MHMTS
613     if (access (msg, 04) == NOTOK)
614         adios (msg, "unable to read");
615 #endif  /* MHMTS */
616     if ((in = fopen (msg, "r")) == NULL)
617         adios (msg, "unable to open");
618
619     start_headers ();
620     if (debug) {
621         verbose++;
622         discard (out = stdout); /* XXX: reference discard() to help loader */
623 #ifdef  MHMTS
624         if (deliver) {
625             (void) strcpy (tmpfil, msg);
626             putfmt ("To", deliver, out);
627             goto daemon;
628         }
629 #endif  /* MHMTS */
630     }
631     else
632 #ifdef  MHMTS
633     if (deliver) {
634         if ((out = fopen ("/dev/null", "r")) == NULL)
635             adios ("/dev/null", "unable to write");
636         (void) strcpy (tmpfil, msg);
637         putfmt ("To", deliver, out);
638         goto daemon;
639     }
640     else
641 #endif  /* MHMTS */
642         if (whomsw) {
643             if ((out = fopen (fill_in ? fill_in : "/dev/null", "w")) == NULL)
644                 adios ("/dev/null", "unable to open");
645         }
646         else {
647             (void) strcpy (tmpfil, m_scratch ("", m_maildir (invo_name)));
648             if ((out = fopen (tmpfil, "w")) == NULL) {
649                 (void) strcpy (tmpfil, m_tmpfil (invo_name));
650                 if ((out = fopen (tmpfil, "w")) == NULL)
651                     adios (tmpfil, "unable to create");
652             }
653 #ifdef  MHMTS
654             (void) chown (tmpfil, myuid, mygid);
655 #endif  /* MHMTS */
656             (void) chmod (tmpfil, 0600);
657         }
658
659 /* \f */
660
661     hdrtab = msgstate == NORMAL ? NHeaders : RHeaders;
662
663     for (compnum = 1, state = FLD;;) {
664         switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
665             case FLD: 
666             case FLDEOF: 
667             case FLDPLUS: 
668                 compnum++;
669                 cp = add (buf, NULLCP);
670                 while (state == FLDPLUS) {
671                     state = m_getfld (state, name, buf, sizeof buf, in);
672                     cp = add (buf, cp);
673                 }
674                 putfmt (name, cp, out);
675                 free (cp);
676                 if (state != FLDEOF)
677                     continue;
678                 finish_headers (out);
679                 break;
680
681             case BODY: 
682             case BODYEOF: 
683                 finish_headers (out);
684                 if (whomsw && !fill_in)
685                     break;
686                 fprintf (out, "\n%s", buf);
687                 while (state == BODY) {
688                     state = m_getfld (state, name, buf, sizeof buf, in);
689                     fputs (buf, out);
690                 }
691                 break;
692
693             case FILEEOF: 
694                 finish_headers (out);
695                 break;
696
697             case LENERR: 
698             case FMTERR: 
699                 adios (NULLCP, "message format error in component #%d",
700                         compnum);
701
702             default: 
703                 adios (NULLCP, "getfld() returned %d", state);
704         }
705         break;
706     }
707
708 /* \f */
709
710 #ifdef  MHMTS
711 daemon: ;
712 #endif  /* MHMTS */
713     if (pfd != NOTOK)
714         anno ();
715     (void) fclose (in);
716     if (debug) {
717         pl ();
718         done (0);
719     }
720     else
721         (void) fclose (out);
722
723 #ifdef  TMA
724     if (encryptsw)
725         tmastart (tmasnoop);
726 #endif  /* TMA */
727     if (whomsw) {
728         if (!fill_up)
729             verify_all_addresses (1);
730         done (0);
731     }
732
733 #ifdef  MMDFMTS
734     (void) strcat (submitopts, submitmode);
735     if (watch)
736         (void) strcat (submitopts, "nw");
737 #endif  /* MMDFMTS */
738 #ifdef  MHMTS
739     verify_all_addresses (0);
740 #endif  /* MHMTS */
741     if (encryptsw)
742         verify_all_addresses (verbose);
743     if (msgflags & MINV) {
744         make_bcc_file ();
745         if (msgflags & MVIS) {
746 #ifndef MHMTS
747             if (!encryptsw)
748                 verify_all_addresses (verbose);
749 #endif  /* not MHMTS */
750             post (tmpfil, 0, verbose);
751         }
752         post (bccfil, 1, verbose);
753         (void) unlink (bccfil);
754     }
755     else
756         post (tmpfil, 0, isatty (1));
757 #ifdef  TMA
758     if (encryptsw)
759         tmastop ();
760 #endif  /* TMA */
761
762     p_refile (tmpfil);
763
764     p_record ();
765
766 #ifdef  MHMTS
767     if (!deliver)
768 #endif  /* MHMTS */
769         (void) unlink (tmpfil);
770
771     if (verbose)
772         printf (partno ? "Partial Message #%s Processed\n" : "Message Processed\n",
773                 partno);
774
775     done (0);
776 }
777
778 /* \f   DRAFT GENERATION */
779
780 static putfmt (name, str, out)
781 register char   *name,
782                 *str;
783 register FILE *out;
784 {
785     int     count,
786             grp,
787             i,
788             keep;
789     register char  *cp,
790                    *pp,
791                    *qp;
792     char    namep[BUFSIZ];
793     register struct mailname   *mp,
794                                *np;
795     register struct headers *hdr;
796
797     while (*str == ' ' || *str == '\t')
798         str++;
799
800     if (msgstate == NORMAL && uprf (name, "resent")) {
801         advise (NULLCP, "illegal header line -- %s:", name);
802         badmsg++;
803         return;
804     }
805
806     if ((i = get_header (name, hdrtab)) == NOTOK) {
807         fprintf (out, "%s: %s", name, str);
808         return;
809     }
810
811     hdr = &hdrtab[i];
812     if (hdr -> flags & HIGN) {
813         if (fill_in)
814             fprintf (out, "%s: %s", name, str);
815         return;
816     }
817     if (hdr -> flags & HBAD) {
818         if (fill_in)
819             fprintf (out, "%s: %s", name, str);
820         else {
821             advise (NULLCP, "illegal header line -- %s:", name);
822             badmsg++;
823         }
824         return;
825     }
826     msgflags |= (hdr -> set & ~(MVIS | MINV));
827
828     if (hdr -> set & MFRM)
829         msgfrom = msgfrom ? add (str, add (",", msgfrom)) : getcpy (str);
830     if (hdr -> flags & HSUB)
831         subject = subject ? add (str, add ("\t", subject)) : getcpy (str);
832     if (hdr -> flags & HFCC) {
833         if (fill_in) {
834             fprintf (out, "%s: %s", name, str);
835             return;
836         }
837
838         if (cp = rindex (str, '\n'))
839             *cp = 0;
840         for (cp = pp = str; cp = index (pp, ','); pp = cp) {
841             *cp++ = 0;
842             insert_fcc (hdr, pp);
843         }
844         insert_fcc (hdr, pp);
845         return;
846     }
847
848 /* \f */
849
850     if (!(hdr -> flags & HADR)) {
851         fprintf (out, "%s: %s", name, str);
852         return;
853     }
854
855     tmpaddrs.m_next = NULL;
856     for (count = 0; cp = getname (str); count++)
857         if (mp = getm (cp, NULLCP, 0, AD_HOST, NULLCP)) {
858             if (tmpaddrs.m_next)
859                 np -> m_next = mp;
860             else
861                 tmpaddrs.m_next = mp;
862             np = mp;
863         }
864         else
865             if (hdr -> flags & HTRY)
866                 badadr++;
867             else
868                 badmsg++;
869
870     if (count < 1) {
871         if (hdr -> flags & HNIL) {
872             if (!(hdr -> flags & HBCC))
873                 fprintf (out, "%s: %s", name, str);
874         }
875         else {
876 #ifdef  notdef
877             advise (NULLCP, "%s: field requires at least one address", name);
878             badmsg++;
879 #endif  /* notdef */
880         }
881         return;
882     }
883
884 /* \f */
885
886     nameoutput = linepos = 0;
887     (void) sprintf (namep, "%s%s",
888                     !fill_in && (hdr -> flags & HMNG) ? "Original-" : "",
889                     name);
890
891     for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np)
892         if (mp -> m_nohost) {   /* also used to test (hdr -> flags & HTRY) */
893             pp = akvalue (mp -> m_mbox);
894             qp = akvisible () ? mp -> m_mbox : "";
895             np = mp;
896             if (np -> m_gname)
897                 putgrp (namep, np -> m_gname, out, hdr -> flags);
898             while (cp = getname (pp)) {
899                 if (!(mp = getm (cp, NULLCP, 0, AD_HOST, NULLCP))) {
900                     badadr++;
901                     continue;
902                 }
903                 if (hdr -> flags & HBCC)
904                     mp -> m_bcc++;
905                 if (np -> m_ingrp)
906                     mp -> m_ingrp = np -> m_ingrp;
907                 else
908                     if (mp -> m_gname)
909                         putgrp (namep, mp -> m_gname, out, hdr -> flags);
910                 if (mp -> m_ingrp)
911                     grp++;
912 #ifdef  MHMTS
913                 mp -> m_aka = getcpy (np -> m_mbox);
914 #endif  /* MHMTS */
915                 if (putadr (namep, qp, mp, out, hdr -> flags))
916                     msgflags |= (hdr -> set & (MVIS | MINV));
917                 else
918                     mnfree (mp);
919             }
920             mp = np;
921             np = np -> m_next;
922             mnfree (mp);
923         }
924         else {
925             if (hdr -> flags & HBCC)
926                 mp -> m_bcc++;
927             if (mp -> m_gname)
928                 putgrp (namep, mp -> m_gname, out, hdr -> flags);
929             if (mp -> m_ingrp)
930                 grp++;
931             keep = putadr (namep, "", mp, out, hdr -> flags);
932             np = mp -> m_next;
933             if (keep) {
934                 mp -> m_next = NULL;
935                 msgflags |= (hdr -> set & (MVIS | MINV));
936             }
937             else
938                 mnfree (mp);
939         }
940
941     if (grp > 0 && (hdr -> flags & HNGR)) {
942         advise (NULLCP, "%s: field does not allow groups", name);
943         badmsg++;
944     }
945     if (linepos) {
946         if (fill_in && grp > 0)
947             (void) putc (';', out);
948         (void) putc ('\n', out);
949     }
950 }
951
952 /* \f */
953
954 static  start_headers () {
955     register char  *cp;
956     char    myhost[BUFSIZ],
957             sigbuf[BUFSIZ];
958     register struct mailname   *mp;
959
960     myuid = getuid ();
961     mygid = getgid ();
962     (void) time (&tclock);
963
964     (void) strcpy (from, adrsprintf (NULLCP, NULLCP));
965
966     (void) strcpy (myhost, LocalName ());
967     for (cp = myhost; *cp; cp++)
968         *cp = uptolow (*cp);
969
970 #ifdef  MHMTS
971     if (deliver) {
972         if (geteuid () == 0 && myuid != 0 && myuid != 1 && mygid != 1)
973             adios (NULLCP, "-deliver unknown");
974         (void) strcpy (signature, from);
975     }
976 #endif  /* MHMTS */
977
978     if ((cp = getfullname ()) && *cp) {
979         (void) strcpy (sigbuf, cp);
980         (void) sprintf (signature, "%s <%s>", sigbuf, adrsprintf (NULLCP, NULLCP));
981         if ((cp = getname (signature)) == NULL)
982             adios (NULLCP, "getname () failed -- you lose extraordinarily big");
983         if ((mp = getm (cp, NULLCP, 0, AD_HOST, NULLCP)) == NULL)
984             adios (NULLCP, "bad signature '%s'", sigbuf);
985         mnfree (mp);
986         while (getname (""))
987             continue;
988     }
989     else
990         (void) strcpy (signature, adrsprintf (NULLCP, NULLCP));
991 }
992
993 /* \f */
994
995 static finish_headers (out)
996 register FILE *out;
997 {
998     switch (msgstate) {
999         case NORMAL: 
1000             if (whomsw && !fill_up)
1001                 break;
1002
1003             fprintf (out, "Date: %s\n", dtime (&tclock));
1004             if (msgid)
1005                 fprintf (out, "Message-ID: <%d.%ld@%s>\n",
1006                         getpid (), tclock, LocalName ());
1007             if (msgflags & MFRM)
1008                 fprintf (out, "Sender: %s\n", from);
1009             else
1010                 fprintf (out, "From: %s\n", signature);
1011             if (whomsw)
1012                 break;
1013
1014             if (!(msgflags & MVIS))
1015                 fprintf (out, "Bcc: Blind Distribution List: ;\n");
1016             break;
1017
1018         case RESENT: 
1019             if (!(msgflags & MDAT)) {
1020                 advise (NULLCP, "message has no Date: header");
1021                 badmsg++;
1022             }
1023             if (!(msgflags & MFRM)) {
1024                 advise (NULLCP, "message has no From: header");
1025                 badmsg++;
1026             }
1027             if (whomsw && !fill_up)
1028                 break;
1029
1030 #ifdef  MMDFI                   /* sigh */
1031             fprintf (out, "Sender: %s\n", from);
1032 #endif  /* MMDFI */
1033
1034             fprintf (out, "Resent-Date: %s\n", dtime (&tclock));
1035             if (msgid)
1036                 fprintf (out, "Resent-Message-ID: <%d.%ld@%s>\n",
1037                         getpid (), tclock, LocalName ());
1038             if (msgflags & MRFM)
1039                 fprintf (out, "Resent-Sender: %s\n", from);
1040             else
1041                 fprintf (out, "Resent-From: %s\n", signature);
1042             if (whomsw)
1043                 break;
1044             if (!(msgflags & MVIS))
1045                 fprintf (out, "Resent-Bcc: Blind Re-Distribution List: ;\n");
1046             break;
1047     }
1048
1049     if (badmsg)
1050         adios (NULLCP, "re-format message and try again");
1051     if (!recipients)
1052         adios (NULLCP, "no addressees");
1053 }
1054
1055 /* \f */
1056
1057 static int     get_header (header, table)
1058 register char   *header;
1059 register struct headers *table;
1060 {
1061     register struct headers *h;
1062
1063     for (h = table; h -> value; h++)
1064         if (uleq (header, h -> value))
1065             return (h - table);
1066
1067     return NOTOK;
1068 }
1069
1070 /* \f */
1071
1072 static int     putadr (name, aka, mp, out, flags)
1073 register char   *name,
1074                 *aka;
1075 register struct mailname *mp;
1076 register FILE *out;
1077 unsigned int    flags;
1078 {
1079     int     len;
1080     register char   *cp;
1081     char    buffer[BUFSIZ];
1082
1083     if (mp -> m_mbox == NULL || ((flags & HTRY) && !insert (mp)))
1084         return 0;
1085     if (!fill_in && (flags & (HBCC | HDCC)) || mp -> m_ingrp)
1086         return 1;
1087
1088     if (!nameoutput) {
1089         fprintf (out, "%s: ", name);
1090         linepos += (nameoutput = strlen (name) + 2);
1091     }
1092
1093     if (*aka && mp -> m_type != UUCPHOST && !mp -> m_pers)
1094         mp -> m_pers = getcpy (aka);
1095     if (format) {
1096         if (mp -> m_gname && !fill_in)
1097             (void) sprintf (cp = buffer, "%s;", mp -> m_gname);
1098         else
1099             cp = adrformat (mp);
1100     }
1101     else
1102         cp = mp -> m_text;
1103     len = strlen (cp);
1104
1105     if (linepos != nameoutput)
1106         if (len + linepos + 2 > outputlinelen)
1107             fprintf (out, ",\n%*s", linepos = nameoutput, "");
1108         else {
1109             fputs (", ", out);
1110             linepos += 2;
1111         }
1112
1113     fputs (cp, out);
1114     linepos += len;
1115
1116     return (flags & HTRY);
1117 }
1118
1119 /* \f */
1120
1121 static putgrp (name, group, out, flags)
1122 register char   *name,
1123                 *group;
1124 register FILE *out;
1125 unsigned int    flags;
1126 {
1127     int     len;
1128     char   *cp;
1129
1130     if (!fill_in && (flags & HBCC))
1131         return;
1132
1133     if (!nameoutput) {
1134         fprintf (out, "%s: ", name);
1135         linepos += (nameoutput = strlen (name) + 2);
1136         if (fill_in)
1137             linepos -= strlen (group);
1138     }
1139
1140     cp = fill_in ? group : concat (group, ";", NULLCP);
1141     len = strlen (cp);
1142
1143     if (linepos > nameoutput)
1144         if (len + linepos + 2 > outputlinelen) {
1145             fprintf (out, ",\n%*s", nameoutput, "");
1146             linepos = nameoutput;
1147         }
1148         else {
1149             fputs (", ", out);
1150             linepos += 2;
1151         }
1152
1153     fputs (cp, out);
1154     linepos += len;
1155 }
1156
1157 /* \f */
1158
1159 static int     insert (np)
1160 register struct mailname   *np;
1161 {
1162     register struct mailname   *mp;
1163
1164     if (np -> m_mbox == NULL)
1165         return 0;
1166
1167     for (mp = np -> m_type == LOCALHOST ? &localaddrs
1168             : np -> m_type == UUCPHOST ? &uuaddrs
1169             : &netaddrs;
1170             mp -> m_next;
1171             mp = mp -> m_next)
1172         if (uleq (np -> m_host, mp -> m_next -> m_host)
1173                 && uleq (np -> m_mbox, mp -> m_next -> m_mbox)
1174                 && np -> m_bcc == mp -> m_next -> m_bcc)
1175             return 0;
1176
1177     mp -> m_next = np;
1178     recipients++;
1179     return 1;
1180 }
1181
1182
1183 static  pl () {
1184     register int     i;
1185     register struct mailname *mp;
1186
1187     printf ("-------\n\t-- Addresses --\nlocal:\t");
1188     for (mp = localaddrs.m_next; mp; mp = mp -> m_next)
1189         printf ("%s%s%s", mp -> m_mbox,
1190                 mp -> m_bcc ? "[BCC]" : "",
1191                 mp -> m_next ? ",\n\t" : "");
1192
1193     printf ("\nnet:\t");
1194     for (mp = netaddrs.m_next; mp; mp = mp -> m_next)
1195         printf ("%s%s@%s%s%s", mp -> m_path ? mp -> m_path : "",
1196                 mp -> m_mbox, mp -> m_host,
1197                 mp -> m_bcc ? "[BCC]" : "",
1198                 mp -> m_next ? ",\n\t" : "");
1199
1200     printf ("\nuucp:\t");
1201     for (mp = uuaddrs.m_next; mp; mp = mp -> m_next)
1202         printf ("%s!%s%s", mp -> m_host, mp -> m_mbox,
1203                 mp -> m_bcc ? "[BCC]" : "",
1204                 mp -> m_next ? ",\n\t" : "");
1205
1206     printf ("\n\t-- Folder Copies --\nfcc:\t");
1207     for (i = 0; i < fccind; i++)
1208         printf ("%s%s", fccfold[i], i + 1 < fccind ? ",\n\t" : "");
1209     printf ("\n");
1210 }
1211
1212 /* \f */
1213
1214 static  anno () {
1215     register struct mailname *mp;
1216
1217     for (mp = localaddrs.m_next; mp; mp = mp -> m_next)
1218         if (annoaux (mp) == NOTOK)
1219             goto oops;
1220
1221     for (mp = netaddrs.m_next; mp; mp = mp -> m_next)
1222         if (annoaux (mp) == NOTOK)
1223             goto oops;
1224
1225     for (mp = uuaddrs.m_next; mp; mp = mp -> m_next)
1226         if (annoaux (mp) == NOTOK)
1227             break;
1228
1229 oops: ;
1230     (void) close (pfd);
1231     pfd = NOTOK;
1232 }
1233
1234
1235 static int  annoaux (mp)
1236 register struct mailname *mp;
1237 {
1238     int     i;
1239     char    buffer[BUFSIZ];
1240
1241     (void) sprintf (buffer, "%s\n", adrformat (mp));
1242     i = strlen (buffer);
1243
1244     return (write (pfd, buffer, i) == i ? OK : NOTOK);
1245 }
1246
1247 /* \f */
1248
1249 static  insert_fcc (hdr, pp)
1250 register struct headers *hdr;
1251 register char   *pp;
1252 {
1253     register char   *cp;
1254
1255     for (cp = pp; isspace (*cp); cp++)
1256         continue;
1257     for (pp += strlen (pp) - 1; pp > cp && isspace (*pp); pp--)
1258         continue;
1259     if (pp >= cp)
1260         *++pp = 0;
1261     if (*cp == 0)
1262         return;
1263
1264     if (fccind >= FCCS)
1265         adios (NULLCP, "too many %ss", hdr -> value);
1266     fccfold[fccind++] = getcpy (cp);
1267 }
1268
1269 /* \f   BCC GENERATION */
1270
1271 static  make_bcc_file () {
1272     int     fd,
1273             i,
1274             child_id;
1275     char   *vec[6];
1276     register FILE   *out;
1277
1278     (void) strcpy (bccfil, m_tmpfil ("bccs"));
1279     if ((out = fopen (bccfil, "w")) == NULL)
1280         adios (bccfil, "unable to create");
1281     (void) chmod (bccfil, 0600);
1282
1283     fprintf (out, "Date: %s\n", dtime (&tclock));
1284     if (msgid)
1285         fprintf (out, "Message-ID: <%d.%ld.1@%s>\n",
1286                 getpid (), tclock, LocalName ());
1287     if (msgflags & MFRM) {
1288         fprintf (out, "From: %s", msgfrom);
1289         fprintf (out, "Sender: %s\n", from);
1290     }
1291     else
1292         fprintf (out, "From: %s\n", signature);
1293     if (subject)
1294         fprintf (out, "Subject: %s", subject);
1295     fprintf (out, "BCC:\n");
1296 #ifdef MIME
1297     if (mime) {
1298         char   *cp;
1299
1300         if ((cp = index (prefix, 'a')) == NULL)
1301             adios (NULLCP, "lost prefix start");
1302         while (find_prefix () == NOTOK)
1303             if (*cp < 'z')
1304                 (*cp)++;
1305             else
1306                 if (*++cp == 0)
1307                     adios (NULLCP,
1308                            "giving up trying to find a unique delimiter string");
1309                 else
1310                     (*cp)++;
1311
1312         fprintf (out, "%s: %s\n%s: multipart/digest; boundary=\"",
1313                  VRSN_FIELD, VRSN_VALUE, TYPE_FIELD);
1314         fprintf (out, "%s\"\n%s: %s\n\n--%s\n%s: %s\n%s: %s\n\n", prefix,
1315                  DESCR_FIELD, "Blind Carbon Copy", prefix,
1316                  TYPE_FIELD, "message/rfc822",
1317                  DESCR_FIELD, "Original Message");
1318     }
1319     else
1320 #endif /* MIME */
1321         fprintf (out, "\n------- Blind-Carbon-Copy\n\n");
1322     (void) fflush (out);
1323
1324     if (filter == NULL) {
1325         if ((fd = open (tmpfil, 0)) == NOTOK)
1326             adios (tmpfil, "unable to re-open");
1327 #ifdef MIME
1328         if (mime)
1329             cpydata (fd, fileno (out), tmpfil, bccfil);
1330         else
1331 #endif /* MIME */
1332             cpydgst (fd, fileno (out), tmpfil, bccfil);
1333         (void) close (fd);
1334     }
1335     else {
1336         vec[0] = r1bindex (mhlproc, '/');
1337
1338         for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
1339             sleep (5);
1340         switch (child_id) {
1341             case NOTOK: 
1342                 adios ("fork", "unable to");
1343
1344             case OK: 
1345                 (void) dup2 (fileno (out), 1);
1346
1347                 i = 1;
1348                 vec[i++] = "-forward";
1349                 vec[i++] = "-form";
1350                 vec[i++] = filter;
1351                 vec[i++] = tmpfil;
1352                 vec[i] = NULL;
1353
1354                 execvp (mhlproc, vec);
1355                 fprintf (stderr, "unable to exec ");
1356                 perror (mhlproc);
1357                 _exit (-1);
1358
1359             default: 
1360                 (void) pidXwait (child_id, mhlproc);
1361                 break;
1362         }
1363     }
1364
1365     (void) fseek (out, 0L, 2);
1366 #ifdef  MIME
1367     if (mime)
1368         fprintf (out, "\n--%s--\n", prefix);
1369     else
1370 #endif /* MIME */
1371         fprintf (out, "\n------- End of Blind-Carbon-Copy\n");
1372     (void) fclose (out);
1373 }
1374
1375 /* \f */
1376
1377 #ifdef MIME
1378 static int  find_prefix ()
1379 {
1380     int     len,
1381             result;
1382     char    buffer[BUFSIZ];
1383     FILE   *in;
1384
1385     if ((in = fopen (tmpfil, "r")) == NULL)
1386         adios (tmpfil, "unable to re-open");
1387
1388     len = strlen (prefix);
1389
1390     result = OK;
1391     while (fgets (buffer, sizeof buffer - 1, in))
1392         if (buffer[0] == '-' && buffer[1] == '-') {
1393             register char *cp;
1394
1395             for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
1396                 if (!isspace (*cp))
1397                     break;
1398             *++cp = NULL;
1399             if (strcmp (buffer + 2, prefix) == 0) {
1400                 result = NOTOK;
1401                 break;
1402             }
1403         }
1404
1405     (void) fclose (in);
1406         
1407     return result;
1408 }
1409 #endif /* MIME */
1410
1411 /* \f   ADDRESS VERIFICATION */
1412
1413 static  verify_all_addresses (talk)
1414 int     talk;
1415 {
1416 #ifndef MHMTS
1417     int     retval;
1418 #endif  /* not MHMTS */
1419 #ifdef  MMDFMTS
1420 #ifdef  RP_NS
1421     int     len;
1422     struct rp_bufstruct reply;
1423 #endif  /* RP_NS */
1424 #endif  /* MMDFMTS */
1425     register struct mailname *lp;
1426
1427 #ifndef MHMTS
1428     sigon ();
1429 #endif  /* not MHMTS */
1430
1431 #ifdef  MMDFMTS
1432     if (!whomsw || checksw) {
1433         if (rp_isbad (retval = mm_init ())
1434                 || rp_isbad (retval = mm_sbinit ())
1435                 || rp_isbad (retval = mm_winit (NULLCP, submitopts, from)))
1436             die (NULLCP, "problem initializing MMDF system [%s]",
1437                     rp_valstr (retval));
1438 #ifdef  RP_NS
1439         if (rp_isbad (retval = mm_rrply (&reply, &len)))
1440             die (NULLCP, "problem with sender address [%s]",
1441                     rp_valstr (retval));
1442 #endif  /* RP_NS */
1443     }
1444 #endif  /* MMDFMTS */
1445 #ifdef  SENDMTS
1446     if (!whomsw || checksw)
1447         if (rp_isbad (retval = sm_init (clientsw, serversw, 0, 0, snoop, 0, 0))
1448                 || rp_isbad (retval = sm_winit (smtpmode, from)))
1449             die (NULLCP, "problem initializing server; %s",
1450                     rp_string (retval));
1451 #endif  /* SENDMTS */
1452
1453     if (talk && !whomsw)
1454         printf (" -- Address Verification --\n");
1455 #ifndef BERK
1456     if (talk && localaddrs.m_next)
1457         printf ("  -- Local Recipients --\n");
1458 #endif  /* BERK */
1459     for (lp = localaddrs.m_next; lp; lp = lp -> m_next)
1460         do_an_address (lp, talk, encryptsw);
1461
1462 #ifndef BERK
1463     if (talk && uuaddrs.m_next)
1464         printf ("  -- UUCP Recipients --\n");
1465 #endif  /* BERK */
1466     for (lp = uuaddrs.m_next; lp; lp = lp -> m_next)
1467         do_an_address (lp, talk, encryptsw);
1468
1469 #ifndef BERK
1470     if (talk && netaddrs.m_next)
1471         printf ("  -- Network Recipients --\n");
1472 #endif  /* BERK */
1473     for (lp = netaddrs.m_next; lp; lp = lp -> m_next)
1474         do_an_address (lp, talk, encryptsw);
1475
1476     chkadr ();
1477     if (talk && !whomsw)
1478         printf (" -- Address Verification Successful --\n");
1479
1480 #ifdef  MMDFMTS
1481     if (!whomsw || checksw)
1482         (void) mm_end (NOTOK);
1483 #endif  /* MMDFMTS */
1484 #ifdef  SENDMTS
1485     if (!whomsw || checksw)
1486         (void) sm_end (DONE);
1487 #endif  /* SENDMTS */
1488     (void) fflush (stdout);
1489
1490 #ifndef MHMTS
1491     sigoff ();
1492 #endif  /* not MHMTS */
1493 }
1494
1495 /* \f */
1496
1497 static  chkadr () {
1498 #define plural(x) (x == 1 ? "" : "s")
1499
1500     if (badadr && unkadr)
1501         die (NULLCP, "%d address%s unparsable, %d addressee%s undeliverable",
1502                 badadr, plural (badadr), unkadr, plural (badadr));
1503     if (badadr)
1504         die (NULLCP, "%d address%s unparsable", badadr, plural (badadr));
1505     if (unkadr)
1506         die (NULLCP, "%d addressee%s undeliverable", unkadr, plural (unkadr));
1507 }
1508
1509 /* \f   MTS INTERACTION */
1510
1511 #ifdef  TMA
1512 static postplain (file, bccque, talk)
1513 #else   /* TMA */
1514 static post (file, bccque, talk)
1515 #endif  /* TMA */
1516 register char   *file;
1517 int     bccque,
1518         talk;
1519 {
1520     int     fd,
1521             onex = !(msgflags & MINV) || bccque;
1522 #ifndef MHMTS
1523     int     retval;
1524 #ifdef  MMDFMTS
1525 #ifdef  RP_NS
1526     int     len;
1527     struct rp_bufstruct reply;
1528 #endif  /* RP_NS */
1529 #endif  /* MMDFMTS */
1530 #else   /* MHMTS */
1531     int     ud;
1532 #endif  /* MHMTS */
1533
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     sigon ();
1542
1543 #ifdef  MMDFMTS
1544     if (rp_isbad (retval = mm_init ())
1545             || rp_isbad (retval = mm_sbinit ())
1546             || rp_isbad (retval = mm_winit (NULLCP, submitopts, from)))
1547         die (NULLCP, "problem initializing MMDF system [%s]",
1548                 rp_valstr (retval));
1549 #ifdef  RP_NS
1550         if (rp_isbad (retval = mm_rrply (&reply, &len)))
1551             die (NULLCP, "problem with sender address [%s]",
1552                     rp_valstr (retval));
1553 #endif  /* RP_NS */
1554 #endif  /* MMDFMTS */
1555 #ifdef  SENDMTS
1556     if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose, snoop,
1557                                     onex, queued))
1558             || rp_isbad (retval = sm_winit (smtpmode, from)))
1559         die (NULLCP, "problem initializing server; %s", rp_string (retval));
1560 #endif  /* SENDMTS */
1561
1562 #ifndef MHMTS
1563     do_addresses (bccque, talk && verbose);
1564     if ((fd = open (file, 0)) == NOTOK)
1565         die (file, "unable to re-open");
1566     do_text (file, fd);
1567 #else   /* MHMTS */
1568     if ((fd = open (file, 0)) == NULL)
1569         adios (file, "unable to re-open");
1570 #ifdef  MF
1571     ud = UucpChan () && uuaddrs.m_next ? make_uucp_file (fd) : NOTOK;
1572 #else   /* not MF */
1573     ud = NOTOK;
1574 #endif  /* not MF */
1575     do_addresses (file, fd, ud, bccque, talk && verbose);
1576     if (ud != NOTOK)
1577         (void) close (ud);
1578 #endif  /* MHMTS */
1579     (void) close (fd);
1580     (void) fflush (stdout);
1581
1582 #ifdef  MMDFMTS
1583     (void) mm_sbend ();
1584     (void) mm_end (OK);
1585 #endif  /* MMDFMTS */
1586 #ifdef  SENDMTS
1587     (void) sm_end (onex ? OK : DONE);
1588 #endif  /* SENDMTS */
1589
1590     sigoff ();
1591
1592     if (verbose)
1593         if (msgflags & MINV)
1594             printf (" -- %s Recipient Copies Posted --\n",
1595                     bccque ? "Blind" : "Sighted");
1596         else
1597             printf (" -- Recipient Copies Posted --\n");
1598     (void) fflush (stdout);
1599 }
1600
1601 /* \f */
1602
1603 #ifdef  TMA
1604 static postcipher (file, bccque, talk)
1605 register char   *file;
1606 int     bccque,
1607         talk;
1608 {
1609     int     fdP,
1610             state;
1611     char    reason[BUFSIZ];
1612     struct mailname *lp;
1613
1614     if (verbose)
1615         if (msgflags & MINV)
1616             printf (" -- Posting for %s Recipients --\n",
1617                     bccque ? "Blind" : "Sighted");
1618         else
1619             printf (" -- Posting for All Recipients --\n");
1620
1621     if ((fdP = open (file, 0)) == NOTOK)
1622         adios (file, "unable to re-open");
1623     if (ciphinit (fdP, reason) == NOTOK)
1624         adios (NULLCP, "%s", reason);
1625     (void) close (fdP);
1626
1627     for (state = 0, lp = localaddrs.m_next; lp; lp = lp -> m_next)
1628         if (lp -> m_bcc ? bccque : !bccque) {
1629 #ifndef BERK
1630             if (talk && !state)
1631                 printf ("  -- Local Recipients --\n");
1632 #endif  /* BERK */
1633             do_a_cipher (lp, talk);
1634 #ifndef BERK
1635             state++;
1636 #endif  /* BERK */
1637         }
1638
1639     for (state = 0, lp = uuaddrs.m_next; lp; lp = lp -> m_next)
1640         if (lp -> m_bcc ? bccque : !bccque) {
1641 #ifndef BERK
1642             if (talk && !state)
1643                 printf ("  -- UUCP Recipients --\n");
1644 #endif  /* BERK */
1645             do_a_cipher (lp, talk);
1646 #ifndef BERK
1647             state++;
1648 #endif  /* BERK */
1649         }
1650
1651     for (state = 0, lp = netaddrs.m_next; lp; lp = lp -> m_next)
1652         if (lp -> m_bcc ? bccque : !bccque) {
1653 #ifndef BERK
1654             if (talk && !state)
1655                 printf ("  -- Network Recipients --\n");
1656 #endif  /* BERK */
1657             do_a_cipher (lp, talk);
1658 #ifndef BERK
1659             state++;
1660 #endif  /* BERK */
1661         }
1662
1663     if (ciphdone (reason) == NOTOK)
1664         admonish (NULLCP, "%s", reason);
1665 #ifdef  SENDMTS
1666     if (!(msgflags & MINV) || bccque)
1667         (void) sm_end (OK);
1668 #endif  /* SENDMTS */
1669
1670     if (verbose)
1671         if (msgflags & MINV)
1672             printf (" -- %s Recipient Copies Posted --\n",
1673                     bccque ? "Blind" : "Sighted");
1674         else
1675             printf (" -- Recipient Copies Posted --\n");
1676     (void) fflush (stdout);
1677 }
1678
1679 /* \f */
1680
1681 static do_a_cipher (lp, talk)
1682 register struct mailname *lp;
1683 int     talk;
1684 {
1685     int     fd,
1686             retval;
1687     register char  *mbox,
1688                    *host;
1689     char    addr[BUFSIZ],
1690             reason[BUFSIZ];
1691 #ifdef  MMDFMTS
1692 #ifdef  RP_NS
1693     int     len;
1694     struct rp_bufstruct reply;
1695 #endif  /* RP_NS */
1696 #endif  /* MMDFMTS */
1697
1698     sigon ();
1699
1700 #ifdef  MMDFMTS
1701     if (rp_isbad (retval = mm_init ())
1702             || rp_isbad (retval = mm_sbinit ())
1703             || rp_isbad (retval = mm_winit (NULL, submitopts, from)))
1704         die (NULLCP, "problem initializing MMDF system [%s]",
1705                 rp_valstr (retval));
1706 #ifdef  RP_NS
1707         if (rp_isbad (retval = mm_rrply (&reply, &len)))
1708             die (NULLCP, "problem with sender address [%s]",
1709                     rp_valstr (retval));
1710 #endif  /* RP_NS */
1711 #endif  /* MMDFMTS */
1712 #ifdef  SENDMTS
1713     if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose, snoop,
1714                                     0, 0))
1715             || rp_isbad (retval = sm_winit (smtpmode, from)))
1716         die (NULLCP, "problem initializing server; %s", rp_string (retval));
1717 #endif  /* SENDMTS */
1718
1719     do_an_address (lp, talk, 0);
1720
1721     switch (lp -> m_type) {
1722         case LOCALHOST: 
1723             mbox = lp -> m_mbox;
1724             host = LocalName ();
1725             (void) strcpy (addr, mbox);
1726             break;
1727
1728         case UUCPHOST: 
1729 #ifdef  MMDFMTS
1730             mbox = concat (lp -> m_host, "!", lp -> m_mbox, NULLCP);
1731             host = UucpChan ();
1732 #endif  /* MMDFMTS */
1733 #ifdef  SENDMTS
1734             mbox = auxformat (lp, 0);
1735             host = NULL;
1736 #endif  /* SENDMTS */
1737             (void) sprintf (addr, "%s!%s", lp -> m_host, lp -> m_mbox);
1738             break;
1739
1740         default: 
1741             mbox = lp -> m_mbox;
1742             host = lp -> m_host;
1743             (void) sprintf (addr, "%s at %s", lp -> m_mbox, lp -> m_host);
1744             break;
1745     }
1746     chkadr ();                  /* XXX */
1747
1748 #ifdef  MMDFMTS
1749     if (rp_isbad (retval = mm_waend ()))
1750         die (NULLCP, "problem ending addresses [%s]\n",
1751                 rp_valstr (retval));
1752 #endif  /* MMDFMTS */
1753 #ifdef  SENDMTS
1754     if (rp_isbad (retval = sm_waend ()))
1755         die (NULLCP, "problem ending addresses; %s", rp_string (retval));
1756 #endif  /* SENDMTS */
1757
1758     if ((fd = encipher (mbox, host, reason)) == NOTOK)
1759         die (NULLCP, "%s: %s", addr, reason);
1760     do_text ("temporary file", fd);
1761     (void) close (fd);
1762     (void) fflush (stdout);
1763
1764 #ifdef  MMDFMTS
1765     (void) mm_sbend ();
1766     (void) mm_end (OK);
1767 #endif  /* MMDFMTS */
1768 #ifdef  SENDMTS
1769     (void) sm_end (DONE);
1770 #endif  /* SENDMTS */
1771
1772     sigoff ();
1773 }
1774 #endif  /* TMA */
1775
1776 /* \f */
1777
1778 #ifndef MHMTS
1779 static do_addresses (bccque, talk)
1780 #else   /* MHMTS */
1781 static do_addresses (file, fd, ud, bccque, talk)
1782 register char   *file;
1783 int     fd,
1784         ud;
1785 #endif  /* MHMTS */
1786 int     bccque,
1787         talk;
1788 {
1789     int     retval;
1790 #ifndef BERK
1791     int     state;
1792 #endif  /* not BERK */
1793     register struct mailname *lp;
1794
1795 #ifndef BERK
1796     state = 0;
1797 #endif  /* not BERK */
1798     for (lp = localaddrs.m_next; lp; lp = lp -> m_next)
1799         if (lp -> m_bcc ? bccque : !bccque) {
1800 #ifndef BERK
1801             if (talk && !state)
1802                 printf ("  -- Local Recipients --\n");
1803 #endif  /* not BERK */
1804 #ifndef MHMTS
1805             do_an_address (lp, talk, 0);
1806 #else   /* MHMTS */
1807             localmail (lp, talk, fd);
1808 #endif  /* MHMTS */
1809 #ifndef BERK
1810             state++;
1811 #endif  /* not BERK */
1812         }
1813
1814 #ifndef BERK
1815     state = 0;
1816 #endif  /* not BERK */
1817     for (lp = uuaddrs.m_next; lp; lp = lp -> m_next)
1818         if (lp -> m_bcc ? bccque : !bccque) {
1819 #ifndef BERK
1820             if (talk && !state)
1821                 printf ("  -- UUCP Recipients --\n");
1822 #endif  /* not BERK */
1823 #ifndef MHMTS
1824             do_an_address (lp, talk, 0);
1825 #else   /* MHMTS */
1826             uucpmail (lp, talk, ud != NOTOK ? ud : fd, ud == NOTOK);
1827 #endif  /* MHMTS */
1828 #ifndef BERK
1829             state++;
1830 #endif  /* not BERK */
1831         }
1832
1833 #ifndef BERK
1834     state = 0;
1835 #endif  /* not BERK */
1836     for (lp = netaddrs.m_next; lp; lp = lp -> m_next)
1837         if (lp -> m_bcc ? bccque : !bccque) {
1838 #ifndef BERK
1839             if (talk && !state)
1840                 printf ("  -- Network Recipients --\n");
1841 #endif  /* not BERK */
1842 #ifndef MHMTS
1843             do_an_address (lp, talk, 0);
1844 #else   /* MHMTS */
1845             netmail (talk, fd, bccque);
1846 #endif  /* MHMTS */
1847 #ifndef BERK
1848             state++;
1849 #endif  /* not BERK */
1850         }
1851
1852 /* \f */
1853
1854     chkadr ();
1855
1856 #ifdef  MMDFMTS
1857     if (rp_isbad (retval = mm_waend ()))
1858         die (NULLCP, "problem ending addresses [%s]\n",
1859                 rp_valstr (retval));
1860 #endif  /* MMDFMTS */
1861 #ifdef  SENDMTS
1862     if (rp_isbad (retval = sm_waend ()))
1863         die (NULLCP, "problem ending addresses; %s", rp_string (retval));
1864 #endif  /* SENDMTS */
1865 }
1866
1867 /* \f */
1868
1869 #ifndef MHMTS
1870 static  do_text (file, fd)
1871 register char   *file;
1872 int     fd;
1873 {
1874     int     retval,
1875             state;
1876     char    buf[BUFSIZ];
1877 #ifdef  MMDFMTS
1878     struct rp_bufstruct reply;
1879 #endif  /* MMDFMTS */
1880
1881     (void) lseek (fd, (off_t)0, 0);
1882     while ((state = read (fd, buf, sizeof buf)) > 0)
1883 #ifdef  MMDFMTS
1884         if (rp_isbad (mm_wtxt (buf, state)))
1885             die (NULLCP, "problem writing text [%s]\n", rp_valstr (retval));
1886 #endif  /* MMDFMTS */
1887 #ifdef  SENDMTS
1888         if (rp_isbad (retval = sm_wtxt (buf, state)))
1889             die (NULLCP, "problem writing text; %s\n", rp_string (retval));
1890 #endif  /* SENDMTS */
1891
1892     if (state == NOTOK)
1893         die (file, "problem reading from");
1894
1895 #ifdef  MMDFMTS
1896     if (rp_isbad (retval = mm_wtend ()))
1897         die (NULLCP, "problem ending text [%s]\n", rp_valstr (retval));
1898
1899     if (rp_isbad (retval = mm_rrply (&reply, &state)))
1900         die (NULLCP, "problem getting submission status [%s]\n",
1901                 rp_valstr (retval));
1902
1903     switch (rp_gval (reply.rp_val)) {
1904         case RP_OK: 
1905         case RP_MOK: 
1906             break;
1907
1908         case RP_NO: 
1909             die (NULLCP, "you lose; %s", reply.rp_line);
1910
1911         case RP_NDEL: 
1912             die (NULLCP, "no delivery occurred; %s", reply.rp_line);
1913
1914         case RP_AGN: 
1915             die (NULLCP, "try again later; %s", reply.rp_line);
1916
1917         case RP_NOOP: 
1918             die (NULLCP, "nothing done; %s", reply.rp_line);
1919
1920         default: 
1921             die (NULLCP, "unexpected response;\n\t[%s] -- %s",
1922                     rp_valstr (reply.rp_val), reply.rp_line);
1923     }
1924 #endif  /* MMDFMTS */
1925 #ifdef  SENDMTS
1926     switch (retval = sm_wtend ()) {
1927         case RP_OK: 
1928             break;
1929
1930         case RP_NO: 
1931         case RP_NDEL: 
1932             die (NULLCP, "posting failed; %s", rp_string (retval));
1933
1934         default: 
1935             die (NULLCP, "unexpected response; %s", rp_string (retval));
1936     }
1937 #endif  /* SENDMTS */
1938 }
1939 #endif  /* not MHMTS */
1940
1941 /* \f   MTS-SPECIFIC INTERACTION */
1942
1943 #ifdef  MMDFMTS
1944
1945 #ifndef TMA
1946 /* ARGSUSED */
1947 #endif  /* TMA */
1948
1949 static do_an_address (lp, talk, tma)
1950 register struct mailname *lp;
1951 int     talk,
1952         tma;
1953 {
1954     int     len,
1955             retval;
1956     register char  *mbox,
1957                    *host,
1958                    *text,
1959                    *path;
1960     char    addr[BUFSIZ];
1961 #ifdef  TMA
1962     char    reason[BUFSIZ];
1963 #endif  /* TMA */
1964     struct rp_bufstruct reply;
1965
1966     switch (lp -> m_type) {
1967         case LOCALHOST: 
1968             mbox = lp -> m_mbox;
1969             host = LocalName ();
1970             (void) strcpy (addr, mbox);
1971             break;
1972
1973         case UUCPHOST: 
1974 #ifdef  MF
1975             mbox = concat (lp -> m_host, "!", lp -> m_mbox, NULLCP);
1976             host = UucpChan ();
1977             (void) strcpy (addr, mbox);
1978             break;
1979 #else   /* MF */
1980             fprintf (talk ? stdout : stderr, "  %s!%s: %s\n",
1981                 lp -> m_host, lp -> m_mbox, "not supported; UUCP address");
1982             unkadr++;
1983             (void) fflush (stdout);
1984             return;
1985 #endif  /* MF */
1986
1987         default:                /* let MMDF decide if the host is bad */
1988             mbox = lp -> m_mbox;
1989             host = lp -> m_host;
1990             (void) sprintf (addr, "%s at %s", mbox, host);
1991             break;
1992     }
1993 #ifdef  TMA
1994     if ((!whomsw || checksw)
1995             && tma
1996             && seekaddr (mbox, host, reason) == NOTOK) {
1997         fprintf (talk ? stdout : stderr, "  %s%s: %s\n",
1998                 addr, "[TMA]", reason);
1999         unkadr++;
2000     }
2001 #endif  /* TMA */
2002
2003     if (talk)
2004         printf ("  %s%s", addr, whomsw && lp -> m_bcc ? "[BCC]" : "");
2005
2006     if (whomsw && !checksw) {
2007         (void) putchar ('\n');
2008         return;
2009     }
2010     if (talk)
2011         printf (": ");
2012     (void) fflush (stdout);
2013
2014 /* \f */
2015
2016 #ifdef  MMDFII
2017     if (lp -> m_path)
2018         path = concat (lp -> m_path, mbox, "@", host, NULLCP);
2019     else
2020 #endif  /* MMDFII */
2021         path = NULLCP;
2022     if (rp_isbad (retval = mm_wadr (path ? NULLCP : host, path ? path : mbox))
2023             || rp_isbad (retval = mm_rrply (&reply, &len)))
2024         die (NULLCP, "problem submitting address [%s]", rp_valstr (retval));
2025
2026     switch (rp_gval (reply.rp_val)) {
2027         case RP_AOK: 
2028             if (talk)
2029                 printf ("address ok\n");
2030             (void) fflush (stdout);
2031             return;
2032
2033 #ifdef  RP_DOK
2034         case RP_DOK: 
2035             if (talk)
2036                 printf ("nameserver timeout - queued for checking\n");
2037             (void) fflush (stdout);
2038             return;
2039 #endif  /* RP_DOK */
2040
2041         case RP_NO: 
2042             text = "you lose";
2043             break;
2044
2045 #ifdef  RP_NS
2046         case RP_NS: 
2047             text = "temporary nameserver failure";
2048             break;
2049
2050 #endif  /* RP_NS */
2051
2052         case RP_USER: 
2053         case RP_NDEL: 
2054             text = "not deliverable";
2055             break;
2056
2057         case RP_AGN: 
2058             text = "try again later";
2059             break;
2060
2061         case RP_NOOP: 
2062             text = "nothing done";
2063             break;
2064
2065         default: 
2066             if (!talk)
2067                 fprintf (stderr, "  %s: ", addr);
2068             text = "unexpected response";
2069             die (NULLCP, "%s;\n    [%s] -- %s", text,
2070                     rp_valstr (reply.rp_val), reply.rp_line);
2071     }
2072
2073     if (!talk)
2074         fprintf (stderr, "  %s: ", addr);
2075     fprintf (talk ? stdout : stderr, "%s;\n    %s\n", text, reply.rp_line);
2076     unkadr++;
2077
2078     (void) fflush (stdout);
2079 }
2080 #endif  /* MMDFMTS */
2081
2082 /* \f */
2083
2084 #ifdef  MHMTS
2085 /* ARGSUSED */
2086
2087 static do_an_address (lp, talk, tma)
2088 register struct mailname *lp;
2089 int     talk,
2090         tma;
2091 {
2092     register char  *mbox;
2093     char    addr[BUFSIZ];
2094
2095     switch (lp -> m_type) {
2096         case LOCALHOST: 
2097             (void) strcpy (addr, lp -> m_mbox);
2098             break;
2099
2100         case UUCPHOST: 
2101             (void) sprintf (addr, "%s!%s", lp -> m_host, lp -> m_mbox);
2102             break;
2103
2104         default: 
2105             (void) sprintf (addr, "%s at %s", lp -> m_mbox, lp -> m_host);
2106             break;
2107     }
2108     if (talk)
2109         printf ("  %s%s", addr, whomsw && lp -> m_bcc ? "[BCC]" : "");
2110
2111     if (whomsw && !checksw) {
2112         (void) putchar ('\n');
2113         return;
2114     }
2115     if (talk)
2116         printf (": ");
2117     (void) fflush (stdout);
2118
2119 /* \f */
2120
2121     switch (lp -> m_type) {
2122         case LOCALHOST: 
2123             mbox = lp -> m_mbox;
2124             if (*mbox == '~')
2125                 mbox++;
2126             if (seek_home (mbox)) {
2127                 lp -> m_mbox = mbox;
2128                 if (talk)
2129                     printf ("address ok\n");
2130             }
2131             else {
2132                 if (!talk)
2133                     fprintf (stderr, "  %s: ", addr);
2134                 fprintf (talk ? stdout : stderr,
2135                         "not deliverable; unknown user\n");
2136                 unkadr++;
2137             }
2138             break;
2139
2140         case UUCPHOST: 
2141             if (uucpsite (lp -> m_host) == OK) {
2142                 if (talk)
2143                     printf ("address ok\n");
2144             }
2145             else {
2146                 if (!talk)
2147                     fprintf (stderr, "  %s: ", addr);
2148                 fprintf (talk ? stdout : stderr,
2149                         "not deliverable; unknown system\n");
2150                 unkadr++;
2151             }
2152             break;
2153
2154         case NETHOST: 
2155             if (talk)
2156                 printf ("address ok\n");
2157             break;
2158
2159         default: 
2160             if (!talk)
2161                 fprintf (stderr, "  %s: ", addr);
2162             fprintf (talk ? stdout : stderr,
2163                     "not deliverable; unknown host\n");
2164             unkadr++;
2165             break;
2166     }
2167
2168     (void) fflush (stdout);
2169 }
2170 #endif  /* MHMTS */
2171
2172 /* \f */
2173
2174 #ifdef  SENDMTS
2175
2176 #ifndef TMA
2177 /* ARGSUSED */
2178 #endif  /* TMA */
2179
2180 static do_an_address (lp, talk, tma)
2181 register struct mailname *lp;
2182 int     talk,
2183         tma;
2184 {
2185     int     retval;
2186     register char  *mbox,
2187                    *host;
2188     char    addr[BUFSIZ];
2189 #ifdef  TMA
2190     char    reason[BUFSIZ];
2191 #endif  /* TMA */
2192
2193     switch (lp -> m_type) {
2194         case LOCALHOST: 
2195             mbox = lp -> m_mbox;
2196             host = lp -> m_host;
2197             (void) strcpy (addr, mbox);
2198             break;
2199
2200         case UUCPHOST: 
2201             mbox = auxformat (lp, 0);
2202             host = NULL;
2203             (void) sprintf (addr, "%s!%s", lp -> m_host, lp -> m_mbox);
2204             break;
2205
2206         default:                /* let SendMail decide if the host is bad  */
2207             mbox = lp -> m_mbox;
2208             host = lp -> m_host;
2209             (void) sprintf (addr, "%s at %s", mbox, host);
2210             break;
2211     }
2212
2213 #ifdef  TMA
2214     if ((!whomsw || checksw)
2215             && tma
2216             && seekaddr (mbox, host, reason) == NOTOK) {
2217         fprintf (talk ? stdout : stderr, "  %s%s: %s\n",
2218                 addr, "[TMA]", reason);
2219         unkadr++;
2220     }
2221 #endif  /* TMA */
2222
2223     if (talk)
2224         printf ("  %s%s", addr, whomsw && lp -> m_bcc ? "[BCC]" : "");
2225
2226     if (whomsw && !checksw) {
2227         (void) putchar ('\n');
2228         return;
2229     }
2230     if (talk)
2231         printf (": ");
2232     (void) fflush (stdout);
2233
2234 /* \f */
2235
2236     switch (retval = sm_wadr (mbox, host,
2237                          lp -> m_type != UUCPHOST ? lp -> m_path : NULLCP)) {
2238         case RP_OK: 
2239             if (talk)
2240                 printf ("address ok\n");
2241             break;
2242
2243         case RP_NO: 
2244         case RP_USER: 
2245             if (!talk)
2246                 fprintf (stderr, "  %s: ", addr);
2247             fprintf (talk ? stdout : stderr, "loses; %s\n",
2248                         rp_string (retval));
2249             unkadr++;
2250             break;
2251
2252         default: 
2253             if (!talk)
2254                 fprintf (stderr, "  %s: ", addr);
2255             die (NULLCP, "unexpected response; %s", rp_string (retval));
2256     }
2257
2258     (void) fflush (stdout);
2259 }
2260 #endif  /* SENDMTS */
2261
2262 /* \f   SIGNAL HANDLING */
2263
2264 #ifndef MHMTS
2265
2266 /* ARGSUSED */
2267
2268 static  TYPESIG sigser (i)
2269 int     i;
2270 {
2271 #ifndef BSD42
2272     (void) signal (i, SIG_IGN);
2273 #endif  /* not BSD42 */
2274     (void) unlink (tmpfil);
2275     if (msgflags & MINV)
2276         (void) unlink (bccfil);
2277 #ifdef  MMDFMTS
2278     if (!whomsw || checksw)
2279         (void) mm_end (NOTOK);
2280 #endif  /* MMDFMTS */
2281 #ifdef  SENDMTS
2282     if (!whomsw || checksw)
2283         (void) sm_end (NOTOK);
2284 #endif  /* SENDMTS */
2285     done (1);
2286 }
2287 #endif  /* not MHMTS */
2288
2289
2290 static  sigon () {
2291     if (debug)
2292         return;
2293
2294 #ifndef MHMTS
2295     setsigx (hstat, SIGHUP, sigser);
2296     setsigx (istat, SIGINT, sigser);
2297     setsigx (qstat, SIGQUIT, sigser);
2298     setsigx (tstat, SIGTERM, sigser);
2299 #else   /* MHMTS */
2300     setsigx (hstat, SIGHUP, SIG_IGN);
2301     setsigx (istat, SIGINT, SIG_IGN);
2302     setsigx (qstat, SIGQUIT, SIG_IGN);
2303     setsigx (tstat, SIGTERM, SIG_IGN);
2304 #endif  /* MHMTS */
2305 }
2306
2307
2308 static sigoff () {
2309     if (debug)
2310         return;
2311
2312     (void) signal (SIGHUP, hstat);
2313     (void) signal (SIGINT, istat);
2314     (void) signal (SIGQUIT, qstat);
2315     (void) signal (SIGTERM, tstat);
2316 }
2317
2318 /* \f   FCC INTERACTION */
2319
2320 static  p_refile (file)
2321 register char   *file;
2322 {
2323     register int     i;
2324
2325     if (fccind == 0)
2326         return;
2327
2328 #ifdef  MHMTS
2329     (void) setuid (myuid);
2330 #endif  /* MHMTS */
2331     if (verbose)
2332         printf (" -- Filing Folder Copies --\n");
2333     for (i = 0; i < fccind; i++)
2334         fcc (file, fccfold[i]);
2335     if (verbose)
2336         printf (" -- Folder Copies Filed --\n");
2337 }
2338
2339
2340 static fcc (file, folder)
2341 register char   *file,
2342                 *folder;
2343 {
2344     int     i,
2345             child_id,
2346             status;
2347     char    fold[BUFSIZ];
2348
2349     if (verbose)
2350         printf ("  %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", folder);
2351     (void) fflush (stdout);
2352
2353     for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
2354         sleep (5);
2355     switch (child_id) {
2356         case NOTOK: 
2357             if (!verbose)
2358                 fprintf (stderr, "  %sFcc %s: ",
2359                         msgstate == RESENT ? "Resent-" : "", folder);
2360             fprintf (verbose ? stdout : stderr, "no forks, so not ok\n");
2361             break;
2362
2363         case OK: 
2364             (void) sprintf (fold, "%s%s",
2365                     *folder == '+' || *folder == '@' ? "" : "+", folder);
2366             execlp (fileproc, r1bindex (fileproc, '/'),
2367                     "-link", "-file", file, fold, NULLCP);
2368             _exit (-1);
2369
2370         default: 
2371             if (status = pidwait (child_id, OK)) {
2372                 if (!verbose)
2373                     fprintf (stderr, "  %sFcc %s: ",
2374                             msgstate == RESENT ? "Resent-" : "", folder);
2375                 (void) pidstatus (status, verbose ? stdout : stderr, NULLCP);
2376             }
2377             else
2378                 if (verbose)
2379                     printf ("folder ok\n");
2380     }
2381
2382     (void) fflush (stdout);
2383 }
2384
2385 /* \f   RECORD RECIPIENTS */
2386
2387 static  p_record ()
2388 {
2389     int     i,
2390             child_id,
2391             status;
2392     char    recfile[BUFSIZ];
2393     register struct mailname  *ap,
2394                              **app;
2395     struct mailname *addrs[3];
2396     register FILE   *out;
2397
2398     if (!record || (msgflags & (MFRM | MRFM | MRPY)))
2399         return;
2400
2401     addrs[0] = &localaddrs;
2402     addrs[1] = &netaddrs;
2403     addrs[2] = NULL;
2404     if (verbose) {
2405         printf ("recording recipients... ");
2406         fflush (stdout);
2407     }
2408
2409     (void) strcpy (recfile, m_tmpfil ("record"));
2410     if ((out = fopen (recfile, "w")) == NULL) {
2411         fprintf (verbose ? stdout : stderr, "unable to create temporary file");
2412         if (!verbose)
2413             fprintf (stderr, ", so can't record recipients");
2414         fprintf (verbose ? stdout : stderr, "\n");
2415         return;
2416     }
2417     (void) chmod (recfile, 0600);
2418
2419     for (app = addrs; ap = *app; app++) {
2420         register struct mailname *mp;
2421
2422         for (mp = ap -> m_next; mp; mp = mp -> m_next)
2423             fprintf (out, "%s\n", adrformat (mp));
2424     }
2425
2426     (void) fclose (out);
2427
2428     for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
2429         sleep (5);
2430     switch (child_id) {
2431         case NOTOK:
2432             fprintf (verbose ? stdout : stderr, "unable to fork");
2433             if (!verbose)
2434                 fprintf (stderr, ", so can't record recipients");
2435             fprintf (verbose ? stdout : stderr, "\n");
2436             break;
2437
2438         case OK:
2439             execlp (record, r1bindex (record, '/'), recfile, NULLCP);
2440             _exit (-1);
2441
2442         default:
2443             if (status = pidwait (child_id, OK)) {
2444                 if (!verbose)
2445                     fprintf (stderr, "problem with %s: ", recfile);
2446                 (void) pidstatus (status, verbose ? stdout : stderr, NULLCP);
2447             }
2448             else
2449                 if (verbose)
2450                     printf ("done\n");
2451     }
2452
2453     (void) unlink (recfile);
2454 }
2455
2456 /* \f   TERMINATION */
2457
2458 /* VARARGS2 */
2459
2460 static die (what, fmt, a, b, c, d)
2461 char   *what,
2462        *fmt,
2463        *a,
2464        *b,
2465        *c,
2466        *d;
2467 {
2468 #ifndef MHMTS
2469     (void) unlink (tmpfil);
2470     if (msgflags & MINV)
2471         (void) unlink (bccfil);
2472 #endif  /* MHMTS */
2473 #ifdef  MMDFMTS
2474     if (!whomsw || checksw)
2475         (void) mm_end (NOTOK);
2476 #endif  /* MMDFMTS */
2477 #ifdef  SENDMTS
2478     if (!whomsw || checksw)
2479         (void) sm_end (NOTOK);
2480 #endif  /* SENDMTS */
2481
2482     adios (what, fmt, a, b, c, d);
2483 }
2484
2485
2486 #ifdef  MMDFMTS
2487 /* 
2488  *    err_abrt() is used by the mm_ routines
2489  *               do not, under *ANY* circumstances, remove it from post,
2490  *               or you will lose *BIG*
2491  */
2492
2493 err_abrt (code, fmt, a, b, c)
2494 int     code;
2495 char   *fmt,
2496        *a,
2497        *b,
2498        *c;
2499 {
2500     char    buffer[BUFSIZ];
2501
2502     (void) sprintf (buffer, "[%s]", rp_valstr (code));
2503
2504     adios (buffer, fmt, a, b, c);
2505 }
2506 #endif  /* MMDFMTS */
2507
2508 /* \f   STAND-ALONE DELIVERY */
2509
2510 #ifdef  MHMTS
2511
2512 /* BUG: MHMTS ignores 822-style route addresses... */
2513
2514 static  localmail (lp, talk, fd)
2515 register struct mailname *lp;
2516 int     talk,
2517         fd;
2518 {
2519     int     md;
2520     char    mailbox[BUFSIZ],
2521             ddate[BUFSIZ];
2522     register struct home *hp;
2523
2524     if (talk)
2525         printf ("  %s: ", lp -> m_mbox);
2526     (void) fflush (stdout);
2527
2528     if ((hp = seek_home (lp -> m_mbox)) == NULL) {
2529         if (!talk)
2530             fprintf (stderr, "  %s: ", lp -> m_mbox);
2531         fprintf (talk ? stdout : stderr,
2532                 "not deliverable; unknown address\n");
2533         unkadr++;
2534         return;
2535     }
2536
2537     (void) sprintf (mailbox, "%s/%s",
2538             mmdfldir[0] ? mmdfldir : hp -> h_home,
2539             mmdflfil[0] ? mmdflfil : hp -> h_name);
2540
2541 /* \f */
2542
2543     switch (access (slocalproc, 01)) {
2544         default: 
2545             if (talk)
2546                 printf ("(invoking hook)\n\t");
2547             (void) fflush (stdout);
2548
2549             if (usr_hook (lp, talk, fd, hp, mailbox) != NOTOK)
2550                 return;
2551             if (talk)
2552                 printf ("  %s: ", lp -> m_mbox);
2553             (void) fflush (stdout);
2554
2555         case NOTOK: 
2556             (void) lseek (fd, (off_t)0, 0);
2557             if ((md = mbx_open (mailbox, hp -> h_uid, hp -> h_gid, m_gmprot ()))
2558                     == NOTOK) {
2559                 if (!talk)
2560                     fprintf (stderr, "  %s: ", lp -> m_mbox);
2561                 fprintf (talk ? stdout : stderr,
2562                         "error in transmission; unable to open maildrop\n");
2563                 unkadr++;
2564                 return;
2565             }
2566             (void) sprintf (ddate, "Delivery-Date: %s\n", dtimenow ());
2567             if (mbx_copy (mailbox, md, fd, 0, ddate, 0) == NOTOK) {
2568                 if (!talk)
2569                     fprintf (stderr, "  %s: ", lp -> m_mbox);
2570                 fprintf (talk ? stdout : stderr,
2571                         "error in transmission; write to maildrop failed\n");
2572                 unkadr++;
2573                 (void) close (md);
2574                 return;
2575             }
2576             mbx_close (mailbox, md);
2577
2578             if (talk)
2579                 printf ("sent\n");
2580             break;
2581     }
2582
2583     (void) fflush (stdout);
2584 }
2585
2586 /* \f */
2587
2588 static int  usr_hook (lp, talk, fd, hp, mailbox)
2589 register struct mailname *lp;
2590 int     talk,
2591         fd;
2592 register struct home *hp;
2593 register char   *mailbox;
2594 {
2595     int     i,
2596             child_id,
2597             status;
2598     char    tmpfil[BUFSIZ];
2599
2600     if ((fd = copyfile (fd, tmpfil)) == NOTOK) {
2601         if (!talk)
2602             fprintf (stderr, "  %s: ", lp -> m_mbox);
2603         fprintf (talk ? stdout : stderr,
2604                 "unable to copy message; skipping hook\n");
2605         return NOTOK;
2606     }
2607     (void) chown (tmpfil, hp -> h_uid, hp -> h_gid);
2608
2609     (void) fflush (stdout);
2610
2611     for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
2612         sleep (5);
2613     switch (child_id) {
2614         case NOTOK: 
2615             if (!talk)
2616                 fprintf (stderr, "  %s: ", lp -> m_mbox);
2617             fprintf (talk ? stdout : stderr,
2618                     "unable to invoke hook; fork() failed\n");
2619             return NOTOK;
2620
2621         case OK: 
2622             if (fd != 0)
2623                 (void) dup2 (fd, 0);
2624             (void) freopen ("/dev/null", "w", stdout);
2625             (void) freopen ("/dev/null", "w", stderr);
2626             if (fd != 3)        /* backwards compatible... */
2627                 (void) dup2 (fd, 3);
2628             closefds (4);
2629 #ifdef  TIOCNOTTY
2630             if ((fd = open ("/dev/tty", 2)) != NOTOK) {
2631                 (void) ioctl (fd, TIOCNOTTY, NULLCP);
2632                 (void) close (fd);
2633             }
2634 #endif  /* TIOCNOTTY */
2635 #ifdef  BSD42
2636             (void) setpgrp (0, getpid ());
2637 #endif  /* BSD42 */
2638
2639             *environ = NULL;
2640             (void) m_putenv ("USER", hp -> h_name);
2641             (void) m_putenv ("HOME", hp -> h_home);
2642             (void) m_putenv ("SHELL", hp -> h_shell);
2643             if (chdir (hp -> h_home) == NOTOK)
2644                 (void) chdir ("/");
2645             (void) umask (0077);
2646 #ifdef  BSD41A
2647             (void) inigrp (hp -> h_name, hp -> h_gid);
2648 #endif  /* BSD41A */
2649             (void) setgid (hp -> h_gid);
2650 #ifdef  BSD42
2651             (void) initgroups (hp -> h_name, hp -> h_gid);
2652 #endif  /* BSD42 */
2653             (void) setuid (hp -> h_uid);
2654
2655             execlp (slocalproc, r1bindex (slocalproc, '/'),
2656                     "-file", tmpfil, "-mailbox", mailbox,
2657                     "-home", hp -> h_home, "-addr", lp -> m_aka,
2658                     "-user", hp -> h_name, "-sender", from,
2659                     talk ? "-verbose" : NULLCP, NULLCP);
2660             _exit (-1);
2661
2662 /* \f */
2663
2664         default: 
2665             (void) close (fd);
2666
2667             status = pidwait (child_id, OK);
2668
2669             (void) unlink (tmpfil);
2670             if (status == 0) {
2671                 if (talk)
2672                     printf ("accepted\n");
2673                 return OK;
2674             }
2675             if (!talk)
2676                 fprintf (stderr, "  %s: ", lp -> m_mbox);
2677             fprintf (talk ? stdout : stderr,
2678                     "%s error on hook; status=0%o\n",
2679                     status & 0x00ff ? "system" : "user",
2680                     status & 0x00ff ? status & 0xff
2681                     : (status & 0xff00) >> 8);
2682             return NOTOK;
2683     }
2684 }
2685
2686 /* \f */
2687
2688 static int  copyfile (qd, tmpfil)
2689 int     qd;
2690 register char   *tmpfil;
2691 {
2692     int     i,
2693             fd;
2694     char    buffer[BUFSIZ];
2695
2696     (void) strcpy (tmpfil, m_tmpfil ("hook"));
2697     if ((fd = creat (tmpfil, 0600)) == NOTOK)
2698         return NOTOK;
2699     (void) close (fd);
2700     if ((fd = open (tmpfil, 2)) == NOTOK)
2701         return NOTOK;
2702
2703     (void) lseek (qd, (off_t)0, 0);
2704     while ((i = read (qd, buffer, sizeof buffer)) > 0)
2705         if (write (fd, buffer, i) != i) {
2706             (void) close (fd);
2707             return NOTOK;
2708         }
2709     if (i == NOTOK) {
2710         (void) close (fd);
2711         return NOTOK;
2712     }
2713
2714     (void) lseek (fd, (off_t)0, 0);
2715
2716     return fd;
2717 }
2718
2719 /* \f */
2720
2721 static  uucpmail (lp, talk, fd, from)
2722 register struct mailname *lp;
2723 int     talk,
2724         fd,
2725         from;
2726 {
2727     int     i;
2728     TYPESIG     (*pstat) ();
2729     char    addr[BUFSIZ],
2730             buffer[BUFSIZ];
2731     register FILE *fp;
2732
2733     (void) sprintf (addr, "%s!%s", lp -> m_host, lp -> m_mbox);
2734     if (talk)
2735         printf ("  %s: ", addr);
2736     (void) fflush (stdout);
2737
2738 #ifndef UCI
2739     (void) sprintf (buffer, "uux -r -p %s!rmail \\(%s\\)",
2740                 lp -> m_host, lp -> m_mbox);
2741 #else   /* UCI */
2742     (void) sprintf (buffer, "uux -p %s!rmail \\(%s\\)", lp -> m_host,
2743             lp -> m_mbox);
2744 #endif  /* UCI */
2745     if ((fp = popen (buffer, "w")) == NULL) {
2746         if (!talk)
2747             fprintf (stderr, "  %s: ", addr);
2748         fprintf (talk ? stdout : stderr,
2749                 "unable to start uux; popen() failed\n");
2750         unkadr++;
2751         return;
2752     }
2753
2754     pstat = signal (SIGPIPE, SIG_IGN);
2755     if (from) {                 /* no mail filtering, so... */
2756         (void) sprintf (buffer, "From %s %.24s remote from %s\n",
2757                 getusr (), ctime (&tclock), SystemName ());
2758         i = strlen (buffer);
2759         if (fwrite (buffer, sizeof *buffer, i, fp) != i)
2760             goto oops;
2761     }
2762
2763     (void) lseek (fd, (off_t)0, 0);
2764     while ((i = read (fd, buffer, sizeof buffer)) > 0)
2765         if (fwrite (buffer, sizeof *buffer, i, fp) != i) {
2766     oops:   ;
2767             if (!talk)
2768                 fprintf (stderr, "  %s: ", addr);
2769             fprintf (talk ? stdout : stderr,
2770                     "error in transmission; write to uux failed\n");
2771             unkadr++;
2772             (void) pclose (fp);
2773             return;
2774         }
2775     if (pclose (fp))
2776         goto oops;
2777     (void) signal (SIGPIPE, pstat);
2778
2779     if (i < 0) {
2780         if (!talk)
2781             fprintf (stderr, "  %s: ", addr);
2782         fprintf (talk ? stdout : stderr,
2783                 "error in transmission; read failed\n");
2784         unkadr++;
2785         return;
2786     }
2787
2788     if (talk)
2789         printf ("queued (via uux)\n");
2790     (void) fflush (stdout);
2791 }
2792
2793 /* \f */
2794
2795 #ifdef  MF
2796 static int  make_uucp_file (td)
2797 int     td;
2798 {
2799     int     i,
2800             qd,
2801             fd;
2802     char    tmpfil[BUFSIZ];
2803
2804     (void) lseek (td, (off_t)0, 0);
2805     if ((qd = dup (td)) == NOTOK)
2806         adios ("fd", "unable to dup");
2807
2808     (void) strcpy (tmpfil, m_tmpfil ("uumf"));
2809     if ((fd = creat (tmpfil, 0600)) == NOTOK)
2810         adios (tmpfil, "unable to create");
2811     (void) close (fd);
2812     if ((fd = open (tmpfil, 2)) == NOTOK)
2813         adios (tmpfil, "unable to re-open");
2814
2815     switch (i = mmdf2uucp (qd, fd, 1)) {
2816         case OK: 
2817             if (!debug)
2818                 (void) unlink (tmpfil);
2819             break;
2820
2821         default: 
2822             adios (NULLCP, "unable to filter mail(%d), examine %s", i, tmpfil);
2823     }
2824     (void) close (qd);
2825
2826     return fd;
2827 }
2828 #endif  /* MF */
2829
2830 /* \f */
2831
2832 static  netmail (talk, fd, bccque)
2833 int     talk,
2834         fd,
2835         bccque;
2836 {
2837     int     i,
2838             naddrs;
2839     char    buffer[BUFSIZ];
2840     register struct mailname *lp;
2841
2842     naddrs = 0;
2843     if (nm_init (getusr (), &tclock) == NOTOK) {
2844         for (lp = netaddrs.m_next; lp; lp = lp -> m_next)
2845             if (lp -> m_bcc ? bccque : !bccque)
2846                 fprintf (stderr, "  %s at %s: unable to get queue file\n",
2847                         lp -> m_mbox, lp -> m_host);
2848         return;
2849     }
2850
2851     for (lp = netaddrs.m_next; lp; lp = lp -> m_next)
2852         if (lp -> m_bcc ? bccque : !bccque) {
2853             (void) nm_wadr (lp -> m_mbox, lp -> m_host);
2854             naddrs++;
2855             if (talk)
2856                 printf ("  %s at %s: queued\n", lp -> m_mbox, lp -> m_host);
2857             (void) fflush (stdout);
2858         }
2859     nm_waend ();
2860
2861     (void) lseek (fd, (off_t)0, 0);
2862     while ((i = read (fd, buffer, sizeof buffer)) > 0)
2863         if (nm_wtxt (buffer, i) == NOTOK) {
2864             fprintf (stderr,
2865                     "error in transmission; write to temporary failed");
2866             unkadr += naddrs;
2867             return;
2868         }
2869
2870     if (i < 0) {
2871         fprintf (stderr, "error in transmission; read failed\n");
2872         unkadr += naddrs;
2873         return;
2874     }
2875
2876     if (nm_wtend () == NOTOK) {
2877         fprintf (stderr, "error in transmission; unable to queue message\n");
2878         unkadr += naddrs;
2879         return;
2880     }
2881 }
2882 #endif  /* MHMTS */