--- a/src/protocols/oscar/odc.c Sun Apr 09 14:29:27 2006 -0400
+++ b/src/protocols/oscar/odc.c Sun Apr 09 17:37:12 2006 -0400
@@ -204,6 +204,12 @@
g_free(frame.payload.data);
* This is called after a direct IM has been received in its entirety. This
* function is passed a long chunk of data which contains the IM with any
@@ -217,7 +223,7 @@
* create the img store using the given data.
* For somewhat easy reference, here's a sample message
- * (without the whitespace and asterisks):
+ * (with added whitespace): * <HTML><BODY BGCOLOR="#ffffff">
@@ -232,144 +238,189 @@
* <DATA ID="1" SIZE="9894">datadatadatadata</DATA>
* <DATA ID="2" SIZE="65978">datadatadatadata</DATA>
- * TODO: This should be rewritten to parse all the binary data first
- * and add each image, then go through the message afterwrod and
- * substitute in the image tags.
peer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int encoding, gboolean autoreply)
- GaimMessageFlags imflags;
+ const char *msgend, *binary_start, *dataend; + const char *tmp, *start, *end, *idstr, *src, *sizestr; + GHashTable *embedded_datas; + struct embedded_data *embedded_data;
- const char *msgend, *binary_start, *binary;
+ GaimMessageFlags imflags;
account = gaim_connection_get_account(gc);
- newmsg = g_string_new("");
- imflags |= GAIM_MESSAGE_AUTO_RESP;
+ * Create a hash table containing references to each embedded + * data chunk. The key is the "ID" and the value is an + * embedded_data struct. + embedded_datas = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, g_free); - /* message has a binary trailer */
- if ((binary_start = gaim_strcasestr(msg, "<binary>")))
+ * Create an index of any binary chunks. If we run into any + * problems while parsing the binary data section then we stop + * parsing it, and the local user will see broken image icons. + /* TODO: Use a length argument when looking for the <binary> tag! */ + binary_start = gaim_strcasestr(msg, "<binary>"); + if (binary_start == NULL)
- const char *tmp, *start, *end, *last = NULL;
+ /* Move our pointer to immediately after the <binary> tag */ + tmp = binary_start + 8; - /* for each valid image tag... */
- while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs))
+ /* The embedded binary markup has a mimimum length of 29 bytes */ + /* TODO: Use a length argument when looking for the <data> tag! */ + while ((tmp + 29 <= dataend) && + gaim_markup_find_tag("data", tmp, &start, &tmp, &attributes)) - const char *id, *src, *datasize;
- const char *data = NULL;
+ /* Move the binary pointer from ">" to the start of the data */ - /* update the location of the last img tag */
+ idstr = g_datalist_get_data(&attributes, "id"); + g_datalist_clear(&attributes);
- id = g_datalist_get_data(&attribs, "id");
- src = g_datalist_get_data(&attribs, "src");
- datasize = g_datalist_get_data(&attribs, "datasize");
- /* if we have id & datasize, build the data tag */
- tag = g_strdup_printf("<data id=\"%s\" size=\"%s\">", id, datasize);
+ sizestr = g_datalist_get_data(&attributes, "size"); + g_datalist_clear(&attributes); - /* if we have a tag, find the start of the data */
- if (tag && (data = gaim_strcasestr(binary, tag)))
+ g_datalist_clear(&attributes); + if ((size > 0) && (tmp + size > dataend)) + embedded_data = g_new(struct embedded_data, 1); + embedded_data->size = size; + embedded_data->data = (const guint8 *)tmp; + /* Skip past the closing </data> tag */ + if (strncasecmp(tmp, "</data>", 7))
- binary = data + atoi(datasize) + 7; /* for </data> */
- /* check the data is here and store it */
- if (data && (data + (size = atoi(datasize)) <= msgend))
- imgid = gaim_imgstore_add(data, size, src);
+ g_hash_table_insert(embedded_datas, + GINT_TO_POINTER(id), embedded_data); - /* if we have a stored image... */
- /* append the message up to the tag */
- utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn,
- encoding, 0x0000, tmp, start - tmp);
- newmsg = g_string_append(newmsg, utf8);
+ * Loop through the message, replacing OSCAR img tags with the + * equivalent Gaim img tag. + newmsg = g_string_new(""); + while (gaim_markup_find_tag("img", tmp, &start, &end, &attributes)) + idstr = g_datalist_get_data(&attributes, "id"); + src = g_datalist_get_data(&attributes, "src"); + sizestr = g_datalist_get_data(&attributes, "datasize"); - /* write the new image tag */
- g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid);
+ if ((idstr != NULL) && (src != NULL) && (sizestr!= NULL)) - /* and record the image number */
+ embedded_data = g_hash_table_lookup(embedded_datas, + if ((embedded_data != NULL) && (embedded_data->size == size)) + imgid = gaim_imgstore_add(embedded_data->data, size, src); + /* Record the image number */ images = g_slist_append(images, GINT_TO_POINTER(imgid));
- /* otherwise, copy up to the end of the tag */
- utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn,
- encoding, 0x0000, tmp, (end + 1) - tmp);
- newmsg = g_string_append(newmsg, utf8);
- /* clear the attribute list */
- g_datalist_clear(&attribs);
- /* continue from the end of the tag */
- /* append any remaining message data (without the > :-)) */
- if (last++ && (last < binary_start))
- newmsg = g_string_append_len(newmsg, last, binary_start - last);
+ /* Delete the attribute list */ + g_datalist_clear(&attributes); + /* Append the message up to the tag */ + utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn, + encoding, 0x0000, tmp, start - tmp); + g_string_append(newmsg, utf8); - /* set the flag if we caught any images */
- imflags |= GAIM_MESSAGE_IMAGES;
+ /* Write the new image tag */ + g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid); + /* Continue from the end of the tag */ + /* Append any remaining message data */ utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn,
- encoding, 0x0000, msg, len);
+ encoding, 0x0000, tmp, msgend - tmp); g_string_append(newmsg, utf8);
+ imflags |= GAIM_MESSAGE_IMAGES; + imflags |= GAIM_MESSAGE_AUTO_RESP; serv_got_im(gc, conn->sn, newmsg->str, imflags, time(NULL));
g_string_free(newmsg, TRUE);
/* unref any images we allocated */
- for (tmp = images; tmp != NULL; tmp = tmp->next) {
- id = GPOINTER_TO_INT(tmp->data);
- gaim_imgstore_unref(id);
+ for (l = images; l != NULL; l = l->next) + gaim_imgstore_unref(GPOINTER_TO_INT(l->data)); + /* Delete our list of pointers to embedded images */ + g_hash_table_destroy(embedded_datas); --- a/src/protocols/oscar/oscar.c Sun Apr 09 14:29:27 2006 -0400
+++ b/src/protocols/oscar/oscar.c Sun Apr 09 17:37:12 2006 -0400
@@ -1841,7 +1841,6 @@
aim_mpmsg_section_t *curpart;
gaim_debug_misc("oscar", "Received IM from %s with %d parts\n",
@@ -1937,7 +1936,7 @@
* Convert iChat color tags to normal font tags.
- if (gaim_markup_find_tag("body", tmp, &start, &end, &attribs))
+ if (gaim_markup_find_tag("body", tmp, &start, NULL, &attribs)) const char *ichattextcolor, *ichatballooncolor;