Mercurial > pidgin
changeset 24494:3667342896ce
merge of '2f409bcdde5ebbb1edf097aeb4b4366d7c71518d'
and '52e5d841d66390cfc5a59e356e2a53b2e2b9df8a'
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Sun, 23 Nov 2008 07:31:20 +0000 |
parents | 3f80f211417e (current diff) c83ee78ecbe7 (diff) |
children | 637aee10adcb 776da7ede774 |
files | |
diffstat | 2 files changed, 300 insertions(+), 194 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/gg/gg.c Sun Nov 23 04:12:43 2008 +0000 +++ b/libpurple/protocols/gg/gg.c Sun Nov 23 07:31:20 2008 +0000 @@ -61,7 +61,6 @@ * * @return Zero if proxy setup is valid, otherwise -1. */ -/* static int ggp_setup_proxy(PurpleAccount *account) {{{ */ static int ggp_setup_proxy(PurpleAccount *account) { PurpleProxyInfo *gpi; @@ -88,11 +87,7 @@ return 0; } -/* }}} */ -/* - */ -/* static void ggp_async_token_handler(gpointer _gc, gint fd, PurpleInputCondition cond) {{{ */ static void ggp_async_token_handler(gpointer _gc, gint fd, PurpleInputCondition cond) { PurpleConnection *gc = _gc; @@ -157,11 +152,7 @@ token->cb = NULL; cb(gc); } -/* }}} */ -/* - */ -/* static void ggp_token_request(PurpleConnection *gc, GGPTokenCallback cb) {{{ */ static void ggp_token_request(PurpleConnection *gc, GGPTokenCallback cb) { PurpleAccount *account; @@ -199,7 +190,6 @@ * * @param Current action handler. */ -/* static void ggp_action_buddylist_get(PurplePluginAction *action) {{{ */ static void ggp_action_buddylist_get(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *)action->context; @@ -209,14 +199,12 @@ gg_userlist_request(info->session, GG_USERLIST_GET, NULL); } -/* }}} */ /** * Upload the buddylist to the server. * * @param action Current action handler. */ -/* static void ggp_action_buddylist_put(PurplePluginAction *action) {{{ */ static void ggp_action_buddylist_put(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *)action->context; @@ -232,14 +220,12 @@ gg_userlist_request(info->session, GG_USERLIST_PUT, buddylist); g_free(buddylist); } -/* }}} */ /** * Delete buddylist from the server. * * @param action Current action handler. */ -/* static void ggp_action_buddylist_delete(PurplePluginAction *action) {{{ */ static void ggp_action_buddylist_delete(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *)action->context; @@ -249,11 +235,7 @@ gg_userlist_request(info->session, GG_USERLIST_PUT, NULL); } -/* }}} */ -/* - */ -/* static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *file) {{{ */ static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *filename) { PurpleAccount *account = purple_connection_get_account(gc); @@ -284,11 +266,7 @@ g_free(buddylist); } -/* }}} */ -/* - */ -/* static void ggp_callback_buddylist_load_ok(PurpleConnection *gc, gchar *file) {{{ */ static void ggp_callback_buddylist_load_ok(PurpleConnection *gc, gchar *file) { PurpleAccount *account = purple_connection_get_account(gc); @@ -334,11 +312,7 @@ purple_connection_get_account(gc), NULL, NULL, gc); } -/* }}} */ -/* - */ -/* static void ggp_action_buddylist_load(PurplePluginAction *action) {{{ */ static void ggp_action_buddylist_load(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *)action->context; @@ -349,11 +323,7 @@ purple_connection_get_account(gc), NULL, NULL, gc); } -/* }}} */ -/* - */ -/* static void ggp_callback_register_account_ok(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */ static void ggp_callback_register_account_ok(PurpleConnection *gc, PurpleRequestFields *fields) { @@ -435,11 +405,7 @@ g_free(token->id); g_free(token); } -/* }}} */ -/* - */ -/* static void ggp_callback_register_account_cancel(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */ static void ggp_callback_register_account_cancel(PurpleConnection *gc, PurpleRequestFields *fields) { @@ -453,11 +419,7 @@ g_free(token); } -/* }}} */ -/* - */ -/* static void ggp_register_user_dialog(PurpleConnection *gc) {{{ */ static void ggp_register_user_dialog(PurpleConnection *gc) { PurpleAccount *account; @@ -510,13 +472,9 @@ purple_connection_get_account(gc), NULL, NULL, gc); } -/* }}} */ /* ----- PUBLIC DIRECTORY SEARCH ---------------------------------------- */ -/* - */ -/* static void ggp_callback_show_next(PurpleConnection *gc, GList *row, gpointer user_data) {{{ */ static void ggp_callback_show_next(PurpleConnection *gc, GList *row, gpointer user_data) { GGPInfo *info = gc->proto_data; @@ -533,21 +491,13 @@ ggp_search_add(info->searches, seq, form); purple_debug_info("gg", "ggp_callback_show_next(): Added seq %u", seq); } -/* }}} */ -/* - */ -/* static void ggp_callback_add_buddy(PurpleConnection *gc, GList *row, gpointer user_data) {{{ */ static void ggp_callback_add_buddy(PurpleConnection *gc, GList *row, gpointer user_data) { purple_blist_request_add_buddy(purple_connection_get_account(gc), g_list_nth_data(row, 0), NULL, NULL); } -/* }}} */ -/* - */ -/* static void ggp_callback_im(PurpleConnection *gc, GList *row, gpointer user_data) {{{ */ static void ggp_callback_im(PurpleConnection *gc, GList *row, gpointer user_data) { PurpleAccount *account; @@ -560,11 +510,7 @@ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); purple_conversation_present(conv); } -/* }}} */ -/* - */ -/* static void ggp_callback_find_buddies(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */ static void ggp_callback_find_buddies(PurpleConnection *gc, PurpleRequestFields *fields) { GGPInfo *info = gc->proto_data; @@ -611,11 +557,7 @@ ggp_search_add(info->searches, seq, form); purple_debug_info("gg", "ggp_callback_find_buddies(): Added seq %u", seq); } -/* }}} */ -/* - */ -/* static void ggp_find_buddies(PurplePluginAction *action) {{{ */ static void ggp_find_buddies(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *)action->context; @@ -672,13 +614,9 @@ purple_connection_get_account(gc), NULL, NULL, gc); } -/* }}} */ /* ----- CHANGE PASSWORD ------------------------------------------------ */ -/* - */ -/* static void ggp_callback_change_passwd_ok(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */ static void ggp_callback_change_passwd_ok(PurpleConnection *gc, PurpleRequestFields *fields) { PurpleAccount *account; @@ -750,11 +688,7 @@ g_free(info->token->data); g_free(info->token); } -/* }}} */ -/* - */ -/* static void ggp_change_passwd_dialog(PurpleConnection *gc) {{{ */ static void ggp_change_passwd_dialog(PurpleConnection *gc) { PurpleRequestFields *fields; @@ -811,24 +745,16 @@ g_free(msg); } -/* }}} */ -/* - */ -/* static void ggp_change_passwd(PurplePluginAction *action) {{{ */ static void ggp_change_passwd(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *)action->context; ggp_token_request(gc, ggp_change_passwd_dialog); } -/* }}} */ /* ----- CONFERENCES ---------------------------------------------------- */ -/* - */ -/* static void ggp_callback_add_to_chat_ok(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */ static void ggp_callback_add_to_chat_ok(PurpleConnection *gc, PurpleRequestFields *fields) { GGPInfo *info = gc->proto_data; @@ -842,11 +768,7 @@ ggp_confer_participants_add_uin(gc, sel->data, info->tmp_buddy); info->tmp_buddy = 0; } -/* }}} */ -/* - */ -/* static void ggp_bmenu_add_to_chat(PurpleBlistNode *node, gpointer ignored) {{{ */ static void ggp_bmenu_add_to_chat(PurpleBlistNode *node, gpointer ignored) { PurpleBuddy *buddy; @@ -892,13 +814,9 @@ gc); g_free(msg); } -/* }}} */ /* ----- BLOCK BUDDIES -------------------------------------------------- */ -/* - */ -/* static void ggp_bmenu_block(PurpleBlistNode *node, gpointer ignored) {{{ */ static void ggp_bmenu_block(PurpleBlistNode *node, gpointer ignored) { PurpleConnection *gc; @@ -924,7 +842,6 @@ purple_debug_info("gg", "send: uin=%d; mode=BLOCKED\n", uin); } } -/* }}} */ /* ---------------------------------------------------------------------- */ /* ----- INTERNAL CALLBACKS --------------------------------------------- */ @@ -943,7 +860,6 @@ * @param status ID of the status. * @param descr Description. */ -/* static void ggp_generic_status_handler(PurpleConnection *gc, uin_t uin, int status, const char *descr) {{{ */ static void ggp_generic_status_handler(PurpleConnection *gc, uin_t uin, int status, const char *descr) { @@ -983,11 +899,7 @@ g_free(from); g_free(msg); } -/* }}} */ -/* - */ -/* static void ggp_sr_close_cb(gpointer user_data) {{{ */ static void ggp_sr_close_cb(gpointer user_data) { GGPSearchForm *form = user_data; @@ -997,7 +909,6 @@ purple_debug_info("gg", "ggp_sr_close_cb(): Removed seq %u", form->seq); ggp_search_form_destroy(form); } -/* }}} */ /** * Translate a status' ID to a more user-friendly name. @@ -1006,7 +917,6 @@ * * @return The user-friendly name of the status. */ -/* static const char *ggp_status_by_id(unsigned int id) {{{ */ static const char *ggp_status_by_id(unsigned int id) { const char *st; @@ -1029,11 +939,7 @@ return st; } -/* }}} */ -/* - */ -/* static void ggp_pubdir_handle_info(PurpleConnection *gc, gg_pubdir50_t req, GGPSearchForm *form) {{{ */ static void ggp_pubdir_handle_info(PurpleConnection *gc, gg_pubdir50_t req, GGPSearchForm *form) { @@ -1092,11 +998,7 @@ g_free(who); purple_notify_user_info_destroy(user_info); } -/* }}} */ -/* - */ -/* static void ggp_pubdir_handle_full(PurpleConnection *gc, gg_pubdir50_t req, GGPSearchForm *form) {{{ */ static void ggp_pubdir_handle_full(PurpleConnection *gc, gg_pubdir50_t req, GGPSearchForm *form) { @@ -1196,11 +1098,7 @@ purple_notify_searchresults_new_rows(gc, results, form->window); } } -/* }}} */ -/* - */ -/* static void ggp_pubdir_reply_handler(PurpleConnection *gc, gg_pubdir50_t req) {{{ */ static void ggp_pubdir_reply_handler(PurpleConnection *gc, gg_pubdir50_t req) { GGPInfo *info = gc->proto_data; @@ -1239,15 +1137,56 @@ break; } } -/* }}} */ + +static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev) +{ + gint imgid = 0; + GGPInfo *info = gc->proto_data; + GList *entry = g_list_first(info->pending_richtext_messages); + gchar *handlerid = g_strdup_printf("IMGID_HANDLER-%i", ev->event.image_reply.crc32); + + imgid = purple_imgstore_add_with_id( + g_memdup(ev->event.image_reply.image, ev->event.image_reply.size), + ev->event.image_reply.size, + ev->event.image_reply.filename); + + purple_debug_info("gg", "ggp_recv_image_handler: got image with crc32: %u\n", ev->event.image_reply.crc32); + + while(entry) { + if (strstr((gchar *)entry->data, handlerid) != NULL) { + gchar **split = g_strsplit((gchar *)entry->data, handlerid, 3); + gchar *text = g_strdup_printf("%s%i%s", split[0], imgid, split[1]); + purple_debug_info("gg", "ggp_recv_image_handler: found message matching crc32: %s\n", (gchar *)entry->data); + g_strfreev(split); + info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data); + /* We don't have any more images to download */ + if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) { + gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender); + serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, ev->event.msg.time); + g_free(buf); + purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text); + g_free(text); + break; + } + info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, text); + break; + } + entry = g_list_next(entry); + } + g_free(handlerid); + + return; +} + /** * Dispatch a message received from a buddy. * * @param gc PurpleConnection. * @param ev Gadu-Gadu event structure. + * + * Image receiving, some code borrowed from Kadu http://www.kadu.net */ -/* static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) {{{ */ static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) { GGPInfo *info = gc->proto_data; @@ -1264,7 +1203,109 @@ msg = g_markup_escape_text(tmp, -1); g_free(tmp); - purple_debug_info("gg", "msg form (%s): %s (class = %d; rcpt_count = %d)\n", + /* We got richtext message */ + if (ev->event.msg.formats_length) + { + gboolean got_image = FALSE, bold = FALSE, italic = FALSE, under = FALSE; + char *cformats = (char *)ev->event.msg.formats; + char *cformats_end = cformats + ev->event.msg.formats_length; + gint increased_len = 0; + struct gg_msg_richtext_format *actformat; + struct gg_msg_richtext_image *actimage; + GString *message = g_string_new(msg); + gchar *handlerid; + + purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->event.msg.formats_length); + + while (cformats < cformats_end) + { + gint byteoffset; + actformat = (struct gg_msg_richtext_format *)cformats; + cformats += sizeof(struct gg_msg_richtext_format); + byteoffset = g_utf8_offset_to_pointer(message->str, actformat->position + increased_len) - message->str; + + if(actformat->position == 0 && actformat->font == 0) { + purple_debug_warning("gg", "ggp_recv_message_handler: bogus formatting (inc: %i)\n", increased_len); + continue; + } + purple_debug_info("gg", "ggp_recv_message_handler: format at pos: %i, image:%i, bold:%i, italic: %i, under:%i (inc: %i)\n", + actformat->position, + (actformat->font & GG_FONT_IMAGE) != 0, + (actformat->font & GG_FONT_BOLD) != 0, + (actformat->font & GG_FONT_ITALIC) != 0, + (actformat->font & GG_FONT_UNDERLINE) != 0, + increased_len); + + if (actformat->font & GG_FONT_IMAGE) { + got_image = TRUE; + actimage = (struct gg_msg_richtext_image*)(cformats); + cformats += sizeof(struct gg_msg_richtext_image); + purple_debug_info("gg", "ggp_recv_message_handler: image received, size: %d, crc32: %i\n", actimage->size, actimage->crc32); + + /* Checking for errors, image size shouldn't be + * larger than 255.000 bytes */ + if (actimage->size > 255000) { + purple_debug_warning("gg", "ggp_recv_message_handler: received image large than 255 kb\n"); + continue; + } + + gg_image_request(info->session, ev->event.msg.sender, + actimage->size, actimage->crc32); + + handlerid = g_strdup_printf("<IMG ID=\"IMGID_HANDLER-%i\">", actimage->crc32); + g_string_insert(message, byteoffset, handlerid); + increased_len += strlen(handlerid); + g_free(handlerid); + continue; + } + + if (actformat->font & GG_FONT_BOLD) { + if (bold == FALSE) { + g_string_insert(message, byteoffset, "<b>"); + increased_len += 3; + bold = TRUE; + } + } else if (bold) { + g_string_insert(message, byteoffset, "</b>"); + increased_len += 4; + bold = FALSE; + } + + if (actformat->font & GG_FONT_ITALIC) { + if (italic == FALSE) { + g_string_insert(message, byteoffset, "<i>"); + increased_len += 3; + italic = TRUE; + } + } else if (italic) { + g_string_insert(message, byteoffset, "</i>"); + increased_len += 4; + italic = FALSE; + } + + if (actformat->font & GG_FONT_UNDERLINE) { + if (under == FALSE) { + g_string_insert(message, byteoffset, "<u>"); + increased_len += 3; + under = TRUE; + } + } else if (under) { + g_string_insert(message, byteoffset, "</u>"); + increased_len += 4; + under = FALSE; + } + } + + msg = message->str; + g_string_free(message, FALSE); + + if (got_image) { + info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, msg); + return; + } + } + + purple_debug_info("gg", "ggp_recv_message_handler: msg from (%s): %s (class = %d; rcpt_count = %d)\n", from, msg, ev->event.msg.msgclass, ev->event.msg.recipients_count); @@ -1301,11 +1342,32 @@ g_free(msg); g_free(from); } -/* }}} */ + +static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev) +{ + GGPInfo *info = gc->proto_data; + PurpleStoredImage *image; + gint imgid = GPOINTER_TO_INT(g_hash_table_lookup(info->pending_images, &ev->event.image_request.crc32)); + + purple_debug_info("gg", "ggp_send_image_handler: image request received, crc32: %u\n", ev->event.image_request.crc32); -/* - */ -/* static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond) {{{ */ + if(imgid) + { + if((image = purple_imgstore_find_by_id(imgid))) { + gint image_size = purple_imgstore_get_size(image); + gconstpointer image_bin = purple_imgstore_get_data(image); + const char *image_filename = purple_imgstore_get_filename(image); + + purple_debug_info("gg", "ggp_send_image_handler: sending image imgid: %i, crc: %u\n", imgid, ev->event.image_request.crc32); + gg_image_reply(info->session, (unsigned long int)ev->event.image_request.sender, image_filename, image_bin, image_size); + purple_imgstore_unref(image); + } else { + purple_debug_error("gg", "ggp_send_image_handler: image imgid: %i, crc: %u in hash but not found in imgstore!\n", imgid, ev->event.image_request.crc32); + } + g_hash_table_remove(info->pending_images, &ev->event.image_request.crc32); + } +} + static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond) { PurpleConnection *gc = _gc; @@ -1330,11 +1392,18 @@ ggp_recv_message_handler(gc, ev); break; case GG_EVENT_ACK: + /* Changing %u to %i fixes compiler warning */ purple_debug_info("gg", - "message sent to: %u, delivery status=%d, seq=%d\n", + "ggp_callback_recv: message sent to: %i, delivery status=%d, seq=%d\n", ev->event.ack.recipient, ev->event.ack.status, ev->event.ack.seq); break; + case GG_EVENT_IMAGE_REPLY: + ggp_recv_image_handler(gc, ev); + break; + case GG_EVENT_IMAGE_REQUEST: + ggp_send_image_handler(gc, ev); + break; case GG_EVENT_NOTIFY: case GG_EVENT_NOTIFY_DESCR: { @@ -1426,11 +1495,7 @@ gg_free_event(ev); } -/* }}} */ -/* - */ -/* static void ggp_async_login_handler(gpointer _gc, gint fd, PurpleInputCondition cond) {{{ */ static void ggp_async_login_handler(gpointer _gc, gint fd, PurpleInputCondition cond) { PurpleConnection *gc = _gc; @@ -1519,20 +1584,16 @@ gg_free_event(ev); } -/* }}} */ /* ---------------------------------------------------------------------- */ /* ----- PurplePluginProtocolInfo ----------------------------------------- */ /* ---------------------------------------------------------------------- */ -/* static const char *ggp_list_icon(PurpleAccount *account, PurpleBuddy *buddy) {{{ */ static const char *ggp_list_icon(PurpleAccount *account, PurpleBuddy *buddy) { return "gadu-gadu"; } -/* }}} */ -/* static char *ggp_status_text(PurpleBuddy *b) {{{ */ static char *ggp_status_text(PurpleBuddy *b) { PurpleStatus *status; @@ -1558,20 +1619,21 @@ return text; } } -/* }}} */ -/* static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) {{{ */ static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) { PurpleStatus *status; char *text, *tmp; - const char *msg, *name; + const char *msg, *name, *alias; g_return_if_fail(b != NULL); status = purple_presence_get_active_status(purple_buddy_get_presence(b)); msg = purple_status_get_attr_string(status, "message"); name = purple_status_get_name(status); + alias = purple_buddy_get_alias(b); + + purple_notify_user_info_add_pair (user_info, _("Alias"), alias); if (msg != NULL) { text = g_markup_escape_text(msg, -1); @@ -1588,9 +1650,7 @@ purple_notify_user_info_add_pair(user_info, _("Status"), name); } } -/* }}} */ -/* static GList *ggp_status_types(PurpleAccount *account) {{{ */ static GList *ggp_status_types(PurpleAccount *account) { PurpleStatusType *type; @@ -1634,9 +1694,7 @@ return types; } -/* }}} */ -/* static GList *ggp_blist_node_menu(PurpleBlistNode *node) {{{ */ static GList *ggp_blist_node_menu(PurpleBlistNode *node) { PurpleMenuAction *act; @@ -1666,9 +1724,7 @@ return m; } -/* }}} */ -/* static GList *ggp_chat_info(PurpleConnection *gc) {{{ */ static GList *ggp_chat_info(PurpleConnection *gc) { GList *m = NULL; @@ -1682,9 +1738,7 @@ return m; } -/* }}} */ -/* static void ggp_login(PurpleAccount *account) {{{ */ static void ggp_login(PurpleAccount *account) { PurpleConnection *gc; @@ -1706,11 +1760,14 @@ info->chats_count = 0; info->token = NULL; info->searches = ggp_search_new(); + info->pending_richtext_messages = NULL; + info->pending_images = g_hash_table_new(g_int_hash, g_int_equal); gc->proto_data = info; glp->uin = ggp_get_uin(account); glp->password = (char *)purple_account_get_password(account); + glp->image_size = 255; presence = purple_account_get_presence(account); status = purple_presence_get_active_status(presence); @@ -1730,9 +1787,7 @@ gc->inpa = purple_input_add(info->session->fd, PURPLE_INPUT_READ, ggp_async_login_handler, gc); } -/* }}} */ -/* static void ggp_close(PurpleConnection *gc) {{{ */ static void ggp_close(PurpleConnection *gc) { @@ -1760,6 +1815,8 @@ purple_notify_close_with_handle(gc); ggp_search_destroy(info->searches); + g_list_free(info->pending_richtext_messages); + g_hash_table_destroy(info->pending_images); g_free(info); gc->proto_data = NULL; } @@ -1771,25 +1828,108 @@ purple_debug_info("gg", "Connection closed.\n"); } -/* }}} */ -/* static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg, PurpleMessageFlags flags) {{{ */ static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg, PurpleMessageFlags flags) { GGPInfo *info = gc->proto_data; char *tmp, *plain; - int ret = 0; + int ret = 1; + unsigned char format[1024]; + unsigned int format_length = sizeof(struct gg_msg_richtext); + gint pos = 0; + GData *attribs; + const char *start, *end = NULL, *last; - if (strlen(msg) == 0) { + if (msg == NULL || *msg == '\0') { return 0; } - purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg); - plain = purple_unescape_html(msg); + last = msg; + + /* Check if the message is richtext */ + /* TODO: Check formatting, too */ + if(purple_markup_find_tag("img", last, &start, &end, &attribs)) { + + GString *string_buffer = g_string_new(NULL); + struct gg_msg_richtext fmt; + + do { + PurpleStoredImage *image; + const char *id; + + /* Add text before the image */ + if(start - last) { + pos = pos + g_utf8_strlen(last, start - last); + g_string_append_len(string_buffer, last, start - last); + } + + if((id = g_datalist_get_data(&attribs, "id")) && (image = purple_imgstore_find_by_id(atoi(id)))) { + struct gg_msg_richtext_format actformat; + struct gg_msg_richtext_image actimage; + gint image_size = purple_imgstore_get_size(image); + gconstpointer image_bin = purple_imgstore_get_data(image); + const char *image_filename = purple_imgstore_get_filename(image); + uint32_t crc32 = gg_crc32(0, image_bin, image_size); + + g_hash_table_insert(info->pending_images, &crc32, GINT_TO_POINTER(atoi(id))); + purple_imgstore_ref(image); + purple_debug_info("gg", "ggp_send_im_richtext: got crc: %i for imgid: %i\n", crc32, atoi(id)); + + actformat.font = GG_FONT_IMAGE; + actformat.position = pos; + + actimage.unknown1 = 0x0109; + actimage.size = gg_fix32(image_size); + actimage.crc32 = gg_fix32(crc32); + + if (actimage.size > 255000) { + purple_debug_warning("gg", "ggp_send_im_richtext: image over 255kb!\n"); + continue; + } + + purple_debug_info("gg", "ggp_send_im_richtext: adding images to richtext, size: %i, crc32: %u, name: %s\n", actimage.size, actimage.crc32, image_filename); + + memcpy(format + format_length, &actformat, sizeof(actformat)); + format_length += sizeof(actformat); + memcpy(format + format_length, &actimage, sizeof(actimage)); + format_length += sizeof(actimage); + } else { + purple_debug_error("gg", "ggp_send_im_richtext: image not found in the image store!"); + } + + last = end + 1; + g_datalist_clear(&attribs); + + } while(purple_markup_find_tag("img", last, &start, &end, &attribs)); + + /* Add text after the images */ + if(last && *last) { + pos = pos + g_utf8_strlen(last, -1); + g_string_append(string_buffer, last); + } + + fmt.flag = 2; + fmt.length = format_length - sizeof(fmt); + memcpy(format, &fmt, sizeof(fmt)); + + purple_debug_info("gg", "ggp_send_im: richtext msg = %s\n", string_buffer->str); + plain = purple_unescape_html(string_buffer->str); + g_string_free(string_buffer, TRUE); + } else { + purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg); + plain = purple_unescape_html(msg); + } + tmp = charset_convert(plain, "UTF-8", "CP1250"); - if (NULL == tmp || strlen(tmp) == 0) { + if (tmp && (format_length - sizeof(struct gg_msg_richtext))) { + if(gg_send_message_richtext(info->session, GG_CLASS_CHAT, ggp_str_to_uin(who), (unsigned char *)tmp, format, format_length) < 0) { + ret = -1; + } else { + ret = 1; + } + } else if (NULL == tmp || *tmp == 0) { ret = 0; } else if (strlen(tmp) > GG_MSG_MAXSIZE) { ret = -E2BIG; @@ -1805,9 +1945,7 @@ return ret; } -/* }}} */ -/* static void ggp_get_info(PurpleConnection *gc, const char *name) { {{{ */ static void ggp_get_info(PurpleConnection *gc, const char *name) { GGPInfo *info = gc->proto_data; @@ -1825,9 +1963,7 @@ ggp_search_add(info->searches, seq, form); purple_debug_info("gg", "ggp_get_info(): Added seq %u", seq); } -/* }}} */ -/* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */ static int ggp_to_gg_status(PurpleStatus *status, char **msg) { const char *status_id = purple_status_get_id(status); @@ -1872,9 +2008,7 @@ return new_status; } } -/* }}} */ -/* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */ static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) { PurpleConnection *gc; @@ -1900,9 +2034,7 @@ ggp_status_fake_to_self(account); } -/* }}} */ -/* static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {{{ */ static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { PurpleAccount *account; @@ -1915,9 +2047,7 @@ ggp_status_fake_to_self(account); } } -/* }}} */ -/* static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {{{ */ static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { @@ -1925,9 +2055,7 @@ gg_remove_notify(info->session, ggp_str_to_uin(buddy->name)); } -/* }}} */ -/* static void ggp_join_chat(PurpleConnection *gc, GHashTable *data) {{{ */ static void ggp_join_chat(PurpleConnection *gc, GHashTable *data) { GGPInfo *info = gc->proto_data; @@ -1960,15 +2088,11 @@ purple_account_get_username(account), NULL, PURPLE_CBFLAGS_NONE, TRUE); } -/* }}} */ -/* static char *ggp_get_chat_name(GHashTable *data) { {{{ */ static char *ggp_get_chat_name(GHashTable *data) { return g_strdup(g_hash_table_lookup(data, "name")); } -/* }}} */ -/* static int ggp_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) {{{ */ static int ggp_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) { PurpleConversation *conv; @@ -2020,9 +2144,7 @@ return 0; } -/* }}} */ -/* static void ggp_keepalive(PurpleConnection *gc) {{{ */ static void ggp_keepalive(PurpleConnection *gc) { GGPInfo *info = gc->proto_data; @@ -2037,9 +2159,7 @@ _("Not connected to the server.")); } } -/* }}} */ -/* static void ggp_register_user(PurpleAccount *account) {{{ */ static void ggp_register_user(PurpleAccount *account) { PurpleConnection *gc = purple_account_get_connection(account); @@ -2049,9 +2169,7 @@ ggp_token_request(gc, ggp_register_user_dialog); } -/* }}} */ -/* static GList *ggp_actions(PurplePlugin *plugin, gpointer context) {{{ */ static GList *ggp_actions(PurplePlugin *plugin, gpointer context) { GList *m = NULL; @@ -2091,19 +2209,15 @@ return m; } -/* }}} */ -/* static gboolean ggp_offline_message(const PurpleBuddy *buddy) {{{ */ static gboolean ggp_offline_message(const PurpleBuddy *buddy) { return TRUE; } -/* }}} */ -/* prpl_info setup {{{ */ static PurplePluginProtocolInfo prpl_info = { - OPT_PROTO_REGISTER_NOSCREENNAME, + OPT_PROTO_REGISTER_NOSCREENNAME | OPT_PROTO_IM_IMAGE, NULL, /* user_splits */ NULL, /* protocol_options */ {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ @@ -2173,36 +2287,34 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL }; -/* }}} */ -/* PurplePluginInfo setup {{{ */ static PurplePluginInfo info = { - PURPLE_PLUGIN_MAGIC, /* magic */ - PURPLE_MAJOR_VERSION, /* major_version */ - PURPLE_MINOR_VERSION, /* minor_version */ - PURPLE_PLUGIN_PROTOCOL, /* plugin type */ - NULL, /* ui_requirement */ - 0, /* flags */ - NULL, /* dependencies */ + PURPLE_PLUGIN_MAGIC, /* magic */ + PURPLE_MAJOR_VERSION, /* major_version */ + PURPLE_MINOR_VERSION, /* minor_version */ + PURPLE_PLUGIN_PROTOCOL, /* plugin type */ + NULL, /* ui_requirement */ + 0, /* flags */ + NULL, /* dependencies */ PURPLE_PRIORITY_DEFAULT, /* priority */ - "prpl-gg", /* id */ - "Gadu-Gadu", /* name */ - DISPLAY_VERSION, /* version */ + "prpl-gg", /* id */ + "Gadu-Gadu", /* name */ + DISPLAY_VERSION, /* version */ N_("Gadu-Gadu Protocol Plugin"), /* summary */ N_("Polish popular IM"), /* description */ - "boler@sourceforge.net", /* author */ - PURPLE_WEBSITE, /* homepage */ + "boler@sourceforge.net", /* author */ + PURPLE_WEBSITE, /* homepage */ - NULL, /* load */ - NULL, /* unload */ - NULL, /* destroy */ + NULL, /* load */ + NULL, /* unload */ + NULL, /* destroy */ - NULL, /* ui_info */ - &prpl_info, /* extra_info */ - NULL, /* prefs_info */ - ggp_actions, /* actions */ + NULL, /* ui_info */ + &prpl_info, /* extra_info */ + NULL, /* prefs_info */ + ggp_actions, /* actions */ /* padding */ NULL, @@ -2210,9 +2322,7 @@ NULL, NULL }; -/* }}} */ -/* static void purple_gg_debug_handler(int level, const char * format, va_list args) {{{ */ static void purple_gg_debug_handler(int level, const char * format, va_list args) { PurpleDebugLevel purple_level; char *msg = g_strdup_vprintf(format, args); @@ -2235,11 +2345,7 @@ purple_debug(purple_level, "gg", "%s", msg); g_free(msg); } -/* }}} */ -/* - */ -/* static void init_plugin(PurplePlugin *plugin) {{{ */ static void init_plugin(PurplePlugin *plugin) { PurpleAccountOption *option; @@ -2253,7 +2359,6 @@ gg_debug_handler = purple_gg_debug_handler; } -/* }}} */ PURPLE_INIT_PLUGIN(gg, init_plugin, info);
--- a/libpurple/protocols/gg/gg.h Sun Nov 23 04:12:43 2008 +0000 +++ b/libpurple/protocols/gg/gg.h Sun Nov 23 07:31:20 2008 +0000 @@ -65,9 +65,10 @@ uin_t tmp_buddy; int chats_count; + GList *pending_richtext_messages; + GHashTable *pending_images; } GGPInfo; - #endif /* _PURPLE_GG_H */ /* vim: set ts=8 sts=0 sw=8 noet: */