1 # include <errno.h>
2 # include "sendmail.h"
3 
4 SCCSID(@(#)collect.c	4.1		07/25/83);
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.  Leading UNIX-style "From" lines are
11 **	stripped off (after important information is extracted).
12 **
13 **	Parameters:
14 **		sayok -- if set, give an ARPANET style message
15 **			to say we are ready to collect input.
16 **
17 **	Returns:
18 **		none.
19 **
20 **	Side Effects:
21 **		Temp file is created and filled.
22 **		The from person may be set.
23 */
24 
25 collect(sayok)
26 	bool sayok;
27 {
28 	register FILE *tf;
29 	char buf[MAXFIELD+2];
30 	register char *p;
31 	extern char *hvalue();
32 
33 	/*
34 	**  Create the temp file name and create the file.
35 	*/
36 
37 	CurEnv->e_df = newstr(queuename(CurEnv, 'd'));
38 	if ((tf = dfopen(CurEnv->e_df, "w")) == NULL)
39 	{
40 		syserr("Cannot create %s", CurEnv->e_df);
41 		NoReturn = TRUE;
42 		finis();
43 	}
44 	(void) chmod(CurEnv->e_df, FileMode);
45 
46 	/*
47 	**  Tell ARPANET to go ahead.
48 	*/
49 
50 	if (sayok)
51 		message("354", "Enter mail, end with \".\" on a line by itself");
52 
53 	/*
54 	**  Try to read a UNIX-style From line
55 	*/
56 
57 	if (sfgets(buf, sizeof buf, InChannel) == NULL)
58 		return;
59 	fixcrlf(buf, FALSE);
60 # ifndef NOTUNIX
61 	if (!SaveFrom && strncmp(buf, "From ", 5) == 0)
62 	{
63 		eatfrom(buf);
64 		(void) sfgets(buf, sizeof buf, InChannel);
65 		fixcrlf(buf, FALSE);
66 	}
67 # endif NOTUNIX
68 
69 	/*
70 	**  Copy InChannel to temp file & do message editing.
71 	**	To keep certain mailers from getting confused,
72 	**	and to keep the output clean, lines that look
73 	**	like UNIX "From" lines are deleted in the header.
74 	*/
75 
76 	for (; !feof(InChannel); !feof(InChannel) && !ferror(InChannel) &&
77 				 sfgets(buf, MAXFIELD, InChannel) != NULL)
78 	{
79 		register char c;
80 		extern bool isheader();
81 
82 		/* if the line is too long, throw the rest away */
83 		if (index(buf, '\n') == NULL)
84 		{
85 			while ((c = getc(InChannel)) != '\n')
86 				continue;
87 			/* give an error? */
88 		}
89 
90 		fixcrlf(buf, TRUE);
91 
92 		/* see if the header is over */
93 		if (!isheader(buf))
94 			break;
95 
96 		/* get the rest of this field */
97 		while ((c = getc(InChannel)) == ' ' || c == '\t')
98 		{
99 			p = &buf[strlen(buf)];
100 			*p++ = '\n';
101 			*p++ = c;
102 			if (sfgets(p, MAXFIELD - (p - buf), InChannel) == NULL)
103 				break;
104 			fixcrlf(p, TRUE);
105 		}
106 		if (!feof(InChannel))
107 			(void) ungetc(c, InChannel);
108 
109 		CurEnv->e_msgsize += strlen(buf);
110 
111 		/*
112 		**  Snarf header away.
113 		*/
114 
115 		if (bitset(H_EOH, chompheader(buf, FALSE)))
116 			break;
117 	}
118 
119 # ifdef DEBUG
120 	if (tTd(30, 1))
121 		printf("EOH\n");
122 # endif DEBUG
123 
124 	/* throw away a blank line */
125 	if (buf[0] == '\0')
126 	{
127 		(void) sfgets(buf, MAXFIELD, InChannel);
128 		fixcrlf(buf, TRUE);
129 	}
130 
131 	/*
132 	**  Collect the body of the message.
133 	*/
134 
135 	for (; !feof(InChannel); !feof(InChannel) && !ferror(InChannel) &&
136 				 sfgets(buf, sizeof buf, InChannel) != NULL)
137 	{
138 		register char *bp = buf;
139 
140 		fixcrlf(buf, TRUE);
141 
142 		/* check for end-of-message */
143 		if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
144 			break;
145 
146 		/* check for transparent dot */
147 		if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.')
148 			bp++;
149 
150 		/*
151 		**  Figure message length, output the line to the temp
152 		**  file, and insert a newline if missing.
153 		*/
154 
155 		CurEnv->e_msgsize += strlen(bp) + 1;
156 		fputs(bp, tf);
157 		fputs("\n", tf);
158 		if (ferror(tf))
159 			tferror(tf);
160 	}
161 	if (fflush(tf) != 0)
162 		tferror(tf);
163 	(void) fclose(tf);
164 
165 	/* An EOF when running SMTP is an error */
166 	if (feof(InChannel) && OpMode == MD_SMTP)
167 		syserr("collect: unexpected close");
168 
169 	/*
170 	**  Find out some information from the headers.
171 	**	Examples are who is the from person & the date.
172 	*/
173 
174 	eatheader(CurEnv);
175 
176 	/*
177 	**  Add an Apparently-To: line if we have no recipient lines.
178 	*/
179 
180 	if (hvalue("to") == NULL && hvalue("cc") == NULL &&
181 	    hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
182 	{
183 		register ADDRESS *q;
184 
185 		/* create an Apparently-To: field */
186 		/*    that or reject the message.... */
187 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
188 		{
189 			if (q->q_alias != NULL)
190 				continue;
191 # ifdef DEBUG
192 			if (tTd(30, 3))
193 				printf("Adding Apparently-To: %s\n", q->q_paddr);
194 # endif DEBUG
195 			addheader("apparently-to", q->q_paddr, CurEnv);
196 		}
197 	}
198 
199 	if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL)
200 		syserr("Cannot reopen %s", CurEnv->e_df);
201 }
202 /*
203 **  TFERROR -- signal error on writing the temporary file.
204 **
205 **	Parameters:
206 **		tf -- the file pointer for the temporary file.
207 **
208 **	Returns:
209 **		none.
210 **
211 **	Side Effects:
212 **		Gives an error message.
213 **		Arranges for following output to go elsewhere.
214 */
215 
216 tferror(tf)
217 	FILE *tf;
218 {
219 	if (errno == ENOSPC)
220 	{
221 		(void) freopen(CurEnv->e_df, "w", tf);
222 		fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
223 		usrerr("452 Out of disk space for temp file");
224 	}
225 	else
226 		syserr("collect: Cannot write %s", CurEnv->e_df);
227 	(void) freopen("/dev/null", "w", tf);
228 }
229 /*
230 **  EATFROM -- chew up a UNIX style from line and process
231 **
232 **	This does indeed make some assumptions about the format
233 **	of UNIX messages.
234 **
235 **	Parameters:
236 **		fm -- the from line.
237 **
238 **	Returns:
239 **		none.
240 **
241 **	Side Effects:
242 **		extracts what information it can from the header,
243 **		such as the date.
244 */
245 
246 # ifndef NOTUNIX
247 
248 char	*DowList[] =
249 {
250 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
251 };
252 
253 char	*MonthList[] =
254 {
255 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
256 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
257 	NULL
258 };
259 
260 eatfrom(fm)
261 	char *fm;
262 {
263 	register char *p;
264 	register char **dt;
265 
266 # ifdef DEBUG
267 	if (tTd(30, 2))
268 		printf("eatfrom(%s)\n", fm);
269 # endif DEBUG
270 
271 	/* find the date part */
272 	p = fm;
273 	while (*p != '\0')
274 	{
275 		/* skip a word */
276 		while (*p != '\0' && *p != ' ')
277 			*p++;
278 		while (*p == ' ')
279 			*p++;
280 		if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
281 			continue;
282 
283 		/* we have a possible date */
284 		for (dt = DowList; *dt != NULL; dt++)
285 			if (strncmp(*dt, p, 3) == 0)
286 				break;
287 		if (*dt == NULL)
288 			continue;
289 
290 		for (dt = MonthList; *dt != NULL; dt++)
291 			if (strncmp(*dt, &p[4], 3) == 0)
292 				break;
293 		if (*dt != NULL)
294 			break;
295 	}
296 
297 	if (*p != NULL)
298 	{
299 		char *q;
300 		extern char *arpadate();
301 
302 		/* we have found a date */
303 		q = xalloc(25);
304 		strncpy(q, p, 25);
305 		q[24] = '\0';
306 		define('d', q, CurEnv);
307 		q = arpadate(q);
308 		define('a', newstr(q), CurEnv);
309 	}
310 }
311 
312 # endif NOTUNIX
313