copylet.c revision d7c57852794a9ac50d4b6a9c4161cb10919658aa
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
51int
52copylet(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
70int
71xxxcopylet(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