xref: /illumos-gate/usr/src/cmd/mail/copylet.c (revision 3c30f56df862431210f98c7c8f13cf1362b9c574)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2017 Gary Mills
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #include "mail.h"
32 
33 /*
34     NAME
35 	copylet - copy a given letter to a file pointer
36 
37     SYNOPSIS
38 	int copylet(int letnum, FILE *f, int type)
39 
40     DESCRIPTION
41 	Copylet() will copy the letter "letnum" to the
42 	given file pointer.
43 
44 		letnum	-> index into: letter table
45 		f	-> file pointer to copy file to
46 		type	-> copy type
47 
48 	Returns TRUE on a completely successful copy.
49 */
50 
51 int
52 copylet(int letnum, FILE *f, int type)
53 {
54 	int		pos = ftell(f);
55 	int		rc  = xxxcopylet(letnum, f, type);
56 
57 	if (fflush(f) != 0)
58 		rc = FALSE;
59 
60 	/*
61 	 * On error, truncate the file to its original position so that a
62 	 * partial message is not left in the mailbox.
63 	 */
64 	if (rc == FALSE)
65 		ftruncate(fileno(f), pos);
66 
67 	return(rc);
68 }
69 
70 int
71 xxxcopylet(int letnum, FILE *f, int type)
72 {
73 	static char	pn[] = "copylet";
74 	char	buf[LSIZE], lastc;
75 	char	wbuf[LSIZE];
76 	int	n;
77 	long	i, k;
78 	int	num;
79 	int	rtrncont = 1;	/* True: nondelivery&content included, or regular mail */
80 	int	suppress = FALSE;
81 	int	sav_suppress = FALSE; /* Did we suppress previous hdr line? */
82 	int	print_from_struct = FALSE; /* print from hdrlines struct */
83 					   /* rather than fgets() buffer */
84 	int	pushrest = FALSE;
85 	int	ctf = FALSE;
86 	int	didafflines = FALSE;	/* Did we already put out any */
87 					/* H_AFWDFROM lines? */
88 	int	didrcvlines = FALSE;	/* Did we already put out any */
89 					/* H_RECEIVED lines? */
90 	long	clen = -1L;
91 	int	htype;			/* header type */
92 	struct hdrs *hptr;
93 
94 	if (!sending) {
95 		/* Clear out any saved header info from previous message */
96 		clr_hinfo();
97 	}
98 
99 	fseek(tmpf, let[letnum].adr, 0);
100 	/* Get size of message as stored into tempfile by copymt() */
101 	k = let[letnum+1].adr - let[letnum].adr;
102 	Dout(pn, 1, "(letnum = %d, type = %d), k = %ld\n", letnum, type, k);
103 	while (k>0) {	/* process header */
104 		num = ((k < sizeof(buf)) ? k+1 : sizeof(buf));
105 		if (fgets (buf, num, tmpf) == NULL) {
106 			return (FALSE);
107 		}
108 		if ((n = strlen (buf)) == 0) {
109 			k = 0;
110 			break;
111 		}
112 		k -= n;
113 		lastc = buf[n-1];
114 		if (pushrest) {
115 			pushrest = (lastc != '\n');
116 			continue;
117 		}
118 		htype = isheader (buf, &ctf);
119 		Dout(pn, 5, "loop 1: buf = %s, htype= %d/%s\n", buf, htype, header[htype].tag);
120 		if (htype == H_CLEN) {
121 			if (!sending) {
122 				savehdrs(buf,htype);
123 			}
124 			if ((hptr = hdrlines[H_CLEN].head) !=
125 			    (struct hdrs *)NULL) {
126 				clen = atol (hptr->value);
127 			}
128 		}
129 		if (type == ZAP) {
130 			if (htype != FALSE) {
131 				pushrest = (lastc != '\n');
132 				continue;
133 			}
134 			/* end of header.  Print non-blank line and bail. */
135 			Dout(pn, 5, "ZAP end header; n=%d, buf[0] = %d\n", n, buf[0]);
136 			if (buf[0] != '\n') {
137 				if (fwrite(buf,1,n,f) != n) {
138 					sav_errno = errno;
139 					return(FALSE);
140 				}
141 			} else {
142 				n = 0;
143 			}
144 			break;
145 		}
146 		/* Copy From line appropriately */
147 		if (fwrite(buf,1,n-1,f) != n-1)  {
148 			sav_errno = errno;
149 			return(FALSE);
150 		}
151 		if (lastc != '\n') {
152 			if (fwrite(&lastc,1,1,f) != 1) {
153 				sav_errno = errno;
154 				return(FALSE);
155 			}
156 			continue;
157 		}
158 		switch(type) {
159 			case REMOTE:
160 				if (fprintf(f, rmtmsg, thissys) < 0)
161 				{
162 					sav_errno = errno;
163 					return(FALSE);
164 				}
165 
166 				break;
167 
168 			case TTY:
169 			case ORDINARY:
170 			default:
171 				if (fprintf(f, "\n") < 0)
172 				{
173 					sav_errno = errno;
174 					return(FALSE);
175 				}
176 				break;
177 		}
178 		if ((error > 0) && (dflag == 1)) {
179 			Dout(pn, 3, "before gendeliv(), uval = '%s'\n", uval);
180 			gendeliv(f, dflag, uval);
181 			if (!(ckdlivopts(H_TCOPY, (int*)0) & RETURN)) {
182 				rtrncont = 0;
183 			} else {
184 				/* Account for content-type info */
185 				/* of returned msg */
186 				if (fprintf(f, "%s %s\n", header[H_CTYPE].tag,
187 				    (let[letnum].text == TRUE ? "text/plain" : "application/octet-stream")) < 0)
188 				{
189 					sav_errno = errno;
190 					return(FALSE);
191 				}
192 
193 				/* Compute Content-Length of what's being */
194 				/* returned... */
195 				i = k;
196 				/* Account for H_AFWDFROM, H_AFWDCNT, */
197 				/* H_TCOPY, or H_RECEIVED lines which may */
198 				/* be added later */
199 				if (affcnt > 0) {
200 					sprintf(wbuf, "%d", affcnt);
201 					i += (affbytecnt
202 						+ strlen(header[H_AFWDCNT].tag)
203 						+ strlen(wbuf) + 2);
204 				}
205 				if (orig_tcopy) {
206 				    if ((hptr = hdrlines[H_TCOPY].head) !=
207 							(struct hdrs *)NULL) {
208 				        i +=
209 					  strlen(hdrlines[H_TCOPY].head->value);
210 				    }
211 				}
212 				if ((hptr = hdrlines[H_RECEIVED].head) !=
213 							(struct hdrs *)NULL) {
214 				    i += rcvbytecnt;
215 				}
216 				/* Add in strlen of MIME-Version:, */
217 				/* Content-Length: and Content-Type: */
218 				/* values for msg being returned... */
219 				if ((hptr = hdrlines[H_MIMEVERS].head) !=
220 							(struct hdrs *)NULL) {
221 				    i += strlen(hdrlines[H_MIMEVERS].head->value);
222 				}
223 				if ((hptr = hdrlines[H_CTYPE].head) !=
224 							(struct hdrs *)NULL) {
225 				    i += strlen(hdrlines[H_CTYPE].head->value);
226 				}
227 				if ((hptr = hdrlines[H_CLEN].head) !=
228 							(struct hdrs *)NULL) {
229 				    i += strlen(hdrlines[H_CLEN].head->value);
230 				}
231 				if (fprintf(f, "%s %ld\n", header[H_CLEN].tag, i) < 0)
232 				{
233 					sav_errno = errno;
234 					return(FALSE);
235 				}
236 			}
237 			if (fprintf(f, "\n") < 0)
238 			{
239 				sav_errno = errno;
240 				return(FALSE);
241 			}
242 		}
243 		if (fflush(f))
244 		{
245 			sav_errno = errno;
246 			return(FALSE);
247 		}
248 
249 		break;
250 	}
251 	/* if not ZAP, copy balance of header */
252 	n = 0;
253 	if ((type != ZAP) && rtrncont)
254 		while (k>0 || n>0) {
255 			if ((n > 0) && !suppress) {
256 				if (print_from_struct == TRUE) {
257 					if (printhdr (type, htype, hptr, f) < 0) {
258 						return (FALSE);
259 					}
260 				} else {
261 				    if (sel_disp(type, htype, buf) >= 0) {
262 					if (fwrite(buf,1,n,f) != n)  {
263 						sav_errno = errno;
264 						return(FALSE);
265 					}
266 				    }
267 				}
268 				if (htype == H_DATE) {
269 					dumprcv(type, htype,&didrcvlines,&suppress,f);
270 					dumpaff(type, htype,&didafflines,&suppress,f);
271 				}
272 			}
273 			if (k <= 0) {
274 				/* Can only get here if k=0 && n>0, which occurs */
275 				/* in a message with header lines but no content. */
276 				/* If we haven't already done it, force out any */
277 				/* H_AFWDFROM or H_RECEIVED lines */
278 				dumprcv(type, -1,&didrcvlines,&suppress,f);
279 				dumpaff(type, -1,&didafflines,&suppress,f);
280 				break;
281 			}
282 			num = ((k < sizeof(buf)) ? k+1 : sizeof(buf));
283 			if (fgets (buf, num, tmpf) == NULL) {
284 				return (FALSE);
285 			}
286 			n = strlen (buf);
287 			k -= n;
288 			lastc = buf[n-1];
289 
290 			if (pushrest) {
291 				pushrest = (lastc != '\n');
292 				continue;
293 			}
294 			sav_suppress = suppress;
295 			suppress = FALSE;
296 			print_from_struct = FALSE;
297 			htype = isheader (buf, &ctf);
298 			Dout(pn, 5, "loop 2: buf = %s, htype= %d/%s\n", buf, htype, header[htype].tag);
299 			/* The following order is defined in the MTA documents. */
300 			switch (htype) {
301 			case H_CONT:
302 			    if (sending) {
303 				suppress = sav_suppress;
304 			    }
305 			    continue;
306 			case H_TCOPY:
307 			case H_MIMEVERS:
308 			case H_CTYPE:
309 			case H_CLEN:
310 				if (!sending) {
311 					savehdrs(buf,htype);
312 				}
313 				hptr = hdrlines[htype].head;
314 				if (htype == H_CLEN) {
315 					clen = atol (hptr->value);
316 				}
317 				/*
318 				 * Use values saved in hdrlines[] structure
319 				 * rather than what was read from tmp file.
320 				 */
321 				print_from_struct = TRUE;
322 				/* FALLTHROUGH */
323 			case H_EOH:
324 			case H_AFWDFROM:
325 			case H_AFWDCNT:
326 			case H_RECEIVED:
327 				dumprcv(type, htype,&didrcvlines,&suppress,f);
328 				dumpaff(type, htype,&didafflines,&suppress,f);
329 				continue;	/* next header line */
330 			default:
331 				pushrest = (lastc != '\n');
332 				continue;	/* next header line */
333 			case FALSE:	/* end of header */
334 				break;
335 			}
336 
337 			/* Found the blank line after the headers. */
338 			if (n > 0) {
339 				if (fwrite(buf,1,n,f) != n)  {
340 					sav_errno = errno;
341 					return(FALSE);
342 				}
343 			}
344 
345 			Dout(pn, 3,", let[%d].text = %s\n",
346 				letnum, (let[letnum].text ? "TRUE" : "FALSE"));
347 
348 			if ((type == TTY) && (let[letnum].text == FALSE) && !pflg) {
349 				if (fprintf (f, "\n%s\n", binmsg) < 0)
350 				{
351 					sav_errno = errno;
352 					return(FALSE);
353 				}
354 				return (TRUE);
355 			}
356 
357 			if (n == 1 && buf[0] == '\n') {
358 				n = 0;
359 			}
360 			break;
361 		}
362 
363 	Dout(pn, 1, "header processed, clen/k/n = %ld/%ld/%d\n", clen, k, n);
364 
365 	if (clen >= 0) {
366 		if (((clen - n) == k) || ((clen - n) == (k - 1))) {
367 			k = clen - n;
368 		} else {
369 			/* probable content-length mismatch. show it ALL! */
370 			Dout(pn, 1, "clen conflict. using k = %ld\n", k);
371 		}
372 	}
373 
374 	/* copy balance of message */
375 	if (rtrncont)
376 		while (k > 0) {
377 			num = ((k < sizeof(buf)) ? k : sizeof(buf));
378 			if ((n = fread (buf, 1, num, tmpf)) <= 0) {
379 				Dout(pn, 1, "content-length mismatch. return(FALSE)\n");
380 				return(FALSE);
381 			}
382 			k -= n;
383 			if (fwrite(buf,1,n,f) != n)  {
384 				sav_errno = errno;
385 				return(FALSE);
386 			}
387 		}
388 
389 	Dout(pn, 3, "body processed, k=%ld\n", k);
390 
391 	if (rtrncont && type != ZAP && type != REMOTE) {
392 		if (fwrite("\n",1,1,f) != 1)  {
393 			sav_errno = errno;
394 			return(FALSE);
395 		}
396 	}
397 
398 	return(TRUE);
399 }
400