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