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