Mercurial > pidgin.yaz
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 } |