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
35 static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93";
42 * Mail -- a mail program
48 * Send message described by the passed pointer to the
49 * passed output buffer. Return -1 on error.
50 * Adjust the status: field if need be.
51 * If doign is given, suppress ignored header fields.
52 * prefix is a string to prepend to each output line.
55 send(mp, obuf, doign, prefix)
56 register struct message *mp;
58 struct ignoretab *doign;
64 int ishead, infld, ignoring, dostat, firstline;
65 register char *cp, *cp2;
71 * Compute the prefix string, without trailing whitespace
73 if (prefix != NOSTR) {
75 for (cp = prefix; *cp; cp++)
76 if (*cp != ' ' && *cp != '\t')
78 prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1;
83 dostat = doign == 0 || !isign("status", doign);
87 * Process headers first
89 while (count > 0 && ishead) {
90 if (fgets(line, LINESIZE, ibuf) == NULL)
92 count -= length = strlen(line);
95 * First line is the From line, so no headers
96 * there to worry about
99 ignoring = doign == ignoreall;
100 } else if (line[0] == '\n') {
102 * If line is blank, we've reached end of
103 * headers, so force out status: field
104 * and note that we are no longer in header
108 statusput(mp, obuf, prefix);
112 ignoring = doign == ignoreall;
113 } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
115 * If this line is a continuation (via space or tab)
116 * of a previous header field, just echo it
117 * (unless the field should be ignored).
118 * In other words, nothing to do.
122 * Pick up the header field if we have one.
124 for (cp = line; (c = *cp++) && c != ':' && !isspace(c);)
127 while (isspace(*cp++))
131 * Not a header line, force out status:
132 * This happens in uucp style mail where
133 * there are no headers at all.
136 statusput(mp, obuf, prefix);
139 if (doign != ignoreall)
141 (void) putc('\n', obuf);
146 * If it is an ignored field and
147 * we care about such things, skip it.
149 *cp2 = 0; /* temporarily null terminate */
150 if (doign && isign(line, doign))
152 else if ((line[0] == 's' || line[0] == 'S') &&
153 strcasecmp(line, "status") == 0) {
155 * If the field is "status," go compute
156 * and print the real Status: field
159 statusput(mp, obuf, prefix);
165 *cp2 = c; /* restore */
172 * Strip trailing whitespace from prefix
179 (void) fwrite(prefix, sizeof *prefix,
181 (void) fwrite(line, sizeof *line, length, obuf);
187 * Copy out message body
189 if (doign == ignoreall)
190 count--; /* skip final blank line */
193 if (fgets(line, LINESIZE, ibuf) == NULL) {
197 count -= c = strlen(line);
199 * Strip trailing whitespace from prefix
205 (void) fwrite(prefix, sizeof *prefix,
207 (void) fwrite(line, sizeof *line, c, obuf);
213 c = count < LINESIZE ? count : LINESIZE;
214 if ((c = fread(line, sizeof *line, c, ibuf)) <= 0)
217 if (fwrite(line, sizeof *line, c, obuf) != c)
220 if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
221 /* no final blank line */
222 if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
228 * Output a reasonable looking status field.
231 statusput(mp, obuf, prefix)
232 register struct message *mp;
237 register char *cp = statout;
239 if (mp->m_flag & MREAD)
241 if ((mp->m_flag & MNEW) == 0)
245 fprintf(obuf, "%sStatus: %s\n",
246 prefix == NOSTR ? "" : prefix, statout);
250 * Interface between the argument list and the mail1 routine
251 * which does all the dirty work.
254 mail(to, cc, bcc, smopts, subject)
255 struct name *to, *cc, *bcc, *smopts;
261 head.h_subject = subject;
264 head.h_smopts = smopts;
271 * Send mail to a bunch of user names. The interface is through
272 * the mail routine below.
280 head.h_to = extract(str, GTO);
281 head.h_subject = NOSTR;
290 * Mail a message on standard input to the people indicated
291 * in the passed header. (Internal interface).
294 mail1(hp, printheaders)
305 * Collect user's mail from standard input.
306 * Get the result as mtf.
308 if ((mtf = collect(hp, printheaders)) == NULL)
310 if (value("interactive") != NOSTR)
311 if (value("askcc") != NOSTR)
315 (void) fflush(stdout);
318 if (hp->h_subject == NOSTR)
319 printf("No message, no subject; hope that's ok\n");
321 printf("Null message body; hope that's ok\n");
323 * Now, take the user names from the combined
324 * to and cc lists and do all the alias
328 to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
330 printf("No recipients specified\n");
334 * Look through the recipient list for names with /'s
335 * in them which we write to as files directly.
337 to = outof(to, mtf, hp);
344 if ((mtf = infix(hp, mtf)) == NULL) {
345 fprintf(stderr, ". . . message lost, sorry.\n");
348 namelist = unpack(cat(hp->h_smopts, to));
352 printf("Sendmail arguments:");
353 for (t = namelist; *t != NOSTR; t++)
354 printf(" \"%s\"", *t);
358 if ((cp = value("record")) != NOSTR)
359 (void) savemail(expand(cp), mtf);
361 * Fork, set up the temporary mail file as standard
362 * input for "mail", and exec with the user list we generated
372 prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)|
373 sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU),
375 if ((cp = value("sendmail")) != NOSTR)
383 if (value("verbose") != NOSTR)
384 (void) wait_child(pid);
392 * Fix the header by glopping all of the expanded names from
393 * the distribution list into the appropriate fields.
400 register struct name *np;
405 for (np = tolist; np != NIL; np = np->n_flink)
406 if ((np->n_type & GMASK) == GTO)
408 cat(hp->h_to, nalloc(np->n_name, np->n_type));
409 else if ((np->n_type & GMASK) == GCC)
411 cat(hp->h_cc, nalloc(np->n_name, np->n_type));
412 else if ((np->n_type & GMASK) == GBCC)
414 cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
418 * Prepend a header in front of the collected stuff
419 * and return the new file.
426 extern char tempMail[];
427 register FILE *nfo, *nfi;
430 if ((nfo = Fopen(tempMail, "w")) == NULL) {
434 if ((nfi = Fopen(tempMail, "r")) == NULL) {
440 (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
466 * Dump the to, subject, cc header on the
467 * passed file buffer.
478 if (hp->h_to != NIL && w & GTO)
479 fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
480 if (hp->h_subject != NOSTR && w & GSUBJECT)
481 fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
482 if (hp->h_cc != NIL && w & GCC)
483 fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
484 if (hp->h_bcc != NIL && w & GBCC)
485 fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
486 if (gotcha && w & GNL)
487 (void) putc('\n', fo);
492 * Format the given header line to not exceed 72 characters.
495 fmt(str, np, fo, comma)
497 register struct name *np;
503 comma = comma ? 1 : 0;
507 for (; np != NIL; np = np->n_flink) {
508 if (np->n_flink == NIL)
510 len = strlen(np->n_name);
511 col++; /* for the space */
512 if (col + len + comma > 72 && col > 4) {
517 fputs(np->n_name, fo);
526 * Save the outgoing mail on the passed file.
541 if ((fo = Fopen(name, "a")) == NULL) {
546 fprintf(fo, "From %s %s", myname, ctime(&now));
547 while ((i = fread(buf, 1, sizeof buf, fi)) > 0)
548 (void) fwrite(buf, 1, i, fo);
549 (void) putc('\n', fo);