libpurple/protocols/sametime/im_mime.c

changeset 39526
4f678f514b69
parent 39524
b49e731857a2
child 39528
0fa64a08fd5b
equal deleted inserted replaced
39525:e1280f3aaea8 39526:4f678f514b69
22 */ 22 */
23 23
24 #include "internal.h" 24 #include "internal.h"
25 25
26 #include <glib.h> 26 #include <glib.h>
27 #include <gmime/gmime.h>
27 28
28 /* purple includes */ 29 /* purple includes */
29 #include "image-store.h" 30 #include "image-store.h"
30 #include "mime.h"
31 31
32 /* plugin includes */ 32 /* plugin includes */
33 #include "sametime.h" 33 #include "sametime.h"
34 #include "im_mime.h" 34 #include "im_mime.h"
35 35
36 36
37 /** generate "cid:908@20582notesbuddy" from "<908@20582notesbuddy>" */ 37 /** generate "cid:908@20582notesbuddy" from "<908@20582notesbuddy>" */
38 static char * 38 static char *
39 make_cid(const char *cid) 39 make_cid(const char *cid)
40 { 40 {
41 gsize n;
42 char *c, *d;
43
44 g_return_val_if_fail(cid != NULL, NULL); 41 g_return_val_if_fail(cid != NULL, NULL);
45 42
46 n = strlen(cid); 43 return g_strdup_printf("cid:%s", cid);
47 g_return_val_if_fail(n > 2, NULL); 44 }
48 45
49 c = g_strndup(cid+1, n-2); 46
50 d = g_strdup_printf("cid:%s", c); 47 /* Create a MIME parser from some input data. */
51 48 static GMimeParser *
52 g_free(c); 49 create_parser(const char *data)
53 return d; 50 {
51 GMimeStream *stream;
52 GMimeFilter *filter;
53 GMimeStream *filtered_stream;
54 GMimeParser *parser;
55
56 stream = g_mime_stream_mem_new_with_buffer(data, strlen(data));
57
58 filtered_stream = g_mime_stream_filter_new(stream);
59 g_object_unref(G_OBJECT(stream));
60
61 /* Add a dos2unix filter so in-message newlines are simplified. */
62 filter = g_mime_filter_dos2unix_new(FALSE);
63 g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), filter);
64 g_object_unref(G_OBJECT(filter));
65
66 parser = g_mime_parser_new_with_stream(filtered_stream);
67 g_object_unref(G_OBJECT(filtered_stream));
68
69 return parser;
54 } 70 }
55 71
56 72
57 gchar * 73 gchar *
58 im_mime_parse(const char *data) 74 im_mime_parse(const char *data)
59 { 75 {
60 GHashTable *img_by_cid; 76 GHashTable *img_by_cid;
61 77
62 GString *str; 78 GString *str;
63 79
64 PurpleMimeDocument *doc; 80 GMimeParser *parser;
65 GList *parts; 81 GMimeObject *doc;
82 int i, count;
66 83
67 img_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, 84 img_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
68 g_object_unref); 85 g_object_unref);
69 86
70 /* don't want the contained string to ever be NULL */ 87 /* don't want the contained string to ever be NULL */
71 str = g_string_new(""); 88 str = g_string_new("");
72 89
73 doc = purple_mime_document_parse(data); 90 parser = create_parser(data);
91 doc = g_mime_parser_construct_part(parser, NULL);
92 if (!GMIME_IS_MULTIPART(doc)) {
93 g_object_unref(G_OBJECT(doc));
94 g_object_unref(G_OBJECT(parser));
95 return g_string_free(str, FALSE);
96 }
74 97
75 /* handle all the MIME parts */ 98 /* handle all the MIME parts */
76 parts = purple_mime_document_get_parts(doc); 99 count = g_mime_multipart_get_count(GMIME_MULTIPART(doc));
77 for (; parts; parts = parts->next) { 100 for (i = 0; i < count; i++) {
78 PurpleMimePart *part = parts->data; 101 GMimeObject *obj = g_mime_multipart_get_part(GMIME_MULTIPART(doc), i);
79 const char *type; 102 GMimeContentType *type = g_mime_object_get_content_type(obj);
80
81 type = purple_mime_part_get_field(part, "content-type");
82 purple_debug_info("sametime", "MIME part Content-Type: %s\n",
83 type);
84 103
85 if (!type) { 104 if (!type) {
86 ; /* feh */ 105 ; /* feh */
87 106
88 } else if (purple_str_has_prefix(type, "image")) { 107 } else if (g_mime_content_type_is_type(type, "image", "*")) {
89 /* put images into the image store */ 108 /* put images into the image store */
90 109
91 guchar *d_dat; 110 GMimePart *part = GMIME_PART(obj);
92 gsize d_len; 111 GMimeDataWrapper *wrapper;
112 GMimeStream *stream;
113 GByteArray *bytearray;
114 GBytes *data;
93 char *cid; 115 char *cid;
94 PurpleImage *image; 116 PurpleImage *image;
95 117
96 /* obtain and unencode the data */ 118 /* obtain and unencode the data */
97 purple_mime_part_get_data_decoded(part, &d_dat, &d_len); 119 bytearray = g_byte_array_new();
120 stream = g_mime_stream_mem_new_with_byte_array(bytearray);
121 g_mime_stream_mem_set_owner(GMIME_STREAM_MEM(stream), FALSE);
122 wrapper = g_mime_part_get_content(part);
123 g_mime_data_wrapper_write_to_stream(wrapper, stream);
124 data = g_byte_array_free_to_bytes(bytearray);
125 g_clear_object(&stream);
98 126
99 /* look up the content id */ 127 /* look up the content id */
100 cid = (char *)purple_mime_part_get_field(part, 128 cid = make_cid(g_mime_part_get_content_id(part));
101 "Content-ID");
102 cid = make_cid(cid);
103 129
104 /* add image to the purple image store */ 130 /* add image to the purple image store */
105 image = purple_image_new_from_data(d_dat, d_len); 131 image = purple_image_new_from_bytes(data);
106 purple_image_set_friendly_filename(image, cid); 132 purple_image_set_friendly_filename(image, cid);
133 g_bytes_unref(data);
107 134
108 /* map the cid to the image store identifier */ 135 /* map the cid to the image store identifier */
109 g_hash_table_insert(img_by_cid, cid, image); 136 g_hash_table_insert(img_by_cid, cid, image);
110 137
111 } else if (purple_str_has_prefix(type, "text")) { 138 } else if (GMIME_IS_TEXT_PART(obj)) {
112
113 /* concatenate all the text parts together */ 139 /* concatenate all the text parts together */
114 guchar *data; 140 char *data;
115 gsize len; 141
116 142 data = g_mime_text_part_get_text(GMIME_TEXT_PART(obj));
117 purple_mime_part_get_data_decoded(part, &data, &len); 143 g_string_append(str, data);
118 g_string_append(str, (const char *)data);
119 g_free(data); 144 g_free(data);
120 } 145 }
121 } 146 }
122 147
123 purple_mime_document_free(doc); 148 g_object_unref(G_OBJECT(doc));
149 g_object_unref(G_OBJECT(parser));
124 150
125 /* @todo should put this in its own function */ 151 /* @todo should put this in its own function */
126 { /* replace each IMG tag's SRC attribute with an ID attribute. This 152 { /* replace each IMG tag's SRC attribute with an ID attribute. This
127 actually modifies the contents of str */ 153 actually modifies the contents of str */
128 GData *attribs; 154 GData *attribs;
192 return g_strdup_printf("%03x@%05xmeanwhile", 218 return g_strdup_printf("%03x@%05xmeanwhile",
193 g_random_int() & 0xfff, g_random_int() & 0xfffff); 219 g_random_int() & 0xfff, g_random_int() & 0xfffff);
194 } 220 }
195 221
196 222
197 /** generates a multipart/related content type with a random-ish 223 /** generates a random-ish boundary value */
198 boundary value */
199 static char * 224 static char *
200 im_mime_content_type(void) 225 im_mime_boundary(void)
201 { 226 {
202 return g_strdup_printf( 227 return g_strdup_printf("related_MW%03x_%04x",
203 "multipart/related; boundary=related_MW%03x_%04x",
204 g_random_int() & 0xfff, g_random_int() & 0xffff); 228 g_random_int() & 0xfff, g_random_int() & 0xffff);
205 } 229 }
206 230
207 /** determine content type from contents */ 231 /** create MIME image from purple image */
208 static gchar * 232 static GMimePart *
209 im_mime_img_content_type(PurpleImage *img) 233 im_mime_img_to_part(PurpleImage *img)
210 { 234 {
211 const gchar *mimetype; 235 const gchar *mimetype;
236 GMimePart *part;
237 GByteArray *data;
238 GMimeStream *stream;
239 GMimeDataWrapper *wrapper;
212 240
213 mimetype = purple_image_get_mimetype(img); 241 mimetype = purple_image_get_mimetype(img);
214 if (!mimetype) { 242 if (mimetype && g_str_has_prefix(mimetype, "image/")) {
215 mimetype = "image"; 243 mimetype += sizeof("image/") - 1;
216 } 244 }
217 245
218 return g_strdup_printf("%s; name=\"%s\"", mimetype, 246 part = g_mime_part_new_with_type("image", mimetype);
219 purple_image_get_friendly_filename(img)); 247 g_mime_object_set_disposition(GMIME_OBJECT(part),
220 } 248 GMIME_DISPOSITION_ATTACHMENT);
221 249 g_mime_part_set_content_encoding(part, GMIME_CONTENT_ENCODING_BASE64);
222 250 g_mime_part_set_filename(part, purple_image_get_friendly_filename(img));
223 static char * 251
224 im_mime_img_content_disp(PurpleImage *img) 252 data = g_bytes_unref_to_array(purple_image_get_contents(img));
225 { 253 stream = g_mime_stream_mem_new_with_byte_array(data);
226 return g_strdup_printf("attachment; filename=\"%s\"", 254
227 purple_image_get_friendly_filename(img)); 255 wrapper = g_mime_data_wrapper_new_with_stream(stream,
256 GMIME_CONTENT_ENCODING_BINARY);
257 g_object_unref(G_OBJECT(stream));
258
259 g_mime_part_set_content(part, wrapper);
260 g_object_unref(G_OBJECT(wrapper));
261
262 return part;
228 } 263 }
229 264
230 265
231 gchar * 266 gchar *
232 im_mime_generate(const char *message) 267 im_mime_generate(const char *message)
233 { 268 {
234 GString *str; 269 GString *str;
235 PurpleMimeDocument *doc; 270 GMimeMultipart *doc;
236 PurpleMimePart *part; 271 GMimeFormatOptions *opts;
272 GMimeTextPart *text;
237 273
238 GData *attr; 274 GData *attr;
239 char *tmp, *start, *end; 275 char *tmp, *start, *end;
240 276
241 str = g_string_new(NULL); 277 str = g_string_new(NULL);
242 278
243 doc = purple_mime_document_new(); 279 doc = g_mime_multipart_new_with_subtype("related");
244 280
245 purple_mime_document_set_field(doc, "Mime-Version", "1.0"); 281 g_mime_object_set_header(GMIME_OBJECT(doc), "Mime-Version", "1.0", NULL);
246 purple_mime_document_set_field(doc, "Content-Disposition", "inline"); 282 g_mime_object_set_disposition(GMIME_OBJECT(doc), GMIME_DISPOSITION_INLINE);
247 283
248 tmp = im_mime_content_type(); 284 tmp = im_mime_boundary();
249 purple_mime_document_set_field(doc, "Content-Type", tmp); 285 g_mime_multipart_set_boundary(doc, tmp);
250 g_free(tmp); 286 g_free(tmp);
251 287
252 tmp = (char *)message; 288 tmp = (char *)message;
253 while (*tmp && 289 while (*tmp &&
254 purple_markup_find_tag("img", tmp, (const char **) &start, 290 purple_markup_find_tag("img", tmp, (const char **) &start,
267 if (uri) { 303 if (uri) {
268 img = purple_image_store_get_from_uri(uri); 304 img = purple_image_store_get_from_uri(uri);
269 } 305 }
270 306
271 if (img) { 307 if (img) {
308 GMimePart *part;
272 char *cid; 309 char *cid;
273 gpointer data;
274 gsize size;
275
276 part = purple_mime_part_new(doc);
277
278 data = im_mime_img_content_disp(img);
279 purple_mime_part_set_field(part, "Content-Disposition",
280 data);
281 g_free(data);
282
283 data = im_mime_img_content_type(img);
284 purple_mime_part_set_field(part, "Content-Type", data);
285 g_free(data);
286 310
287 cid = im_mime_content_id(); 311 cid = im_mime_content_id();
288 data = g_strdup_printf("<%s>", cid); 312 part = im_mime_img_to_part(img);
289 purple_mime_part_set_field(part, "Content-ID", data); 313 g_mime_part_set_content_id(part, cid);
290 g_free(data); 314 g_mime_multipart_add(doc, GMIME_OBJECT(part));
291 315 g_object_unref(G_OBJECT(part));
292 purple_mime_part_set_field(part,
293 "Content-transfer-encoding", "base64");
294
295 /* obtain and base64 encode the image data, and put it
296 in the mime part */
297 size = purple_image_get_data_size(img);
298 data = g_base64_encode(purple_image_get_data(img), size);
299 purple_mime_part_set_data(part, data);
300 g_free(data);
301 316
302 /* append the modified tag */ 317 /* append the modified tag */
303 g_string_append_printf(str, "<img src=\"cid:%s\">", cid); 318 g_string_append_printf(str, "<img src=\"cid:%s\">", cid);
304 g_free(cid); 319 g_free(cid);
305 320
316 331
317 /* append left-overs */ 332 /* append left-overs */
318 g_string_append(str, tmp); 333 g_string_append(str, tmp);
319 334
320 /* add the text/html part */ 335 /* add the text/html part */
321 part = purple_mime_part_new(doc); 336 text = g_mime_text_part_new_with_subtype("html");
322 purple_mime_part_set_field(part, "Content-Disposition", "inline"); 337 g_mime_object_set_disposition(GMIME_OBJECT(text),
338 GMIME_DISPOSITION_INLINE);
323 339
324 tmp = purple_utf8_ncr_encode(str->str); 340 tmp = purple_utf8_ncr_encode(str->str);
325 purple_mime_part_set_field(part, "Content-Type", "text/html"); 341 g_mime_text_part_set_text(text, tmp);
326 purple_mime_part_set_field(part, "Content-Transfer-Encoding", "7bit");
327 purple_mime_part_set_data(part, tmp);
328 g_free(tmp); 342 g_free(tmp);
329 343
344 g_mime_multipart_insert(doc, 0, GMIME_OBJECT(text));
345 g_object_unref(G_OBJECT(text));
330 g_string_free(str, TRUE); 346 g_string_free(str, TRUE);
331 347
332 str = g_string_new(NULL); 348 opts = g_mime_format_options_new();
333 purple_mime_document_write(doc, str); 349 g_mime_format_options_set_newline_format(opts, GMIME_NEWLINE_FORMAT_DOS);
334 return g_string_free(str, FALSE); 350 tmp = g_mime_object_to_string(GMIME_OBJECT(doc), opts);
335 } 351 g_mime_format_options_free(opts);
352 g_object_unref(G_OBJECT(doc));
353 return tmp;
354 }

mercurial