]>
git.cameronkatri.com Git - apple_cmds.git/blob - mail_cmds/mail/send.c
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 static char sccsid
[] = "@(#)send.c 8.1 (Berkeley) 6/6/93";
38 static const char rcsid
[] =
39 "$FreeBSD: src/usr.bin/mail/send.c,v 1.14 2004/02/29 20:44:44 mikeh Exp $";
42 #include <sys/cdefs.h>
48 * Mail -- a mail program
54 * Send message described by the passed pointer to the
55 * passed output buffer. Return -1 on error.
56 * Adjust the status: field if need be.
57 * If doign is given, suppress ignored header fields.
58 * prefix is a string to prepend to each output line.
61 sendmessage(mp
, obuf
, doign
, prefix
)
64 struct ignoretab
*doign
;
69 char *cp
, *cp2
, line
[LINESIZE
];
70 int ishead
, infld
, ignoring
= 0, dostat
, firstline
;
71 int c
= 0, length
, prefixlen
= 0;
74 * Compute the prefix string, without trailing whitespace
78 for (cp
= prefix
; *cp
!= '\0'; cp
++)
79 if (*cp
!= ' ' && *cp
!= '\t')
81 prefixlen
= cp2
== NULL
? 0 : cp2
- prefix
+ 1;
86 dostat
= doign
== 0 || !isign("status", doign
);
90 * Process headers first
92 while (count
> 0 && ishead
) {
93 if (fgets(line
, sizeof(line
), ibuf
) == NULL
)
95 count
-= length
= strlen(line
);
98 * First line is the From line, so no headers
99 * there to worry about
102 ignoring
= doign
== ignoreall
;
103 } else if (line
[0] == '\n') {
105 * If line is blank, we've reached end of
106 * headers, so force out status: field
107 * and note that we are no longer in header
111 statusput(mp
, obuf
, prefix
);
115 ignoring
= doign
== ignoreall
;
116 } else if (infld
&& (line
[0] == ' ' || line
[0] == '\t')) {
118 * If this line is a continuation (via space or tab)
119 * of a previous header field, just echo it
120 * (unless the field should be ignored).
121 * In other words, nothing to do.
125 * Pick up the header field if we have one.
127 for (cp
= line
; (c
= *cp
++) != '\0' && c
!= ':' &&
128 !isspace((unsigned char)c
);)
131 while (isspace((unsigned char)*cp
++))
135 * Not a header line, force out status:
136 * This happens in uucp style mail where
137 * there are no headers at all.
140 statusput(mp
, obuf
, prefix
);
143 if (doign
!= ignoreall
)
145 (void)putc('\n', obuf
);
150 * If it is an ignored field and
151 * we care about such things, skip it.
153 *cp2
= '\0'; /* temporarily null terminate */
154 if (doign
&& isign(line
, doign
))
156 else if ((line
[0] == 's' || line
[0] == 'S') &&
157 strcasecmp(line
, "status") == 0) {
159 * If the field is "status," go compute
160 * and print the real Status: field
163 statusput(mp
, obuf
, prefix
);
169 *cp2
= c
; /* restore */
176 * Strip trailing whitespace from prefix
179 if (prefix
!= NULL
) {
183 (void)fwrite(prefix
, sizeof(*prefix
),
186 (void)fwrite(line
, sizeof(*line
), length
, obuf
);
192 * Copy out message body
194 if (doign
== ignoreall
)
195 count
--; /* skip final blank line */
198 if (fgets(line
, sizeof(line
), ibuf
) == NULL
) {
202 count
-= c
= strlen(line
);
204 * Strip trailing whitespace from prefix
210 (void)fwrite(prefix
, sizeof(*prefix
),
212 (void)fwrite(line
, sizeof(*line
), c
, obuf
);
218 c
= count
< LINESIZE
? count
: LINESIZE
;
219 if ((c
= fread(line
, sizeof(*line
), c
, ibuf
)) <= 0)
222 if (fwrite(line
, sizeof(*line
), c
, obuf
) != c
)
225 if (doign
== ignoreall
&& c
> 0 && line
[c
- 1] != '\n')
226 /* no final blank line */
227 if ((c
= getc(ibuf
)) != EOF
&& putc(c
, obuf
) == EOF
)
233 * Output a reasonable looking status field.
236 statusput(mp
, obuf
, prefix
)
244 if (mp
->m_flag
& MREAD
)
246 if ((mp
->m_flag
& MNEW
) == 0)
249 if (statout
[0] != '\0')
250 fprintf(obuf
, "%sStatus: %s\n",
251 prefix
== NULL
? "" : prefix
, statout
);
255 * Interface between the argument list and the mail1 routine
256 * which does all the dirty work.
259 mail(to
, cc
, bcc
, smopts
, subject
, replyto
)
260 struct name
*to
, *cc
, *bcc
, *smopts
;
261 char *subject
, *replyto
;
266 head
.h_subject
= subject
;
269 head
.h_smopts
= smopts
;
270 head
.h_replyto
= replyto
;
271 head
.h_inreplyto
= NULL
;
278 * Send mail to a bunch of user names. The interface is through
279 * the mail routine below.
287 head
.h_to
= extract(str
, GTO
);
288 head
.h_subject
= NULL
;
291 head
.h_smopts
= NULL
;
292 head
.h_replyto
= value("REPLYTO");
293 head
.h_inreplyto
= NULL
;
299 * Mail a message on standard input to the people indicated
300 * in the passed header. (Internal interface).
303 mail1(hp
, printheaders
)
311 struct name
*to
, *nsto
= NULL
;
315 * Collect user's mail from standard input.
316 * Get the result as mtf.
318 if ((mtf
= collect(hp
, printheaders
)) == NULL
)
320 if (value("interactive") != NULL
) {
321 if (value("askcc") != NULL
|| value("askbcc") != NULL
) {
322 if (value("askcc") != NULL
)
324 if (value("askbcc") != NULL
)
328 (void)fflush(stdout
);
331 if (fsize(mtf
) == 0) {
332 if (value("dontsendempty") != NULL
)
334 if (hp
->h_subject
== NULL
)
335 printf("No message, no subject; hope that's ok\n");
337 printf("Null message body; hope that's ok\n");
340 * Now, take the user names from the combined
341 * to and cc lists and do all the alias
345 to
= usermap(cat(hp
->h_bcc
, cat(hp
->h_to
, hp
->h_cc
)));
347 printf("No recipients specified\n");
351 * Look through the recipient list for names with /'s
352 * in them which we write to as files directly.
354 to
= outof(to
, mtf
, hp
);
360 if (value("recordrecip") != NULL
) {
362 * Before fixing the header, save old To:.
363 * We do this because elide above has sorted To: list, and
364 * we would like to save message in a file named by the first
365 * recipient the user has entered, not the one being the first
366 * after sorting happened.
368 if ((nsto
= malloc(sizeof(struct name
))) == NULL
)
369 err(1, "Out of memory");
370 bcopy(hp
->h_to
, nsto
, sizeof(struct name
));
373 if ((mtf
= infix(hp
, mtf
)) == NULL
) {
374 fprintf(stderr
, ". . . message lost, sorry.\n");
377 namelist
= unpack(cat(hp
->h_smopts
, to
));
381 printf("Sendmail arguments:");
382 for (t
= namelist
; *t
!= NULL
; t
++)
383 printf(" \"%s\"", *t
);
387 if (value("recordrecip") != NULL
) {
389 * Extract first recipient username from saved To: and use it
392 if ((nbuf
= malloc(strlen(detract(nsto
, 0)) + 1)) == NULL
)
393 err(1, "Out of memory");
394 if ((cp
= yanklogin(detract(nsto
, 0), nbuf
)) != NULL
)
395 (void)savemail(expand(nbuf
), mtf
);
398 } else if ((cp
= value("record")) != NULL
) {
399 char * expanded_record_name
= expand(cp
);
400 char * outfolder
= value("outfolder");
401 if ((outfolder
!= NULL
) && (*expanded_record_name
!= '/')) {
402 char xname
[PATHSIZE
];
403 if (getfold(xname
, sizeof(xname
)) >= 0) {
404 if (xname
[strlen(xname
)-1] != '/')
405 strlcat(xname
, "/", sizeof(xname
)); /* only when needed */
406 strlcat(xname
, expanded_record_name
, sizeof(xname
));
407 (void)savemail(xname
, mtf
);
408 } else { /* folder problem? - just save using "record" */
409 (void)savemail(expanded_record_name
, mtf
);
412 (void)savemail(expanded_record_name
, mtf
);
416 * Fork, set up the temporary mail file as standard
417 * input for "mail", and exec with the user list we generated
428 (void)sigemptyset(&nset
);
429 (void)sigaddset(&nset
, SIGHUP
);
430 (void)sigaddset(&nset
, SIGINT
);
431 (void)sigaddset(&nset
, SIGQUIT
);
432 (void)sigaddset(&nset
, SIGTSTP
);
433 (void)sigaddset(&nset
, SIGTTIN
);
434 (void)sigaddset(&nset
, SIGTTOU
);
435 prepare_child(&nset
, fileno(mtf
), -1);
436 if ((cp
= value("sendmail")) != NULL
)
444 if (value("verbose") != NULL
)
445 (void)wait_child(pid
);
453 * Fix the header by glopping all of the expanded names from
454 * the distribution list into the appropriate fields.
466 for (np
= tolist
; np
!= NULL
; np
= np
->n_flink
) {
467 /* Don't copy deleted addresses to the header */
468 if (np
->n_type
& GDEL
)
470 if ((np
->n_type
& GMASK
) == GTO
)
472 cat(hp
->h_to
, nalloc(np
->n_name
, np
->n_type
));
473 else if ((np
->n_type
& GMASK
) == GCC
)
475 cat(hp
->h_cc
, nalloc(np
->n_name
, np
->n_type
));
476 else if ((np
->n_type
& GMASK
) == GBCC
)
478 cat(hp
->h_bcc
, nalloc(np
->n_name
, np
->n_type
));
483 * Prepend a header in front of the collected stuff
484 * and return the new file.
493 char tempname
[PATHSIZE
];
495 (void)snprintf(tempname
, sizeof(tempname
),
496 "%s/mail.RsXXXXXXXXXX", tmpdir
);
497 if ((fd
= mkstemp(tempname
)) == -1 ||
498 (nfo
= Fdopen(fd
, "w")) == NULL
) {
499 warn("%s", tempname
);
502 if ((nfi
= Fopen(tempname
, "r")) == NULL
) {
503 warn("%s", tempname
);
509 (void)puthead(hp
, nfo
,
510 GTO
|GSUBJECT
|GCC
|GBCC
|GREPLYTO
|GINREPLYTO
|GNL
|GCOMMA
);
523 warn("%s", tempname
);
536 * Dump the to, subject, cc header on the
537 * passed file buffer.
548 if (hp
->h_to
!= NULL
&& w
& GTO
)
549 fmt("To:", hp
->h_to
, fo
, w
&GCOMMA
), gotcha
++;
550 if (hp
->h_subject
!= NULL
&& w
& GSUBJECT
)
551 fprintf(fo
, "Subject: %s\n", hp
->h_subject
), gotcha
++;
552 if (hp
->h_cc
!= NULL
&& w
& GCC
)
553 fmt("Cc:", hp
->h_cc
, fo
, w
&GCOMMA
), gotcha
++;
554 if (hp
->h_bcc
!= NULL
&& w
& GBCC
)
555 fmt("Bcc:", hp
->h_bcc
, fo
, w
&GCOMMA
), gotcha
++;
556 if (hp
->h_replyto
!= NULL
&& w
& GREPLYTO
)
557 fprintf(fo
, "Reply-To: %s\n", hp
->h_replyto
), gotcha
++;
558 if (hp
->h_inreplyto
!= NULL
&& w
& GINREPLYTO
)
559 fprintf(fo
, "In-Reply-To: <%s>\n", hp
->h_inreplyto
), gotcha
++;
560 if (gotcha
&& w
& GNL
)
561 (void)putc('\n', fo
);
566 * Format the given header line to not exceed 72 characters.
569 fmt(str
, np
, fo
, comma
)
577 comma
= comma
? 1 : 0;
581 for (; np
!= NULL
; np
= np
->n_flink
) {
582 if (np
->n_flink
== NULL
)
584 len
= strlen(np
->n_name
);
585 col
++; /* for the space */
586 if (col
+ len
+ comma
> 72 && col
> 4) {
591 fputs(np
->n_name
, fo
);
600 * Save the outgoing mail on the passed file.
614 if ((fo
= Fopen(name
, "a")) == NULL
) {
619 fprintf(fo
, "From %s %s", myname
, ctime(&now
));
620 while ((i
= fread(buf
, 1, sizeof(buf
), fi
)) > 0)
621 (void)fwrite(buf
, 1, i
, fo
);