comparison src/mime.c @ 14038:443aaa05a7c3

[gaim-migrate @ 16642] Formatting/whitespace committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sat, 05 Aug 2006 09:11:46 +0000
parents d4cd7d443795
children
comparison
equal deleted inserted replaced
14037:5dcd38744d43 14038:443aaa05a7c3
1
2 /* 1 /*
3 Gaim 2 * Gaim
4 3 *
5 Gaim is the legal property of its developers, whose names are too 4 * Gaim is the legal property of its developers, whose names are too
6 numerous to list here. Please refer to the COPYRIGHT file distributed 5 * numerous to list here. Please refer to the COPYRIGHT file distributed
7 with this source distribution 6 * with this source distribution
8 7 *
9 This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or (at 10 * the Free Software Foundation; either version 2 of the License, or (at
12 your option) any later version. 11 * your option) any later version.
13 12 *
14 This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details. 16 * General Public License for more details.
18 17 *
19 You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 USA. 21 * USA.
23 */ 22 */
24 23
25 #include <stdio.h> 24 #include <stdio.h>
26 #include <string.h> 25 #include <string.h>
27 26
28 #include <glib.h> 27 #include <glib.h>
29 #include <glib/ghash.h> 28 #include <glib/ghash.h>
30 #include <glib/glist.h> 29 #include <glib/glist.h>
31 #include <glib/gstring.h> 30 #include <glib/gstring.h>
32 31
33 /* this should become "util.h" if we ever get this into gaim proper */ 32 /* this should become "util.h" if we ever get this into gaim proper */
34 #include <debug.h> 33 #include "debug.h"
35 #include <util.h>
36
37 #include "mime.h" 34 #include "mime.h"
38 35 #include "util.h"
39 36
40 /** @struct mime_fields 37 /**
41 38 * @struct mime_fields
42 Utility structure used in both MIME document and parts, which maps 39 *
43 field names to their values, and keeps an easily accessible list of 40 * Utility structure used in both MIME document and parts, which maps
44 keys 41 * field names to their values, and keeps an easily accessible list of
45 */ 42 * keys.
43 */
46 struct mime_fields { 44 struct mime_fields {
47 GHashTable *map; 45 GHashTable *map;
48 GList *keys; 46 GList *keys;
49 }; 47 };
50 48
51
52 struct _GaimMimeDocument { 49 struct _GaimMimeDocument {
53 struct mime_fields fields; 50 struct mime_fields fields;
54 GList *parts; 51 GList *parts;
55 }; 52 };
56 53
57
58 struct _GaimMimePart { 54 struct _GaimMimePart {
59 struct mime_fields fields; 55 struct mime_fields fields;
60 struct _GaimMimeDocument *doc; 56 struct _GaimMimeDocument *doc;
61 GString *data; 57 GString *data;
62 }; 58 };
63 59
64 60 static void
65 static void fields_set(struct mime_fields *mf, 61 fields_set(struct mime_fields *mf, const char *key, const char *val)
66 const char *key, const char *val) { 62 {
67 char *k, *v; 63 char *k, *v;
68 64
69 g_return_if_fail(mf != NULL); 65 g_return_if_fail(mf != NULL);
70 g_return_if_fail(mf->map != NULL); 66 g_return_if_fail(mf->map != NULL);
71 67
72 k = g_ascii_strdown(key, -1); 68 k = g_ascii_strdown(key, -1);
73 v = g_strdup(val); 69 v = g_strdup(val);
74 70
75 /* append to the keys list only if it's not already there */ 71 /* append to the keys list only if it's not already there */
76 if(! g_hash_table_lookup(mf->map, k)) { 72 if(! g_hash_table_lookup(mf->map, k)) {
77 mf->keys = g_list_append(mf->keys, k); 73 mf->keys = g_list_append(mf->keys, k);
78 } 74 }
79 75
80 /* important to use insert. If the key is already in the table, then 76 /* important to use insert. If the key is already in the table, then
81 it's already in the keys list. Insert will free the new instance 77 it's already in the keys list. Insert will free the new instance
82 of the key rather than the old instance. */ 78 of the key rather than the old instance. */
83 g_hash_table_insert(mf->map, k, v); 79 g_hash_table_insert(mf->map, k, v);
84 } 80 }
85 81
86 82
87 static const char *fields_get(struct mime_fields *mf, 83 static const char *
88 const char *key) { 84 fields_get(struct mime_fields *mf, const char *key)
89 char *kdown; 85 {
90 const char *ret; 86 char *kdown;
91 87 const char *ret;
92 g_return_val_if_fail(mf != NULL, NULL); 88
93 g_return_val_if_fail(mf->map != NULL, NULL); 89 g_return_val_if_fail(mf != NULL, NULL);
94 90 g_return_val_if_fail(mf->map != NULL, NULL);
95 kdown = g_ascii_strdown(key, -1); 91
96 ret = g_hash_table_lookup(mf->map, kdown); 92 kdown = g_ascii_strdown(key, -1);
97 g_free(kdown); 93 ret = g_hash_table_lookup(mf->map, kdown);
98 94 g_free(kdown);
99 return ret; 95
100 } 96 return ret;
101 97 }
102 98
103 static void fields_init(struct mime_fields *mf) { 99
104 g_return_if_fail(mf != NULL); 100 static void
105 101 fields_init(struct mime_fields *mf)
106 mf->map = g_hash_table_new_full(g_str_hash, g_str_equal, 102 {
107 g_free, g_free); 103 g_return_if_fail(mf != NULL);
108 } 104
109 105 mf->map = g_hash_table_new_full(g_str_hash, g_str_equal,
110 106 g_free, g_free);
111 static void fields_loadline(struct mime_fields *mf, 107 }
112 const char *line, gsize len) { 108
113 109
114 /* split the line into key: value */ 110 static void
115 char *key, *val; 111 fields_loadline(struct mime_fields *mf, const char *line, gsize len)
116 char **tokens; 112 {
117 113 /* split the line into key: value */
118 /* feh, need it to be NUL terminated */ 114 char *key, *val;
119 key = g_strndup(line, len); 115 char **tokens;
120 116
121 /* split */ 117 /* feh, need it to be NUL terminated */
122 val = strchr(key, ':'); 118 key = g_strndup(line, len);
123 if(! val) { 119
124 g_free(key); 120 /* split */
125 return; 121 val = strchr(key, ':');
126 } 122 if(! val) {
127 *val++ = '\0'; 123 g_free(key);
128 124 return;
129 /* normalize whitespace (sorta) and trim on key and value */ 125 }
130 tokens = g_strsplit(key, "\t\r\n", 0); 126 *val++ = '\0';
131 key = g_strjoinv("", tokens); 127
132 key = g_strstrip(key); 128 /* normalize whitespace (sorta) and trim on key and value */
133 g_strfreev(tokens); 129 tokens = g_strsplit(key, "\t\r\n", 0);
134 130 key = g_strjoinv("", tokens);
135 tokens = g_strsplit(val, "\t\r\n", 0); 131 key = g_strstrip(key);
136 val = g_strjoinv("", tokens); 132 g_strfreev(tokens);
137 val = g_strstrip(val); 133
138 g_strfreev(tokens); 134 tokens = g_strsplit(val, "\t\r\n", 0);
139 135 val = g_strjoinv("", tokens);
140 fields_set(mf, key, val); 136 val = g_strstrip(val);
141 137 g_strfreev(tokens);
142 g_free(key); 138
143 g_free(val); 139 fields_set(mf, key, val);
144 } 140
145 141 g_free(key);
146 142 g_free(val);
147 static void fields_load(struct mime_fields *mf, 143 }
148 char **buf, gsize *len) { 144
149 char *tail; 145
150 146 static void
151 while( (tail = g_strstr_len(*buf, *len, "\r\n")) ) { 147 fields_load(struct mime_fields *mf, char **buf, gsize *len)
152 char *line; 148 {
153 gsize ln; 149 char *tail;
154 150
155 /* determine the current line */ 151 while ((tail = g_strstr_len(*buf, *len, "\r\n")))
156 line = *buf; 152 {
157 ln = tail - line; 153 char *line;
158 154 gsize ln;
159 /* advance our search space past the CRLF */ 155
160 *buf = tail + 2; 156 /* determine the current line */
161 *len -= (ln + 2); 157 line = *buf;
162 158 ln = tail - line;
163 /* empty line, end of headers */ 159
164 if(! ln) return; 160 /* advance our search space past the CRLF */
165 161 *buf = tail + 2;
166 /* look out for line continuations */ 162 *len -= (ln + 2);
167 if(line[ln-1] == ';') { 163
168 tail = g_strstr_len(*buf, *len, "\r\n"); 164 /* empty line, end of headers */
169 if(tail) { 165 if(! ln) return;
170 gsize cln; 166
171 167 /* look out for line continuations */
172 cln = tail - *buf; 168 if(line[ln-1] == ';') {
173 ln = tail - line; 169 tail = g_strstr_len(*buf, *len, "\r\n");
174 170 if(tail) {
175 /* advance our search space past the CRLF (again) */ 171 gsize cln;
176 *buf = tail + 2; 172
177 *len -= (cln + 2); 173 cln = tail - *buf;
178 } 174 ln = tail - line;
179 } 175
180 176 /* advance our search space past the CRLF (again) */
181 /* process our super-cool line */ 177 *buf = tail + 2;
182 fields_loadline(mf, line, ln); 178 *len -= (cln + 2);
183 } 179 }
184 } 180 }
185 181
186 182 /* process our super-cool line */
187 static void field_write(const char *key, const char *val, GString *str) { 183 fields_loadline(mf, line, ln);
188 g_string_append_printf(str, "%s: %s\r\n", key, val); 184 }
189 } 185 }
190 186
191 187
192 static void fields_write(struct mime_fields *mf, GString *str) { 188 static void
193 g_return_if_fail(mf != NULL); 189 field_write(const char *key, const char *val, GString *str)
194 190 {
195 g_hash_table_foreach(mf->map, (GHFunc) field_write, str); 191 g_string_append_printf(str, "%s: %s\r\n", key, val);
196 g_string_append(str, "\r\n"); 192 }
197 } 193
198 194
199 195 static void
200 static void fields_destroy(struct mime_fields *mf) { 196 fields_write(struct mime_fields *mf, GString *str)
201 g_return_if_fail(mf != NULL); 197 {
202 198 g_return_if_fail(mf != NULL);
203 g_hash_table_destroy(mf->map); 199
204 g_list_free(mf->keys); 200 g_hash_table_foreach(mf->map, (GHFunc) field_write, str);
205 201 g_string_append(str, "\r\n");
206 mf->map = NULL; 202 }
207 mf->keys = NULL; 203
208 } 204
209 205 static void
210 206 fields_destroy(struct mime_fields *mf)
211 static GaimMimePart *part_new(GaimMimeDocument *doc) { 207 {
212 GaimMimePart *part; 208 g_return_if_fail(mf != NULL);
213 209
214 part = g_new0(GaimMimePart, 1); 210 g_hash_table_destroy(mf->map);
215 fields_init(&part->fields); 211 g_list_free(mf->keys);
216 part->doc = doc; 212
217 part->data = g_string_new(NULL); 213 mf->map = NULL;
218 214 mf->keys = NULL;
219 doc->parts = g_list_prepend(doc->parts, part); 215 }
220 216
221 return part; 217
222 } 218 static GaimMimePart *
223 219 part_new(GaimMimeDocument *doc)
224 220 {
225 static void part_load(GaimMimePart *part, 221 GaimMimePart *part;
226 const char *buf, gsize len) { 222
227 223 part = g_new0(GaimMimePart, 1);
228 char *b = (char *) buf; 224 fields_init(&part->fields);
229 gsize n = len; 225 part->doc = doc;
230 226 part->data = g_string_new(NULL);
231 fields_load(&part->fields, &b, &n); 227
232 228 doc->parts = g_list_prepend(doc->parts, part);
233 /* the remainder will have a blank line, if there's anything at all, 229
234 so check if there's anything then trim off the trailing four 230 return part;
235 bytes, \r\n\r\n */ 231 }
236 if(n > 4) n -= 4; 232
237 g_string_append_len(part->data, b, n); 233
238 } 234 static void
239 235 part_load(GaimMimePart *part, const char *buf, gsize len)
240 236 {
241 static void part_write(GaimMimePart *part, GString *str) { 237
242 fields_write(&part->fields, str); 238 char *b = (char *) buf;
243 g_string_append_printf(str, "%s\r\n\r\n", part->data->str); 239 gsize n = len;
244 } 240
245 241 fields_load(&part->fields, &b, &n);
246 242
247 static void part_free(GaimMimePart *part) { 243 /* the remainder will have a blank line, if there's anything at all,
248 244 so check if there's anything then trim off the trailing four
249 fields_destroy(&part->fields); 245 bytes, \r\n\r\n */
250 246 if(n > 4) n -= 4;
251 g_string_free(part->data, TRUE); 247 g_string_append_len(part->data, b, n);
252 part->data = NULL; 248 }
253 249
254 g_free(part); 250
255 } 251 static void
256 252 part_write(GaimMimePart *part, GString *str)
257 253 {
258 GaimMimePart *gaim_mime_part_new(GaimMimeDocument *doc) { 254 fields_write(&part->fields, str);
259 g_return_val_if_fail(doc != NULL, NULL); 255 g_string_append_printf(str, "%s\r\n\r\n", part->data->str);
260 return part_new(doc); 256 }
261 } 257
262 258
263 259 static void
264 const GList *gaim_mime_part_get_fields(GaimMimePart *part) { 260 part_free(GaimMimePart *part)
265 g_return_val_if_fail(part != NULL, NULL); 261 {
266 return part->fields.keys; 262
267 } 263 fields_destroy(&part->fields);
268 264
269 265 g_string_free(part->data, TRUE);
270 const char *gaim_mime_part_get_field(GaimMimePart *part, 266 part->data = NULL;
271 const char *field) { 267
272 268 g_free(part);
273 g_return_val_if_fail(part != NULL, NULL); 269 }
274 return fields_get(&part->fields, field); 270
275 } 271
276 272 GaimMimePart *
277 273 gaim_mime_part_new(GaimMimeDocument *doc)
278 char *gaim_mime_part_get_field_decoded(GaimMimePart *part, 274 {
279 const char *field) { 275 g_return_val_if_fail(doc != NULL, NULL);
280 276 return part_new(doc);
281 const char *f; 277 }
282 278
283 g_return_val_if_fail(part != NULL, NULL); 279
284 280 const GList *
285 f = fields_get(&part->fields, field); 281 gaim_mime_part_get_fields(GaimMimePart *part)
286 return gaim_mime_decode_field(f); 282 {
287 } 283 g_return_val_if_fail(part != NULL, NULL);
288 284 return part->fields.keys;
289 285 }
290 void gaim_mime_part_set_field(GaimMimePart *part, 286
291 const char *field, 287
292 const char *value) { 288 const char *
293 g_return_if_fail(part != NULL); 289 gaim_mime_part_get_field(GaimMimePart *part, const char *field)
294 fields_set(&part->fields, field, value); 290 {
295 } 291 g_return_val_if_fail(part != NULL, NULL);
296 292 return fields_get(&part->fields, field);
297 293 }
298 const char *gaim_mime_part_get_data(GaimMimePart *part) { 294
299 g_return_val_if_fail(part != NULL, NULL); 295
300 g_return_val_if_fail(part->data != NULL, NULL); 296 char *
301 297 gaim_mime_part_get_field_decoded(GaimMimePart *part, const char *field)
302 return part->data->str; 298 {
303 } 299 const char *f;
304 300
305 301 g_return_val_if_fail(part != NULL, NULL);
306 void gaim_mime_part_get_data_decoded(GaimMimePart *part, 302
307 guchar **data, gsize *len) { 303 f = fields_get(&part->fields, field);
308 const char *enc; 304 return gaim_mime_decode_field(f);
309 305 }
310 g_return_if_fail(part != NULL); 306
311 g_return_if_fail(data != NULL); 307
312 g_return_if_fail(len != NULL); 308 void
313 309 gaim_mime_part_set_field(GaimMimePart *part, const char *field, const char *value)
314 g_return_if_fail(part->data != NULL); 310 {
315 311 g_return_if_fail(part != NULL);
316 enc = gaim_mime_part_get_field(part, "content-transfer-encoding"); 312 fields_set(&part->fields, field, value);
317 313 }
318 if(! enc) { 314
319 *data = (guchar *)g_strdup(part->data->str); 315
320 *len = part->data->len; 316 const char *
321 317 gaim_mime_part_get_data(GaimMimePart *part)
322 } else if(! g_ascii_strcasecmp(enc, "7bit")) { 318 {
323 *data = (guchar *)g_strdup(part->data->str); 319 g_return_val_if_fail(part != NULL, NULL);
324 *len = part->data->len; 320 g_return_val_if_fail(part->data != NULL, NULL);
325 321
326 } else if(! g_ascii_strcasecmp(enc, "8bit")) { 322 return part->data->str;
327 *data = (guchar *)g_strdup(part->data->str); 323 }
328 *len = part->data->len; 324
329 325
330 } else if(! g_ascii_strcasecmp(enc, "base16")) { 326 void
331 *data = gaim_base16_decode(part->data->str, len); 327 gaim_mime_part_get_data_decoded(GaimMimePart *part, guchar **data, gsize *len)
332 328 {
333 } else if(! g_ascii_strcasecmp(enc, "base64")) { 329 const char *enc;
330
331 g_return_if_fail(part != NULL);
332 g_return_if_fail(data != NULL);
333 g_return_if_fail(len != NULL);
334
335 g_return_if_fail(part->data != NULL);
336
337 enc = gaim_mime_part_get_field(part, "content-transfer-encoding");
338
339 if(! enc) {
340 *data = (guchar *)g_strdup(part->data->str);
341 *len = part->data->len;
342
343 } else if(! g_ascii_strcasecmp(enc, "7bit")) {
344 *data = (guchar *)g_strdup(part->data->str);
345 *len = part->data->len;
346
347 } else if(! g_ascii_strcasecmp(enc, "8bit")) {
348 *data = (guchar *)g_strdup(part->data->str);
349 *len = part->data->len;
350
351 } else if(! g_ascii_strcasecmp(enc, "base16")) {
352 *data = gaim_base16_decode(part->data->str, len);
353
354 } else if(! g_ascii_strcasecmp(enc, "base64")) {
334 *data = gaim_base64_decode(part->data->str, len); 355 *data = gaim_base64_decode(part->data->str, len);
335 356
336 } else if(! g_ascii_strcasecmp(enc, "quoted-printable")) { 357 } else if(! g_ascii_strcasecmp(enc, "quoted-printable")) {
337 *data = gaim_quotedp_decode(part->data->str, len); 358 *data = gaim_quotedp_decode(part->data->str, len);
338 359
339 } else { 360 } else {
340 gaim_debug_warning("mime", "gaim_mime_part_get_data_decoded:" 361 gaim_debug_warning("mime", "gaim_mime_part_get_data_decoded:"
341 " unknown encoding '%s'\n", enc); 362 " unknown encoding '%s'\n", enc);
342 *data = NULL; 363 *data = NULL;
343 *len = 0; 364 *len = 0;
344 } 365 }
345 } 366 }
346 367
347 368
348 gsize gaim_mime_part_get_length(GaimMimePart *part) { 369 gsize
349 g_return_val_if_fail(part != NULL, 0); 370 gaim_mime_part_get_length(GaimMimePart *part)
350 g_return_val_if_fail(part->data != NULL, 0); 371 {
351 372 g_return_val_if_fail(part != NULL, 0);
352 return part->data->len; 373 g_return_val_if_fail(part->data != NULL, 0);
353 } 374
354 375 return part->data->len;
355 376 }
356 void gaim_mime_part_set_data(GaimMimePart *part, const char *data) { 377
357 g_return_if_fail(part != NULL); 378
358 g_string_free(part->data, TRUE); 379 void
359 part->data = g_string_new(data); 380 gaim_mime_part_set_data(GaimMimePart *part, const char *data)
360 } 381 {
361 382 g_return_if_fail(part != NULL);
362 383 g_string_free(part->data, TRUE);
363 GaimMimeDocument *gaim_mime_document_new() { 384 part->data = g_string_new(data);
364 GaimMimeDocument *doc; 385 }
365 386
366 doc = g_new0(GaimMimeDocument, 1); 387
367 fields_init(&doc->fields); 388 GaimMimeDocument *
368 389 gaim_mime_document_new()
369 return doc; 390 {
370 } 391 GaimMimeDocument *doc;
371 392
372 393 doc = g_new0(GaimMimeDocument, 1);
373 static void doc_parts_load(GaimMimeDocument *doc, 394 fields_init(&doc->fields);
374 const char *boundary, 395
375 const char *buf, gsize len) { 396 return doc;
376 397 }
377 char *b = (char *) buf; 398
378 gsize n = len; 399
379 400 static void
380 const char *bnd; 401 doc_parts_load(GaimMimeDocument *doc, const char *boundary, const char *buf, gsize len)
381 gsize bl; 402 {
382 403 char *b = (char *) buf;
383 bnd = g_strdup_printf("--%s", boundary); 404 gsize n = len;
384 bl = strlen(bnd); 405
385 406 const char *bnd;
386 for(b = g_strstr_len(b, n, bnd); b; ) { 407 gsize bl;
387 char *tail; 408
388 409 bnd = g_strdup_printf("--%s", boundary);
389 /* skip the boundary */ 410 bl = strlen(bnd);
390 b += bl; 411
391 n -= bl; 412 for(b = g_strstr_len(b, n, bnd); b; ) {
392 413 char *tail;
393 /* skip the trailing \r\n or -- as well */ 414
394 if(n >= 2) { 415 /* skip the boundary */
395 b += 2; 416 b += bl;
396 n -= 2; 417 n -= bl;
397 } 418
398 419 /* skip the trailing \r\n or -- as well */
399 /* find the next boundary */ 420 if(n >= 2) {
400 tail = g_strstr_len(b, n, bnd); 421 b += 2;
401 422 n -= 2;
402 if(tail) { 423 }
403 gsize sl; 424
404 425 /* find the next boundary */
405 sl = tail - b; 426 tail = g_strstr_len(b, n, bnd);
406 if(sl) { 427
407 GaimMimePart *part = part_new(doc); 428 if(tail) {
408 part_load(part, b, sl); 429 gsize sl;
409 } 430
410 } 431 sl = tail - b;
411 432 if(sl) {
412 b = tail; 433 GaimMimePart *part = part_new(doc);
413 } 434 part_load(part, b, sl);
414 } 435 }
415 436 }
416 437
417 GaimMimeDocument *gaim_mime_document_parsen(const char *buf, gsize len) { 438 b = tail;
418 439 }
419 GaimMimeDocument *doc; 440 }
420 441
421 char *b = (char *) buf; 442
422 gsize n = len; 443 GaimMimeDocument *
423 444 gaim_mime_document_parsen(const char *buf, gsize len)
424 g_return_val_if_fail(buf != NULL, NULL); 445 {
425 446 GaimMimeDocument *doc;
426 doc = gaim_mime_document_new(); 447
427 448 char *b = (char *) buf;
428 if(! len) return doc; 449 gsize n = len;
429 450
430 fields_load(&doc->fields, &b, &n); 451 g_return_val_if_fail(buf != NULL, NULL);
431 452
432 { 453 doc = gaim_mime_document_new();
433 const char *ct = fields_get(&doc->fields, "content-type"); 454
434 if(ct && gaim_str_has_prefix(ct, "multipart")) { 455 if (!len)
435 char *bd = strrchr(ct, '='); 456 return doc;
436 if(bd++) { 457
437 doc_parts_load(doc, bd, b, n); 458 fields_load(&doc->fields, &b, &n);
438 } 459
439 } 460 {
440 } 461 const char *ct = fields_get(&doc->fields, "content-type");
441 462 if(ct && gaim_str_has_prefix(ct, "multipart")) {
442 return doc; 463 char *bd = strrchr(ct, '=');
443 } 464 if(bd++) {
444 465 doc_parts_load(doc, bd, b, n);
445 466 }
446 GaimMimeDocument *gaim_mime_document_parse(const char *buf) { 467 }
447 g_return_val_if_fail(buf != NULL, NULL); 468 }
448 return gaim_mime_document_parsen(buf, strlen(buf)); 469
449 } 470 return doc;
450 471 }
451 472
452 void gaim_mime_document_write(GaimMimeDocument *doc, GString *str) { 473
453 const char *bd = NULL; 474 GaimMimeDocument *
454 475 gaim_mime_document_parse(const char *buf)
455 g_return_if_fail(doc != NULL); 476 {
456 g_return_if_fail(str != NULL); 477 g_return_val_if_fail(buf != NULL, NULL);
457 478 return gaim_mime_document_parsen(buf, strlen(buf));
458 { 479 }
459 const char *ct = fields_get(&doc->fields, "content-type"); 480
460 if(ct && gaim_str_has_prefix(ct, "multipart")) { 481
461 char *b = strrchr(ct, '='); 482 void
462 if(b++) bd = b; 483 gaim_mime_document_write(GaimMimeDocument *doc, GString *str)
463 } 484 {
464 } 485 const char *bd = NULL;
465 486
466 fields_write(&doc->fields, str); 487 g_return_if_fail(doc != NULL);
467 488 g_return_if_fail(str != NULL);
468 if(bd) { 489
469 GList *l; 490 {
470 491 const char *ct = fields_get(&doc->fields, "content-type");
471 for(l = doc->parts; l; l = l->next) { 492 if(ct && gaim_str_has_prefix(ct, "multipart")) {
472 g_string_append_printf(str, "--%s\r\n", bd); 493 char *b = strrchr(ct, '=');
473 494 if(b++) bd = b;
474 part_write(l->data, str); 495 }
475 496 }
476 if(! l->next) { 497
477 g_string_append_printf(str, "--%s--\r\n", bd); 498 fields_write(&doc->fields, str);
478 } 499
479 } 500 if(bd) {
480 } 501 GList *l;
481 } 502
482 503 for(l = doc->parts; l; l = l->next) {
483 504 g_string_append_printf(str, "--%s\r\n", bd);
484 const GList *gaim_mime_document_get_fields(GaimMimeDocument *doc) { 505
485 g_return_val_if_fail(doc != NULL, NULL); 506 part_write(l->data, str);
486 return doc->fields.keys; 507
487 } 508 if(! l->next) {
488 509 g_string_append_printf(str, "--%s--\r\n", bd);
489 510 }
490 const char *gaim_mime_document_get_field(GaimMimeDocument *doc, 511 }
491 const char *field) { 512 }
492 g_return_val_if_fail(doc != NULL, NULL); 513 }
493 return fields_get(&doc->fields, field); 514
494 } 515
495 516 const GList *
496 517 gaim_mime_document_get_fields(GaimMimeDocument *doc)
497 void gaim_mime_document_set_field(GaimMimeDocument *doc, 518 {
498 const char *field, 519 g_return_val_if_fail(doc != NULL, NULL);
499 const char *value) { 520 return doc->fields.keys;
500 g_return_if_fail(doc != NULL); 521 }
501 fields_set(&doc->fields, field, value); 522
502 } 523
503 524 const char *
504 525 gaim_mime_document_get_field(GaimMimeDocument *doc, const char *field)
505 const GList *gaim_mime_document_get_parts(GaimMimeDocument *doc) { 526 {
506 g_return_val_if_fail(doc != NULL, NULL); 527 g_return_val_if_fail(doc != NULL, NULL);
507 return doc->parts; 528 return fields_get(&doc->fields, field);
508 } 529 }
509 530
510 531
511 void gaim_mime_document_free(GaimMimeDocument *doc) { 532 void
512 if(! doc) return; 533 gaim_mime_document_set_field(GaimMimeDocument *doc, const char *field, const char *value)
513 534 {
514 fields_destroy(&doc->fields); 535 g_return_if_fail(doc != NULL);
515 536 fields_set(&doc->fields, field, value);
516 while(doc->parts) { 537 }
517 part_free(doc->parts->data); 538
518 doc->parts = g_list_delete_link(doc->parts, doc->parts); 539
519 } 540 const GList *
520 541 gaim_mime_document_get_parts(GaimMimeDocument *doc)
521 g_free(doc); 542 {
522 } 543 g_return_val_if_fail(doc != NULL, NULL);
523 544 return doc->parts;
545 }
546
547
548 void
549 gaim_mime_document_free(GaimMimeDocument *doc)
550 {
551 if (!doc)
552 return;
553
554 fields_destroy(&doc->fields);
555
556 while(doc->parts) {
557 part_free(doc->parts->data);
558 doc->parts = g_list_delete_link(doc->parts, doc->parts);
559 }
560
561 g_free(doc);
562 }