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
copylet(int letnum,FILE * f,int type)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
xxxcopylet(int letnum,FILE * f,int type)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