1 # include <errno.h>
2 # include "sendmail.h"
3 
4 static char	SccsId[] = "@(#)collect.c	3.25	10/20/81";
5 
6 /*
7 **  COLLECT -- read & parse message header & make temp file.
8 **
9 **	Creates a temporary file name and copies the standard
10 **	input to that file.  While it is doing it, it looks for
11 **	"From:" and "Sender:" fields to use as the from-person
12 **	(but only if the -a flag is specified).  It prefers to
13 **	to use the "Sender:" field.
14 **
15 **	MIT seems to like to produce "Sent-By:" fields instead
16 **	of "Sender:" fields.  We used to catch this, but it turns
17 **	out that the "Sent-By:" field doesn't always correspond
18 **	to someone real ("___057", for instance), as required by
19 **	the protocol.  So we limp by.....
20 **
21 **	Parameters:
22 **		none
23 **
24 **	Returns:
25 **		none.
26 **
27 **	Side Effects:
28 **		Temp file is created and filled.
29 **		The from person may be set.
30 */
31 
32 long	MsgSize;		/* size of message in bytes */
33 FILE	*TempFile;		/* the tempfile (after creation) */
34 
35 collect()
36 {
37 	register FILE *tf;
38 	char buf[MAXFIELD+1];
39 	register char *p;
40 	char *xfrom;
41 	extern char *hvalue();
42 	extern char *mktemp();
43 
44 	/*
45 	**  Create the temp file name and create the file.
46 	*/
47 
48 	(void) mktemp(InFileName);
49 	(void) close(creat(InFileName, 0600));
50 	if ((tf = fopen(InFileName, "w")) == NULL)
51 	{
52 		syserr("Cannot create %s", InFileName);
53 		return;
54 	}
55 
56 	/*
57 	**  Tell ARPANET to go ahead.
58 	*/
59 
60 	if (ArpaMode == ARPA_MAIL)
61 	{
62 		extern char Arpa_Enter[];
63 
64 		message(Arpa_Enter, "Enter mail, end with \".\" on a line by itself");
65 	}
66 
67 	/*
68 	**  Try to read a UNIX-style From line
69 	*/
70 
71 	if (fgets(buf, sizeof buf, stdin) == NULL)
72 		return;
73 	fixcrlf(buf, FALSE);
74 # ifndef NOTUNIX
75 	if (!SaveFrom && strncmp(buf, "From ", 5) == 0)
76 	{
77 		eatfrom(buf);
78 		(void) fgets(buf, sizeof buf, stdin);
79 		fixcrlf(buf, FALSE);
80 	}
81 # endif NOTUNIX
82 
83 	/*
84 	**  Copy stdin to temp file & do message editting.
85 	**	To keep certain mailers from getting confused,
86 	**	and to keep the output clean, lines that look
87 	**	like UNIX "From" lines are deleted in the header,
88 	**	and prepended with ">" in the body.
89 	*/
90 
91 	for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin))
92 	{
93 		register char c;
94 		extern bool isheader();
95 
96 		fixcrlf(buf, FALSE);
97 
98 		/* see if the header is over */
99 		if (!isheader(buf))
100 			break;
101 
102 		/* get the rest of this field */
103 		while ((c = getc(stdin)) == ' ' || c == '\t')
104 		{
105 			p = &buf[strlen(buf)];
106 			*p++ = c;
107 			if (fgets(p, sizeof buf - (p - buf), stdin) == NULL)
108 				break;
109 			fixcrlf(p, FALSE);
110 		}
111 		if (!feof(stdin))
112 			(void) ungetc(c, stdin);
113 
114 		MsgSize += strlen(buf);
115 
116 		/*
117 		**  Snarf header away.
118 		*/
119 
120 		if (bitset(H_EOH, chompheader(buf, FALSE)))
121 			break;
122 	}
123 
124 # ifdef DEBUG
125 	if (Debug)
126 		printf("EOH\n");
127 # endif DEBUG
128 
129 	/* throw away a blank line */
130 	if (buf[0] == '\n')
131 	{
132 		(void) fgets(buf, sizeof buf, stdin);
133 		fixcrlf(buf, FALSE);
134 	}
135 
136 	/*
137 	**  Collect the body of the message.
138 	*/
139 
140 	for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL)
141 	{
142 		register int i;
143 		register char *bp = buf;
144 
145 		fixcrlf(buf, FALSE);
146 
147 		/* check for end-of-message */
148 		if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
149 			break;
150 
151 		/* check for transparent dot */
152 		if (Smtp && *bp == '.')
153 			bp++;
154 
155 # ifndef NOTUNIX
156 		/* Hide UNIX-like From lines */
157 		if (strncmp(bp, "From ", 5) == 0)
158 		{
159 			fputs(">", tf);
160 			MsgSize++;
161 		}
162 # endif NOTUNIX
163 
164 		/*
165 		**  Figure message length, output the line to the temp
166 		**  file, and insert a newline if missing.
167 		*/
168 
169 		i = strlen(bp);
170 		MsgSize += i;
171 		fputs(bp, tf);
172 		if (bp[i - 1] != '\n')
173 			fputs("\n", tf);
174 		if (ferror(tf))
175 		{
176 			if (errno == ENOSPC)
177 			{
178 				(void) freopen(InFileName, "w", tf);
179 				fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
180 				usrerr("452 Out of disk space for temp file");
181 			}
182 			else
183 				syserr("collect: Cannot write %s", InFileName);
184 			(void) freopen("/dev/null", "w", tf);
185 		}
186 	}
187 	(void) fclose(tf);
188 
189 	/*
190 	**  Find out some information from the headers.
191 	**	Examples are who is the from person & the date.
192 	*/
193 
194 	/* from person */
195 	xfrom = hvalue("sender");
196 	if (xfrom == NULL)
197 		xfrom = OrigFrom;
198 	if (ArpaMode != ARPA_NONE)
199 		setfrom(xfrom, (char *) NULL);
200 
201 	/* full name of from person */
202 	p = hvalue("full-name");
203 	if (p != NULL)
204 		define('x', p);
205 	else
206 	{
207 		register char *q;
208 
209 		/*
210 		**  Try to extract the full name from a general From:
211 		**  field.  We take anything which is a comment as a
212 		**  first choice.  Failing in that, we see if there is
213 		**  a "machine readable" name (in <angle brackets>); if
214 		**  so we take anything preceeding that clause.
215 		**
216 		**  If we blow it here it's not all that serious.
217 		*/
218 
219 		p = hvalue("original-from");
220 		if (p == NULL)
221 			p = OrigFrom;
222 		q = index(p, '(');
223 		if (q != NULL)
224 		{
225 			int parenlev = 0;
226 
227 			for (p = q; *p != '\0'; p++)
228 			{
229 				if (*p == '(')
230 					parenlev++;
231 				else if (*p == ')' && --parenlev <= 0)
232 					break;
233 			}
234 			if (*p == ')')
235 			{
236 				*p = '\0';
237 				if (*++q != '\0')
238 					define('x', newstr(q));
239 				*p = ')';
240 			}
241 		}
242 		else if ((q = index(p, '<')) != NULL)
243 		{
244 			char savec;
245 
246 			while (*--q == ' ')
247 				continue;
248 			while (isspace(*p))
249 				p++;
250 			savec = *++q;
251 			*q = '\0';
252 			if (*p != '\0')
253 				define('x', newstr(p));
254 			*q = savec;
255 		}
256 	}
257 
258 	/* date message originated */
259 	p = hvalue("posted-date");
260 	if (p == NULL)
261 		p = hvalue("date");
262 	if (p != NULL)
263 	{
264 		define('a', p);
265 		/* we don't have a good way to do canonical conversion ....
266 		define('d', newstr(arpatounix(p)));
267 		.... so we will ignore the problem for the time being */
268 	}
269 
270 	if ((TempFile = fopen(InFileName, "r")) == NULL)
271 		syserr("Cannot reopen %s", InFileName);
272 
273 # ifdef DEBUG
274 	if (Debug)
275 	{
276 		HDR *h;
277 		extern char *capitalize();
278 
279 		printf("----- collected header -----\n");
280 		for (h = Header; h != NULL; h = h->h_link)
281 			printf("%s: %s\n", capitalize(h->h_field), h->h_value);
282 		printf("----------------------------\n");
283 	}
284 # endif DEBUG
285 	return;
286 }
287 /*
288 **  EATFROM -- chew up a UNIX style from line and process
289 **
290 **	This does indeed make some assumptions about the format
291 **	of UNIX messages.
292 **
293 **	Parameters:
294 **		fm -- the from line.
295 **
296 **	Returns:
297 **		none.
298 **
299 **	Side Effects:
300 **		extracts what information it can from the header,
301 **		such as the date.
302 */
303 
304 # ifndef NOTUNIX
305 
306 char	*DowList[] =
307 {
308 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
309 };
310 
311 char	*MonthList[] =
312 {
313 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
314 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
315 	NULL
316 };
317 
318 eatfrom(fm)
319 	char *fm;
320 {
321 	register char *p;
322 	register char **dt;
323 
324 # ifdef DEBUG
325 	if (Debug > 1)
326 		printf("eatfrom(%s)\n", fm);
327 # endif DEBUG
328 
329 	/* find the date part */
330 	p = fm;
331 	while (*p != '\0')
332 	{
333 		/* skip a word */
334 		while (*p != '\0' && *p != ' ')
335 			*p++;
336 		while (*p == ' ')
337 			*p++;
338 		if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
339 			continue;
340 
341 		/* we have a possible date */
342 		for (dt = DowList; *dt != NULL; dt++)
343 			if (strncmp(*dt, p, 3) == 0)
344 				break;
345 		if (*dt == NULL)
346 			continue;
347 
348 		for (dt = MonthList; *dt != NULL; dt++)
349 			if (strncmp(*dt, &p[4], 3) == 0)
350 				break;
351 		if (*dt != NULL)
352 			break;
353 	}
354 
355 	if (*p != NULL)
356 	{
357 		char *q;
358 
359 		/* we have found a date */
360 		q = xalloc(25);
361 		strncpy(q, p, 25);
362 		q[24] = '\0';
363 		define('d', q);
364 	}
365 }
366 
367 # endif NOTUNIX
368