2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#)send.c 8.1 (Berkeley) 6/6/93
30 * $FreeBSD: src/usr.bin/mail/send.c,v 1.5.6.5 2003/01/06 05:46:03 mikeh Exp $
37 * Mail -- a mail program
43 * Send message described by the passed pointer to the
44 * passed output buffer. Return -1 on error.
45 * Adjust the status: field if need be.
46 * If doign is given, suppress ignored header fields.
47 * prefix is a string to prepend to each output line.
50 sendmessage(struct message
*mp
, FILE *obuf
, struct ignoretab
*doign
,
55 char *cp
, *cp2
, line
[LINESIZE
];
56 int ishead
, infld
, ignoring
, dostat
, firstline
;
57 int c
, length
, prefixlen
;
60 * Compute the prefix string, without trailing whitespace
64 for (cp
= prefix
; *cp
!= '\0'; cp
++)
65 if (*cp
!= ' ' && *cp
!= '\t')
67 prefixlen
= cp2
== NULL
? 0 : cp2
- prefix
+ 1;
72 dostat
= doign
== NULL
|| !isign("status", doign
);
76 * Process headers first
78 while (count
> 0 && ishead
) {
79 if (fgets(line
, sizeof(line
), ibuf
) == NULL
)
81 count
-= length
= strlen(line
);
84 * First line is the From line, so no headers
85 * there to worry about
88 ignoring
= doign
== ignoreall
;
89 } else if (line
[0] == '\n') {
91 * If line is blank, we've reached end of
92 * headers, so force out status: field
93 * and note that we are no longer in header
97 statusput(mp
, obuf
, prefix
);
101 ignoring
= doign
== ignoreall
;
102 } else if (infld
&& (line
[0] == ' ' || line
[0] == '\t')) {
104 * If this line is a continuation (via space or tab)
105 * of a previous header field, just echo it
106 * (unless the field should be ignored).
107 * In other words, nothing to do.
111 * Pick up the header field if we have one.
113 for (cp
= line
; (c
= *cp
++) != '\0' && c
!= ':' &&
114 !isspace((unsigned char)c
);)
117 while (isspace((unsigned char)*cp
++))
121 * Not a header line, force out status:
122 * This happens in uucp style mail where
123 * there are no headers at all.
126 statusput(mp
, obuf
, prefix
);
129 if (doign
!= ignoreall
)
136 * If it is an ignored field and
137 * we care about such things, skip it.
139 *cp2
= '\0'; /* temporarily null terminate */
140 if (doign
&& isign(line
, doign
))
142 else if ((line
[0] == 's' || line
[0] == 'S') &&
143 strcasecmp(line
, "status") == 0) {
145 * If the field is "status," go compute
146 * and print the real Status: field
149 statusput(mp
, obuf
, prefix
);
155 *cp2
= c
; /* restore */
162 * Strip trailing whitespace from prefix
165 if (prefix
!= NULL
) {
169 fwrite(prefix
, sizeof(*prefix
),
172 fwrite(line
, sizeof(*line
), length
, obuf
);
178 * Copy out message body
180 if (doign
== ignoreall
)
181 count
--; /* skip final blank line */
184 if (fgets(line
, sizeof(line
), ibuf
) == NULL
) {
188 count
-= c
= strlen(line
);
190 * Strip trailing whitespace from prefix
196 fwrite(prefix
, sizeof(*prefix
),
198 fwrite(line
, sizeof(*line
), c
, obuf
);
204 c
= count
< LINESIZE
? count
: LINESIZE
;
205 if ((c
= fread(line
, sizeof(*line
), c
, ibuf
)) <= 0)
208 if (fwrite(line
, sizeof(*line
), c
, obuf
) != c
)
211 if (doign
== ignoreall
&& c
> 0 && line
[c
- 1] != '\n')
212 /* no final blank line */
213 if ((c
= getc(ibuf
)) != EOF
&& putc(c
, obuf
) == EOF
)
219 * Output a reasonable looking status field.
222 statusput(struct message
*mp
, FILE *obuf
, char *prefix
)
227 if (mp
->m_flag
& MREAD
)
229 if ((mp
->m_flag
& MNEW
) == 0)
232 if (statout
[0] != '\0')
233 fprintf(obuf
, "%sStatus: %s\n",
234 prefix
== NULL
? "" : prefix
, statout
);
238 * Interface between the argument list and the mail1 routine
239 * which does all the dirty work.
242 mail(struct name
*to
, struct name
*cc
, struct name
*bcc
, struct name
*smopts
,
243 char *subject
, char *replyto
)
248 head
.h_subject
= subject
;
251 head
.h_smopts
= smopts
;
252 head
.h_replyto
= replyto
;
253 head
.h_inreplyto
= NULL
;
260 * Send mail to a bunch of user names. The interface is through
261 * the mail routine below.
268 head
.h_to
= extract(str
, GTO
);
269 head
.h_subject
= NULL
;
272 head
.h_smopts
= NULL
;
273 head
.h_replyto
= value("REPLYTO");
274 head
.h_inreplyto
= NULL
;
280 * Mail a message on standard input to the people indicated
281 * in the passed header. (Internal interface).
284 mail1(struct header
*hp
, int printheaders
)
290 struct name
*to
, *nsto
;
294 * Collect user's mail from standard input.
295 * Get the result as mtf.
297 if ((mtf
= collect(hp
, printheaders
)) == NULL
)
299 if (value("interactive") != NULL
) {
300 if (value("askcc") != NULL
|| value("askbcc") != NULL
) {
301 if (value("askcc") != NULL
)
303 if (value("askbcc") != NULL
)
310 if (fsize(mtf
) == 0) {
311 if (value("dontsendempty") != NULL
)
313 if (hp
->h_subject
== NULL
)
314 printf("No message, no subject; hope that's ok\n");
316 printf("Null message body; hope that's ok\n");
319 * Now, take the user names from the combined
320 * to and cc lists and do all the alias
324 to
= usermap(cat(hp
->h_bcc
, cat(hp
->h_to
, hp
->h_cc
)));
326 printf("No recipients specified\n");
330 * Look through the recipient list for names with /'s
331 * in them which we write to as files directly.
333 to
= outof(to
, mtf
, hp
);
339 if (value("recordrecip") != NULL
) {
341 * Before fixing the header, save old To:.
342 * We do this because elide above has sorted To: list,
343 * and we would like to save the message in a file named by
344 * the first recipient the user has entered, not the one being
345 * the first after sorting happened.
347 if ((nsto
= malloc(sizeof(struct name
))) == NULL
)
348 err(1, "Out of memory");
349 bcopy(hp
->h_to
, nsto
, sizeof(struct name
));
352 if ((mtf
= infix(hp
, mtf
)) == NULL
) {
353 fprintf(stderr
, ". . . message lost, sorry.\n");
356 namelist
= unpack(cat(hp
->h_smopts
, to
));
360 printf("Sendmail arguments:");
361 for (t
= namelist
; *t
!= NULL
; t
++)
362 printf(" \"%s\"", *t
);
366 if (value("recordrecip") != NULL
) {
368 * Extract first recipient username from save To: and use it
371 if ((nbuf
= malloc(strlen(detract(nsto
, 0)) + 1)) == NULL
)
372 err(1, "Out of memory");
373 if ((cp
= yanklogin(detract(nsto
, 0), nbuf
)) != NULL
)
374 savemail(expand(nbuf
), mtf
);
377 } else if ((cp
= value("record")) != NULL
)
378 savemail(expand(cp
), mtf
);
380 * Fork, set up the temporary mail file as standard
381 * input for "mail", and exec with the user list we generated
393 sigaddset(&nset
, SIGHUP
);
394 sigaddset(&nset
, SIGINT
);
395 sigaddset(&nset
, SIGQUIT
);
396 sigaddset(&nset
, SIGTSTP
);
397 sigaddset(&nset
, SIGTTIN
);
398 sigaddset(&nset
, SIGTTOU
);
399 prepare_child(&nset
, fileno(mtf
), -1);
400 if ((cp
= value("sendmail")) != NULL
)
408 if (value("verbose") != NULL
)
417 * Fix the header by glopping all of the expanded names from
418 * the distribution list into the appropriate fields.
421 fixhead(struct header
*hp
, struct name
*tolist
)
428 for (np
= tolist
; np
!= NULL
; np
= np
->n_flink
) {
429 /* Don't copy deleted addresses to the header */
430 if (np
->n_type
& GDEL
)
432 if ((np
->n_type
& GMASK
) == GTO
)
434 cat(hp
->h_to
, nalloc(np
->n_name
, np
->n_type
));
435 else if ((np
->n_type
& GMASK
) == GCC
)
437 cat(hp
->h_cc
, nalloc(np
->n_name
, np
->n_type
));
438 else if ((np
->n_type
& GMASK
) == GBCC
)
440 cat(hp
->h_bcc
, nalloc(np
->n_name
, np
->n_type
));
445 * Prepend a header in front of the collected stuff
446 * and return the new file.
449 infix(struct header
*hp
, FILE *fi
)
453 char tempname
[PATHSIZE
];
455 snprintf(tempname
, sizeof(tempname
), "%s/mail.RsXXXXXXXXXX", tmpdir
);
456 if ((fd
= mkstemp(tempname
)) == -1 ||
457 (nfo
= Fdopen(fd
, "w")) == NULL
) {
458 warn("%s", tempname
);
461 if ((nfi
= Fopen(tempname
, "r")) == NULL
) {
462 warn("%s", tempname
);
468 puthead(hp
, nfo
, GTO
|GSUBJECT
|GCC
|GBCC
|GREPLYTO
|GINREPLYTO
|GNL
|GCOMMA
);
481 warn("%s", tempname
);
494 * Dump the to, subject, cc header on the
495 * passed file buffer.
498 puthead(struct header
*hp
, FILE *fo
, int w
)
503 if (hp
->h_to
!= NULL
&& w
& GTO
)
504 fmt("To:", hp
->h_to
, fo
, w
&GCOMMA
), gotcha
++;
505 if (hp
->h_subject
!= NULL
&& w
& GSUBJECT
)
506 fprintf(fo
, "Subject: %s\n", hp
->h_subject
), gotcha
++;
507 if (hp
->h_cc
!= NULL
&& w
& GCC
)
508 fmt("Cc:", hp
->h_cc
, fo
, w
&GCOMMA
), gotcha
++;
509 if (hp
->h_bcc
!= NULL
&& w
& GBCC
)
510 fmt("Bcc:", hp
->h_bcc
, fo
, w
&GCOMMA
), gotcha
++;
511 if (hp
->h_replyto
!= NULL
&& w
& GREPLYTO
)
512 fprintf(fo
, "Reply-To: %s\n", hp
->h_replyto
), gotcha
++;
513 if (hp
->h_inreplyto
!= NULL
&& w
& GINREPLYTO
)
514 fprintf(fo
, "In-Reply-To: <%s>\n", hp
->h_inreplyto
), gotcha
++;
515 if (gotcha
&& w
& GNL
)
521 * Format the given header line to not exceed 72 characters.
524 fmt(const char *str
, struct name
*np
, FILE *fo
, int comma
)
528 comma
= comma
? 1 : 0;
532 for (; np
!= NULL
; np
= np
->n_flink
) {
533 if (np
->n_flink
== NULL
)
535 len
= strlen(np
->n_name
);
536 col
++; /* for the space */
537 if (col
+ len
+ comma
> 72 && col
> 4) {
542 fputs(np
->n_name
, fo
);
551 * Save the outgoing mail on the passed file.
556 savemail(char *name
, FILE *fi
)
563 if ((fo
= Fopen(name
, "a")) == NULL
) {
568 fprintf(fo
, "From %s %s", myname
, ctime(&now
));
569 while ((i
= fread(buf
, 1, sizeof(buf
), fi
)) > 0)
570 fwrite(buf
, 1, i
, fo
);