Gadu-Gadu: refactoring of buddy avatars handling. Fixes #13739, #14305
1.1 --- a/libpurple/protocols/gg/Makefile.am
1.2 +++ b/libpurple/protocols/gg/Makefile.am
1.3 @@ -67,7 +67,11 @@
1.4 purplew.h \
1.5 purplew.c \
1.6 libgaduw.h \
1.7 - libgaduw.c
1.8 + libgaduw.c \
1.9 + avatar.h \
1.10 + avatar.c \
1.11 + libgadu-events.h \
1.12 + libgadu-events.c
1.13
1.14 AM_CFLAGS = $(st)
1.15
2.1 new file mode 100644
2.2 --- /dev/null
2.3 +++ b/libpurple/protocols/gg/avatar.c
2.4 @@ -0,0 +1,254 @@
2.5 +#include "avatar.h"
2.6 +
2.7 +#include <debug.h>
2.8 +
2.9 +#include "gg.h"
2.10 +#include "utils.h"
2.11 +
2.12 +// Common
2.13 +
2.14 +static inline ggp_avatar_session_data *
2.15 +ggp_avatar_get_avdata(PurpleConnection *gc);
2.16 +
2.17 +static gboolean ggp_avatar_timer_cb(gpointer _gc);
2.18 +
2.19 +#define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562"
2.20 +#define GGP_AVATAR_SIZE_MAX 1048576
2.21 +
2.22 +// Buddy avatars updating
2.23 +
2.24 +typedef struct
2.25 +{
2.26 + uin_t uin;
2.27 + time_t timestamp;
2.28 +
2.29 + PurpleConnection *gc;
2.30 + PurpleUtilFetchUrlData *request;
2.31 +} ggp_avatar_buddy_update_req;
2.32 +
2.33 +static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc);
2.34 +static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
2.35 + gpointer _pending_update, const gchar *url_text, gsize len,
2.36 + const gchar *error_message);
2.37 +
2.38 +#define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big"
2.39 +
2.40 +/*******************************************************************************
2.41 + * Common.
2.42 + ******************************************************************************/
2.43 +
2.44 +void ggp_avatar_setup(PurpleConnection *gc)
2.45 +{
2.46 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
2.47 +
2.48 + avdata->pending_updates = NULL;
2.49 + avdata->current_update = NULL;
2.50 +
2.51 + avdata->timer = purple_timeout_add_seconds(1, ggp_avatar_timer_cb, gc);
2.52 +}
2.53 +
2.54 +void ggp_avatar_cleanup(PurpleConnection *gc)
2.55 +{
2.56 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
2.57 +
2.58 + purple_timeout_remove(avdata->timer);
2.59 +
2.60 + if (avdata->current_update != NULL)
2.61 + {
2.62 + ggp_avatar_buddy_update_req *current_update =
2.63 + avdata->current_update;
2.64 +
2.65 + purple_util_fetch_url_cancel(current_update->request);
2.66 + g_free(current_update);
2.67 + }
2.68 + avdata->current_update = NULL;
2.69 +
2.70 + g_list_free_full(avdata->pending_updates, &g_free);
2.71 + avdata->pending_updates = NULL;
2.72 +}
2.73 +
2.74 +static inline ggp_avatar_session_data *
2.75 +ggp_avatar_get_avdata(PurpleConnection *gc)
2.76 +{
2.77 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
2.78 + return &accdata->avatar_data;
2.79 +}
2.80 +
2.81 +static gboolean ggp_avatar_timer_cb(gpointer _gc)
2.82 +{
2.83 + PurpleConnection *gc = _gc;
2.84 + ggp_avatar_session_data *avdata;
2.85 +
2.86 + g_return_val_if_fail(PURPLE_CONNECTION_IS_VALID(gc), FALSE);
2.87 +
2.88 + avdata = ggp_avatar_get_avdata(gc);
2.89 + if (avdata->current_update != NULL)
2.90 + {
2.91 + //TODO: verbose mode
2.92 + //purple_debug_misc("gg", "ggp_avatar_timer_cb(%p): there is "
2.93 + // "already an update running\n", gc);
2.94 + return TRUE;
2.95 + }
2.96 +
2.97 + while (!ggp_avatar_buddy_update_next(gc));
2.98 +
2.99 + return TRUE;
2.100 +}
2.101 +
2.102 +/*******************************************************************************
2.103 + * Buddy avatars updating.
2.104 + ******************************************************************************/
2.105 +
2.106 +void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp)
2.107 +{
2.108 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
2.109 + ggp_avatar_buddy_update_req *pending_update =
2.110 + g_new(ggp_avatar_buddy_update_req, 1);
2.111 +
2.112 + purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)\n", gc,
2.113 + uin, timestamp);
2.114 +
2.115 + pending_update->uin = uin;
2.116 + pending_update->timestamp = timestamp;
2.117 +
2.118 + avdata->pending_updates = g_list_append(avdata->pending_updates,
2.119 + pending_update);
2.120 +}
2.121 +
2.122 +void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin)
2.123 +{
2.124 + //TODO: verbose mode
2.125 + //purple_debug_misc("gg", "ggp_avatar_buddy_remove(%p, %u) - "
2.126 + // "probably not necessary, thus not implemented\n", gc, uin);
2.127 +}
2.128 +
2.129 +/* return TRUE if avatar update was performed or there is no new requests,
2.130 + FALSE if we can request another one immediately */
2.131 +static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc)
2.132 +{
2.133 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
2.134 + GList *pending_update_it;
2.135 + ggp_avatar_buddy_update_req *pending_update;
2.136 + PurpleBuddy *buddy;
2.137 + PurpleAccount *account = purple_connection_get_account(gc);
2.138 + time_t old_timestamp;
2.139 + const char *old_timestamp_str;
2.140 + gchar *avatar_url;
2.141 +
2.142 + pending_update_it = g_list_first(avdata->pending_updates);
2.143 + if (pending_update_it == NULL)
2.144 + return TRUE;
2.145 +
2.146 + pending_update = pending_update_it->data;
2.147 + avdata->pending_updates = g_list_remove(avdata->pending_updates,
2.148 + pending_update);
2.149 + buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
2.150 +
2.151 + if (!buddy)
2.152 + {
2.153 + if (ggp_str_to_uin(purple_account_get_username(account)) ==
2.154 + pending_update->uin)
2.155 + {
2.156 + purple_debug_misc("gg",
2.157 + "ggp_avatar_buddy_update_next(%p): own "
2.158 + "avatar update requested, but we don't have "
2.159 + "ourselves on buddy list\n", gc);
2.160 + }
2.161 + else
2.162 + {
2.163 + purple_debug_warning("gg",
2.164 + "ggp_avatar_buddy_update_next(%p): "
2.165 + "%u update requested, but he's not on buddy "
2.166 + "list\n", gc, pending_update->uin);
2.167 + }
2.168 + return FALSE;
2.169 + }
2.170 +
2.171 + old_timestamp_str = purple_buddy_icons_get_checksum_for_user(buddy);
2.172 + old_timestamp = old_timestamp_str ? g_ascii_strtoull(
2.173 + old_timestamp_str, NULL, 10) : 0;
2.174 + if (old_timestamp == pending_update->timestamp)
2.175 + {
2.176 + purple_debug_misc("gg",
2.177 + "ggp_avatar_buddy_update_next(%p): "
2.178 + "%u have up to date avatar with ts=%lu\n", gc,
2.179 + pending_update->uin, pending_update->timestamp);
2.180 + return FALSE;
2.181 + }
2.182 + if (old_timestamp > pending_update->timestamp)
2.183 + {
2.184 + purple_debug_warning("gg",
2.185 + "ggp_avatar_buddy_update_next(%p): "
2.186 + "saved timestamp for %u is newer than received "
2.187 + "(%lu > %lu)\n", gc, pending_update->uin, old_timestamp,
2.188 + pending_update->timestamp);
2.189 + }
2.190 +
2.191 + purple_debug_info("gg",
2.192 + "ggp_avatar_buddy_update_next(%p): "
2.193 + "updating %u with ts=%lu...\n", gc, pending_update->uin,
2.194 + pending_update->timestamp);
2.195 +
2.196 + pending_update->gc = gc;
2.197 + avdata->current_update = pending_update;
2.198 + avatar_url = g_strdup_printf(GGP_AVATAR_BUDDY_URL, pending_update->uin);
2.199 + pending_update->request = purple_util_fetch_url_request(account,
2.200 + avatar_url, FALSE, GGP_AVATAR_USERAGENT, TRUE, NULL, FALSE,
2.201 + GGP_AVATAR_SIZE_MAX, ggp_avatar_buddy_update_received,
2.202 + pending_update);
2.203 + g_free(avatar_url);
2.204 +
2.205 + return TRUE;
2.206 +}
2.207 +
2.208 +static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
2.209 + gpointer _pending_update, const gchar *url_text, gsize len,
2.210 + const gchar *error_message)
2.211 +{
2.212 + ggp_avatar_buddy_update_req *pending_update = _pending_update;
2.213 + PurpleBuddy *buddy;
2.214 + PurpleAccount *account;
2.215 + PurpleConnection *gc = pending_update->gc;
2.216 + ggp_avatar_session_data *avdata;
2.217 + gchar timestamp_str[20];
2.218 +
2.219 + if (!PURPLE_CONNECTION_IS_VALID(gc))
2.220 + {
2.221 + g_free(pending_update);
2.222 + return;
2.223 + }
2.224 +
2.225 + avdata = ggp_avatar_get_avdata(gc);
2.226 + g_assert(pending_update == avdata->current_update);
2.227 + avdata->current_update = NULL;
2.228 +
2.229 + if (len == 0)
2.230 + {
2.231 + purple_debug_error("gg", "ggp_avatar_buddy_update_received: bad"
2.232 + " response while getting avatar for %u: %s\n",
2.233 + pending_update->uin, error_message);
2.234 + g_free(pending_update);
2.235 + return;
2.236 + }
2.237 +
2.238 + account = purple_connection_get_account(gc);
2.239 + buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
2.240 +
2.241 + if (!buddy)
2.242 + {
2.243 + purple_debug_warning("gg", "ggp_avatar_buddy_update_received: "
2.244 + "buddy %u disappeared\n", pending_update->uin);
2.245 + g_free(pending_update);
2.246 + return;
2.247 + }
2.248 +
2.249 + g_snprintf(timestamp_str, sizeof(timestamp_str), "%lu",
2.250 + pending_update->timestamp);
2.251 + purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy),
2.252 + g_memdup(url_text, len), len, timestamp_str);
2.253 +
2.254 + purple_debug_info("gg", "ggp_avatar_buddy_update_received: "
2.255 + "got avatar for buddy %u [ts=%lu]\n", pending_update->uin,
2.256 + pending_update->timestamp);
2.257 + g_free(pending_update);
2.258 +}
3.1 new file mode 100644
3.2 --- /dev/null
3.3 +++ b/libpurple/protocols/gg/avatar.h
3.4 @@ -0,0 +1,21 @@
3.5 +#ifndef _GGP_AVATAR_H
3.6 +#define _GGP_AVATAR_H
3.7 +
3.8 +#include <internal.h>
3.9 +#include <libgadu.h>
3.10 +
3.11 +typedef struct
3.12 +{
3.13 + guint timer;
3.14 + GList *pending_updates;
3.15 +
3.16 + gpointer current_update;
3.17 +} ggp_avatar_session_data;
3.18 +
3.19 +void ggp_avatar_setup(PurpleConnection *gc);
3.20 +void ggp_avatar_cleanup(PurpleConnection *gc);
3.21 +
3.22 +void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp);
3.23 +void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin);
3.24 +
3.25 +#endif /* _GGP_AVATAR_H */
4.1 --- a/libpurple/protocols/gg/gg.c
4.2 +++ b/libpurple/protocols/gg/gg.c
4.3 @@ -48,6 +48,7 @@
4.4 #include "account.h"
4.5 #include "deprecated.h"
4.6 #include "purplew.h"
4.7 +#include "libgadu-events.h"
4.8
4.9 /* Prototypes */
4.10 static void ggp_set_status(PurpleAccount *account, PurpleStatus *status);
4.11 @@ -481,164 +482,6 @@
4.12 /* ----- INTERNAL CALLBACKS --------------------------------------------- */
4.13 /* ---------------------------------------------------------------------- */
4.14
4.15 -struct gg_fetch_avatar_data
4.16 -{
4.17 - PurpleConnection *gc;
4.18 - gchar *uin;
4.19 - gchar *avatar_url;
4.20 -};
4.21 -
4.22 -
4.23 -static void gg_fetch_avatar_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
4.24 - const gchar *data, size_t len, const gchar *error_message) {
4.25 - struct gg_fetch_avatar_data *d = user_data;
4.26 - PurpleAccount *account;
4.27 - PurpleBuddy *buddy;
4.28 - gpointer buddy_icon_data;
4.29 -
4.30 - purple_debug_info("gg", "gg_fetch_avatar_cb: got avatar image for %s\n",
4.31 - d->uin);
4.32 -
4.33 - /* FIXME: This shouldn't be necessary */
4.34 - if (!PURPLE_CONNECTION_IS_VALID(d->gc)) {
4.35 - g_free(d->uin);
4.36 - g_free(d->avatar_url);
4.37 - g_free(d);
4.38 - g_return_if_reached();
4.39 - }
4.40 -
4.41 - account = purple_connection_get_account(d->gc);
4.42 - buddy = purple_find_buddy(account, d->uin);
4.43 -
4.44 - if (buddy == NULL)
4.45 - goto out;
4.46 -
4.47 - buddy_icon_data = g_memdup(data, len);
4.48 -
4.49 - purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy),
4.50 - buddy_icon_data, len, d->avatar_url);
4.51 - purple_debug_info("gg", "gg_fetch_avatar_cb: UIN %s should have avatar "
4.52 - "now\n", d->uin);
4.53 -
4.54 -out:
4.55 - g_free(d->uin);
4.56 - g_free(d->avatar_url);
4.57 - g_free(d);
4.58 -}
4.59 -
4.60 -static void gg_get_avatar_url_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
4.61 - const gchar *url_text, size_t len, const gchar *error_message) {
4.62 - struct gg_fetch_avatar_data *data;
4.63 - PurpleConnection *gc = user_data;
4.64 - PurpleAccount *account;
4.65 - PurpleBuddy *buddy;
4.66 - const char *uin;
4.67 - const char *is_blank;
4.68 - const char *checksum;
4.69 -
4.70 - gchar *bigavatar = NULL;
4.71 - xmlnode *xml = NULL;
4.72 - xmlnode *xmlnode_users;
4.73 - xmlnode *xmlnode_user;
4.74 - xmlnode *xmlnode_avatars;
4.75 - xmlnode *xmlnode_avatar;
4.76 - xmlnode *xmlnode_bigavatar;
4.77 -
4.78 - g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
4.79 - account = purple_connection_get_account(gc);
4.80 -
4.81 - if (error_message != NULL)
4.82 - purple_debug_error("gg", "gg_get_avatars_cb error: %s\n", error_message);
4.83 - else if (len > 0 && url_text && *url_text) {
4.84 - xml = xmlnode_from_str(url_text, -1);
4.85 - if (xml == NULL)
4.86 - goto out;
4.87 -
4.88 - xmlnode_users = xmlnode_get_child(xml, "users");
4.89 - if (xmlnode_users == NULL)
4.90 - goto out;
4.91 -
4.92 - xmlnode_user = xmlnode_get_child(xmlnode_users, "user");
4.93 - if (xmlnode_user == NULL)
4.94 - goto out;
4.95 -
4.96 - uin = xmlnode_get_attrib(xmlnode_user, "uin");
4.97 -
4.98 - xmlnode_avatars = xmlnode_get_child(xmlnode_user, "avatars");
4.99 - if (xmlnode_avatars == NULL)
4.100 - goto out;
4.101 -
4.102 - xmlnode_avatar = xmlnode_get_child(xmlnode_avatars, "avatar");
4.103 - if (xmlnode_avatar == NULL)
4.104 - goto out;
4.105 -
4.106 - xmlnode_bigavatar = xmlnode_get_child(xmlnode_avatar, "originBigAvatar");
4.107 - if (xmlnode_bigavatar == NULL)
4.108 - goto out;
4.109 -
4.110 - is_blank = xmlnode_get_attrib(xmlnode_avatar, "blank");
4.111 - bigavatar = xmlnode_get_data(xmlnode_bigavatar);
4.112 -
4.113 - purple_debug_info("gg", "gg_get_avatar_url_cb: UIN %s, IS_BLANK %s, "
4.114 - "URL %s\n",
4.115 - uin ? uin : "(null)", is_blank ? is_blank : "(null)",
4.116 - bigavatar ? bigavatar : "(null)");
4.117 -
4.118 - if (uin != NULL && bigavatar != NULL) {
4.119 - buddy = purple_find_buddy(account, uin);
4.120 - if (buddy == NULL)
4.121 - goto out;
4.122 -
4.123 - checksum = purple_buddy_icons_get_checksum_for_user(buddy);
4.124 -
4.125 - if (purple_strequal(is_blank, "1")) {
4.126 - purple_buddy_icons_set_for_user(account,
4.127 - purple_buddy_get_name(buddy), NULL, 0, NULL);
4.128 - } else if (!purple_strequal(checksum, bigavatar)) {
4.129 - data = g_new0(struct gg_fetch_avatar_data, 1);
4.130 - data->gc = gc;
4.131 - data->uin = g_strdup(uin);
4.132 - data->avatar_url = g_strdup(bigavatar);
4.133 -
4.134 - purple_debug_info("gg", "gg_get_avatar_url_cb: "
4.135 - "requesting avatar for %s\n", uin);
4.136 - /* FIXME: This should be cancelled somewhere if not needed. */
4.137 - url_data = purple_util_fetch_url_request(account,
4.138 - bigavatar, TRUE, "Mozilla/4.0 (compatible; MSIE 5.0)",
4.139 - FALSE, NULL, FALSE, -1, gg_fetch_avatar_cb, data);
4.140 - }
4.141 - }
4.142 - }
4.143 -
4.144 -out:
4.145 - if (xml)
4.146 - xmlnode_free(xml);
4.147 - g_free(bigavatar);
4.148 -}
4.149 -
4.150 -/**
4.151 - * Try to update avatar of the buddy.
4.152 - *
4.153 - * @param gc PurpleConnection
4.154 - * @param uin UIN of the buddy.
4.155 - */
4.156 -static void ggp_update_buddy_avatar(PurpleConnection *gc, uin_t uin)
4.157 -{
4.158 - gchar *avatarurl;
4.159 - PurpleUtilFetchUrlData *url_data;
4.160 -
4.161 - purple_debug_info("gg", "ggp_update_buddy_avatar(gc, %u)\n", uin);
4.162 -
4.163 - avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%u/0.xml", uin);
4.164 -
4.165 - /* FIXME: This should be cancelled somewhere if not needed. */
4.166 - url_data = purple_util_fetch_url_request(
4.167 - purple_connection_get_account(gc), avatarurl, TRUE,
4.168 - "Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1,
4.169 - gg_get_avatar_url_cb, gc);
4.170 -
4.171 - g_free(avatarurl);
4.172 -}
4.173
4.174 /**
4.175 * Handle change of the status of the buddy.
4.176 @@ -655,8 +498,6 @@
4.177 const char *st;
4.178 char *status_msg = NULL;
4.179
4.180 - ggp_update_buddy_avatar(gc, uin);
4.181 -
4.182 from = g_strdup_printf("%u", uin);
4.183
4.184 switch (status) {
4.185 @@ -1170,6 +1011,7 @@
4.186 * @param data Raw XML contents.
4.187 *
4.188 * @see http://toxygen.net/libgadu/protocol/#ch1.13
4.189 + * @todo: this may not be necessary anymore
4.190 */
4.191 static void ggp_xml_event_handler(PurpleConnection *gc, char *data)
4.192 {
4.193 @@ -1218,7 +1060,6 @@
4.194 purple_debug_info("gg",
4.195 "ggp_xml_event_handler: avatar updated (uid: %u)\n",
4.196 event_sender);
4.197 - ggp_update_buddy_avatar(gc, event_sender);
4.198 break;
4.199 default:
4.200 purple_debug_error("gg",
4.201 @@ -1354,7 +1195,7 @@
4.202 ggp_xml_event_handler(gc, ev->event.xml_event.data);
4.203 break;
4.204 case GG_EVENT_USER_DATA:
4.205 - purple_debug_misc("gg", "GG_EVENT_USER_DATA\n");
4.206 + ggp_events_user_data(gc, &ev->event.user_data);
4.207 break;
4.208 default:
4.209 purple_debug_error("gg",
4.210 @@ -1726,6 +1567,7 @@
4.211 purple_connection_set_protocol_data(gc, info);
4.212
4.213 ggp_image_setup(gc);
4.214 + ggp_avatar_setup(gc);
4.215
4.216 glp->uin = ggp_str_to_uin(purple_account_get_username(account));
4.217 glp->password = ggp_convert_to_cp1250(purple_account_get_password(account));
4.218 @@ -1839,7 +1681,8 @@
4.219 purple_notify_close_with_handle(gc);
4.220
4.221 ggp_search_destroy(info->searches);
4.222 - ggp_image_free(gc);
4.223 + ggp_image_cleanup(gc);
4.224 + ggp_avatar_cleanup(gc);
4.225
4.226 if (info->inpa > 0)
4.227 purple_input_remove(info->inpa);
5.1 --- a/libpurple/protocols/gg/gg.h
5.2 +++ b/libpurple/protocols/gg/gg.h
5.3 @@ -30,6 +30,7 @@
5.4 #include "connection.h"
5.5
5.6 #include "image.h"
5.7 +#include "avatar.h"
5.8 #include "account.h"
5.9
5.10
5.11 @@ -55,6 +56,7 @@
5.12 gboolean status_broadcasting; //When TRUE status is visible to all, when FALSE status is visible only to friends.
5.13
5.14 ggp_image_connection_data image_data;
5.15 + ggp_avatar_session_data avatar_data;
5.16 } GGPInfo;
5.17
5.18 #endif /* _PURPLE_GG_H */
6.1 --- a/libpurple/protocols/gg/image.c
6.2 +++ b/libpurple/protocols/gg/image.c
6.3 @@ -52,7 +52,7 @@
6.4 ggp_image_pending_image_free);
6.5 }
6.6
6.7 -void ggp_image_free(PurpleConnection *gc)
6.8 +void ggp_image_cleanup(PurpleConnection *gc)
6.9 {
6.10 ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
6.11
7.1 --- a/libpurple/protocols/gg/image.h
7.2 +++ b/libpurple/protocols/gg/image.h
7.3 @@ -20,7 +20,7 @@
7.4 } ggp_image_prepare_result;
7.5
7.6 void ggp_image_setup(PurpleConnection *gc);
7.7 -void ggp_image_free(PurpleConnection *gc);
7.8 +void ggp_image_cleanup(PurpleConnection *gc);
7.9
7.10 const char * ggp_image_pending_placeholder(uint32_t id);
7.11
8.1 new file mode 100644
8.2 --- /dev/null
8.3 +++ b/libpurple/protocols/gg/libgadu-events.c
8.4 @@ -0,0 +1,47 @@
8.5 +#include "libgadu-events.h"
8.6 +
8.7 +#include <debug.h>
8.8 +
8.9 +#include "avatar.h"
8.10 +
8.11 +void ggp_events_user_data(PurpleConnection *gc, struct gg_event_user_data *data)
8.12 +{
8.13 + int user_idx;
8.14 + gboolean is_update;
8.15 +
8.16 + purple_debug_info("gg", "GG_EVENT_USER_DATA [type=%d, user_count=%d]\n",
8.17 + data->type, data->user_count);
8.18 +
8.19 + /*
8.20 + type =
8.21 + 1, 3: user information sent after connecting (divided by
8.22 + 20 contacts; 3 - last one; 1 - rest of them)
8.23 + 0: data update
8.24 + */
8.25 + is_update = (data->type == 0);
8.26 +
8.27 + for (user_idx = 0; user_idx < data->user_count; user_idx++)
8.28 + {
8.29 + struct gg_event_user_data_user *data_user =
8.30 + &data->users[user_idx];
8.31 + uin_t uin = data_user->uin;
8.32 + int attr_idx;
8.33 + gboolean got_avatar = FALSE;
8.34 + for (attr_idx = 0; attr_idx < data_user->attr_count; attr_idx++)
8.35 + {
8.36 + struct gg_event_user_data_attr *data_attr =
8.37 + &data_user->attrs[attr_idx];
8.38 + if (strcmp(data_attr->key, "avatar") == 0)
8.39 + {
8.40 + time_t timestamp = atoi(data_attr->value);
8.41 + if (timestamp <= 0)
8.42 + continue;
8.43 + got_avatar = TRUE;
8.44 + ggp_avatar_buddy_update(gc, uin, timestamp);
8.45 + }
8.46 + }
8.47 +
8.48 + if (!is_update && !got_avatar)
8.49 + ggp_avatar_buddy_remove(gc, uin);
8.50 + }
8.51 +}
9.1 new file mode 100644
9.2 --- /dev/null
9.3 +++ b/libpurple/protocols/gg/libgadu-events.h
9.4 @@ -0,0 +1,10 @@
9.5 +#ifndef _GGP_LIBGADU_EVENTS_H
9.6 +#define _GGP_LIBGADU_EVENTS_H
9.7 +
9.8 +#include <internal.h>
9.9 +#include <libgadu.h>
9.10 +
9.11 +void ggp_events_user_data(PurpleConnection *gc,
9.12 + struct gg_event_user_data *data);
9.13 +
9.14 +#endif /* _GGP_LIBGADU_EVENTS_H */