1 # include <stdio.h>
2 # include <ctype.h>
3 # include <errno.h>
4 # include "sendmail.h"
5 
6 static char	SccsId[] = "@(#)collect.c	3.14	08/18/81";
7 
8 /*
9 **  COLLECT -- read & parse message header & make temp file.
10 **
11 **	Creates a temporary file name and copies the standard
12 **	input to that file.  While it is doing it, it looks for
13 **	"From:" and "Sender:" fields to use as the from-person
14 **	(but only if the -a flag is specified).  It prefers to
15 **	to use the "Sender:" field.
16 **
17 **	MIT seems to like to produce "Sent-By:" fields instead
18 **	of "Sender:" fields.  We used to catch this, but it turns
19 **	out that the "Sent-By:" field doesn't always correspond
20 **	to someone real ("___057", for instance), as required by
21 **	the protocol.  So we limp by.....
22 **
23 **	Parameters:
24 **		none
25 **
26 **	Returns:
27 **		Name of temp file.
28 **
29 **	Side Effects:
30 **		Temp file is created and filled.
31 **
32 **	Called By:
33 **		main
34 **
35 **	Notes:
36 **		This is broken off from main largely so that the
37 **		temp buffer can be deallocated.
38 */
39 
40 long	MsgSize;		/* size of message in bytes */
41 
42 char *
43 collect()
44 {
45 	register FILE *tf;
46 	char buf[MAXFIELD+1];
47 	register char *p;
48 	char c;
49 	extern bool isheader();
50 	char *xfrom;
51 	extern char *hvalue();
52 	extern char *mktemp();
53 	extern char *capitalize();
54 # ifdef DEBUG
55 	HDR *h;
56 # endif
57 
58 	/*
59 	**  Create the temp file name and create the file.
60 	*/
61 
62 	(void) mktemp(InFileName);
63 	(void) close(creat(InFileName, 0600));
64 	if ((tf = fopen(InFileName, "w")) == NULL)
65 	{
66 		syserr("Cannot create %s", InFileName);
67 		return (NULL);
68 	}
69 
70 	/* try to read a UNIX-style From line */
71 	if (fgets(buf, sizeof buf, stdin) == NULL)
72 		return (NULL);
73 	if (strncmp(buf, "From ", 5) == 0)
74 	{
75 		eatfrom(buf);
76 		(void) fgets(buf, sizeof buf, stdin);
77 	}
78 
79 	/*
80 	**  Copy stdin to temp file & do message editting.
81 	**	To keep certain mailers from getting confused,
82 	**	and to keep the output clean, lines that look
83 	**	like UNIX "From" lines are deleted in the header,
84 	**	and prepended with ">" in the body.
85 	*/
86 
87 	for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin))
88 	{
89 		/* see if the header is over */
90 		if (!isheader(buf))
91 			break;
92 
93 		/* get the rest of this field */
94 		while ((c = getc(stdin)) == ' ' || c == '\t')
95 		{
96 			p = &buf[strlen(buf)];
97 			*p++ = c;
98 			if (fgets(p, sizeof buf - (p - buf), stdin) == NULL)
99 				break;
100 		}
101 		if (!feof(stdin))
102 			(void) ungetc(c, stdin);
103 
104 		MsgSize += strlen(buf);
105 
106 		/*
107 		**  Snarf header away.
108 		*/
109 
110 		if (bitset(H_EOH, chompheader(buf, FALSE)))
111 			break;
112 	}
113 
114 # ifdef DEBUG
115 	if (Debug)
116 		printf("EOH\n");
117 # endif DEBUG
118 
119 	/* throw away a blank line */
120 	if (buf[0] == '\n')
121 		(void) fgets(buf, sizeof buf, stdin);
122 
123 	/*
124 	**  Collect the body of the message.
125 	*/
126 
127 	for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL)
128 	{
129 		register int i;
130 
131 		/* check for end-of-message */
132 		if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
133 			break;
134 
135 		/* Hide UNIX-like From lines */
136 		if (strncmp(buf, "From ", 5) == 0)
137 		{
138 			fputs(">", tf);
139 			MsgSize++;
140 		}
141 
142 		/*
143 		**  Figure message length, output the line to the temp
144 		**  file, and insert a newline if missing.
145 		*/
146 
147 		i = strlen(buf);
148 		MsgSize += i;
149 		fputs(buf, tf);
150 		if (buf[i - 1] != '\n')
151 			fputs("\n", tf);
152 		if (ferror(tf))
153 		{
154 			if (errno == ENOSPC)
155 			{
156 				(void) freopen(InFileName, "w", tf);
157 				fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
158 				syserr("Out of disk space for temp file");
159 			}
160 			else
161 				syserr("Cannot write %s", InFileName);
162 			(void) freopen("/dev/null", "w", tf);
163 		}
164 	}
165 	(void) fclose(tf);
166 
167 	/*
168 	**  Find out some information from the headers.
169 	**	Examples are who is the from person & the date.
170 	*/
171 
172 	/* from person */
173 	xfrom = hvalue("sender");
174 	if (xfrom == NULL)
175 		xfrom = hvalue("from");
176 
177 	/* full name of from person */
178 	p = hvalue("full-name");
179 	if (p != NULL)
180 		define('x', p);
181 
182 	/* date message originated */
183 	p = hvalue("posted-date");
184 	if (p == NULL)
185 		p = hvalue("date");
186 	if (p != NULL)
187 	{
188 		define('a', p);
189 		/* we don't have a good way to do canonical conversion ....
190 		define('d', newstr(arpatounix(p)));
191 		.... so we will ignore the problem for the time being */
192 	}
193 
194 	if (freopen(InFileName, "r", stdin) == NULL)
195 		syserr("Cannot reopen %s", InFileName);
196 
197 # ifdef DEBUG
198 	if (Debug)
199 	{
200 		printf("----- collected header -----\n");
201 		for (h = Header; h != NULL; h = h->h_link)
202 			printf("%s: %s\n", capitalize(h->h_field), h->h_value);
203 		printf("----------------------------\n");
204 	}
205 # endif DEBUG
206 	return (ArpaFmt ? xfrom : NULL);
207 }
208 /*
209 **  EATFROM -- chew up a UNIX style from line and process
210 **
211 **	This does indeed make some assumptions about the format
212 **	of UNIX messages.
213 **
214 **	Parameters:
215 **		fm -- the from line.
216 **
217 **	Returns:
218 **		none.
219 **
220 **	Side Effects:
221 **		extracts what information it can from the header,
222 **		such as the date.
223 */
224 
225 char	*MonthList[] =
226 {
227 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
228 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
229 	NULL
230 };
231 
232 eatfrom(fm)
233 	char *fm;
234 {
235 	register char *p;
236 	register char **dt;
237 
238 	/* find the date part */
239 	p = fm;
240 	while (*p != '\0')
241 	{
242 		/* skip a word */
243 		while (*p != '\0' && *p != ' ')
244 			*p++;
245 		while (*p == ' ')
246 			*p++;
247 		if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
248 			continue;
249 
250 		/* we have a possible date */
251 		for (dt = MonthList; *dt != NULL; dt++)
252 			if (strncmp(*dt, p, 3) == 0)
253 				break;
254 
255 		if (*dt != NULL)
256 			break;
257 	}
258 
259 	if (*p != NULL)
260 	{
261 		char *q;
262 
263 		/* we have found a date */
264 		q = xalloc(25);
265 		strncpy(q, p, 25);
266 		q[24] = '\0';
267 		define('d', q);
268 	}
269 }
270