load(): handle NULL arg ourself, do not pass to Fopen()
[s-mailx.git] / sendout.c
blob687fa9e74366e4bcda75f463a005391d6190ccfb
1 /*
2 * S-nail - 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 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #include "rcv.h"
41 #include "extern.h"
42 #include <errno.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <time.h>
49 * Mail -- a mail program
51 * Mail to others.
54 static char *send_boundary;
56 static char *getencoding(enum conversion convert);
57 static struct name *fixhead(struct header *hp, struct name *tolist);
58 static int put_signature(FILE *fo, int convert);
59 static int attach_file1(struct attachment *ap, FILE *fo, int dosign);
60 static int attach_file(struct attachment *ap, FILE *fo, int dosign);
61 static int attach_message(struct attachment *ap, FILE *fo, int dosign);
62 static int make_multipart(struct header *hp, int convert, FILE *fi, FILE *fo,
63 const char *contenttype, const char *charset, int dosign);
64 static FILE *infix(struct header *hp, FILE *fi, int dosign);
65 static int savemail(char *name, FILE *fi);
66 static int sendmail_internal(void *v, int recipient_record);
67 static enum okay transfer(struct name *to, FILE *input, struct header *hp);
68 static char ** prepare_mta_args(struct name *to);
69 static enum okay start_mta(struct name *to, FILE *input, struct header *hp);
70 static void message_id(FILE *fo, struct header *hp);
71 static int fmt(char *str, struct name *np, FILE *fo, int comma,
72 int dropinvalid, int domime);
73 static int infix_resend(FILE *fi, FILE *fo, struct message *mp,
74 struct name *to, int add_resent);
77 * Generate a boundary for MIME multipart messages.
79 char *
80 makeboundary(void)
82 static char bound[70];
83 time_t now;
85 time(&now);
86 snprintf(bound, sizeof bound, "=_%lx.%s", (long)now, getrandstring(48));
87 send_boundary = bound;
88 return send_boundary;
92 * Get an encoding flag based on the given string.
94 static char *
95 getencoding(enum conversion convert)
97 switch (convert) {
98 case CONV_7BIT:
99 return "7bit";
100 case CONV_8BIT:
101 return "8bit";
102 case CONV_TOQP:
103 return "quoted-printable";
104 case CONV_TOB64:
105 return "base64";
106 default:
107 break;
109 /*NOTREACHED*/
110 return NULL;
114 * Fix the header by glopping all of the expanded names from
115 * the distribution list into the appropriate fields.
117 static struct name *
118 fixhead(struct header *hp, struct name *tolist) /* TODO !HAVE_ASSERTS legacy*/
120 struct name *np;
122 hp->h_to = hp->h_cc = hp->h_bcc = NULL;
123 for (np = tolist; np != NULL; np = np->n_flink)
124 if (np->n_type & GDEL) {
125 #ifdef HAVE_ASSERTS
126 assert(0); /* Shouldn't happen here, but later on :)) */
127 #else
128 continue;
129 #endif
130 } else switch (np->n_type & GMASK) {
131 case (GTO):
132 hp->h_to = cat(hp->h_to, ndup(np, np->n_type|GFULL));
133 break;
134 case (GCC):
135 hp->h_cc = cat(hp->h_cc, ndup(np, np->n_type|GFULL));
136 break;
137 case (GBCC):
138 hp->h_bcc = cat(hp->h_bcc, ndup(np, np->n_type|GFULL));
139 break;
140 default:
141 break;
143 return (tolist);
148 * Do not change, you get incorrect base64 encodings else!
150 #define INFIX_BUF 972
153 * Put the signature file at fo.
155 static int
156 put_signature(FILE *fo, int convert)
158 char *sig, buf[INFIX_BUF], c = '\n';
159 FILE *fsig;
160 size_t sz;
162 sig = value("signature");
163 if (sig == NULL || *sig == '\0')
164 return 0;
165 else if ((sig = file_expand(sig)) == NULL)
166 return (-1);
167 if ((fsig = Fopen(sig, "r")) == NULL) {
168 perror(sig);
169 return -1;
171 while ((sz = fread(buf, sizeof *buf, INFIX_BUF, fsig)) != 0) {
172 c = buf[sz - 1];
173 if (mime_write(buf, sz, fo, convert, TD_NONE,
174 NULL, (size_t)0, NULL, NULL)
175 == 0) {
176 perror(sig);
177 Fclose(fsig);
178 return -1;
181 if (ferror(fsig)) {
182 perror(sig);
183 Fclose(fsig);
184 return -1;
186 Fclose(fsig);
187 if (c != '\n')
188 putc('\n', fo);
189 return 0;
193 * Write an attachment to the file buffer, converting to MIME.
195 static int
196 attach_file1(struct attachment *ap, FILE *fo, int dosign)
198 FILE *fi;
199 char *charset = NULL, *contenttype = NULL, *basename;
200 enum conversion convert = CONV_TOB64;
201 int err = 0;
202 enum mimeclean isclean;
203 size_t sz;
204 char *buf;
205 size_t bufsize, count;
206 int lastc = EOF;
207 #ifdef HAVE_ICONV
208 char *tcs;
209 #endif
211 if ((fi = Fopen(ap->a_name, "r")) == NULL) {
212 perror(ap->a_name);
213 return -1;
215 if ((basename = strrchr(ap->a_name, '/')) == NULL)
216 basename = ap->a_name;
217 else
218 basename++;
219 if (ap->a_content_type)
220 contenttype = ap->a_content_type;
221 else
222 contenttype = mime_filecontent(basename);
223 if (ap->a_charset)
224 charset = ap->a_charset;
225 convert = get_mime_convert(fi, &contenttype, &charset, &isclean,
226 dosign);
227 fprintf(fo,
228 "\n--%s\n"
229 "Content-Type: %s",
230 send_boundary, contenttype);
231 if (charset == NULL)
232 putc('\n', fo);
233 else
234 fprintf(fo, ";\n charset=%s\n", charset);
235 if (ap->a_content_disposition == NULL)
236 ap->a_content_disposition = "attachment";
237 fprintf(fo, "Content-Transfer-Encoding: %s\n"
238 "Content-Disposition: %s;\n"
239 " filename=\"",
240 getencoding(convert),
241 ap->a_content_disposition);
242 mime_write(basename, strlen(basename), fo,
243 CONV_TOHDR, TD_NONE, NULL, (size_t)0, NULL, NULL);
244 fwrite("\"\n", sizeof (char), 2, fo);
245 if (ap->a_content_id)
246 fprintf(fo, "Content-ID: %s\n", ap->a_content_id);
247 if (ap->a_content_description)
248 fprintf(fo, "Content-Description: %s\n",
249 ap->a_content_description);
250 putc('\n', fo);
251 #ifdef HAVE_ICONV
252 if (iconvd != (iconv_t)-1) {
253 iconv_close(iconvd);
254 iconvd = (iconv_t)-1;
256 tcs = gettcharset();
257 if ((isclean & (MIME_HASNUL|MIME_CTRLCHAR)) == 0 &&
258 ascncasecmp(contenttype, "text/", 5) == 0 &&
259 isclean & MIME_HIGHBIT &&
260 charset != NULL) {
261 if ((iconvd = iconv_open_ft(charset, tcs)) == (iconv_t)-1 &&
262 errno != 0) {
263 if (errno == EINVAL)
264 fprintf(stderr, catgets(catd, CATSET, 179,
265 "Cannot convert from %s to %s\n"), tcs, charset);
266 else
267 perror("iconv_open");
268 Fclose(fi);
269 return -1;
272 #endif /* HAVE_ICONV */
273 buf = smalloc(bufsize = INFIX_BUF);
274 if (convert == CONV_TOQP
275 #ifdef HAVE_ICONV
276 || iconvd != (iconv_t)-1
277 #endif
279 fflush(fi);
280 count = fsize(fi);
282 for (;;) {
283 if (convert == CONV_TOQP
284 #ifdef HAVE_ICONV
285 || iconvd != (iconv_t)-1
286 #endif
288 if (fgetline(&buf, &bufsize, &count, &sz, fi, 0)
289 == NULL)
290 break;
291 } else {
292 if ((sz = fread(buf, sizeof *buf, bufsize, fi)) == 0)
293 break;
295 lastc = buf[sz-1];
296 if (mime_write(buf, sz, fo, convert, TD_ICONV,
297 NULL, (size_t)0, NULL, NULL) == 0)
298 err = -1;
300 if (convert == CONV_TOQP && lastc != '\n')
301 fwrite("=\n", 1, 2, fo);
302 if (ferror(fi))
303 err = -1;
304 Fclose(fi);
305 free(buf);
306 return err;
310 * Try out different character set conversions to attach a file.
312 static int
313 attach_file(struct attachment *ap, FILE *fo, int dosign)
315 char *_wantcharset, *charsets, *ncs;
316 size_t offs = ftell(fo);
318 if (ap->a_charset || (charsets = value("sendcharsets")) == NULL)
319 return attach_file1(ap, fo, dosign);
320 _wantcharset = wantcharset;
321 wantcharset = savestr(charsets);
322 loop: if ((ncs = strchr(wantcharset, ',')) != NULL)
323 *ncs++ = '\0';
324 try: if (attach_file1(ap, fo, dosign) != 0) {
325 if (errno == EILSEQ || errno == EINVAL) {
326 if (ncs && *ncs) {
327 wantcharset = ncs;
328 clearerr(fo);
329 fseek(fo, offs, SEEK_SET);
330 goto loop;
332 if (wantcharset) {
333 if (wantcharset == (char *)-1)
334 wantcharset = NULL;
335 else {
336 wantcharset = (char *)-1;
337 clearerr(fo);
338 fseek(fo, offs, SEEK_SET);
339 goto try;
344 wantcharset = _wantcharset;
345 return 0;
349 * Attach a message to the file buffer.
351 static int
352 attach_message(struct attachment *ap, FILE *fo, int dosign)
354 struct message *mp;
355 (void)dosign;
357 fprintf(fo, "\n--%s\n"
358 "Content-Type: message/rfc822\n"
359 "Content-Disposition: inline\n\n", send_boundary);
360 mp = &message[ap->a_msgno - 1];
361 touch(mp);
362 if (send(mp, fo, 0, NULL, SEND_RFC822, NULL) < 0)
363 return -1;
364 return 0;
368 * Generate the body of a MIME multipart message.
370 static int
371 make_multipart(struct header *hp, int convert, FILE *fi, FILE *fo,
372 const char *contenttype, const char *charset, int dosign)
374 struct attachment *att;
376 fputs("This is a multi-part message in MIME format.\n", fo);
377 if (fsize(fi) != 0) {
378 char *buf, c = '\n';
379 size_t sz, bufsize, count;
381 fprintf(fo, "\n--%s\n", send_boundary);
382 fprintf(fo, "Content-Type: %s", contenttype);
383 if (charset)
384 fprintf(fo, "; charset=%s", charset);
385 fprintf(fo, "\nContent-Transfer-Encoding: %s\n"
386 "Content-Disposition: inline\n\n",
387 getencoding(convert));
388 buf = smalloc(bufsize = INFIX_BUF);
389 if (convert == CONV_TOQP
390 #ifdef HAVE_ICONV
391 || iconvd != (iconv_t)-1
392 #endif /* HAVE_ICONV */
394 fflush(fi);
395 count = fsize(fi);
397 for (;;) {
398 if (convert == CONV_TOQP
399 #ifdef HAVE_ICONV
400 || iconvd != (iconv_t)-1
401 #endif /* HAVE_ICONV */
403 if (fgetline(&buf, &bufsize, &count, &sz, fi, 0)
404 == NULL)
405 break;
406 } else {
407 sz = fread(buf, sizeof *buf, bufsize, fi);
408 if (sz == 0)
409 break;
411 c = buf[sz - 1];
412 if (mime_write(buf, sz, fo, convert,
413 TD_ICONV, NULL, (size_t)0,
414 NULL, NULL) == 0) {
415 free(buf);
416 return -1;
419 free(buf);
420 if (ferror(fi))
421 return -1;
422 if (c != '\n')
423 putc('\n', fo);
424 if (charset != NULL)
425 put_signature(fo, convert);
427 for (att = hp->h_attach; att != NULL; att = att->a_flink) {
428 if (att->a_msgno) {
429 if (attach_message(att, fo, dosign) != 0)
430 return -1;
431 } else {
432 if (attach_file(att, fo, dosign) != 0)
433 return -1;
436 /* the final boundary with two attached dashes */
437 fprintf(fo, "\n--%s--\n", send_boundary);
438 return 0;
442 * Prepend a header in front of the collected stuff
443 * and return the new file.
445 static FILE *
446 infix(struct header *hp, FILE *fi, int dosign)
448 FILE *nfo, *nfi;
449 char *tempMail;
450 #ifdef HAVE_ICONV
451 char *tcs, *convhdr = NULL;
452 #endif
453 enum mimeclean isclean;
454 enum conversion convert;
455 char *charset = NULL, *contenttype = NULL;
456 int lastc = EOF;
458 if ((nfo = Ftemp(&tempMail, "Rs", "w", 0600, 1)) == NULL) {
459 perror(catgets(catd, CATSET, 178, "temporary mail file"));
460 return(NULL);
462 if ((nfi = Fopen(tempMail, "r")) == NULL) {
463 perror(tempMail);
464 Fclose(nfo);
465 return(NULL);
467 rm(tempMail);
468 Ftfree(&tempMail);
469 convert = get_mime_convert(fi, &contenttype, &charset,
470 &isclean, dosign);
471 #ifdef HAVE_ICONV
472 tcs = gettcharset();
473 if ((convhdr = need_hdrconv(hp, GTO|GSUBJECT|GCC|GBCC|GIDENT)) != 0) {
474 if (iconvd != (iconv_t)-1)
475 iconv_close(iconvd);
476 if ((iconvd = iconv_open_ft(convhdr, tcs)) == (iconv_t)-1
477 && errno != 0) {
478 if (errno == EINVAL)
479 fprintf(stderr, catgets(catd, CATSET, 179,
480 "Cannot convert from %s to %s\n"), tcs, convhdr);
481 else
482 perror("iconv_open");
483 Fclose(nfo);
484 return NULL;
487 #endif /* HAVE_ICONV */
488 if (puthead(hp, nfo,
489 GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA|GUA|GMIME
490 |GMSGID|GIDENT|GREF|GDATE,
491 SEND_MBOX, convert, contenttype, charset)) {
492 Fclose(nfo);
493 Fclose(nfi);
494 #ifdef HAVE_ICONV
495 if (iconvd != (iconv_t)-1) {
496 iconv_close(iconvd);
497 iconvd = (iconv_t)-1;
499 #endif
500 return NULL;
502 #ifdef HAVE_ICONV
503 if (convhdr && iconvd != (iconv_t)-1) {
504 iconv_close(iconvd);
505 iconvd = (iconv_t)-1;
507 if ((isclean & (MIME_HASNUL|MIME_CTRLCHAR)) == 0 &&
508 ascncasecmp(contenttype, "text/", 5) == 0 &&
509 isclean & MIME_HIGHBIT &&
510 charset != NULL) {
511 if (iconvd != (iconv_t)-1)
512 iconv_close(iconvd);
513 if ((iconvd = iconv_open_ft(charset, tcs)) == (iconv_t)-1
514 && errno != 0) {
515 if (errno == EINVAL)
516 fprintf(stderr, catgets(catd, CATSET, 179,
517 "Cannot convert from %s to %s\n"), tcs, charset);
518 else
519 perror("iconv_open");
520 Fclose(nfo);
521 return NULL;
524 #endif
525 if (hp->h_attach != NULL) {
526 if (make_multipart(hp, convert, fi, nfo,
527 contenttype, charset, dosign) != 0) {
528 Fclose(nfo);
529 Fclose(nfi);
530 #ifdef HAVE_ICONV
531 if (iconvd != (iconv_t)-1) {
532 iconv_close(iconvd);
533 iconvd = (iconv_t)-1;
535 #endif
536 return NULL;
538 } else {
539 size_t sz, bufsize, count;
540 char *buf;
542 if (convert == CONV_TOQP
543 #ifdef HAVE_ICONV
544 || iconvd != (iconv_t)-1
545 #endif /* HAVE_ICONV */
547 fflush(fi);
548 count = fsize(fi);
550 buf = smalloc(bufsize = INFIX_BUF);
551 for (;;) {
552 if (convert == CONV_TOQP
553 #ifdef HAVE_ICONV
554 || iconvd != (iconv_t)-1
555 #endif /* HAVE_ICONV */
557 if (fgetline(&buf, &bufsize, &count, &sz, fi, 0)
558 == NULL)
559 break;
560 } else {
561 sz = fread(buf, sizeof *buf, bufsize, fi);
562 if (sz == 0)
563 break;
565 lastc = buf[sz - 1];
566 if (mime_write(buf, sz, nfo, convert,
567 TD_ICONV, NULL, (size_t)0,
568 NULL, NULL) == 0) {
569 Fclose(nfo);
570 Fclose(nfi);
571 #ifdef HAVE_ICONV
572 if (iconvd != (iconv_t)-1) {
573 iconv_close(iconvd);
574 iconvd = (iconv_t)-1;
576 #endif
577 free(buf);
578 return NULL;
581 if (convert == CONV_TOQP && lastc != '\n')
582 fwrite("=\n", 1, 2, nfo);
583 free(buf);
584 if (ferror(fi)) {
585 Fclose(nfo);
586 Fclose(nfi);
587 #ifdef HAVE_ICONV
588 if (iconvd != (iconv_t)-1) {
589 iconv_close(iconvd);
590 iconvd = (iconv_t)-1;
592 #endif
593 return NULL;
595 if (charset != NULL)
596 put_signature(nfo, convert);
598 #ifdef HAVE_ICONV
599 if (iconvd != (iconv_t)-1) {
600 iconv_close(iconvd);
601 iconvd = (iconv_t)-1;
603 #endif
604 fflush(nfo);
605 if (ferror(nfo)) {
606 perror(catgets(catd, CATSET, 180, "temporary mail file"));
607 Fclose(nfo);
608 Fclose(nfi);
609 return NULL;
611 Fclose(nfo);
612 Fclose(fi);
613 fflush(nfi);
614 rewind(nfi);
615 return(nfi);
619 * Save the outgoing mail on the passed file.
622 /*ARGSUSED*/
623 static int
624 savemail(char *name, FILE *fi)
626 FILE *fo;
627 char *buf;
628 size_t bufsize, buflen, count;
629 char *p;
630 time_t now;
631 int prependnl = 0;
632 int error = 0;
634 buf = smalloc(bufsize = LINESIZE);
635 time(&now);
636 if ((fo = Zopen(name, "a+", NULL)) == NULL) {
637 if ((fo = Zopen(name, "wx", NULL)) == NULL) {
638 perror(name);
639 free(buf);
640 return (-1);
642 } else {
643 if (fseek(fo, -2L, SEEK_END) == 0) {
644 switch (fread(buf, sizeof *buf, 2, fo)) {
645 case 2:
646 if (buf[1] != '\n') {
647 prependnl = 1;
648 break;
650 /*FALLTHRU*/
651 case 1:
652 if (buf[0] != '\n')
653 prependnl = 1;
654 break;
655 default:
656 if (ferror(fo)) {
657 perror(name);
658 free(buf);
659 return -1;
662 fflush(fo);
663 if (prependnl) {
664 putc('\n', fo);
665 fflush(fo);
669 fprintf(fo, "From %s %s", myname, ctime(&now));
670 buflen = 0;
671 fflush(fi);
672 rewind(fi);
673 count = fsize(fi);
674 while (fgetline(&buf, &bufsize, &count, &buflen, fi, 0) != NULL) {
675 if (*buf == '>') {
676 p = buf + 1;
677 while (*p == '>')
678 p++;
679 if (strncmp(p, "From ", 5) == 0)
680 /* we got a masked From line */
681 putc('>', fo);
682 } else if (strncmp(buf, "From ", 5) == 0)
683 putc('>', fo);
684 fwrite(buf, sizeof *buf, buflen, fo);
686 if (buflen && *(buf + buflen - 1) != '\n')
687 putc('\n', fo);
688 putc('\n', fo);
689 fflush(fo);
690 if (ferror(fo)) {
691 perror(name);
692 error = -1;
694 if (Fclose(fo) != 0)
695 error = -1;
696 fflush(fi);
697 rewind(fi);
698 free(buf);
699 return error;
703 * Interface between the argument list and the mail1 routine
704 * which does all the dirty work.
706 int
707 mail(struct name *to, struct name *cc, struct name *bcc,
708 char *subject, struct attachment *attach,
709 char *quotefile, int recipient_record, int tflag, int Eflag)
711 struct header head;
712 struct str in, out;
714 memset(&head, 0, sizeof head);
715 /* The given subject may be in RFC1522 format. */
716 if (subject != NULL) {
717 in.s = subject;
718 in.l = strlen(subject);
719 mime_fromhdr(&in, &out, TD_ISPR | TD_ICONV);
720 head.h_subject = out.s;
722 if (tflag == 0) {
723 head.h_to = to;
724 head.h_cc = cc;
725 head.h_bcc = bcc;
727 head.h_attach = attach;
728 mail1(&head, 0, NULL, quotefile, recipient_record, 0, tflag, Eflag);
729 if (subject != NULL)
730 free(out.s);
731 return(0);
735 * Send mail to a bunch of user names. The interface is through
736 * the mail routine below.
738 static int
739 sendmail_internal(void *v, int recipient_record)
741 int Eflag;
742 char *str = v;
743 struct header head;
745 memset(&head, 0, sizeof head);
746 head.h_to = lextract(str, GTO|GFULL);
747 Eflag = value("skipemptybody") != NULL;
748 mail1(&head, 0, NULL, NULL, recipient_record, 0, 0, Eflag);
749 return(0);
752 int
753 sendmail(void *v)
755 return sendmail_internal(v, 0);
758 int
759 Sendmail(void *v)
761 return sendmail_internal(v, 1);
764 static enum okay
765 transfer(struct name *to, FILE *input, struct header *hp)
767 char o[LINESIZE], *cp;
768 struct name *np, *nt;
769 int cnt = 0;
770 FILE *ef;
771 enum okay ok = OKAY;
773 np = to;
774 while (np) {
775 snprintf(o, sizeof o, "smime-encrypt-%s", np->n_name);
776 if ((cp = value(o)) != NULL) {
777 if ((ef = smime_encrypt(input, cp, np->n_name)) != 0) {
778 nt = ndup(np, np->n_type & ~(GFULL|GSKIN));
779 if (start_mta(nt, ef, hp) != OKAY)
780 ok = STOP;
781 Fclose(ef);
782 } else {
783 fprintf(stderr, "Message not sent to <%s>\n",
784 np->n_name);
785 senderr++;
787 rewind(input);
788 if (np->n_flink)
789 np->n_flink->n_blink = np->n_blink;
790 if (np->n_blink)
791 np->n_blink->n_flink = np->n_flink;
792 if (np == to)
793 to = np->n_flink;
794 np = np->n_flink;
795 } else {
796 cnt++;
797 np = np->n_flink;
800 if (cnt) {
801 if (value("smime-force-encryption") ||
802 start_mta(to, input, hp) != OKAY)
803 ok = STOP;
805 return ok;
808 static char **
809 prepare_mta_args(struct name *to)
811 size_t j, i = 4 + smopts_count + count(to) + 1;
812 char **args = salloc(i * sizeof(char*));
814 args[0] = "send-mail";
815 args[1] = "-i";
816 i = 2;
817 if (value("metoo"))
818 args[i++] = "-m";
819 if (value("verbose"))
820 args[i++] = "-v";
821 for (j = 0; j < smopts_count; ++j, ++i)
822 args[i] = smopts[j];
823 for (; to != NULL; to = to->n_flink)
824 if ((to->n_type & GDEL) == 0)
825 args[i++] = to->n_name;
826 args[i] = NULL;
827 return (args);
831 * Start the Mail Transfer Agent
832 * mailing to namelist and stdin redirected to input.
834 static enum okay
835 start_mta(struct name *to, FILE *input, struct header *hp)
837 #ifdef USE_SMTP
838 struct termios otio;
839 int reset_tio;
840 #endif
841 char **args = NULL, *user = NULL, *password = NULL, *skinned = NULL,
842 **t, *smtp, *mta;
843 enum okay ok = STOP;
844 pid_t pid;
845 sigset_t nset;
847 if ((smtp = value("smtp")) == NULL) {
848 if ((mta = value("sendmail")) != NULL) {
849 if ((mta = file_expand(mta)) == NULL)
850 goto jstop;
851 } else
852 mta = SENDMAIL;
854 args = prepare_mta_args(to);
855 if (debug || value("debug")) {
856 printf(tr(181, "Sendmail arguments:"));
857 for (t = args; *t != NULL; t++)
858 printf(" \"%s\"", *t);
859 printf("\n");
860 return (OKAY);
863 #ifdef USE_SMTP
864 else {
865 skinned = skin(myorigin(hp));
866 if ((user = smtp_auth_var("-user", skinned)) != NULL &&
867 (password = smtp_auth_var("-password",
868 skinned)) == NULL)
869 password = getpassword(&otio, &reset_tio, NULL);
871 #endif
873 * Fork, set up the temporary mail file as standard
874 * input for "mail", and exec with the user list we generated
875 * far above.
877 if ((pid = fork()) == -1) {
878 perror("fork");
879 jstop: savedeadletter(input);
880 senderr++;
881 return STOP;
883 if (pid == 0) {
884 sigemptyset(&nset);
885 sigaddset(&nset, SIGHUP);
886 sigaddset(&nset, SIGINT);
887 sigaddset(&nset, SIGQUIT);
888 sigaddset(&nset, SIGTSTP);
889 sigaddset(&nset, SIGTTIN);
890 sigaddset(&nset, SIGTTOU);
891 freopen("/dev/null", "r", stdin);
892 if (smtp != NULL) {
893 prepare_child(&nset, 0, 1);
894 if (smtp_mta(smtp, to, input, hp,
895 user, password, skinned) == 0)
896 _exit(0);
897 } else {
898 prepare_child(&nset, fileno(input), -1);
899 execv(mta, args);
900 perror(mta);
902 savedeadletter(input);
903 fputs(tr(182, ". . . message not sent.\n"), stderr);
904 _exit(1);
906 if (value("verbose") != NULL || value("sendwait") || debug
907 || value("debug")) {
908 if (wait_child(pid) == 0)
909 ok = OKAY;
910 else
911 senderr++;
912 } else {
913 ok = OKAY;
914 free_child(pid);
916 return (ok);
920 * Record outgoing mail if instructed to do so.
922 static enum okay
923 mightrecord(FILE *fp, struct name *to, int recipient_record)
925 char *cp, *cq, *ep;
927 if (recipient_record) {
928 cq = skinned_name(to);
929 cp = salloc(strlen(cq) + 1);
930 strcpy(cp, cq);
931 for (cq = cp; *cq && *cq != '@'; cq++);
932 *cq = '\0';
933 } else
934 cp = value("record");
935 if (cp != NULL) {
936 ep = expand(cp);
937 if (ep == NULL) {
938 ep = "NULL";
939 goto jbail;
941 if (value("outfolder") && *ep != '/' && *ep != '+' &&
942 which_protocol(ep) == PROTO_FILE) {
943 cq = salloc(strlen(cp) + 2);
944 cq[0] = '+';
945 strcpy(&cq[1], cp);
946 cp = cq;
947 ep = expand(cp);
948 if (ep == NULL) {
949 ep = "NULL";
950 goto jbail;
953 if (savemail(ep, fp) != 0) {
954 jbail: fprintf(stderr, tr(285,
955 "Failed to save message in %s - "
956 "message not sent\n"), ep);
957 rewind(fp);
958 exit_status |= 1;
959 savedeadletter(fp);
960 return STOP;
963 return OKAY;
967 * Mail a message on standard input to the people indicated
968 * in the passed header. (Internal interface).
970 enum okay
971 mail1(struct header *hp, int printheaders, struct message *quote,
972 char *quotefile, int recipient_record, int doprefix, int tflag,
973 int Eflag)
975 struct name *to;
976 FILE *mtf, *nmtf;
977 enum okay ok = STOP;
978 int dosign = -1;
979 char *charsets, *ncs = NULL, *cp;
981 #ifdef notdef
982 if ((hp->h_to = checkaddrs(hp->h_to)) == NULL) {
983 senderr++;
984 return STOP;
986 #endif
987 if ((cp = value("autocc")) != NULL && *cp)
988 hp->h_cc = cat(hp->h_cc, checkaddrs(lextract(cp, GCC|GFULL)));
989 if ((cp = value("autobcc")) != NULL && *cp)
990 hp->h_bcc = cat(hp->h_bcc, checkaddrs(lextract(cp,GBCC|GFULL)));
992 * Collect user's mail from standard input.
993 * Get the result as mtf.
995 if ((mtf = collect(hp, printheaders, quote, quotefile, doprefix,
996 tflag)) == NULL)
997 return STOP;
998 if (value("interactive") != NULL) {
999 if (((value("bsdcompat") || value("askatend"))
1000 && (value("askcc") != NULL ||
1001 value("askbcc") != NULL)) ||
1002 value("askattach") != NULL ||
1003 value("asksign") != NULL) {
1004 if (value("askcc") != NULL)
1005 grabh(hp, GCC, 1);
1006 if (value("askbcc") != NULL)
1007 grabh(hp, GBCC, 1);
1008 if (value("askattach") != NULL)
1009 hp->h_attach = edit_attachments(hp->h_attach);
1010 if (value("asksign") != NULL)
1011 dosign = yorn("Sign this message (y/n)? ");
1012 } else {
1013 printf(catgets(catd, CATSET, 183, "EOT\n"));
1014 fflush(stdout);
1017 if (fsize(mtf) == 0) {
1018 if (Eflag)
1019 goto out;
1020 if (hp->h_subject == NULL)
1021 printf(catgets(catd, CATSET, 184,
1022 "No message, no subject; hope that's ok\n"));
1023 else if (value("bsdcompat") || value("bsdmsgs"))
1024 printf(catgets(catd, CATSET, 185,
1025 "Null message body; hope that's ok\n"));
1027 if (dosign < 0) {
1028 if (value("smime-sign") != NULL)
1029 dosign = 1;
1030 else
1031 dosign = 0;
1034 * Now, take the user names from the combined
1035 * to and cc lists and do all the alias
1036 * processing.
1038 senderr = 0;
1039 if ((to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)))) == NULL) {
1040 printf(catgets(catd, CATSET, 186, "No recipients specified\n"));
1041 senderr++;
1043 to = fixhead(hp, to);
1044 if (hp->h_charset) {
1045 wantcharset = hp->h_charset;
1046 goto try;
1048 hloop: wantcharset = NULL;
1049 if ((charsets = value("sendcharsets")) != NULL) {
1050 wantcharset = savestr(charsets);
1051 loop: if ((ncs = strchr(wantcharset, ',')) != NULL)
1052 *ncs++ = '\0';
1054 try: if ((nmtf = infix(hp, mtf, dosign)) == NULL) {
1055 if (hp->h_charset && (errno == EILSEQ || errno == EINVAL)) {
1056 rewind(mtf);
1057 hp->h_charset = NULL;
1058 goto hloop;
1060 if (errno == EILSEQ || errno == EINVAL) {
1061 if (ncs && *ncs) {
1062 rewind(mtf);
1063 wantcharset = ncs;
1064 goto loop;
1066 if (wantcharset && value("interactive") == NULL) {
1067 if (wantcharset == (char *)-1)
1068 wantcharset = NULL;
1069 else {
1070 rewind(mtf);
1071 wantcharset = (char *)-1;
1072 goto try;
1076 /* fprintf(stderr, ". . . message lost, sorry.\n"); */
1077 perror("");
1078 fail: senderr++;
1079 rewind(mtf);
1080 savedeadletter(mtf);
1081 fputs(catgets(catd, CATSET, 187,
1082 ". . . message not sent.\n"), stderr);
1083 return STOP;
1085 mtf = nmtf;
1086 if (dosign) {
1087 if ((nmtf = smime_sign(mtf, hp)) == NULL)
1088 goto fail;
1089 Fclose(mtf);
1090 mtf = nmtf;
1093 * Look through the recipient list for names with /'s
1094 * in them which we write to as files directly.
1096 to = outof(to, mtf, hp);
1097 if (senderr)
1098 savedeadletter(mtf);
1099 to = elide(to);
1100 if (count(to) == 0) {
1101 if (senderr == 0)
1102 ok = OKAY;
1103 goto out;
1105 if (mightrecord(mtf, to, recipient_record) != OKAY)
1106 goto out;
1107 ok = transfer(to, mtf, hp);
1108 out:
1109 Fclose(mtf);
1110 return ok;
1114 * Create a Message-Id: header field.
1115 * Use either the host name or the from address.
1117 static void
1118 message_id(FILE *fo, struct header *hp)
1120 time_t now;
1121 struct tm *tmp;
1122 char *h;
1123 size_t rl;
1125 time(&now);
1126 tmp = gmtime(&now);
1127 if ((h = value("hostname")) != NULL)
1128 rl = 24;
1129 else if ((h = skin(myorigin(hp))) != NULL && strchr(h, '@') != NULL)
1130 rl = 16;
1131 else
1132 /* Delivery seems to dependent on a MTA -- it's up to it */
1133 return;
1135 fprintf(fo, "Message-ID: <%04d%02d%02d%02d%02d%02d.%s%c%s>\n",
1136 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
1137 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
1138 getrandstring(rl), (rl == 16 ? '%' : '@'), h);
1141 static const char *weekday_names[] = {
1142 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1145 const char *month_names[] = {
1146 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
1151 * Create a Date: header field.
1152 * We compare the localtime() and gmtime() results to get the timezone,
1153 * because numeric timezones are easier to read and because $TZ is
1154 * not set on most GNU systems.
1157 mkdate(FILE *fo, const char *field)
1159 time_t t;
1160 struct tm *tmptr;
1161 int tzdiff, tzdiff_hour, tzdiff_min;
1163 time(&t);
1164 tzdiff = t - mktime(gmtime(&t));
1165 tzdiff_hour = (int)(tzdiff / 60);
1166 tzdiff_min = tzdiff_hour % 60;
1167 tzdiff_hour /= 60;
1168 tmptr = localtime(&t);
1169 if (tmptr->tm_isdst > 0)
1170 tzdiff_hour++;
1171 return fprintf(fo, "%s: %s, %02d %s %04d %02d:%02d:%02d %+05d\n",
1172 field,
1173 weekday_names[tmptr->tm_wday],
1174 tmptr->tm_mday, month_names[tmptr->tm_mon],
1175 tmptr->tm_year + 1900, tmptr->tm_hour,
1176 tmptr->tm_min, tmptr->tm_sec,
1177 tzdiff_hour * 100 + tzdiff_min);
1180 static enum okay
1181 putname(char *line, enum gfield w, enum sendaction action, int *gotcha,
1182 char *prefix, FILE *fo, struct name **xp)
1184 struct name *np;
1186 np = lextract(line, GEXTRA|GFULL);
1187 if (xp)
1188 *xp = np;
1189 if (np == NULL)
1190 return 0;
1191 if (fmt(prefix, np, fo, w&(GCOMMA|GFILES), 0, action != SEND_TODISP))
1192 return 1;
1193 if (gotcha)
1194 (*gotcha)++;
1195 return 0;
1198 #define FMT_CC_AND_BCC { \
1199 if (hp->h_cc != NULL && w & GCC) { \
1200 if (fmt("Cc:", hp->h_cc, fo, \
1201 w&(GCOMMA|GFILES), 0, \
1202 action!=SEND_TODISP)) \
1203 return 1; \
1204 gotcha++; \
1206 if (hp->h_bcc != NULL && w & GBCC) { \
1207 if (fmt("Bcc:", hp->h_bcc, fo, \
1208 w&(GCOMMA|GFILES), 0, \
1209 action!=SEND_TODISP)) \
1210 return 1; \
1211 gotcha++; \
1215 * Dump the to, subject, cc header on the
1216 * passed file buffer.
1219 puthead(struct header *hp, FILE *fo, enum gfield w,
1220 enum sendaction action, enum conversion convert,
1221 char *contenttype, char *charset)
1223 int gotcha;
1224 char *addr/*, *cp*/;
1225 int stealthmua;
1226 struct name *np, *fromfield = NULL, *senderfield = NULL;
1229 if ((addr = value("stealthmua")) != NULL) {
1230 stealthmua = (strcmp(addr, "noagent") == 0) ? -1 : 1;
1231 } else
1232 stealthmua = 0;
1233 gotcha = 0;
1234 if (w & GDATE) {
1235 mkdate(fo, "Date"), gotcha++;
1237 if (w & GIDENT) {
1238 if (hp->h_from != NULL) {
1239 if (fmt("From:", hp->h_from, fo, w&(GCOMMA|GFILES), 0,
1240 action!=SEND_TODISP))
1241 return 1;
1242 gotcha++;
1243 fromfield = hp->h_from;
1244 } else if ((addr = myaddrs(hp)) != NULL)
1245 if (putname(addr, w, action, &gotcha, "From:", fo,
1246 &fromfield))
1247 return 1;
1248 if (((addr = hp->h_organization) != NULL ||
1249 (addr = value("ORGANIZATION")) != NULL)
1250 && strlen(addr) > 0) {
1251 fwrite("Organization: ", sizeof (char), 14, fo);
1252 if (mime_write(addr, strlen(addr), fo,
1253 action == SEND_TODISP ?
1254 CONV_NONE:CONV_TOHDR,
1255 action == SEND_TODISP ?
1256 TD_ISPR|TD_ICONV:TD_ICONV,
1257 NULL, (size_t)0,
1258 NULL, NULL) == 0)
1259 return 1;
1260 gotcha++;
1261 putc('\n', fo);
1263 if (hp->h_replyto != NULL) {
1264 if (fmt("Reply-To:", hp->h_replyto, fo,
1265 w&(GCOMMA|GFILES), 0,
1266 action!=SEND_TODISP))
1267 return 1;
1268 gotcha++;
1269 } else if ((addr = value("replyto")) != NULL)
1270 if (putname(addr, w, action, &gotcha, "Reply-To:", fo,
1271 NULL))
1272 return 1;
1273 if (hp->h_sender != NULL) {
1274 if (fmt("Sender:", hp->h_sender, fo,
1275 w&(GCOMMA|GFILES), 0,
1276 action!=SEND_TODISP))
1277 return 1;
1278 gotcha++;
1279 senderfield = hp->h_sender;
1280 } else if ((addr = value("sender")) != NULL)
1281 if (putname(addr, w, action, &gotcha, "Sender:", fo,
1282 &senderfield))
1283 return 1;
1284 if (check_from_and_sender(fromfield, senderfield))
1285 return 1;
1287 if (hp->h_to != NULL && w & GTO) {
1288 if (fmt("To:", hp->h_to, fo, w&(GCOMMA|GFILES), 0,
1289 action!=SEND_TODISP))
1290 return 1;
1291 gotcha++;
1293 if (value("bsdcompat") == NULL && value("bsdorder") == NULL)
1294 FMT_CC_AND_BCC
1295 if (hp->h_subject != NULL && w & GSUBJECT) {
1296 fwrite("Subject: ", sizeof (char), 9, fo);
1297 if (ascncasecmp(hp->h_subject, "re: ", 4) == 0) {
1298 fwrite("Re: ", sizeof (char), 4, fo);
1299 if (strlen(hp->h_subject + 4) > 0 &&
1300 mime_write(hp->h_subject + 4,
1301 strlen(hp->h_subject + 4),
1302 fo, action == SEND_TODISP ?
1303 CONV_NONE:CONV_TOHDR,
1304 action == SEND_TODISP ?
1305 TD_ISPR|TD_ICONV:TD_ICONV,
1306 NULL, (size_t)0,
1307 NULL, NULL) == 0)
1308 return 1;
1309 } else if (*hp->h_subject) {
1310 if (mime_write(hp->h_subject,
1311 strlen(hp->h_subject),
1312 fo, action == SEND_TODISP ?
1313 CONV_NONE:CONV_TOHDR,
1314 action == SEND_TODISP ?
1315 TD_ISPR|TD_ICONV:TD_ICONV,
1316 NULL, (size_t)0,
1317 NULL, NULL) == 0)
1318 return 1;
1320 gotcha++;
1321 fwrite("\n", sizeof (char), 1, fo);
1323 if (value("bsdcompat") || value("bsdorder"))
1324 FMT_CC_AND_BCC
1325 if (w & GMSGID && stealthmua <= 0)
1326 message_id(fo, hp), gotcha++;
1327 if ((np = hp->h_ref) != NULL && w & GREF) {
1328 fmt("References:", np, fo, 0, 1, 0);
1329 if (np->n_name) {
1330 while (np->n_flink)
1331 np = np->n_flink;
1332 if (is_addr_invalid(np, 0) == 0) {
1333 fprintf(fo, "In-Reply-To: %s\n", np->n_name);
1334 gotcha++;
1338 if (w & GUA && stealthmua == 0)
1339 fprintf(fo, "User-Agent: %s %s\n", uagent, version), gotcha++;
1340 if (w & GMIME) {
1341 fputs("MIME-Version: 1.0\n", fo), gotcha++;
1342 if (hp->h_attach != NULL) {
1343 makeboundary();
1344 fprintf(fo, "Content-Type: multipart/mixed;\n"
1345 " boundary=\"%s\"\n", send_boundary);
1346 } else {
1347 fprintf(fo, "Content-Type: %s", contenttype);
1348 if (charset)
1349 fprintf(fo, "; charset=%s", charset);
1350 fprintf(fo, "\nContent-Transfer-Encoding: %s\n",
1351 getencoding(convert));
1354 if (gotcha && w & GNL)
1355 putc('\n', fo);
1356 return(0);
1360 * Format the given header line to not exceed 72 characters.
1362 static int
1363 fmt(char *str, struct name *np, FILE *fo, int flags, int dropinvalid,
1364 int domime)
1366 enum {
1367 m_INIT = 1<<0,
1368 m_COMMA = 1<<1,
1369 m_NOPF = 1<<2,
1370 m_CSEEN = 1<<3
1371 } m = (flags & GCOMMA) ? m_COMMA : 0;
1372 int col, len;
1374 col = strlen(str);
1375 if (col) {
1376 fwrite(str, sizeof *str, strlen(str), fo);
1377 if ((flags&GFILES) == 0 && ! value("add-file-recipients") &&
1378 ((col == 3 && ((asccasecmp(str, "to:") == 0) ||
1379 asccasecmp(str, "cc:") == 0)) ||
1380 (col == 4 && asccasecmp(str, "bcc:") == 0) ||
1381 (col == 10 &&
1382 asccasecmp(str, "Resent-To:") == 0)))
1383 m |= m_NOPF;
1385 for (; np != NULL; np = np->n_flink) {
1386 if ((m & m_NOPF) && is_fileorpipe_addr(np))
1387 continue;
1388 if (is_addr_invalid(np, ! dropinvalid)) {
1389 if (dropinvalid)
1390 continue;
1391 else
1392 return (1);
1394 if ((m & (m_INIT | m_COMMA)) == (m_INIT | m_COMMA)) {
1395 putc(',', fo);
1396 m |= m_CSEEN;
1397 ++col;
1399 len = strlen(np->n_fullname);
1400 ++col; /* The separating space */
1401 if ((m & m_INIT) && col > 1 && col + len > 72) {
1402 fputs("\n ", fo);
1403 col = 1;
1404 m &= ~m_CSEEN;
1405 } else
1406 putc(' ', fo);
1407 m = (m & ~m_CSEEN) | m_INIT;
1408 len = mime_write(np->n_fullname,
1409 len, fo,
1410 domime?CONV_TOHDR_A:CONV_NONE,
1411 TD_ICONV, NULL, (size_t)0,
1412 NULL, NULL);
1413 col += len;
1415 putc('\n', fo);
1416 return (0);
1420 * Rewrite a message for resending, adding the Resent-Headers.
1422 static int
1423 infix_resend(FILE *fi, FILE *fo, struct message *mp, struct name *to,
1424 int add_resent)
1426 size_t count;
1427 char *buf = NULL, *cp/*, *cp2*/;
1428 size_t c, bufsize = 0;
1429 struct name *fromfield = NULL, *senderfield = NULL;
1431 count = mp->m_size;
1433 * Write the Resent-Fields.
1435 if (add_resent) {
1436 fputs("Resent-", fo);
1437 mkdate(fo, "Date");
1438 if ((cp = myaddrs(NULL)) != NULL) {
1439 if (putname(cp, GCOMMA, SEND_MBOX, NULL,
1440 "Resent-From:", fo, &fromfield))
1441 return 1;
1443 if ((cp = value("sender")) != NULL) {
1444 if (putname(cp, GCOMMA, SEND_MBOX, NULL,
1445 "Resent-Sender:", fo, &senderfield))
1446 return 1;
1448 if (fmt("Resent-To:", to, fo, 1, 1, 0)) {
1449 if (buf)
1450 free(buf);
1451 return 1;
1453 if ((cp = value("stealthmua")) == NULL ||
1454 strcmp(cp, "noagent") == 0) {
1455 fputs("Resent-", fo);
1456 message_id(fo, NULL);
1459 if (check_from_and_sender(fromfield, senderfield))
1460 return 1;
1462 * Write the original headers.
1464 while (count > 0) {
1465 if ((cp = foldergets(&buf, &bufsize, &count, &c, fi)) == NULL)
1466 break;
1467 if (ascncasecmp("status: ", buf, 8) != 0
1468 && strncmp("From ", buf, 5) != 0) {
1469 fwrite(buf, sizeof *buf, c, fo);
1471 if (count > 0 && *buf == '\n')
1472 break;
1475 * Write the message body.
1477 while (count > 0) {
1478 if (foldergets(&buf, &bufsize, &count, &c, fi) == NULL)
1479 break;
1480 if (count == 0 && *buf == '\n')
1481 break;
1482 fwrite(buf, sizeof *buf, c, fo);
1484 if (buf)
1485 free(buf);
1486 if (ferror(fo)) {
1487 perror(catgets(catd, CATSET, 188, "temporary mail file"));
1488 return 1;
1490 return 0;
1493 enum okay
1494 resend_msg(struct message *mp, struct name *to, int add_resent)
1496 FILE *ibuf, *nfo, *nfi;
1497 char *tempMail;
1498 struct header head;
1499 enum okay ok = STOP;
1501 memset(&head, 0, sizeof head);
1502 if ((to = checkaddrs(to)) == NULL) {
1503 senderr++;
1504 return STOP;
1506 if ((nfo = Ftemp(&tempMail, "Rs", "w", 0600, 1)) == NULL) {
1507 senderr++;
1508 perror(catgets(catd, CATSET, 189, "temporary mail file"));
1509 return STOP;
1511 if ((nfi = Fopen(tempMail, "r")) == NULL) {
1512 senderr++;
1513 perror(tempMail);
1514 return STOP;
1516 rm(tempMail);
1517 Ftfree(&tempMail);
1518 if ((ibuf = setinput(&mb, mp, NEED_BODY)) == NULL)
1519 return STOP;
1520 head.h_to = to;
1521 to = fixhead(&head, to);
1522 if (infix_resend(ibuf, nfo, mp, head.h_to, add_resent) != 0) {
1523 senderr++;
1524 rewind(nfo);
1525 savedeadletter(nfi);
1526 fputs(catgets(catd, CATSET, 190,
1527 ". . . message not sent.\n"), stderr);
1528 Fclose(nfo);
1529 Fclose(nfi);
1530 return STOP;
1532 fflush(nfo);
1533 rewind(nfo);
1534 Fclose(nfo);
1535 to = outof(to, nfi, &head);
1536 if (senderr)
1537 savedeadletter(nfi);
1538 to = elide(to);
1539 if (count(to) != 0) {
1540 if (value("record-resent") == NULL ||
1541 mightrecord(nfi, to, 0) == OKAY)
1542 ok = transfer(to, nfi, NULL);
1543 } else if (senderr == 0)
1544 ok = OKAY;
1545 Fclose(nfi);
1546 return ok;