Split overlong line
[s-mailx.git] / sendout.c
blob2f916d86f2f386265f91491faa6d1876662bb9a1
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen Daode Nurpmeso.
6 * All rights reserved.
7 */
8 /*
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
41 #ifndef lint
42 #ifdef DOSCCS
43 static char sccsid[] = "@(#)sendout.c 2.100 (gritter) 3/1/09";
44 #endif
45 #endif /* not lint */
47 #include "rcv.h"
48 #include "extern.h"
49 #include <errno.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <time.h>
54 #include "md5.h"
57 * Mail -- a mail program
59 * Mail to others.
62 static char *send_boundary;
64 static char *getencoding(enum conversion convert);
65 static struct name *fixhead(struct header *hp, struct name *tolist);
66 static int put_signature(FILE *fo, int convert);
67 static int attach_file1(struct attachment *ap, FILE *fo, int dosign);
68 static int attach_file(struct attachment *ap, FILE *fo, int dosign);
69 static int attach_message(struct attachment *ap, FILE *fo, int dosign);
70 static int make_multipart(struct header *hp, int convert, FILE *fi, FILE *fo,
71 const char *contenttype, const char *charset, int dosign);
72 static FILE *infix(struct header *hp, FILE *fi, int dosign);
73 static int savemail(char *name, FILE *fi);
74 static int sendmail_internal(void *v, int recipient_record);
75 static enum okay transfer(struct name *to, struct name *mailargs, FILE *input,
76 struct header *hp);
77 static enum okay start_mta(struct name *to, struct name *mailargs, FILE *input,
78 struct header *hp);
79 static void message_id(FILE *fo, struct header *hp);
80 static int fmt(char *str, struct name *np, FILE *fo, int comma,
81 int dropinvalid, int domime);
82 static int infix_resend(FILE *fi, FILE *fo, struct message *mp,
83 struct name *to, int add_resent);
86 * Generate a boundary for MIME multipart messages.
88 char *
89 makeboundary(void)
91 static char bound[70];
92 time_t now;
94 time(&now);
95 snprintf(bound, sizeof bound, "=_%lx.%s", (long)now, getrandstring(48));
96 send_boundary = bound;
97 return send_boundary;
101 * Get an encoding flag based on the given string.
103 static char *
104 getencoding(enum conversion convert)
106 switch (convert) {
107 case CONV_7BIT:
108 return "7bit";
109 case CONV_8BIT:
110 return "8bit";
111 case CONV_TOQP:
112 return "quoted-printable";
113 case CONV_TOB64:
114 return "base64";
115 default:
116 break;
118 /*NOTREACHED*/
119 return NULL;
123 * Fix the header by glopping all of the expanded names from
124 * the distribution list into the appropriate fields.
126 static struct name *
127 fixhead(struct header *hp, struct name *tolist)
129 struct name *np;
131 hp->h_to = NULL;
132 hp->h_cc = NULL;
133 hp->h_bcc = NULL;
134 for (np = tolist; np != NULL; np = np->n_flink)
135 if ((np->n_type & GMASK) == GTO)
136 hp->h_to =
137 cat(hp->h_to, nalloc(np->n_fullname,
138 np->n_type|GFULL));
139 else if ((np->n_type & GMASK) == GCC)
140 hp->h_cc =
141 cat(hp->h_cc, nalloc(np->n_fullname,
142 np->n_type|GFULL));
143 else if ((np->n_type & GMASK) == GBCC)
144 hp->h_bcc =
145 cat(hp->h_bcc, nalloc(np->n_fullname,
146 np->n_type|GFULL));
147 return tolist;
152 * Do not change, you get incorrect base64 encodings else!
154 #define INFIX_BUF 972
157 * Put the signature file at fo.
159 static int
160 put_signature(FILE *fo, int convert)
162 char *sig, buf[INFIX_BUF], c = '\n';
163 FILE *fsig;
164 size_t sz;
166 sig = value("signature");
167 if (sig == NULL || *sig == '\0')
168 return 0;
169 else
170 sig = expand(sig);
171 if ((fsig = Fopen(sig, "r")) == NULL) {
172 perror(sig);
173 return -1;
175 while ((sz = fread(buf, sizeof *buf, INFIX_BUF, fsig)) != 0) {
176 c = buf[sz - 1];
177 if (mime_write(buf, sz, fo, convert, TD_NONE,
178 NULL, (size_t)0, NULL, NULL)
179 == 0) {
180 perror(sig);
181 Fclose(fsig);
182 return -1;
185 if (ferror(fsig)) {
186 perror(sig);
187 Fclose(fsig);
188 return -1;
190 Fclose(fsig);
191 if (c != '\n')
192 putc('\n', fo);
193 return 0;
197 * Write an attachment to the file buffer, converting to MIME.
199 static int
200 attach_file1(struct attachment *ap, FILE *fo, int dosign)
202 FILE *fi;
203 char *charset = NULL, *contenttype = NULL, *basename;
204 enum conversion convert = CONV_TOB64;
205 int err = 0;
206 enum mimeclean isclean;
207 size_t sz;
208 char *buf;
209 size_t bufsize, count;
210 int lastc = EOF;
211 #ifdef HAVE_ICONV
212 char *tcs;
213 #endif
215 if ((fi = Fopen(ap->a_name, "r")) == NULL) {
216 perror(ap->a_name);
217 return -1;
219 if ((basename = strrchr(ap->a_name, '/')) == NULL)
220 basename = ap->a_name;
221 else
222 basename++;
223 if (ap->a_content_type)
224 contenttype = ap->a_content_type;
225 else
226 contenttype = mime_filecontent(basename);
227 if (ap->a_charset)
228 charset = ap->a_charset;
229 convert = get_mime_convert(fi, &contenttype, &charset, &isclean,
230 dosign);
231 fprintf(fo,
232 "\n--%s\n"
233 "Content-Type: %s",
234 send_boundary, contenttype);
235 if (charset == NULL)
236 putc('\n', fo);
237 else
238 fprintf(fo, ";\n charset=%s\n", charset);
239 if (ap->a_content_disposition == NULL)
240 ap->a_content_disposition = "attachment";
241 fprintf(fo, "Content-Transfer-Encoding: %s\n"
242 "Content-Disposition: %s;\n"
243 " filename=\"",
244 getencoding(convert),
245 ap->a_content_disposition);
246 mime_write(basename, strlen(basename), fo,
247 CONV_TOHDR, TD_NONE, NULL, (size_t)0, NULL, NULL);
248 fwrite("\"\n", sizeof (char), 2, fo);
249 if (ap->a_content_id)
250 fprintf(fo, "Content-ID: %s\n", ap->a_content_id);
251 if (ap->a_content_description)
252 fprintf(fo, "Content-Description: %s\n",
253 ap->a_content_description);
254 putc('\n', fo);
255 #ifdef HAVE_ICONV
256 if (iconvd != (iconv_t)-1) {
257 iconv_close(iconvd);
258 iconvd = (iconv_t)-1;
260 tcs = gettcharset();
261 if ((isclean & (MIME_HASNUL|MIME_CTRLCHAR)) == 0 &&
262 ascncasecmp(contenttype, "text/", 5) == 0 &&
263 isclean & MIME_HIGHBIT &&
264 charset != NULL) {
265 if ((iconvd = iconv_open_ft(charset, tcs)) == (iconv_t)-1 &&
266 errno != 0) {
267 if (errno == EINVAL)
268 fprintf(stderr, catgets(catd, CATSET, 179,
269 "Cannot convert from %s to %s\n"), tcs, charset);
270 else
271 perror("iconv_open");
272 Fclose(fi);
273 return -1;
276 #endif /* HAVE_ICONV */
277 buf = smalloc(bufsize = INFIX_BUF);
278 if (convert == CONV_TOQP
279 #ifdef HAVE_ICONV
280 || iconvd != (iconv_t)-1
281 #endif
283 fflush(fi);
284 count = fsize(fi);
286 for (;;) {
287 if (convert == CONV_TOQP
288 #ifdef HAVE_ICONV
289 || iconvd != (iconv_t)-1
290 #endif
292 if (fgetline(&buf, &bufsize, &count, &sz, fi, 0)
293 == NULL)
294 break;
295 } else {
296 if ((sz = fread(buf, sizeof *buf, bufsize, fi)) == 0)
297 break;
299 lastc = buf[sz-1];
300 if (mime_write(buf, sz, fo, convert, TD_ICONV,
301 NULL, (size_t)0, NULL, NULL) == 0)
302 err = -1;
304 if (convert == CONV_TOQP && lastc != '\n')
305 fwrite("=\n", 1, 2, fo);
306 if (ferror(fi))
307 err = -1;
308 Fclose(fi);
309 free(buf);
310 return err;
314 * Try out different character set conversions to attach a file.
316 static int
317 attach_file(struct attachment *ap, FILE *fo, int dosign)
319 char *_wantcharset, *charsets, *ncs;
320 size_t offs = ftell(fo);
322 if (ap->a_charset || (charsets = value("sendcharsets")) == NULL)
323 return attach_file1(ap, fo, dosign);
324 _wantcharset = wantcharset;
325 wantcharset = savestr(charsets);
326 loop: if ((ncs = strchr(wantcharset, ',')) != NULL)
327 *ncs++ = '\0';
328 try: if (attach_file1(ap, fo, dosign) != 0) {
329 if (errno == EILSEQ || errno == EINVAL) {
330 if (ncs && *ncs) {
331 wantcharset = ncs;
332 clearerr(fo);
333 fseek(fo, offs, SEEK_SET);
334 goto loop;
336 if (wantcharset) {
337 if (wantcharset == (char *)-1)
338 wantcharset = NULL;
339 else {
340 wantcharset = (char *)-1;
341 clearerr(fo);
342 fseek(fo, offs, SEEK_SET);
343 goto try;
348 wantcharset = _wantcharset;
349 return 0;
353 * Attach a message to the file buffer.
355 static int
356 attach_message(struct attachment *ap, FILE *fo, int dosign)
358 struct message *mp;
360 fprintf(fo, "\n--%s\n"
361 "Content-Type: message/rfc822\n"
362 "Content-Disposition: inline\n\n", send_boundary);
363 mp = &message[ap->a_msgno - 1];
364 touch(mp);
365 if (send(mp, fo, 0, NULL, SEND_RFC822, NULL) < 0)
366 return -1;
367 return 0;
371 * Generate the body of a MIME multipart message.
373 static int
374 make_multipart(struct header *hp, int convert, FILE *fi, FILE *fo,
375 const char *contenttype, const char *charset, int dosign)
377 struct attachment *att;
379 fputs("This is a multi-part message in MIME format.\n", fo);
380 if (fsize(fi) != 0) {
381 char *buf, c = '\n';
382 size_t sz, bufsize, count;
384 fprintf(fo, "\n--%s\n", send_boundary);
385 fprintf(fo, "Content-Type: %s", contenttype);
386 if (charset)
387 fprintf(fo, "; charset=%s", charset);
388 fprintf(fo, "\nContent-Transfer-Encoding: %s\n"
389 "Content-Disposition: inline\n\n",
390 getencoding(convert));
391 buf = smalloc(bufsize = INFIX_BUF);
392 if (convert == CONV_TOQP
393 #ifdef HAVE_ICONV
394 || iconvd != (iconv_t)-1
395 #endif /* HAVE_ICONV */
397 fflush(fi);
398 count = fsize(fi);
400 for (;;) {
401 if (convert == CONV_TOQP
402 #ifdef HAVE_ICONV
403 || iconvd != (iconv_t)-1
404 #endif /* HAVE_ICONV */
406 if (fgetline(&buf, &bufsize, &count, &sz, fi, 0)
407 == NULL)
408 break;
409 } else {
410 sz = fread(buf, sizeof *buf, bufsize, fi);
411 if (sz == 0)
412 break;
414 c = buf[sz - 1];
415 if (mime_write(buf, sz, fo, convert,
416 TD_ICONV, NULL, (size_t)0,
417 NULL, NULL) == 0) {
418 free(buf);
419 return -1;
422 free(buf);
423 if (ferror(fi))
424 return -1;
425 if (c != '\n')
426 putc('\n', fo);
427 if (charset != NULL)
428 put_signature(fo, convert);
430 for (att = hp->h_attach; att != NULL; att = att->a_flink) {
431 if (att->a_msgno) {
432 if (attach_message(att, fo, dosign) != 0)
433 return -1;
434 } else {
435 if (attach_file(att, fo, dosign) != 0)
436 return -1;
439 /* the final boundary with two attached dashes */
440 fprintf(fo, "\n--%s--\n", send_boundary);
441 return 0;
445 * Prepend a header in front of the collected stuff
446 * and return the new file.
448 static FILE *
449 infix(struct header *hp, FILE *fi, int dosign)
451 FILE *nfo, *nfi;
452 char *tempMail;
453 #ifdef HAVE_ICONV
454 char *tcs, *convhdr = NULL;
455 #endif
456 enum mimeclean isclean;
457 enum conversion convert;
458 char *charset = NULL, *contenttype = NULL;
459 int lastc = EOF;
461 if ((nfo = Ftemp(&tempMail, "Rs", "w", 0600, 1)) == NULL) {
462 perror(catgets(catd, CATSET, 178, "temporary mail file"));
463 return(NULL);
465 if ((nfi = Fopen(tempMail, "r")) == NULL) {
466 perror(tempMail);
467 Fclose(nfo);
468 return(NULL);
470 rm(tempMail);
471 Ftfree(&tempMail);
472 convert = get_mime_convert(fi, &contenttype, &charset,
473 &isclean, dosign);
474 #ifdef HAVE_ICONV
475 tcs = gettcharset();
476 if ((convhdr = need_hdrconv(hp, GTO|GSUBJECT|GCC|GBCC|GIDENT)) != 0) {
477 if (iconvd != (iconv_t)-1)
478 iconv_close(iconvd);
479 if ((iconvd = iconv_open_ft(convhdr, tcs)) == (iconv_t)-1
480 && errno != 0) {
481 if (errno == EINVAL)
482 fprintf(stderr, catgets(catd, CATSET, 179,
483 "Cannot convert from %s to %s\n"), tcs, convhdr);
484 else
485 perror("iconv_open");
486 Fclose(nfo);
487 return NULL;
490 #endif /* HAVE_ICONV */
491 if (puthead(hp, nfo,
492 GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA|GUA|GMIME
493 |GMSGID|GIDENT|GREF|GDATE,
494 SEND_MBOX, convert, contenttype, charset)) {
495 Fclose(nfo);
496 Fclose(nfi);
497 #ifdef HAVE_ICONV
498 if (iconvd != (iconv_t)-1) {
499 iconv_close(iconvd);
500 iconvd = (iconv_t)-1;
502 #endif
503 return NULL;
505 #ifdef HAVE_ICONV
506 if (convhdr && iconvd != (iconv_t)-1) {
507 iconv_close(iconvd);
508 iconvd = (iconv_t)-1;
510 if ((isclean & (MIME_HASNUL|MIME_CTRLCHAR)) == 0 &&
511 ascncasecmp(contenttype, "text/", 5) == 0 &&
512 isclean & MIME_HIGHBIT &&
513 charset != NULL) {
514 if (iconvd != (iconv_t)-1)
515 iconv_close(iconvd);
516 if ((iconvd = iconv_open_ft(charset, tcs)) == (iconv_t)-1
517 && errno != 0) {
518 if (errno == EINVAL)
519 fprintf(stderr, catgets(catd, CATSET, 179,
520 "Cannot convert from %s to %s\n"), tcs, charset);
521 else
522 perror("iconv_open");
523 Fclose(nfo);
524 return NULL;
527 #endif
528 if (hp->h_attach != NULL) {
529 if (make_multipart(hp, convert, fi, nfo,
530 contenttype, charset, dosign) != 0) {
531 Fclose(nfo);
532 Fclose(nfi);
533 #ifdef HAVE_ICONV
534 if (iconvd != (iconv_t)-1) {
535 iconv_close(iconvd);
536 iconvd = (iconv_t)-1;
538 #endif
539 return NULL;
541 } else {
542 size_t sz, bufsize, count;
543 char *buf;
545 if (convert == CONV_TOQP
546 #ifdef HAVE_ICONV
547 || iconvd != (iconv_t)-1
548 #endif /* HAVE_ICONV */
550 fflush(fi);
551 count = fsize(fi);
553 buf = smalloc(bufsize = INFIX_BUF);
554 for (;;) {
555 if (convert == CONV_TOQP
556 #ifdef HAVE_ICONV
557 || iconvd != (iconv_t)-1
558 #endif /* HAVE_ICONV */
560 if (fgetline(&buf, &bufsize, &count, &sz, fi, 0)
561 == NULL)
562 break;
563 } else {
564 sz = fread(buf, sizeof *buf, bufsize, fi);
565 if (sz == 0)
566 break;
568 lastc = buf[sz - 1];
569 if (mime_write(buf, sz, nfo, convert,
570 TD_ICONV, NULL, (size_t)0,
571 NULL, NULL) == 0) {
572 Fclose(nfo);
573 Fclose(nfi);
574 #ifdef HAVE_ICONV
575 if (iconvd != (iconv_t)-1) {
576 iconv_close(iconvd);
577 iconvd = (iconv_t)-1;
579 #endif
580 free(buf);
581 return NULL;
584 if (convert == CONV_TOQP && lastc != '\n')
585 fwrite("=\n", 1, 2, nfo);
586 free(buf);
587 if (ferror(fi)) {
588 Fclose(nfo);
589 Fclose(nfi);
590 #ifdef HAVE_ICONV
591 if (iconvd != (iconv_t)-1) {
592 iconv_close(iconvd);
593 iconvd = (iconv_t)-1;
595 #endif
596 return NULL;
598 if (charset != NULL)
599 put_signature(nfo, convert);
601 #ifdef HAVE_ICONV
602 if (iconvd != (iconv_t)-1) {
603 iconv_close(iconvd);
604 iconvd = (iconv_t)-1;
606 #endif
607 fflush(nfo);
608 if (ferror(nfo)) {
609 perror(catgets(catd, CATSET, 180, "temporary mail file"));
610 Fclose(nfo);
611 Fclose(nfi);
612 return NULL;
614 Fclose(nfo);
615 Fclose(fi);
616 fflush(nfi);
617 rewind(nfi);
618 return(nfi);
622 * Save the outgoing mail on the passed file.
625 /*ARGSUSED*/
626 static int
627 savemail(char *name, FILE *fi)
629 FILE *fo;
630 char *buf;
631 size_t bufsize, buflen, count;
632 char *p;
633 time_t now;
634 int prependnl = 0;
635 int error = 0;
637 buf = smalloc(bufsize = LINESIZE);
638 time(&now);
639 if ((fo = Zopen(name, "a+", NULL)) == NULL) {
640 if ((fo = Zopen(name, "wx", NULL)) == NULL) {
641 perror(name);
642 free(buf);
643 return (-1);
645 } else {
646 if (fseek(fo, -2L, SEEK_END) == 0) {
647 switch (fread(buf, sizeof *buf, 2, fo)) {
648 case 2:
649 if (buf[1] != '\n') {
650 prependnl = 1;
651 break;
653 /*FALLTHRU*/
654 case 1:
655 if (buf[0] != '\n')
656 prependnl = 1;
657 break;
658 default:
659 if (ferror(fo)) {
660 perror(name);
661 free(buf);
662 return -1;
665 fflush(fo);
666 if (prependnl) {
667 putc('\n', fo);
668 fflush(fo);
672 fprintf(fo, "From %s %s", myname, ctime(&now));
673 buflen = 0;
674 fflush(fi);
675 rewind(fi);
676 count = fsize(fi);
677 while (fgetline(&buf, &bufsize, &count, &buflen, fi, 0) != NULL) {
678 if (*buf == '>') {
679 p = buf + 1;
680 while (*p == '>')
681 p++;
682 if (strncmp(p, "From ", 5) == 0)
683 /* we got a masked From line */
684 putc('>', fo);
685 } else if (strncmp(buf, "From ", 5) == 0)
686 putc('>', fo);
687 fwrite(buf, sizeof *buf, buflen, fo);
689 if (buflen && *(buf + buflen - 1) != '\n')
690 putc('\n', fo);
691 putc('\n', fo);
692 fflush(fo);
693 if (ferror(fo)) {
694 perror(name);
695 error = -1;
697 if (Fclose(fo) != 0)
698 error = -1;
699 fflush(fi);
700 rewind(fi);
702 * OpenBSD 3.2 and NetBSD 1.5.2 were reported not to
703 * reset the kernel file offset after the calls above,
704 * a clear violation of IEEE Std 1003.1, 1996, 8.2.3.7.
705 * So do it 'manually'.
707 lseek(fileno(fi), 0, SEEK_SET);
708 free(buf);
709 return error;
713 * Interface between the argument list and the mail1 routine
714 * which does all the dirty work.
716 int
717 mail(struct name *to, struct name *cc, struct name *bcc,
718 struct name *smopts, char *subject, struct attachment *attach,
719 char *quotefile, int recipient_record, int tflag, int Eflag)
721 struct header head;
722 struct str in, out;
724 memset(&head, 0, sizeof head);
725 /* The given subject may be in RFC1522 format. */
726 if (subject != NULL) {
727 in.s = subject;
728 in.l = strlen(subject);
729 mime_fromhdr(&in, &out, TD_ISPR | TD_ICONV);
730 head.h_subject = out.s;
732 if (tflag == 0) {
733 head.h_to = to;
734 head.h_cc = cc;
735 head.h_bcc = bcc;
737 head.h_attach = attach;
738 head.h_smopts = smopts;
739 mail1(&head, 0, NULL, quotefile, recipient_record, 0, tflag, Eflag);
740 if (subject != NULL)
741 free(out.s);
742 return(0);
746 * Send mail to a bunch of user names. The interface is through
747 * the mail routine below.
749 static int
750 sendmail_internal(void *v, int recipient_record)
752 int Eflag;
753 char *str = v;
754 struct header head;
756 memset(&head, 0, sizeof head);
757 head.h_to = extract(str, GTO|GFULL);
758 Eflag = value("skipemptybody") != NULL;
759 mail1(&head, 0, NULL, NULL, recipient_record, 0, 0, Eflag);
760 return(0);
763 int
764 sendmail(void *v)
766 return sendmail_internal(v, 0);
769 int
770 Sendmail(void *v)
772 return sendmail_internal(v, 1);
775 static enum okay
776 transfer(struct name *to, struct name *mailargs, FILE *input, struct header *hp)
778 char o[LINESIZE], *cp;
779 struct name *np, *nt;
780 int cnt = 0;
781 FILE *ef;
782 enum okay ok = OKAY;
784 np = to;
785 while (np) {
786 snprintf(o, sizeof o, "smime-encrypt-%s", np->n_name);
787 if ((cp = value(o)) != NULL) {
788 if ((ef = smime_encrypt(input, cp, np->n_name)) != 0) {
789 nt = nalloc(np->n_name,
790 np->n_type & ~(GFULL|GSKIN));
791 if (start_mta(nt, mailargs, ef, hp) != OKAY)
792 ok = STOP;
793 Fclose(ef);
794 } else {
795 fprintf(stderr, "Message not sent to <%s>\n",
796 np->n_name);
797 senderr++;
799 rewind(input);
800 if (np->n_flink)
801 np->n_flink->n_blink = np->n_blink;
802 if (np->n_blink)
803 np->n_blink->n_flink = np->n_flink;
804 if (np == to)
805 to = np->n_flink;
806 np = np->n_flink;
807 } else {
808 cnt++;
809 np = np->n_flink;
812 if (cnt) {
813 if (value("smime-force-encryption") ||
814 start_mta(to, mailargs, input, hp) != OKAY)
815 ok = STOP;
817 return ok;
821 * Start the Mail Transfer Agent
822 * mailing to namelist and stdin redirected to input.
824 static enum okay
825 start_mta(struct name *to, struct name *mailargs, FILE *input,
826 struct header *hp)
828 char **args = NULL, **t;
829 pid_t pid;
830 sigset_t nset;
831 char *cp, *smtp;
832 char *user = NULL, *password = NULL, *skinned = NULL;
833 enum okay ok = STOP;
834 #ifdef HAVE_SOCKETS
835 struct termios otio;
836 int reset_tio;
837 #endif /* HAVE_SOCKETS */
839 if ((smtp = value("smtp")) == NULL) {
840 args = unpack(cat(mailargs, to));
841 if (debug || value("debug")) {
842 printf(catgets(catd, CATSET, 181,
843 "Sendmail arguments:"));
844 for (t = args; *t != NULL; t++)
845 printf(" \"%s\"", *t);
846 printf("\n");
847 return OKAY;
850 #ifdef HAVE_SOCKETS
851 if (smtp != NULL) {
852 skinned = skin(myorigin(hp));
853 if ((user = smtp_auth_var("-user", skinned)) != NULL &&
854 (password = smtp_auth_var("-password",
855 skinned)) == NULL)
856 password = getpassword(&otio, &reset_tio, NULL);
858 #endif /* HAVE_SOCKETS */
860 * Fork, set up the temporary mail file as standard
861 * input for "mail", and exec with the user list we generated
862 * far above.
864 if ((pid = fork()) == -1) {
865 perror("fork");
866 savedeadletter(input);
867 senderr++;
868 return STOP;
870 if (pid == 0) {
871 sigemptyset(&nset);
872 sigaddset(&nset, SIGHUP);
873 sigaddset(&nset, SIGINT);
874 sigaddset(&nset, SIGQUIT);
875 sigaddset(&nset, SIGTSTP);
876 sigaddset(&nset, SIGTTIN);
877 sigaddset(&nset, SIGTTOU);
878 freopen("/dev/null", "r", stdin);
879 if (smtp != NULL) {
880 prepare_child(&nset, 0, 1);
881 if (smtp_mta(smtp, to, input, hp,
882 user, password, skinned) == 0)
883 _exit(0);
884 } else {
885 prepare_child(&nset, fileno(input), -1);
886 if ((cp = value("sendmail")) != NULL)
887 cp = expand(cp);
888 else
889 cp = SENDMAIL;
890 execv(cp, args);
891 perror(cp);
893 savedeadletter(input);
894 fputs(catgets(catd, CATSET, 182,
895 ". . . message not sent.\n"), stderr);
896 _exit(1);
898 if (value("verbose") != NULL || value("sendwait") || debug
899 || value("debug")) {
900 if (wait_child(pid) == 0)
901 ok = OKAY;
902 else
903 senderr++;
904 } else {
905 ok = OKAY;
906 free_child(pid);
908 return ok;
912 * Record outgoing mail if instructed to do so.
914 static enum okay
915 mightrecord(FILE *fp, struct name *to, int recipient_record)
917 char *cp, *cq, *ep;
919 if (recipient_record) {
920 cq = skin(to->n_name);
921 cp = salloc(strlen(cq) + 1);
922 strcpy(cp, cq);
923 for (cq = cp; *cq && *cq != '@'; cq++);
924 *cq = '\0';
925 } else
926 cp = value("record");
927 if (cp != NULL) {
928 ep = expand(cp);
929 if (value("outfolder") && *ep != '/' && *ep != '+' &&
930 which_protocol(ep) == PROTO_FILE) {
931 cq = salloc(strlen(cp) + 2);
932 cq[0] = '+';
933 strcpy(&cq[1], cp);
934 cp = cq;
935 ep = expand(cp);
937 if (savemail(ep, fp) != 0) {
938 fprintf(stderr,
939 "Error while saving message to %s - "
940 "message not sent\n", ep);
941 rewind(fp);
942 exit_status |= 1;
943 savedeadletter(fp);
944 return STOP;
947 return OKAY;
951 * Mail a message on standard input to the people indicated
952 * in the passed header. (Internal interface).
954 enum okay
955 mail1(struct header *hp, int printheaders, struct message *quote,
956 char *quotefile, int recipient_record, int doprefix, int tflag,
957 int Eflag)
959 struct name *to;
960 FILE *mtf, *nmtf;
961 enum okay ok = STOP;
962 int dosign = -1;
963 char *charsets, *ncs = NULL, *cp;
965 #ifdef notdef
966 if ((hp->h_to = checkaddrs(hp->h_to)) == NULL) {
967 senderr++;
968 return STOP;
970 #endif
971 if ((cp = value("autocc")) != NULL && *cp)
972 hp->h_cc = cat(hp->h_cc, checkaddrs(sextract(cp, GCC|GFULL)));
973 if ((cp = value("autobcc")) != NULL && *cp)
974 hp->h_bcc = cat(hp->h_bcc,
975 checkaddrs(sextract(cp, GBCC|GFULL)));
977 * Collect user's mail from standard input.
978 * Get the result as mtf.
980 if ((mtf = collect(hp, printheaders, quote, quotefile, doprefix,
981 tflag)) == NULL)
982 return STOP;
983 if (value("interactive") != NULL) {
984 if (((value("bsdcompat") || value("askatend"))
985 && (value("askcc") != NULL ||
986 value("askbcc") != NULL)) ||
987 value("askattach") != NULL ||
988 value("asksign") != NULL) {
989 if (value("askcc") != NULL)
990 grabh(hp, GCC, 1);
991 if (value("askbcc") != NULL)
992 grabh(hp, GBCC, 1);
993 if (value("askattach") != NULL)
994 hp->h_attach = edit_attachments(hp->h_attach);
995 if (value("asksign") != NULL)
996 dosign = yorn("Sign this message (y/n)? ");
997 } else {
998 printf(catgets(catd, CATSET, 183, "EOT\n"));
999 fflush(stdout);
1002 if (fsize(mtf) == 0) {
1003 if (Eflag)
1004 goto out;
1005 if (hp->h_subject == NULL)
1006 printf(catgets(catd, CATSET, 184,
1007 "No message, no subject; hope that's ok\n"));
1008 else if (value("bsdcompat") || value("bsdmsgs"))
1009 printf(catgets(catd, CATSET, 185,
1010 "Null message body; hope that's ok\n"));
1012 if (dosign < 0) {
1013 if (value("smime-sign") != NULL)
1014 dosign = 1;
1015 else
1016 dosign = 0;
1019 * Now, take the user names from the combined
1020 * to and cc lists and do all the alias
1021 * processing.
1023 senderr = 0;
1024 if ((to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)))) == NULL) {
1025 printf(catgets(catd, CATSET, 186, "No recipients specified\n"));
1026 senderr++;
1028 to = fixhead(hp, to);
1029 if (hp->h_charset) {
1030 wantcharset = hp->h_charset;
1031 goto try;
1033 hloop: wantcharset = NULL;
1034 if ((charsets = value("sendcharsets")) != NULL) {
1035 wantcharset = savestr(charsets);
1036 loop: if ((ncs = strchr(wantcharset, ',')) != NULL)
1037 *ncs++ = '\0';
1039 try: if ((nmtf = infix(hp, mtf, dosign)) == NULL) {
1040 if (hp->h_charset && (errno == EILSEQ || errno == EINVAL)) {
1041 rewind(mtf);
1042 hp->h_charset = NULL;
1043 goto hloop;
1045 if (errno == EILSEQ || errno == EINVAL) {
1046 if (ncs && *ncs) {
1047 rewind(mtf);
1048 wantcharset = ncs;
1049 goto loop;
1051 if (wantcharset && value("interactive") == NULL) {
1052 if (wantcharset == (char *)-1)
1053 wantcharset = NULL;
1054 else {
1055 rewind(mtf);
1056 wantcharset = (char *)-1;
1057 goto try;
1061 /* fprintf(stderr, ". . . message lost, sorry.\n"); */
1062 perror("");
1063 fail: senderr++;
1064 rewind(mtf);
1065 savedeadletter(mtf);
1066 fputs(catgets(catd, CATSET, 187,
1067 ". . . message not sent.\n"), stderr);
1068 return STOP;
1070 mtf = nmtf;
1071 if (dosign) {
1072 if ((nmtf = smime_sign(mtf, hp)) == NULL)
1073 goto fail;
1074 Fclose(mtf);
1075 mtf = nmtf;
1078 * Look through the recipient list for names with /'s
1079 * in them which we write to as files directly.
1081 to = outof(to, mtf, hp);
1082 if (senderr)
1083 savedeadletter(mtf);
1084 to = elide(to);
1085 if (count(to) == 0) {
1086 if (senderr == 0)
1087 ok = OKAY;
1088 goto out;
1090 if (mightrecord(mtf, to, recipient_record) != OKAY)
1091 goto out;
1092 ok = transfer(to, hp->h_smopts, mtf, hp);
1093 out:
1094 Fclose(mtf);
1095 return ok;
1099 * Create a Message-Id: header field.
1100 * Use either the host name or the from address.
1102 static void
1103 message_id(FILE *fo, struct header *hp)
1105 char *cp;
1106 time_t now;
1108 time(&now);
1109 if ((cp = value("hostname")) != NULL)
1110 fprintf(fo, "Message-ID: <%lx.%s@%s>\n",
1111 (long)now, getrandstring(24), cp);
1112 else if ((cp = skin(myorigin(hp))) != NULL && strchr(cp, '@') != NULL)
1113 fprintf(fo, "Message-ID: <%lx.%s%%%s>\n",
1114 (long)now, getrandstring(16), cp);
1117 static const char *weekday_names[] = {
1118 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1121 const char *month_names[] = {
1122 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1123 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
1127 * Create a Date: header field.
1128 * We compare the localtime() and gmtime() results to get the timezone,
1129 * because numeric timezones are easier to read and because $TZ is
1130 * not set on most GNU systems.
1133 mkdate(FILE *fo, const char *field)
1135 time_t t;
1136 struct tm *tmptr;
1137 int tzdiff, tzdiff_hour, tzdiff_min;
1139 time(&t);
1140 tzdiff = t - mktime(gmtime(&t));
1141 tzdiff_hour = (int)(tzdiff / 60);
1142 tzdiff_min = tzdiff_hour % 60;
1143 tzdiff_hour /= 60;
1144 tmptr = localtime(&t);
1145 if (tmptr->tm_isdst > 0)
1146 tzdiff_hour++;
1147 return fprintf(fo, "%s: %s, %02d %s %04d %02d:%02d:%02d %+05d\n",
1148 field,
1149 weekday_names[tmptr->tm_wday],
1150 tmptr->tm_mday, month_names[tmptr->tm_mon],
1151 tmptr->tm_year + 1900, tmptr->tm_hour,
1152 tmptr->tm_min, tmptr->tm_sec,
1153 tzdiff_hour * 100 + tzdiff_min);
1156 static enum okay
1157 putname(char *line, enum gfield w, enum sendaction action, int *gotcha,
1158 char *prefix, FILE *fo, struct name **xp)
1160 struct name *np;
1162 np = sextract(line, GEXTRA|GFULL);
1163 if (xp)
1164 *xp = np;
1165 if (np == NULL)
1166 return 0;
1167 if (fmt(prefix, np, fo, w&(GCOMMA|GFILES), 0, action != SEND_TODISP))
1168 return 1;
1169 if (gotcha)
1170 (*gotcha)++;
1171 return 0;
1174 #define FMT_CC_AND_BCC { \
1175 if (hp->h_cc != NULL && w & GCC) { \
1176 if (fmt("Cc:", hp->h_cc, fo, \
1177 w&(GCOMMA|GFILES), 0, \
1178 action!=SEND_TODISP)) \
1179 return 1; \
1180 gotcha++; \
1182 if (hp->h_bcc != NULL && w & GBCC) { \
1183 if (fmt("Bcc:", hp->h_bcc, fo, \
1184 w&(GCOMMA|GFILES), 0, \
1185 action!=SEND_TODISP)) \
1186 return 1; \
1187 gotcha++; \
1191 * Dump the to, subject, cc header on the
1192 * passed file buffer.
1195 puthead(struct header *hp, FILE *fo, enum gfield w,
1196 enum sendaction action, enum conversion convert,
1197 char *contenttype, char *charset)
1199 int gotcha;
1200 char *addr/*, *cp*/;
1201 int stealthmua;
1202 struct name *np, *fromfield = NULL, *senderfield = NULL;
1205 if (value("stealthmua"))
1206 stealthmua = 1;
1207 else
1208 stealthmua = 0;
1209 gotcha = 0;
1210 if (w & GDATE) {
1211 mkdate(fo, "Date"), gotcha++;
1213 if (w & GIDENT) {
1214 if (hp->h_from != NULL) {
1215 if (fmt("From:", hp->h_from, fo, w&(GCOMMA|GFILES), 0,
1216 action!=SEND_TODISP))
1217 return 1;
1218 gotcha++;
1219 fromfield = hp->h_from;
1220 } else if ((addr = myaddrs(hp)) != NULL)
1221 if (putname(addr, w, action, &gotcha, "From:", fo,
1222 &fromfield))
1223 return 1;
1224 if (((addr = hp->h_organization) != NULL ||
1225 (addr = value("ORGANIZATION")) != NULL)
1226 && strlen(addr) > 0) {
1227 fwrite("Organization: ", sizeof (char), 14, fo);
1228 if (mime_write(addr, strlen(addr), fo,
1229 action == SEND_TODISP ?
1230 CONV_NONE:CONV_TOHDR,
1231 action == SEND_TODISP ?
1232 TD_ISPR|TD_ICONV:TD_ICONV,
1233 NULL, (size_t)0,
1234 NULL, NULL) == 0)
1235 return 1;
1236 gotcha++;
1237 putc('\n', fo);
1239 if (hp->h_replyto != NULL) {
1240 if (fmt("Reply-To:", hp->h_replyto, fo,
1241 w&(GCOMMA|GFILES), 0,
1242 action!=SEND_TODISP))
1243 return 1;
1244 gotcha++;
1245 } else if ((addr = value("replyto")) != NULL)
1246 if (putname(addr, w, action, &gotcha, "Reply-To:", fo,
1247 NULL))
1248 return 1;
1249 if (hp->h_sender != NULL) {
1250 if (fmt("Sender:", hp->h_sender, fo,
1251 w&(GCOMMA|GFILES), 0,
1252 action!=SEND_TODISP))
1253 return 1;
1254 gotcha++;
1255 senderfield = hp->h_sender;
1256 } else if ((addr = value("sender")) != NULL)
1257 if (putname(addr, w, action, &gotcha, "Sender:", fo,
1258 &senderfield))
1259 return 1;
1260 if (check_from_and_sender(fromfield, senderfield))
1261 return 1;
1263 if (hp->h_to != NULL && w & GTO) {
1264 if (fmt("To:", hp->h_to, fo, w&(GCOMMA|GFILES), 0,
1265 action!=SEND_TODISP))
1266 return 1;
1267 gotcha++;
1269 if (value("bsdcompat") == NULL && value("bsdorder") == NULL)
1270 FMT_CC_AND_BCC
1271 if (hp->h_subject != NULL && w & GSUBJECT) {
1272 fwrite("Subject: ", sizeof (char), 9, fo);
1273 if (ascncasecmp(hp->h_subject, "re: ", 4) == 0) {
1274 fwrite("Re: ", sizeof (char), 4, fo);
1275 if (strlen(hp->h_subject + 4) > 0 &&
1276 mime_write(hp->h_subject + 4,
1277 strlen(hp->h_subject + 4),
1278 fo, action == SEND_TODISP ?
1279 CONV_NONE:CONV_TOHDR,
1280 action == SEND_TODISP ?
1281 TD_ISPR|TD_ICONV:TD_ICONV,
1282 NULL, (size_t)0,
1283 NULL, NULL) == 0)
1284 return 1;
1285 } else if (*hp->h_subject) {
1286 if (mime_write(hp->h_subject,
1287 strlen(hp->h_subject),
1288 fo, action == SEND_TODISP ?
1289 CONV_NONE:CONV_TOHDR,
1290 action == SEND_TODISP ?
1291 TD_ISPR|TD_ICONV:TD_ICONV,
1292 NULL, (size_t)0,
1293 NULL, NULL) == 0)
1294 return 1;
1296 gotcha++;
1297 fwrite("\n", sizeof (char), 1, fo);
1299 if (value("bsdcompat") || value("bsdorder"))
1300 FMT_CC_AND_BCC
1301 if (w & GMSGID && stealthmua == 0)
1302 message_id(fo, hp), gotcha++;
1303 if (hp->h_ref != NULL && w & GREF) {
1304 fmt("References:", hp->h_ref, fo, 0, 1, 0);
1305 if ((np = hp->h_ref) != NULL && np->n_name) {
1306 while (np->n_flink)
1307 np = np->n_flink;
1308 if (mime_name_invalid(np->n_name, 0) == 0) {
1309 fprintf(fo, "In-Reply-To: %s\n", np->n_name);
1310 gotcha++;
1314 if (w & GUA && stealthmua == 0)
1315 fprintf(fo, "User-Agent: S-nail %s\n",
1316 version), gotcha++;
1317 if (w & GMIME) {
1318 fputs("MIME-Version: 1.0\n", fo), gotcha++;
1319 if (hp->h_attach != NULL) {
1320 makeboundary();
1321 fprintf(fo, "Content-Type: multipart/mixed;\n"
1322 " boundary=\"%s\"\n", send_boundary);
1323 } else {
1324 fprintf(fo, "Content-Type: %s", contenttype);
1325 if (charset)
1326 fprintf(fo, "; charset=%s", charset);
1327 fprintf(fo, "\nContent-Transfer-Encoding: %s\n",
1328 getencoding(convert));
1331 if (gotcha && w & GNL)
1332 putc('\n', fo);
1333 return(0);
1337 * Format the given header line to not exceed 72 characters.
1339 static int
1340 fmt(char *str, struct name *np, FILE *fo, int flags, int dropinvalid,
1341 int domime)
1343 int col, len, count = 0;
1344 int is_to = 0, comma;
1346 comma = flags&GCOMMA ? 1 : 0;
1347 col = strlen(str);
1348 if (col) {
1349 fwrite(str, sizeof *str, strlen(str), fo);
1350 if ((flags&GFILES) == 0 &&
1351 col == 3 && asccasecmp(str, "to:") == 0 ||
1352 col == 3 && asccasecmp(str, "cc:") == 0 ||
1353 col == 4 && asccasecmp(str, "bcc:") == 0 ||
1354 col == 10 && asccasecmp(str, "Resent-To:") == 0)
1355 is_to = 1;
1357 for (; np != NULL; np = np->n_flink) {
1358 if (is_to && is_fileaddr(np->n_name))
1359 continue;
1360 if (np->n_flink == NULL)
1361 comma = 0;
1362 if (mime_name_invalid(np->n_name, !dropinvalid)) {
1363 if (dropinvalid)
1364 continue;
1365 else
1366 return 1;
1368 len = strlen(np->n_fullname);
1369 col++; /* for the space */
1370 if (count && col + len + comma > 72 && col > 1) {
1371 fputs("\n ", fo);
1372 col = 1;
1373 } else
1374 putc(' ', fo);
1375 len = mime_write(np->n_fullname,
1376 len, fo,
1377 domime?CONV_TOHDR_A:CONV_NONE,
1378 TD_ICONV, NULL, (size_t)0,
1379 NULL, NULL);
1380 if (comma && !(is_to && is_fileaddr(np->n_flink->n_name)))
1381 putc(',', fo);
1382 col += len + comma;
1383 count++;
1385 putc('\n', fo);
1386 return 0;
1390 * Rewrite a message for resending, adding the Resent-Headers.
1392 static int
1393 infix_resend(FILE *fi, FILE *fo, struct message *mp, struct name *to,
1394 int add_resent)
1396 size_t count;
1397 char *buf = NULL, *cp/*, *cp2*/;
1398 size_t c, bufsize = 0;
1399 struct name *fromfield = NULL, *senderfield = NULL;
1401 count = mp->m_size;
1403 * Write the Resent-Fields.
1405 if (add_resent) {
1406 fputs("Resent-", fo);
1407 mkdate(fo, "Date");
1408 if ((cp = myaddrs(NULL)) != NULL) {
1409 if (putname(cp, GCOMMA, SEND_MBOX, NULL,
1410 "Resent-From:", fo, &fromfield))
1411 return 1;
1413 if ((cp = value("sender")) != NULL) {
1414 if (putname(cp, GCOMMA, SEND_MBOX, NULL,
1415 "Resent-Sender:", fo, &senderfield))
1416 return 1;
1418 #ifdef notdef
1420 * RFC 2822 disallows generation of this field.
1422 cp = value("replyto");
1423 if (cp != NULL) {
1424 if (mime_name_invalid(cp, 1)) {
1425 if (buf)
1426 free(buf);
1427 return 1;
1429 fwrite("Resent-Reply-To: ", sizeof (char),
1430 17, fo);
1431 mime_write(cp, strlen(cp), fo,
1432 CONV_TOHDR_A, TD_ICONV,
1433 NULL, (size_t)0,
1434 NULL, NULL);
1435 putc('\n', fo);
1437 #endif /* notdef */
1438 if (fmt("Resent-To:", to, fo, 1, 1, 0)) {
1439 if (buf)
1440 free(buf);
1441 return 1;
1443 if (value("stealthmua") == NULL) {
1444 fputs("Resent-", fo);
1445 message_id(fo, NULL);
1448 if (check_from_and_sender(fromfield, senderfield))
1449 return 1;
1451 * Write the original headers.
1453 while (count > 0) {
1454 if ((cp = foldergets(&buf, &bufsize, &count, &c, fi)) == NULL)
1455 break;
1456 if (ascncasecmp("status: ", buf, 8) != 0
1457 && strncmp("From ", buf, 5) != 0) {
1458 fwrite(buf, sizeof *buf, c, fo);
1460 if (count > 0 && *buf == '\n')
1461 break;
1464 * Write the message body.
1466 while (count > 0) {
1467 if (foldergets(&buf, &bufsize, &count, &c, fi) == NULL)
1468 break;
1469 if (count == 0 && *buf == '\n')
1470 break;
1471 fwrite(buf, sizeof *buf, c, fo);
1473 if (buf)
1474 free(buf);
1475 if (ferror(fo)) {
1476 perror(catgets(catd, CATSET, 188, "temporary mail file"));
1477 return 1;
1479 return 0;
1482 enum okay
1483 resend_msg(struct message *mp, struct name *to, int add_resent)
1485 FILE *ibuf, *nfo, *nfi;
1486 char *tempMail;
1487 struct header head;
1488 enum okay ok = STOP;
1490 memset(&head, 0, sizeof head);
1491 if ((to = checkaddrs(to)) == NULL) {
1492 senderr++;
1493 return STOP;
1495 if ((nfo = Ftemp(&tempMail, "Rs", "w", 0600, 1)) == NULL) {
1496 senderr++;
1497 perror(catgets(catd, CATSET, 189, "temporary mail file"));
1498 return STOP;
1500 if ((nfi = Fopen(tempMail, "r")) == NULL) {
1501 senderr++;
1502 perror(tempMail);
1503 return STOP;
1505 rm(tempMail);
1506 Ftfree(&tempMail);
1507 if ((ibuf = setinput(&mb, mp, NEED_BODY)) == NULL)
1508 return STOP;
1509 head.h_to = to;
1510 to = fixhead(&head, to);
1511 if (infix_resend(ibuf, nfo, mp, head.h_to, add_resent) != 0) {
1512 senderr++;
1513 rewind(nfo);
1514 savedeadletter(nfi);
1515 fputs(catgets(catd, CATSET, 190,
1516 ". . . message not sent.\n"), stderr);
1517 Fclose(nfo);
1518 Fclose(nfi);
1519 return STOP;
1521 fflush(nfo);
1522 rewind(nfo);
1523 Fclose(nfo);
1524 to = outof(to, nfi, &head);
1525 if (senderr)
1526 savedeadletter(nfi);
1527 to = elide(to);
1528 if (count(to) != 0) {
1529 if (value("record-resent") == NULL ||
1530 mightrecord(nfi, to, 0) == OKAY)
1531 ok = transfer(to, head.h_smopts, nfi, NULL);
1532 } else if (senderr == 0)
1533 ok = OKAY;
1534 Fclose(nfi);
1535 return ok;