/soc/2012/tomkiewicz/gg: 5a0c6582d5b1: Gadu-Gadu: refactoring of...
Tomasz Wasilczyk
tomkiewicz at cpw.pidgin.im
Fri Jul 6 08:54:12 EDT 2012
Changeset: 5a0c6582d5b103bcfb4e488f13137656a95fc219
Author: Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date: 2012-07-06 14:54 +0200
Branch: soc.2012.gg
URL: http://hg.pidgin.im/soc/2012/tomkiewicz/gg/rev/5a0c6582d5b1
Description:
Gadu-Gadu: refactoring of buddy avatars handling. Fixes #13739, #14305
diffstat:
libpurple/protocols/gg/Makefile.am | 6 +-
libpurple/protocols/gg/avatar.c | 254 ++++++++++++++++++++++++++++++++
libpurple/protocols/gg/avatar.h | 21 ++
libpurple/protocols/gg/gg.c | 169 +--------------------
libpurple/protocols/gg/gg.h | 2 +
libpurple/protocols/gg/image.c | 2 +-
libpurple/protocols/gg/image.h | 2 +-
libpurple/protocols/gg/libgadu-events.c | 47 +++++
libpurple/protocols/gg/libgadu-events.h | 10 +
9 files changed, 347 insertions(+), 166 deletions(-)
diffs (truncated from 639 to 300 lines):
diff --git a/libpurple/protocols/gg/Makefile.am b/libpurple/protocols/gg/Makefile.am
--- a/libpurple/protocols/gg/Makefile.am
+++ b/libpurple/protocols/gg/Makefile.am
@@ -67,7 +67,11 @@
purplew.h \
purplew.c \
libgaduw.h \
- libgaduw.c
+ libgaduw.c \
+ avatar.h \
+ avatar.c \
+ libgadu-events.h \
+ libgadu-events.c
AM_CFLAGS = $(st)
diff --git a/libpurple/protocols/gg/avatar.c b/libpurple/protocols/gg/avatar.c
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/gg/avatar.c
@@ -0,0 +1,254 @@
+#include "avatar.h"
+
+#include <debug.h>
+
+#include "gg.h"
+#include "utils.h"
+
+// Common
+
+static inline ggp_avatar_session_data *
+ggp_avatar_get_avdata(PurpleConnection *gc);
+
+static gboolean ggp_avatar_timer_cb(gpointer _gc);
+
+#define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562"
+#define GGP_AVATAR_SIZE_MAX 1048576
+
+// Buddy avatars updating
+
+typedef struct
+{
+ uin_t uin;
+ time_t timestamp;
+
+ PurpleConnection *gc;
+ PurpleUtilFetchUrlData *request;
+} ggp_avatar_buddy_update_req;
+
+static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc);
+static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
+ gpointer _pending_update, const gchar *url_text, gsize len,
+ const gchar *error_message);
+
+#define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big"
+
+/*******************************************************************************
+ * Common.
+ ******************************************************************************/
+
+void ggp_avatar_setup(PurpleConnection *gc)
+{
+ ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
+
+ avdata->pending_updates = NULL;
+ avdata->current_update = NULL;
+
+ avdata->timer = purple_timeout_add_seconds(1, ggp_avatar_timer_cb, gc);
+}
+
+void ggp_avatar_cleanup(PurpleConnection *gc)
+{
+ ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
+
+ purple_timeout_remove(avdata->timer);
+
+ if (avdata->current_update != NULL)
+ {
+ ggp_avatar_buddy_update_req *current_update =
+ avdata->current_update;
+
+ purple_util_fetch_url_cancel(current_update->request);
+ g_free(current_update);
+ }
+ avdata->current_update = NULL;
+
+ g_list_free_full(avdata->pending_updates, &g_free);
+ avdata->pending_updates = NULL;
+}
+
+static inline ggp_avatar_session_data *
+ggp_avatar_get_avdata(PurpleConnection *gc)
+{
+ GGPInfo *accdata = purple_connection_get_protocol_data(gc);
+ return &accdata->avatar_data;
+}
+
+static gboolean ggp_avatar_timer_cb(gpointer _gc)
+{
+ PurpleConnection *gc = _gc;
+ ggp_avatar_session_data *avdata;
+
+ g_return_val_if_fail(PURPLE_CONNECTION_IS_VALID(gc), FALSE);
+
+ avdata = ggp_avatar_get_avdata(gc);
+ if (avdata->current_update != NULL)
+ {
+ //TODO: verbose mode
+ //purple_debug_misc("gg", "ggp_avatar_timer_cb(%p): there is "
+ // "already an update running\n", gc);
+ return TRUE;
+ }
+
+ while (!ggp_avatar_buddy_update_next(gc));
+
+ return TRUE;
+}
+
+/*******************************************************************************
+ * Buddy avatars updating.
+ ******************************************************************************/
+
+void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp)
+{
+ ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
+ ggp_avatar_buddy_update_req *pending_update =
+ g_new(ggp_avatar_buddy_update_req, 1);
+
+ purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)\n", gc,
+ uin, timestamp);
+
+ pending_update->uin = uin;
+ pending_update->timestamp = timestamp;
+
+ avdata->pending_updates = g_list_append(avdata->pending_updates,
+ pending_update);
+}
+
+void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin)
+{
+ //TODO: verbose mode
+ //purple_debug_misc("gg", "ggp_avatar_buddy_remove(%p, %u) - "
+ // "probably not necessary, thus not implemented\n", gc, uin);
+}
+
+/* return TRUE if avatar update was performed or there is no new requests,
+ FALSE if we can request another one immediately */
+static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc)
+{
+ ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
+ GList *pending_update_it;
+ ggp_avatar_buddy_update_req *pending_update;
+ PurpleBuddy *buddy;
+ PurpleAccount *account = purple_connection_get_account(gc);
+ time_t old_timestamp;
+ const char *old_timestamp_str;
+ gchar *avatar_url;
+
+ pending_update_it = g_list_first(avdata->pending_updates);
+ if (pending_update_it == NULL)
+ return TRUE;
+
+ pending_update = pending_update_it->data;
+ avdata->pending_updates = g_list_remove(avdata->pending_updates,
+ pending_update);
+ buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
+
+ if (!buddy)
+ {
+ if (ggp_str_to_uin(purple_account_get_username(account)) ==
+ pending_update->uin)
+ {
+ purple_debug_misc("gg",
+ "ggp_avatar_buddy_update_next(%p): own "
+ "avatar update requested, but we don't have "
+ "ourselves on buddy list\n", gc);
+ }
+ else
+ {
+ purple_debug_warning("gg",
+ "ggp_avatar_buddy_update_next(%p): "
+ "%u update requested, but he's not on buddy "
+ "list\n", gc, pending_update->uin);
+ }
+ return FALSE;
+ }
+
+ old_timestamp_str = purple_buddy_icons_get_checksum_for_user(buddy);
+ old_timestamp = old_timestamp_str ? g_ascii_strtoull(
+ old_timestamp_str, NULL, 10) : 0;
+ if (old_timestamp == pending_update->timestamp)
+ {
+ purple_debug_misc("gg",
+ "ggp_avatar_buddy_update_next(%p): "
+ "%u have up to date avatar with ts=%lu\n", gc,
+ pending_update->uin, pending_update->timestamp);
+ return FALSE;
+ }
+ if (old_timestamp > pending_update->timestamp)
+ {
+ purple_debug_warning("gg",
+ "ggp_avatar_buddy_update_next(%p): "
+ "saved timestamp for %u is newer than received "
+ "(%lu > %lu)\n", gc, pending_update->uin, old_timestamp,
+ pending_update->timestamp);
+ }
+
+ purple_debug_info("gg",
+ "ggp_avatar_buddy_update_next(%p): "
+ "updating %u with ts=%lu...\n", gc, pending_update->uin,
+ pending_update->timestamp);
+
+ pending_update->gc = gc;
+ avdata->current_update = pending_update;
+ avatar_url = g_strdup_printf(GGP_AVATAR_BUDDY_URL, pending_update->uin);
+ pending_update->request = purple_util_fetch_url_request(account,
+ avatar_url, FALSE, GGP_AVATAR_USERAGENT, TRUE, NULL, FALSE,
+ GGP_AVATAR_SIZE_MAX, ggp_avatar_buddy_update_received,
+ pending_update);
+ g_free(avatar_url);
+
+ return TRUE;
+}
+
+static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
+ gpointer _pending_update, const gchar *url_text, gsize len,
+ const gchar *error_message)
+{
+ ggp_avatar_buddy_update_req *pending_update = _pending_update;
+ PurpleBuddy *buddy;
+ PurpleAccount *account;
+ PurpleConnection *gc = pending_update->gc;
+ ggp_avatar_session_data *avdata;
+ gchar timestamp_str[20];
+
+ if (!PURPLE_CONNECTION_IS_VALID(gc))
+ {
+ g_free(pending_update);
+ return;
+ }
+
+ avdata = ggp_avatar_get_avdata(gc);
+ g_assert(pending_update == avdata->current_update);
+ avdata->current_update = NULL;
+
+ if (len == 0)
+ {
+ purple_debug_error("gg", "ggp_avatar_buddy_update_received: bad"
+ " response while getting avatar for %u: %s\n",
+ pending_update->uin, error_message);
+ g_free(pending_update);
+ return;
+ }
+
+ account = purple_connection_get_account(gc);
+ buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
+
+ if (!buddy)
+ {
+ purple_debug_warning("gg", "ggp_avatar_buddy_update_received: "
+ "buddy %u disappeared\n", pending_update->uin);
+ g_free(pending_update);
+ return;
+ }
+
+ g_snprintf(timestamp_str, sizeof(timestamp_str), "%lu",
+ pending_update->timestamp);
+ purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy),
+ g_memdup(url_text, len), len, timestamp_str);
+
+ purple_debug_info("gg", "ggp_avatar_buddy_update_received: "
+ "got avatar for buddy %u [ts=%lu]\n", pending_update->uin,
+ pending_update->timestamp);
+ g_free(pending_update);
+}
diff --git a/libpurple/protocols/gg/avatar.h b/libpurple/protocols/gg/avatar.h
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/gg/avatar.h
@@ -0,0 +1,21 @@
+#ifndef _GGP_AVATAR_H
+#define _GGP_AVATAR_H
+
+#include <internal.h>
+#include <libgadu.h>
+
+typedef struct
+{
+ guint timer;
+ GList *pending_updates;
+
+ gpointer current_update;
+} ggp_avatar_session_data;
+
+void ggp_avatar_setup(PurpleConnection *gc);
+void ggp_avatar_cleanup(PurpleConnection *gc);
+
+void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp);
+void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin);
+
More information about the Commits
mailing list