xref: /illumos-gate/usr/src/cmd/mail/copylet.c (revision b7d62af5b42f0da2eb668e8d33d24d2f4fdd98a8)
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 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include "mail.h"
33 
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 
52 int
53 copylet(int letnum, FILE *f, int type)
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 
71 int
72 xxxcopylet(int letnum, FILE *f, int type)
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