1 /*
2 ** Copyright 1998 - 2001 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #if	HAVE_CONFIG_H
7 #include	"config.h"
8 #endif
9 #include	"imaptoken.h"
10 #include	"imapwrite.h"
11 #include	"rfc822/rfc822.h"
12 #include	"rfc2045/rfc2045.h"
13 #include	<stdio.h>
14 #include	<ctype.h>
15 #include	<stdlib.h>
16 #include	<string.h>
17 
18 
19 extern void msgenvelope(void (*)(const char *, size_t),
20 		FILE *, struct rfc2045 *);
21 
22 extern void msgappends(void (*)(const char *, size_t), const char *, size_t);
23 
do_param_list(void (* writefunc)(const char *,size_t),struct rfc2045attr * a)24 static void do_param_list(void (*writefunc)(const char *, size_t),
25 	struct rfc2045attr *a)
26 {
27 int	flag;
28 char	*p;
29 
30 	flag=0;
31 	p="(";
32 	for (; a; a=a->next)
33 	{
34 		(*writefunc)(p, strlen(p));
35 		(*writefunc)("\"", 1);
36 		if (a->name)
37 			msgappends(writefunc, a->name, strlen(a->name));
38 		(*writefunc)("\" \"", 3);
39 		if (a->value)
40 		{
41 #if	IMAP_CLIENT_BUGS
42 
43 		/* NETSCAPE */
44 
45 		char *u, *v, *w;
46 
47 			u=strdup(a->value);
48 			if (!u)	write_error_exit(0);
49 			strcpy(u, a->value);
50 			for (v=w=u; *v; v++)
51 				if (*v != '\\')	*w++ = *v;
52 			*w=0;
53 			msgappends(writefunc, u, strlen(u));
54 			free(u);
55 
56 #else
57 			msgappends(writefunc, a->value, strlen(a->value));
58 #endif
59 		}
60 		(*writefunc)("\"", 1);
61 		flag=1;
62 		p=" ";
63 	}
64 	if (flag)
65 		(*writefunc)(")", 1);
66 	else
67 		(*writefunc)("NIL", 3);
68 }
69 
contentstr(void (* writefunc)(const char *,size_t),const char * s)70 static void contentstr( void (*writefunc)(const char *, size_t), const char *s)
71 {
72 	if (!s || !*s)
73 	{
74 		(*writefunc)("NIL", 3);
75 		return;
76 	}
77 
78 	(*writefunc)("\"", 1);
79 	msgappends(writefunc, s, strlen(s));
80 	(*writefunc)("\"", 1);
81 }
82 
83 
do_disposition(void (* writefunc)(const char *,size_t),const char * disposition_s,struct rfc2045attr * disposition_a)84 static void do_disposition(
85 	void (*writefunc)(const char *, size_t), const char *disposition_s,
86 	struct rfc2045attr *disposition_a)
87 {
88 	if ( (disposition_s == 0 || *disposition_s == 0) &&
89 		disposition_a == 0)
90 	{
91 		(*writefunc)("NIL", 3);
92 		return;
93 	}
94 	(*writefunc)("(", 1);
95 
96 	if (disposition_s && *disposition_s)
97 	{
98 		(*writefunc)("\"", 1);
99 		msgappends(writefunc, disposition_s,
100 			strlen(disposition_s));
101 		(*writefunc)("\"", 1);
102 	}
103 	else
104 		(*writefunc)("\"\"", 2);
105 
106 	(*writefunc)(" ", 1);
107 	do_param_list(writefunc, disposition_a);
108 	(*writefunc)(")", 1);
109 }
110 
msgbodystructure(void (* writefunc)(const char *,size_t),int dox,FILE * fp,struct rfc2045 * mimep)111 void msgbodystructure( void (*writefunc)(const char *, size_t), int dox,
112 	FILE *fp, struct rfc2045 *mimep)
113 {
114 const char *content_type_s;
115 const char *content_transfer_encoding_s;
116 const char *charset_s;
117 off_t start_pos, end_pos, start_body;
118 off_t nlines, nbodylines;
119 const char *disposition_s;
120 
121 char	*p, *q;
122 
123 	rfc2045_mimeinfo(mimep, &content_type_s, &content_transfer_encoding_s,
124 		&charset_s);
125 	rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body,
126 		&nlines, &nbodylines);
127 
128 	disposition_s=mimep->content_disposition;
129 
130 	(*writefunc)("(", 1);
131 
132 	if (mimep->firstpart && mimep->firstpart->isdummy &&
133 		mimep->firstpart->next)
134 		/* MULTIPART */
135 	{
136 	struct rfc2045	*childp;
137 
138 		for (childp=mimep->firstpart; (childp=childp->next) != 0; )
139 			msgbodystructure(writefunc, dox, fp, childp);
140 
141 		(*writefunc)(" \"", 2);
142 		p=strchr(content_type_s, '/');
143 		if (p)
144 			msgappends(writefunc, p+1, strlen(p+1));
145 		(*writefunc)("\"", 1);
146 
147 		if (dox)
148 		{
149 			(*writefunc)(" ", 1);
150 			do_param_list(writefunc, mimep->content_type_attr);
151 
152 			(*writefunc)(" ", 1);
153 			do_disposition(writefunc, disposition_s,
154 				mimep->content_disposition_attr);
155 
156 			(*writefunc)(" ", 1);
157 			contentstr(writefunc, rfc2045_content_language(mimep));
158 		}
159 	}
160 	else
161 	{
162 	char	*mybuf;
163 	char	buf[40];
164 	const	char *cp;
165 
166 		mybuf=my_strdup(content_type_s);
167 		q=strtok(mybuf, " /");
168 		(*writefunc)("\"", 1);
169 		if (q)
170 			msgappends(writefunc, q, strlen(q));
171 		(*writefunc)("\" \"", 3);
172 		if (q)	q=strtok(0, " /");
173 		if (q)
174 			msgappends(writefunc, q, strlen(q));
175 		free(mybuf);
176 		(*writefunc)("\" ", 2);
177 
178 		do_param_list(writefunc, mimep->content_type_attr);
179 
180 		(*writefunc)(" ", 1);
181 		cp=rfc2045_content_id(mimep);
182 		if (!cp || !*cp)
183 			contentstr(writefunc, cp);
184 		else
185 		{
186 			(*writefunc)("\"<", 2);
187 			msgappends(writefunc, cp, strlen(cp));
188 			(*writefunc)(">\"", 2);
189 		}
190 		(*writefunc)(" ", 1);
191 		contentstr(writefunc, rfc2045_content_description(mimep));
192 
193 		(*writefunc)(" \"", 2);
194 		msgappends(writefunc, content_transfer_encoding_s,
195 			strlen(content_transfer_encoding_s));
196 		(*writefunc)("\" ", 2);
197 
198 		sprintf(buf, "%lu", (unsigned long)
199 			(end_pos-start_body+nbodylines));
200 			/* nbodylines added for CRs */
201 		(*writefunc)(buf, strlen(buf));
202 
203 		if (
204 		(content_type_s[0] == 't' || content_type_s[0] == 'T') &&
205 		(content_type_s[1] == 'e' || content_type_s[1] == 'E') &&
206 		(content_type_s[2] == 'x' || content_type_s[2] == 'X') &&
207 		(content_type_s[3] == 't' || content_type_s[3] == 'T') &&
208 			(content_type_s[4] == '/' ||
209 			 content_type_s[4] == 0))
210 		{
211 			(*writefunc)(" ", 1);
212 			sprintf(buf, "%lu", (unsigned long)nbodylines);
213 			(*writefunc)(buf, strlen(buf));
214 		}
215 
216 		if (mimep->firstpart && !mimep->firstpart->isdummy)
217 			/* message/rfc822 */
218 		{
219 			(*writefunc)(" ", 1);
220 			msgenvelope(writefunc, fp, mimep->firstpart);
221 			(*writefunc)(" ", 1);
222 			msgbodystructure(writefunc, dox, fp, mimep->firstpart);
223 			(*writefunc)(" ", 1);
224 			sprintf(buf, "%lu", (unsigned long)nbodylines);
225 			(*writefunc)(buf, strlen(buf));
226 		}
227 
228 		if (dox)
229 		{
230 			(*writefunc)(" ", 1);
231 			contentstr(writefunc, rfc2045_content_md5(mimep));
232 
233 			(*writefunc)(" ", 1);
234 			do_disposition(writefunc, disposition_s,
235 				mimep->content_disposition_attr);
236 
237 			(*writefunc)(" NIL", 4);
238 				/* TODO Content-Language: */
239 		}
240 	}
241 	(*writefunc)(")", 1);
242 }
243