Tue, 09 Apr 2024 21:55:54 -0500
Remove the GaduGadu protocol plugin
This protocol plugin depends on libgadu which hasn't been maintained since
2019. That said it is still currently functional as far as I know. However, the
protocol plugin needs a lot of work for the changes in purple 3 and at this
point, it is probably easier to rewrite it even if it still uses libgadu.
Testing Done:
Ran meson dist.
Reviewed at https://reviews.imfreedom.org/r/3051/
--- a/libpurple/protocols/gg/avatar.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,344 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "avatar.h" - -#include "libpurple/glibcompat.h" - -#include "gg.h" -#include "utils.h" -#include "oauth/oauth-purple.h" - -/* Common */ - -#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; - SoupMessage *msg; -} ggp_avatar_buddy_update_req; - -#define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big" - -/* Own avatar setting */ - -struct _ggp_avatar_session_data { - PurpleImage *own_img; -}; - -#define GGP_AVATAR_RESPONSE_MAX 10240 - -/******************************************************************************* - * Common. - ******************************************************************************/ - -static inline ggp_avatar_session_data * -ggp_avatar_get_avdata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return accdata->avatar_data; -} - -void ggp_avatar_setup(PurpleConnection *gc) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - - info->avatar_data = g_new0(ggp_avatar_session_data, 1); -} - -void ggp_avatar_cleanup(PurpleConnection *gc) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - - g_free(info->avatar_data); -} - -/******************************************************************************* - * Buddy avatars updating. - ******************************************************************************/ - -void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin) -{ - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_avatar_buddy_remove(%p, %u)\n", gc, uin); - } - - purple_buddy_icons_set_for_user(purple_connection_get_account(gc), - ggp_uin_to_str(uin), NULL, 0, NULL); -} - -static void -ggp_avatar_buddy_update_received(GObject *source, GAsyncResult *result, - gpointer data) -{ - ggp_avatar_buddy_update_req *pending_update = data; - GBytes *response_body = NULL; - GError *error = NULL; - const char *error_message = NULL; - PurpleBuddy *buddy; - PurpleAccount *account; - PurpleConnection *gc = pending_update->gc; - gchar timestamp_str[20]; - char *got_data = NULL; - gsize got_len = 0; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - if(SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(pending_update->msg))) { - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - error_message = error != NULL ? error->message : "unknown"; - } else { - error_message = soup_message_get_reason_phrase(pending_update->msg); - } - if(response_body == NULL) { - purple_debug_error("gg", - "ggp_avatar_buddy_update_received: bad response " - "while getting avatar for %u: %s", - pending_update->uin, error_message); - g_object_unref(pending_update->msg); - g_free(pending_update); - g_clear_error(&error); - return; - } - - account = purple_connection_get_account(gc); - buddy = purple_blist_find_buddy(account, - ggp_uin_to_str(pending_update->uin)); - - if (!buddy) { - purple_debug_warning( - "gg", "ggp_avatar_buddy_update_received: buddy %u disappeared", - pending_update->uin); - g_object_unref(pending_update->msg); - g_free(pending_update); - return; - } - - g_snprintf(timestamp_str, sizeof(timestamp_str), "%lu", - pending_update->timestamp); - got_data = g_bytes_unref_to_data(response_body, &got_len); - purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy), - got_data, got_len, timestamp_str); - - purple_debug_info("gg", - "ggp_avatar_buddy_update_received: got avatar for buddy " - "%u [ts=%lu]", - pending_update->uin, pending_update->timestamp); - g_object_unref(pending_update->msg); - g_free(pending_update); -} - -void -ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - gchar *url; - SoupMessage *req; - 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; - - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)", gc, uin, - timestamp); - } - - buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); - - if (!buddy) { - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - - if (ggp_str_to_uin(purple_contact_info_get_username(info)) == uin) { - purple_debug_misc( - "gg", - "ggp_avatar_buddy_update(%p): own avatar update requested, " - "but we don't have ourselves on buddy list", - gc); - } else { - purple_debug_warning("gg", - "ggp_avatar_buddy_update(%p): %u update " - "requested, but he's not on buddy list", - gc, uin); - } - return; - } - - 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 == timestamp) { - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", - "ggp_avatar_buddy_update(%p): %u have up to date " - "avatar with ts=%lu", - gc, uin, timestamp); - } - return; - } - if (old_timestamp > timestamp) { - purple_debug_warning("gg", - "ggp_avatar_buddy_update(%p): saved timestamp for " - "%u is newer than received (%lu > %lu)", - gc, uin, old_timestamp, timestamp); - } - - purple_debug_info("gg", - "ggp_avatar_buddy_update(%p): updating %u with ts=%lu...", - gc, uin, timestamp); - - pending_update = g_new(ggp_avatar_buddy_update_req, 1); - pending_update->uin = uin; - pending_update->timestamp = timestamp; - pending_update->gc = gc; - - url = g_strdup_printf(GGP_AVATAR_BUDDY_URL, pending_update->uin); - pending_update->msg = req = soup_message_new("GET", url); - g_free(url); - soup_message_headers_replace(soup_message_get_request_headers(req), - "User-Agent", GGP_AVATAR_USERAGENT); - // purple_http_request_set_max_len(req, GGP_AVATAR_SIZE_MAX); - soup_session_send_and_read_async(info->http, req, G_PRIORITY_DEFAULT, NULL, - ggp_avatar_buddy_update_received, - pending_update); -} - -/******************************************************************************* - * Own avatar setting. - ******************************************************************************/ - -/* - * TODO: use new, GG11 method, when IMToken will be provided by libgadu. - * - * POST https://avatars.mpa.gg.pl/avatars/user,<uin>/0 - * Authorization: IMToken 0123456789abcdef0123456789abcdef01234567 - * photo=<avatar content> - */ - -static void -ggp_avatar_own_sent(GObject *source, GAsyncResult *result, gpointer data) { - SoupMessage *msg = data; - GBytes *response_body = NULL; - GError *error = NULL; - const char *buffer = NULL; - gsize size = 0; - - if (!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(msg))) { - purple_debug_error("gg", "ggp_avatar_own_sent: avatar not sent. %s", - soup_message_get_reason_phrase(msg)); - g_object_unref(msg); - return; - } - g_clear_object(&msg); - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - if(response_body == NULL) { - purple_debug_error("gg", "ggp_avatar_own_sent: avatar not sent. %s", - error->message); - g_error_free(error); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - purple_debug_info("gg", "ggp_avatar_own_sent: %.*s", (int)size, buffer); - g_bytes_unref(response_body); -} - -static void -ggp_avatar_own_got_token(PurpleConnection *gc, const gchar *token, - gpointer _img) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc); - SoupMessage *req; - SoupMessageHeaders *headers; - PurpleImage *img = _img; - gchar *img_data, *uin_str; - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *contact_info = PURPLE_CONTACT_INFO(account); - uin_t uin = ggp_str_to_uin(purple_contact_info_get_username(contact_info)); - - if (img != avdata->own_img) { - purple_debug_warning("gg", "ggp_avatar_own_got_token: " - "avatar was changed in meantime\n"); - return; - } - avdata->own_img = NULL; - - img_data = g_base64_encode(purple_image_get_data(img), - purple_image_get_data_size(img)); - uin_str = g_strdup_printf("%d", uin); - - purple_debug_misc("gg", "ggp_avatar_own_got_token: " - "uploading new avatar...\n"); - - req = soup_message_new_from_encoded_form( - "POST", "http://avatars.nowe.gg/upload", - soup_form_encode("uin", uin_str, "photo", img_data, NULL)); - // purple_http_request_set_max_len(req, GGP_AVATAR_RESPONSE_MAX); - headers = soup_message_get_request_headers(req); - soup_message_headers_replace(headers, "Authorization", token); - soup_message_headers_replace(headers, "From", "avatars to avatars"); - soup_session_send_and_read_async(info->http, req, G_PRIORITY_DEFAULT, NULL, - ggp_avatar_own_sent, req); - g_free(img_data); - g_free(uin_str); -} - -void -ggp_avatar_own_set(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, PurpleImage *img) -{ - ggp_avatar_session_data *avdata; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - purple_debug_info("gg", "ggp_avatar_own_set(%p, %p)", gc, img); - - avdata = ggp_avatar_get_avdata(gc); - - if (img == NULL) { - purple_debug_warning("gg", "ggp_avatar_own_set: avatar removing is " - "probably not possible within old protocol"); - return; - } - - avdata->own_img = img; - - ggp_oauth_request(gc, ggp_avatar_own_got_token, img, NULL, NULL); -}
--- a/libpurple/protocols/gg/avatar.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_AVATAR_H -#define PURPLE_GG_AVATAR_H - -#include <purple.h> -#include <libgadu.h> - -typedef struct _ggp_avatar_session_data 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); - -void ggp_avatar_own_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleImage *img); - -#endif /* PURPLE_GG_AVATAR_H */
--- a/libpurple/protocols/gg/blist.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/** - * @file buddylist.c - * - * purple - * - * Copyright (C) 2005 Bartosz Oler <bartosz@bzimage.us> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - - -#include <libgadu.h> - -#include "gg.h" -#include "utils.h" -#include "blist.h" - -#define F_FIRSTNAME 0 -#define F_LASTNAME 1 -/* #define F_ 2 */ -#define F_NICKNAME 3 -#define F_PHONE 4 -#define F_GROUP 5 -#define F_UIN 6 - -/* void ggp_buddylist_send(PurpleConnection *gc) {{{ */ -/* this is for for notify purposes, not synchronizing buddy list */ -void ggp_buddylist_send(PurpleConnection *gc) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - PurpleAccount *account = purple_connection_get_account(gc); - GSList *buddies; - uin_t *userlist; - gchar *types; - int i = 0, ret = 0; - int size; - - buddies = purple_blist_find_buddies(account, NULL); - - size = g_slist_length(buddies); - userlist = g_new(uin_t, size); - types = g_new(gchar, size); - - for (buddies = purple_blist_find_buddies(account, NULL); buddies; - buddies = g_slist_delete_link(buddies, buddies), ++i) - { - PurpleBuddy *buddy = buddies->data; - const gchar *name = purple_buddy_get_name(buddy); - - userlist[i] = ggp_str_to_uin(name); - types[i] = GG_USER_NORMAL; - purple_debug_info("gg", "ggp_buddylist_send: adding %d\n", - userlist[i]); - } - - ret = gg_notify_ex(info->session, userlist, types, size); - purple_debug_info("gg", "send: ret=%d; size=%d\n", ret, size); - - if (userlist) { - g_free(userlist); - g_free(types); - } -} -/* }}} */ - -/* void ggp_buddylist_load(PurpleConnection *gc, char *buddylist) {{{ */ -void ggp_buddylist_load(PurpleConnection *gc, char *buddylist) -{ - PurpleBuddy *buddy; - PurpleGroup *group; - gchar **users_tbl; - int i; - char *utf8buddylist = ggp_convert_from_cp1250(buddylist); - - /* Don't limit the number of records in a buddylist. */ - users_tbl = g_strsplit(utf8buddylist, "\r\n", -1); - - for (i = 0; users_tbl[i] != NULL; i++) { - gchar **data_tbl; - gchar *name, *show, *g; - - if (!*users_tbl[i]) - continue; - - data_tbl = g_strsplit(users_tbl[i], ";", 8); - if (g_strv_length(data_tbl) < 8) { - purple_debug_warning("gg", - "Something is wrong on line %d of the buddylist. Skipping.\n", - i + 1); - continue; - } - - show = data_tbl[F_NICKNAME]; - name = data_tbl[F_UIN]; - if ('\0' == *name || !atol(name)) { - purple_debug_warning("gg", - "Identifier on line %d of the buddylist is not a number. Skipping.\n", - i + 1); - continue; - } - - if ('\0' == *show) { - show = name; - } - - purple_debug_info("gg", "got buddy: name=%s; show=%s\n", name, show); - - if (purple_blist_find_buddy(purple_connection_get_account(gc), name)) { - g_strfreev(data_tbl); - continue; - } - - g = g_strdup("Gadu-Gadu"); - - if ('\0' != *(data_tbl[F_GROUP])) { - /* XXX: Probably buddy should be added to all the groups. */ - /* Hard limit to at most 50 groups */ - gchar **group_tbl = g_strsplit(data_tbl[F_GROUP], ",", 50); - if (g_strv_length(group_tbl) > 0) { - g_free(g); - g = g_strdup(group_tbl[0]); - } - g_strfreev(group_tbl); - } - - buddy = purple_buddy_new(purple_connection_get_account(gc), - name, *show == '\0' ? NULL : show); - - if (!(group = purple_blist_find_group(g))) { - group = purple_group_new(g); - purple_blist_add_group(group, NULL); - } - - purple_blist_add_buddy(buddy, NULL, group, NULL); - g_free(g); - - g_strfreev(data_tbl); - } - g_strfreev(users_tbl); - g_free(utf8buddylist); - - ggp_buddylist_send(gc); -} -/* }}} */ - -/* char *ggp_buddylist_dump(PurpleAccount *account) {{{ */ -char *ggp_buddylist_dump(PurpleAccount *account) -{ - GSList *buddies; - GString *buddylist = g_string_sized_new(1024); - char *ptr; - - for (buddies = purple_blist_find_buddies(account, NULL); buddies; - buddies = g_slist_delete_link(buddies, buddies)) - { - PurpleBuddy *buddy = buddies->data; - PurpleGroup *group = purple_buddy_get_group(buddy); - const char *bname = purple_buddy_get_name(buddy); - const char *gname = purple_group_get_name(group); - const char *alias = purple_buddy_get_alias(buddy); - - if (alias == NULL) - alias = bname; - - g_string_append_printf(buddylist, - "%s;%s;%s;%s;%s;%s;%s;%s%s\r\n", - alias, alias, alias, alias, - "", gname, bname, "", ""); - } - - ptr = ggp_convert_to_cp1250(buddylist->str); - g_string_free(buddylist, TRUE); - return ptr; -} -/* }}} */ - -const char * ggp_buddylist_get_buddy_name(PurpleConnection *gc, uin_t uin) -{ - const char *uin_s = ggp_uin_to_str(uin); - PurpleBuddy *buddy = purple_blist_find_buddy( - purple_connection_get_account(gc), uin_s); - - if (buddy != NULL) - return purple_buddy_get_alias(buddy); - else - return uin_s; -} - -/* vim: set ts=8 sts=0 sw=8 noet: */
--- a/libpurple/protocols/gg/blist.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/** - * @file blist.h - * - * purple - * - * Copyright (C) 2005 Bartosz Oler <bartosz@bzimage.us> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_BLIST_H -#define PURPLE_GG_BLIST_H - -#include <purple.h> - -void -ggp_buddylist_send(PurpleConnection *gc); - -/** - * Load buddylist from server into the roster. - * - * @param gc PurpleConnection - * @param buddylist Pointer to the buddylist that will be loaded. - */ -/* void ggp_buddylist_load(PurpleConnection *gc, char *buddylist) {{{ */ -void -ggp_buddylist_load(PurpleConnection *gc, char *buddylist); - -/** - * Get all the buddies in the current account. - * - * @param account Current account. - * - * @return List of buddies. - */ -char * -ggp_buddylist_dump(PurpleAccount *account); - -/** - * Returns the best name of a buddy from the buddylist. - * - * @param gc PurpleConnection instance. - * @param uin UIN of the buddy. - * - * @return Name of the buddy, or UIN converted to string, if there is no such - * user on the list. - */ -const char * ggp_buddylist_get_buddy_name(PurpleConnection *gc, uin_t uin); - -#endif /* PURPLE_GG_BLIST_H */ - -/* vim: set ts=8 sts=0 sw=8 noet: */
--- a/libpurple/protocols/gg/chat.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,648 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib.h> -#include <glib/gi18n-lib.h> - -#include "chat.h" - -#include "gg.h" -#include "utils.h" -#include "message-prpl.h" - -typedef struct _ggp_chat_local_info ggp_chat_local_info; - -struct _ggp_chat_session_data -{ - ggp_chat_local_info *chats; - int chats_count; - - gboolean got_all_chats_info; - GSList *pending_joins; -}; - -struct _ggp_chat_local_info -{ - int local_id; - uint64_t id; - - PurpleChatConversation *conv; - PurpleConnection *gc; - - gboolean left; - gboolean previously_joined; - - uin_t *participants; - int participants_count; -}; - -static ggp_chat_local_info * ggp_chat_new(PurpleConnection *gc, uint64_t id); -static ggp_chat_local_info * ggp_chat_get(PurpleConnection *gc, uint64_t id); -static void ggp_chat_open_conv(ggp_chat_local_info *chat); -static ggp_chat_local_info * ggp_chat_get_local(PurpleConnection *gc, - int local_id); -static void ggp_chat_joined(ggp_chat_local_info *chat, uin_t uin); -static void ggp_chat_left(ggp_chat_local_info *chat, uin_t uin); -static const gchar * ggp_chat_get_name_from_id(uint64_t id); -static uint64_t ggp_chat_get_id_from_name(const gchar * name); -static void ggp_chat_join_id(PurpleConnection *gc, uint64_t id); - -static inline ggp_chat_session_data * -ggp_chat_get_sdata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return accdata->chat_data; -} - -void ggp_chat_setup(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_chat_session_data *sdata = g_new0(ggp_chat_session_data, 1); - - accdata->chat_data = sdata; -} - -void ggp_chat_cleanup(PurpleConnection *gc) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - int i; - - g_slist_free_full(sdata->pending_joins, g_free); - for (i = 0; i < sdata->chats_count; i++) - g_free(sdata->chats[i].participants); - g_free(sdata->chats); - g_free(sdata); -} - -static ggp_chat_local_info * ggp_chat_new(PurpleConnection *gc, uint64_t id) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - int local_id; - ggp_chat_local_info *chat; - - if (NULL != (chat = ggp_chat_get(gc, id))) - return chat; - - local_id = sdata->chats_count++; - sdata->chats = g_realloc(sdata->chats, - sdata->chats_count * sizeof(ggp_chat_local_info)); - chat = &sdata->chats[local_id]; - - chat->local_id = local_id; - chat->id = id; - chat->conv = NULL; - chat->gc = gc; - chat->left = FALSE; - chat->previously_joined = FALSE; - chat->participants = NULL; - chat->participants_count = 0; - - return chat; -} - -static ggp_chat_local_info * ggp_chat_get(PurpleConnection *gc, uint64_t id) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - int i; - - for (i = 0; i < sdata->chats_count; i++) { - if (sdata->chats[i].id == id) - return &sdata->chats[i]; - } - - return NULL; -} - -static void ggp_chat_open_conv(ggp_chat_local_info *chat) -{ - PurpleConversation *conv; - int i; - - if (chat->conv != NULL) - return; - - conv = purple_serv_got_joined_chat(chat->gc, chat->local_id, - ggp_chat_get_name_from_id(chat->id)); - chat->conv = PURPLE_CHAT_CONVERSATION(conv); - if (chat->previously_joined) { - purple_conversation_write_system_message( - PURPLE_CONVERSATION(chat->conv), - _("You have re-joined the chat"), 0); - } - chat->previously_joined = TRUE; - - purple_chat_conversation_clear_users(chat->conv); - for (i = 0; i < chat->participants_count; i++) { - purple_chat_conversation_add_user(chat->conv, - ggp_uin_to_str(chat->participants[i]), NULL, - PURPLE_CHAT_USER_NONE, FALSE); - } -} - -static ggp_chat_local_info * ggp_chat_get_local(PurpleConnection *gc, - int local_id) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - int i; - - for (i = 0; i < sdata->chats_count; i++) { - if (sdata->chats[i].local_id == local_id) - return &sdata->chats[i]; - } - - return NULL; -} - -void ggp_chat_got_event(PurpleConnection *gc, const struct gg_event *ev) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - ggp_chat_local_info *chat; - uint32_t i; - - if (ev->type == GG_EVENT_CHAT_INFO) { - const struct gg_event_chat_info *eci = &ev->event.chat_info; - chat = ggp_chat_new(gc, eci->id); - for (i = 0; i < eci->participants_count; i++) - ggp_chat_joined(chat, eci->participants[i]); - } else if (ev->type == GG_EVENT_CHAT_INFO_GOT_ALL) { - GSList *it = sdata->pending_joins; - sdata->got_all_chats_info = TRUE; - while (it) { - uint64_t *id_p = it->data; - ggp_chat_join_id(gc, *id_p); - it = g_slist_next(it); - } - g_clear_slist(&sdata->pending_joins, g_free); - } else if (ev->type == GG_EVENT_CHAT_INFO_UPDATE) { - const struct gg_event_chat_info_update *eciu = - &ev->event.chat_info_update; - chat = ggp_chat_get(gc, eciu->id); - if (!chat) { - purple_debug_error("gg", "ggp_chat_got_event: " - "chat %" G_GUINT64_FORMAT " not found\n", - eciu->id); - return; - } - if (eciu->type == GG_CHAT_INFO_UPDATE_ENTERED) - ggp_chat_joined(chat, eciu->participant); - else if (eciu->type == GG_CHAT_INFO_UPDATE_EXITED) - ggp_chat_left(chat, eciu->participant); - else - purple_debug_warning("gg", "ggp_chat_got_event: " - "unknown update type - %d", eciu->type); - } else if (ev->type == GG_EVENT_CHAT_CREATED) { - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - const struct gg_event_chat_created *ecc = &ev->event.chat_created; - uin_t me = ggp_str_to_uin(purple_contact_info_get_username(info)); - - chat = ggp_chat_new(gc, ecc->id); - ggp_chat_joined(chat, me); - ggp_chat_open_conv(chat); - } else if (ev->type == GG_EVENT_CHAT_INVITE_ACK) { - /* ignore */ - } else { - purple_debug_error("gg", "ggp_chat_got_event: unexpected event - %d", - ev->type); - } -} - -static int ggp_chat_participant_find(ggp_chat_local_info *chat, uin_t uin) -{ - int i; - for (i = 0; i < chat->participants_count; i++) - if (chat->participants[i] == uin) - return i; - return -1; -} - -static void ggp_chat_joined(ggp_chat_local_info *chat, uin_t uin) -{ - int idx = ggp_chat_participant_find(chat, uin); - if (idx >= 0) { - purple_debug_warning("gg", "ggp_chat_joined: " - "user %u is already present in chat %" G_GUINT64_FORMAT - "\n", uin, chat->id); - return; - } - chat->participants_count++; - chat->participants = g_realloc(chat->participants, - sizeof(uin) * chat->participants_count); - chat->participants[chat->participants_count - 1] = uin; - - if (!chat->conv) - return; - purple_chat_conversation_add_user(chat->conv, - ggp_uin_to_str(uin), NULL, PURPLE_CHAT_USER_NONE, TRUE); -} - -static void ggp_chat_left(ggp_chat_local_info *chat, uin_t uin) -{ - PurpleAccount *account = NULL; - PurpleContactInfo *info = NULL; - uin_t me; - int idx = ggp_chat_participant_find(chat, uin); - - if (idx < 0) { - purple_debug_warning("gg", "ggp_chat_joined: " - "user %u isn't present in chat %" G_GUINT64_FORMAT "\n", - uin, chat->id); - return; - } - chat->participants[idx] = - chat->participants[chat->participants_count - 1]; - chat->participants_count--; - chat->participants = g_realloc(chat->participants, - sizeof(uin) * chat->participants_count); - - if (chat->conv == NULL) - return; - - account = purple_connection_get_account(chat->gc); - info = PURPLE_CONTACT_INFO(account); - me = ggp_str_to_uin(purple_contact_info_get_username(info)); - - if (me == uin) { - purple_conversation_write_system_message( - PURPLE_CONVERSATION(chat->conv), - _("You have left the chat"), 0); - purple_serv_got_chat_left(chat->gc, chat->local_id); - chat->conv = NULL; - chat->left = TRUE; - } - purple_chat_conversation_remove_user(chat->conv, ggp_uin_to_str(uin), NULL); -} - -GList * -ggp_chat_info(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - G_GNUC_UNUSED PurpleConnection *gc) -{ - GList *m = NULL; - PurpleProtocolChatEntry *pce; - - pce = g_new0(PurpleProtocolChatEntry, 1); - pce->label = _("_Conference identifier"); - pce->identifier = "id"; - pce->required = FALSE; - m = g_list_append(m, pce); - - return m; -} - -GHashTable * -ggp_chat_info_defaults(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - G_GNUC_UNUSED PurpleConnection *gc, - const gchar *chat_name) -{ - GHashTable *defaults; - - defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); - - if (chat_name != NULL && ggp_chat_get_id_from_name(chat_name) != 0) - g_hash_table_insert(defaults, "id", g_strdup(chat_name)); - - return defaults; -} - -gchar * -ggp_chat_get_name(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - GHashTable *components) -{ - return g_strdup((gchar*)g_hash_table_lookup(components, "id")); -} - -static const gchar * ggp_chat_get_name_from_id(uint64_t id) -{ - static gchar buff[30]; - g_snprintf(buff, sizeof(buff), "%" G_GUINT64_FORMAT, id); - return buff; -} - -static uint64_t ggp_chat_get_id_from_name(const gchar * name) -{ - uint64_t id; - gchar *endptr; - - if (name == NULL) - return 0; - - id = g_ascii_strtoull(name, &endptr, 10); - - if (*endptr != '\0' || id == G_MAXUINT64) - return 0; - - return id; -} - -void -ggp_chat_join(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, GHashTable *components) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - GGPInfo *info = purple_connection_get_protocol_data(gc); - const gchar *id_cs; - gchar *id_s; - uint64_t id; - - id_cs = g_hash_table_lookup(components, "id"); - id_s = g_strdup(id_cs); - if (id_s) - g_strstrip(id_s); - if (id_s == NULL || id_s[0] == '\0') { - g_free(id_s); - if (gg_chat_create(info->session) < 0) { - purple_debug_error("gg", "ggp_chat_join; " - "cannot create\n"); - purple_serv_got_join_chat_failed(gc, components); - } - return; - } - id = ggp_chat_get_id_from_name(id_s); - g_free(id_s); - - if (!id) { - char *buff = g_strdup_printf( - _("%s is not a valid room identifier"), id_cs); - purple_notify_error(gc, _("Invalid Room Identifier"), - _("Invalid Room Identifier"), buff, NULL); - g_free(buff); - purple_serv_got_join_chat_failed(gc, components); - return; - } - - if (sdata->got_all_chats_info) - ggp_chat_join_id(gc, id); - else { - uint64_t *id_p = g_new(uint64_t, 1); - *id_p = id; - sdata->pending_joins = g_slist_append(sdata->pending_joins, id_p); - } - -} - -static void ggp_chat_join_id(PurpleConnection *gc, uint64_t id) -{ - GHashTable *components; - PurpleProtocol *protocol = purple_connection_get_protocol(gc); - - ggp_chat_local_info *chat = ggp_chat_get(gc, id); - - if (chat && !chat->left) { - ggp_chat_open_conv(chat); - return; - } - - if (!chat) { - char *id_s = g_strdup_printf("%" G_GUINT64_FORMAT, id); - char *buff = g_strdup_printf( - _("%s is not a valid room identifier"), id_s); - g_free(id_s); - purple_notify_error(gc, _("Invalid Room Identifier"), - _("Invalid Room Identifier"), buff, NULL); - g_free(buff); - } else { /* if (chat->left) */ - purple_notify_error(gc, _("Could not join chat room"), - _("Could not join chat room"), - _("You have to ask for invitation from another chat " - "participant"), NULL); - } - - components = ggp_chat_info_defaults(PURPLE_PROTOCOL_CHAT(protocol), gc, - ggp_chat_get_name_from_id(id)); - purple_serv_got_join_chat_failed(gc, components); - g_hash_table_destroy(components); -} - -void -ggp_chat_leave(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint local_id) -{ - PurpleAccount *account = NULL; - PurpleContactInfo *contact_info = NULL; - GGPInfo *info = purple_connection_get_protocol_data(gc); - ggp_chat_local_info *chat; - uin_t me; - - chat = ggp_chat_get_local(gc, local_id); - if (!chat) { - purple_debug_error("gg", "ggp_chat_leave: " - "chat %u doesn't exists\n", local_id); - return; - } - - if (gg_chat_leave(info->session, chat->id) < 0) { - purple_debug_error("gg", "ggp_chat_leave: " - "unable to leave chat %" G_GUINT64_FORMAT "\n", - chat->id); - } - chat->conv = NULL; - - account = purple_connection_get_account(chat->gc); - contact_info = PURPLE_CONTACT_INFO(account); - me = ggp_str_to_uin(purple_contact_info_get_username(contact_info)); - - ggp_chat_left(chat, me); - chat->left = TRUE; -} - -void -ggp_chat_invite(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint local_id, - G_GNUC_UNUSED const gchar *message, const gchar *who) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - ggp_chat_local_info *chat; - uin_t invited; - - chat = ggp_chat_get_local(gc, local_id); - if (!chat) { - purple_debug_error("gg", "ggp_chat_invite: " - "chat %u doesn't exists\n", local_id); - return; - } - - invited = ggp_str_to_uin(who); - if (gg_chat_invite(info->session, chat->id, &invited, 1) < 0) { - purple_debug_error("gg", "ggp_chat_invite: " - "unable to invite %s to chat %" G_GUINT64_FORMAT "\n", - who, chat->id); - } -} - -gint -ggp_chat_send(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint local_id, - G_GNUC_UNUSED PurpleConversation *conversation, - PurpleMessage *msg) -{ - PurpleAccount *account = NULL; - PurpleContactInfo *contact_info = NULL; - GGPInfo *info = purple_connection_get_protocol_data(gc); - GDateTime *dt = NULL; - PurpleConversation *conv; - PurpleConversationManager *manager; - ggp_chat_local_info *chat; - gboolean succ = TRUE; - const gchar *me; - gchar *gg_msg; - - chat = ggp_chat_get_local(gc, local_id); - if (!chat) { - purple_debug_error("gg", "ggp_chat_send: " - "chat %u doesn't exists\n", local_id); - return -1; - } - - manager = purple_conversation_manager_get_default(); - conv = purple_conversation_manager_find_chat(manager, - purple_connection_get_account(gc), - ggp_chat_get_name_from_id(chat->id)); - - gg_msg = ggp_message_format_to_gg(conv, - purple_message_get_contents(msg)); - - if (gg_chat_send_message(info->session, chat->id, gg_msg, TRUE) < 0) - succ = FALSE; - g_free(gg_msg); - - account = purple_connection_get_account(gc); - contact_info = PURPLE_CONTACT_INFO(account); - me = purple_contact_info_get_username(contact_info); - dt = purple_message_get_timestamp(msg); - purple_serv_got_chat_in(gc, chat->local_id, me, - purple_message_get_flags(msg), - purple_message_get_contents(msg), - (time_t)g_date_time_to_unix(dt)); - - return succ ? 0 : -1; -} - -void ggp_chat_got_message(PurpleConnection *gc, uint64_t chat_id, - const char *message, time_t time, uin_t who) -{ - PurpleAccount *account = NULL; - PurpleContactInfo *info = NULL; - ggp_chat_local_info *chat; - uin_t me; - - account = purple_connection_get_account(gc); - info = PURPLE_CONTACT_INFO(account); - me = ggp_str_to_uin(purple_contact_info_get_username(info)); - - chat = ggp_chat_get(gc, chat_id); - if (!chat) { - purple_debug_error("gg", "ggp_chat_got_message: " - "chat %" G_GUINT64_FORMAT " doesn't exists\n", chat_id); - return; - } - - ggp_chat_open_conv(chat); - if (who == me) { - GDateTime *dt = NULL; - PurpleMessage *pmsg; - const char *username = NULL; - - username = purple_contact_info_get_name_for_display(info); - - pmsg = purple_message_new_outgoing(username, ggp_uin_to_str(who), - message, 0); - - dt = g_date_time_new_from_unix_local((gint64)time); - purple_message_set_timestamp(pmsg, dt); - g_date_time_unref(dt); - - purple_conversation_write_message( - PURPLE_CONVERSATION(chat->conv), pmsg); - } else { - purple_serv_got_chat_in(gc, chat->local_id, ggp_uin_to_str(who), - PURPLE_MESSAGE_RECV, message, time); - } -} - -static gboolean ggp_chat_roomlist_get_list_finish(gpointer roomlist) -{ - purple_roomlist_set_in_progress(PURPLE_ROOMLIST(roomlist), FALSE); - g_object_unref(roomlist); - - return FALSE; -} - -PurpleRoomlist * -ggp_chat_roomlist_get_list(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist, - PurpleConnection *gc) -{ - ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); - PurpleRoomlist *roomlist; - int i; - - purple_debug_info("gg", "ggp_chat_roomlist_get_list\n"); - - roomlist = purple_roomlist_new(purple_connection_get_account(gc)); - - for (i = sdata->chats_count - 1; i >= 0 ; i--) { - PurpleRoomlistRoom *room; - ggp_chat_local_info *chat = &sdata->chats[i]; - const gchar *name; - GDateTime *date = NULL; - const gchar *status; - int count = chat->participants_count; - - date = g_date_time_new_from_unix_local((uint32_t)(chat->id >> 32)); - - if (chat->conv) { - status = _("Joined"); - } else if (chat->left) { - /* Translators: For Gadu-Gadu, this is one possible status for a - chat room. It means you had previously joined the chat room but - you have since left it. You cannot rejoin without another - invitation. */ - status = _("Chat left"); - } else { - status = _("Can join chat"); - count--; - } - - name = ggp_chat_get_name_from_id(chat->id); - room = purple_roomlist_room_new(name, NULL); - purple_roomlist_room_set_user_count(room, (guint)count); - purple_roomlist_room_add_field(room, "id", g_strdup(name)); - purple_roomlist_room_add_field(room, "date", - g_date_time_format(date, "%c")); - purple_roomlist_room_add_field(room, "status", g_strdup(status)); - purple_roomlist_room_add(roomlist, room); - g_object_unref(room); - g_date_time_unref(date); - } - - /* TODO - * purple_roomlist_set_in_progress(roomlist, FALSE); - */ - g_object_ref(roomlist); - g_timeout_add(1, ggp_chat_roomlist_get_list_finish, roomlist); - return roomlist; -}
--- a/libpurple/protocols/gg/chat.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_CHAT_H -#define PURPLE_GG_CHAT_H - -#include <purple.h> -#include <libgadu.h> - -typedef struct _ggp_chat_session_data ggp_chat_session_data; - -#include "gg.h" - -void ggp_chat_setup(PurpleConnection *gc); -void ggp_chat_cleanup(PurpleConnection *gc); - -void ggp_chat_got_event(PurpleConnection *gc, const struct gg_event *ev); - -GList * ggp_chat_info(PurpleProtocolChat *protocol_chat, PurpleConnection *gc); -GHashTable * ggp_chat_info_defaults(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, - const char *chat_name); -char * ggp_chat_get_name(PurpleProtocolChat *protocol_chat, GHashTable *components); -void ggp_chat_join(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, GHashTable *components); -void ggp_chat_leave(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int local_id); -void ggp_chat_invite(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int local_id, const char *message, - const char *who); -int ggp_chat_send(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int local_id, PurpleConversation *conversation, PurpleMessage *msg); - -void ggp_chat_got_message(PurpleConnection *gc, uint64_t chat_id, - const char *message, time_t time, uin_t who); - -PurpleRoomlist * ggp_chat_roomlist_get_list(PurpleProtocolRoomlist *protocol_roomlist, PurpleConnection *gc); - -#endif /* PURPLE_GG_CHAT_H */
--- a/libpurple/protocols/gg/edisc.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1344 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "edisc.h" - -#include "gg.h" -#include "libgaduw.h" -#include "utils.h" - -#include <json-glib/json-glib.h> - -#include <glib/gi18n-lib.h> - -#include <purple.h> - -#define GGP_EDISC_OS "WINNT x86-msvc" -#define GGP_EDISC_TYPE "desktop" -#define GGP_EDISC_API "6" - -#define GGP_EDISC_RESPONSE_MAX 10240 -#define GGP_EDISC_FNAME_ALLOWED "1234567890" \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - " [](){}-+=_;'<>,.&$!" - -typedef struct _ggp_edisc_xfer ggp_edisc_xfer; - -struct _ggp_edisc_session_data -{ - GHashTable *xfers_initialized; - GHashTable *xfers_history; - - SoupSession *session; - gchar *security_token; - - SoupMessage *auth_request; - gboolean auth_done; - GSList *auth_pending; -}; - -struct _GGPXfer -{ - PurpleXfer parent; - GCancellable *cancellable; - - gchar *filename; - gchar *ticket_id; - - gboolean allowed, ready; - - PurpleConnection *gc; - SoupMessage *msg; - gint handler; -}; - -typedef enum -{ - GGP_EDISC_XFER_ACK_STATUS_UNKNOWN, - GGP_EDISC_XFER_ACK_STATUS_ALLOWED, - GGP_EDISC_XFER_ACK_STATUS_REJECTED -} ggp_edisc_xfer_ack_status; - -typedef void (*ggp_ggdrive_auth_cb)(PurpleConnection *gc, gboolean success, - gpointer user_data); - -/******************************************************************************* - * Setting up. - ******************************************************************************/ - -static inline ggp_edisc_session_data * -ggp_edisc_get_sdata(PurpleConnection *gc) -{ - GGPInfo *accdata; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - accdata = purple_connection_get_protocol_data(gc); - g_return_val_if_fail(accdata != NULL, NULL); - - return accdata->edisc_data; -} - -void -ggp_edisc_setup(PurpleConnection *gc, GProxyResolver *resolver) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_edisc_session_data *sdata = g_new0(ggp_edisc_session_data, 1); - - accdata->edisc_data = sdata; - - sdata->session = soup_session_new_with_options("proxy-resolver", resolver, - NULL); - soup_session_add_feature_by_type(sdata->session, SOUP_TYPE_COOKIE_JAR); - sdata->xfers_initialized = g_hash_table_new(g_str_hash, g_str_equal); - sdata->xfers_history = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); -} - -void ggp_edisc_cleanup(PurpleConnection *gc) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - - g_return_if_fail(sdata != NULL); - - soup_session_abort(sdata->session); - g_slist_free_full(sdata->auth_pending, g_free); - g_free(sdata->security_token); - - g_object_unref(sdata->session); - g_hash_table_destroy(sdata->xfers_initialized); - g_hash_table_destroy(sdata->xfers_history); - - g_free(sdata); -} - -/******************************************************************************* - * Misc. - ******************************************************************************/ - -static void -ggp_edisc_set_defaults(SoupMessage *msg) -{ - SoupMessageHeaders *headers = soup_message_get_request_headers(msg); - - // purple_http_request_set_max_len(msg, GGP_EDISC_RESPONSE_MAX); - soup_message_headers_replace(headers, "X-gged-api-version", - GGP_EDISC_API); - - /* optional fields */ - soup_message_headers_replace( - headers, "User-Agent", - "Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20120613 " - "GG/11.0.0.8169 (WINNT_x86-msvc; pl; beta; standard)"); - soup_message_headers_replace( - headers, "Accept", - "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); - soup_message_headers_replace(headers, "Accept-Language", - "pl,en-us;q=0.7,en;q=0.3"); - /* soup_message_headers_replace(headers, "Accept-Encoding", - * "gzip, deflate"); */ - soup_message_headers_replace(headers, "Accept-Charset", - "ISO-8859-2,utf-8;q=0.7,*;q=0.7"); - soup_message_headers_replace(headers, "Connection", "keep-alive"); - soup_message_headers_replace( - headers, "Content-Type", - "application/x-www-form-urlencoded; charset=UTF-8"); -} - -static int ggp_edisc_parse_error(const gchar *data) -{ - JsonParser *parser; - JsonObject *result; - int error_id; - - parser = ggp_json_parse(data); - result = json_node_get_object(json_parser_get_root(parser)); - result = json_object_get_object_member(result, "result"); - error_id = json_object_get_int_member(result, "appStatus"); - purple_debug_info("gg", "edisc error: %s (%d)\n", - json_object_get_string_member(result, "errorMsg"), - error_id); - g_object_unref(parser); - - return error_id; -} - -static ggp_edisc_xfer_ack_status -ggp_edisc_xfer_parse_ack_status(const gchar *str) -{ - g_return_val_if_fail(str != NULL, GGP_EDISC_XFER_ACK_STATUS_UNKNOWN); - - if (g_strcmp0("unknown", str) == 0) { - return GGP_EDISC_XFER_ACK_STATUS_UNKNOWN; - } - if (g_strcmp0("allowed", str) == 0) { - return GGP_EDISC_XFER_ACK_STATUS_ALLOWED; - } - if (g_strcmp0("rejected", str) == 0) { - return GGP_EDISC_XFER_ACK_STATUS_REJECTED; - } - - purple_debug_warning( - "gg", "ggp_edisc_xfer_parse_ack_status: unknown status (%s)", str); - return GGP_EDISC_XFER_ACK_STATUS_UNKNOWN; -} - -/******************************************************************************* - * General xfer functions. - ******************************************************************************/ - -static const gchar * -ggp_edisc_xfer_ticket_url(const gchar *ticket_id) -{ - static gchar ticket_url[150]; - - g_snprintf(ticket_url, sizeof(ticket_url), - "https://drive.mpa.gg.pl/send_ticket/%s", ticket_id); - - return ticket_url; -} - -static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg) -{ - if (purple_xfer_is_cancelled(xfer)) - g_return_if_reached(); - purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE); - purple_xfer_conversation_write(xfer, msg, TRUE); - purple_xfer_error( - purple_xfer_get_xfer_type(xfer), - purple_xfer_get_account(xfer), - purple_xfer_get_remote_user(xfer), - msg); - purple_xfer_end(xfer); -} - -/******************************************************************************* - * Authentication. - ******************************************************************************/ - -typedef struct _ggp_edisc_auth_data { - ggp_ggdrive_auth_cb cb; - gpointer user_data; -} ggp_edisc_auth_data; - -static void -ggp_ggdrive_auth_results(PurpleConnection *gc, gboolean success) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - GSList *it; - - purple_debug_info("gg", "ggp_ggdrive_auth_results(gc=%p): %d", gc, success); - - g_return_if_fail(sdata != NULL); - - for (it = sdata->auth_pending; it; it = g_slist_delete_link(it, it)) { - ggp_edisc_auth_data *auth = it->data; - - auth->cb(gc, success, auth->user_data); - g_free(auth); - } - sdata->auth_pending = NULL; - sdata->auth_done = TRUE; -} - -static void -ggp_ggdrive_auth_done(GObject *source, GAsyncResult *async_result, - gpointer data) -{ - PurpleConnection *gc = data; - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - GBytes *response_body = NULL; - const char *buffer = NULL; - gsize size = 0; - SoupStatus status_code; - JsonParser *parser; - JsonObject *result; - int status = -1; - GError *error = NULL; - - g_return_if_fail(sdata != NULL); - - status_code = soup_message_get_status(sdata->auth_request); - if (!SOUP_STATUS_IS_SUCCESSFUL(status_code)) { - purple_debug_misc("gg", - "ggp_ggdrive_auth_done: authentication failed due to " - "unsuccessful request (code = %d)", - status_code); - g_clear_object(&sdata->auth_request); - ggp_ggdrive_auth_results(gc, FALSE); - return; - } - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - async_result, &error); - if(response_body == NULL) { - purple_debug_misc("gg", - "ggp_ggdrive_auth_done: authentication failed due to " - "unsuccessful request (%s)", - error->message); - g_error_free(error); - g_clear_object(&sdata->auth_request); - ggp_ggdrive_auth_results(gc, FALSE); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - parser = ggp_json_parse(buffer); - result = json_node_get_object(json_parser_get_root(parser)); - result = json_object_get_object_member(result, "result"); - if (json_object_has_member(result, "status")) - status = json_object_get_int_member(result, "status"); - g_object_unref(parser); - - if (status != 0) { - purple_debug_misc("gg", - "ggp_ggdrive_auth_done: authentication failed due to " - "bad result (status=%d)", - status); - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_ggdrive_auth_done: result = %.*s", - (int)size, buffer); - } - g_bytes_unref(response_body); - g_clear_object(&sdata->auth_request); - ggp_ggdrive_auth_results(gc, FALSE); - return; - } - - sdata->security_token = g_strdup(soup_message_headers_get_one( - soup_message_get_response_headers(sdata->auth_request), - "X-gged-security-token")); - if (!sdata->security_token) { - purple_debug_misc("gg", "ggp_ggdrive_auth_done: authentication failed " - "due to missing security token header"); - g_bytes_unref(response_body); - g_clear_object(&sdata->auth_request); - ggp_ggdrive_auth_results(gc, FALSE); - return; - } - - if (purple_debug_is_unsafe()) { - purple_debug_misc("gg", "ggp_ggdrive_auth_done: security_token=%s", - sdata->security_token); - } - - g_clear_pointer(&response_body, g_bytes_unref); - g_clear_object(&sdata->auth_request); - - ggp_ggdrive_auth_results(gc, TRUE); -} - -static void -ggp_ggdrive_auth(PurpleConnection *gc, ggp_ggdrive_auth_cb cb, - gpointer user_data) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - ggp_edisc_auth_data *auth; - const gchar *imtoken; - gchar *metadata; - gchar *tmp; - SoupMessage *msg; - SoupMessageHeaders *headers; - - g_return_if_fail(sdata != NULL); - - imtoken = ggp_get_imtoken(gc); - if (!imtoken) { - cb(gc, FALSE, user_data); - return; - } - - if (sdata->auth_done) { - cb(gc, sdata->security_token != NULL, user_data); - return; - } - - auth = g_new0(ggp_edisc_auth_data, 1); - auth->cb = cb; - auth->user_data = user_data; - sdata->auth_pending = g_slist_prepend(sdata->auth_pending, auth); - - if (sdata->auth_request) { - return; - } - - purple_debug_info("gg", "ggp_ggdrive_auth(gc=%p)", gc); - - msg = soup_message_new("PUT", "https://drive.mpa.gg.pl/signin"); - ggp_edisc_set_defaults(msg); - headers = soup_message_get_request_headers(msg); - - metadata = g_strdup_printf("{" - "\"id\": \"%032x\", " - "\"name\": \"%s\", " - "\"os_version\": \"" GGP_EDISC_OS "\", " - "\"client_version\": \"%s\", " - "\"type\": \"" GGP_EDISC_TYPE "\"}", - g_random_int_range(1, 1 << 16), - g_get_host_name(), ggp_libgaduw_version(gc)); - - tmp = g_strdup_printf("IMToken %s", imtoken); - soup_message_headers_replace(headers, "Authorization", tmp); - g_free(tmp); - tmp = g_strdup_printf("gg/pl:%u", accdata->session->uin); - soup_message_headers_replace(headers, "X-gged-user", tmp); - g_free(tmp); - soup_message_headers_replace(headers, "X-gged-client-metadata", metadata); - g_free(metadata); - - sdata->auth_request = msg; - soup_session_send_and_read_async(sdata->session, msg, G_PRIORITY_DEFAULT, - NULL, ggp_ggdrive_auth_done, gc); -} - -static void -ggp_edisc_xfer_send_ticket_changed(G_GNUC_UNUSED PurpleConnection *gc, - PurpleXfer *xfer, gboolean is_allowed) -{ - GGPXfer *edisc_xfer = GGP_XFER(xfer); - if (!edisc_xfer) { - purple_debug_error( - "gg", - "ggp_edisc_event_ticket_changed: transfer %p already free'd", - xfer); - return; - } - - if (!is_allowed) { - purple_debug_info( - "gg", "ggp_edisc_event_ticket_changed: transfer %p rejected", - xfer); - purple_xfer_cancel_remote(xfer); - return; - } - - if (edisc_xfer->allowed) { - purple_debug_misc( - "gg", - "ggp_edisc_event_ticket_changed: transfer %p already allowed", - xfer); - return; - } - edisc_xfer->allowed = TRUE; - - purple_xfer_start(xfer, -1, NULL, 0); -} - -/******************************************************************************* - * Sending a file. - ******************************************************************************/ - -gboolean -ggp_edisc_xfer_can_receive_file(G_GNUC_UNUSED PurpleProtocolXfer *prplxfer, - PurpleConnection *gc, const char *who) -{ - PurpleBuddy *buddy; - - g_return_val_if_fail(gc != NULL, FALSE); - g_return_val_if_fail(who != NULL, FALSE); - - buddy = purple_blist_find_buddy(purple_connection_get_account(gc), who); - if (buddy == NULL) { - return FALSE; - } - - /* TODO: check, if this buddy have us on his list */ - - return PURPLE_BUDDY_IS_ONLINE(buddy); -} - -static void -ggp_edisc_xfer_send_init_ticket_created(GObject *source, GAsyncResult *result, - gpointer data) -{ - PurpleXfer *xfer = data; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(edisc_xfer->gc); - GBytes *response_body = NULL; - const char *buffer = NULL; - gsize size = 0; - ggp_edisc_xfer_ack_status ack_status; - JsonParser *parser; - JsonObject *ticket; - GError *error = NULL; - - if (purple_xfer_is_cancelled(xfer)) - return; - - g_return_if_fail(sdata != NULL); - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - if(response_body == NULL) { - purple_debug_error("gg", - "ggp_edisc_xfer_send_init_ticket_created: failed " - "to send file: %s", error->message); - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Unable to send file")); - g_error_free(error); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - - if(!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(edisc_xfer->msg))) { - int error_id = ggp_edisc_parse_error(buffer); - - g_bytes_unref(response_body); - g_clear_object(&edisc_xfer->msg); - - if(error_id == 206) { - /* recipient not logged in */ - ggp_edisc_xfer_error(xfer, _("Recipient not logged in")); - } else if(error_id == 207) { - /* bad sender recipient relation */ - ggp_edisc_xfer_error(xfer, - _("You aren't on the recipient's buddy list")); - } else { - ggp_edisc_xfer_error(xfer, _("Unable to send file")); - } - return; - } - - parser = ggp_json_parse(buffer); - ticket = json_node_get_object(json_parser_get_root(parser)); - ticket = json_object_get_object_member(ticket, "result"); - ticket = json_object_get_object_member(ticket, "send_ticket"); - edisc_xfer->ticket_id = g_strdup(json_object_get_string_member( - ticket, "id")); - ack_status = ggp_edisc_xfer_parse_ack_status( - json_object_get_string_member(ticket, "ack_status")); - /* send_mode: "normal", "publink" (for legacy clients) */ - - g_object_unref(parser); - g_bytes_unref(response_body); - g_clear_object(&edisc_xfer->msg); - - if (edisc_xfer->ticket_id == NULL) { - purple_debug_error("gg", - "ggp_edisc_xfer_send_init_ticket_created: " - "couldn't get ticket id\n"); - return; - } - - purple_debug_info("gg", "ggp_edisc_xfer_send_init_ticket_created: " - "ticket \"%s\" created\n", edisc_xfer->ticket_id); - - g_hash_table_insert(sdata->xfers_initialized, edisc_xfer->ticket_id, xfer); - g_hash_table_add(sdata->xfers_history, g_strdup(edisc_xfer->ticket_id)); - - if (ack_status != GGP_EDISC_XFER_ACK_STATUS_UNKNOWN) - ggp_edisc_xfer_send_ticket_changed(edisc_xfer->gc, xfer, - ack_status == GGP_EDISC_XFER_ACK_STATUS_ALLOWED); -} - -static void -ggp_edisc_xfer_send_init_authenticated(PurpleConnection *gc, gboolean success, - gpointer _xfer) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - SoupMessage *msg; - PurpleXfer *xfer = _xfer; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - gchar *data; - GBytes *body = NULL; - - if (purple_xfer_is_cancelled(xfer)) { - return; - } - - if (!success) { - ggp_edisc_xfer_error(xfer, _("Authentication failed")); - return; - } - - g_return_if_fail(sdata != NULL); - - msg = soup_message_new("PUT", "https://drive.mpa.gg.pl/send_ticket"); - ggp_edisc_set_defaults(msg); - - soup_message_headers_replace(soup_message_get_request_headers(msg), - "X-gged-security-token", - sdata->security_token); - - data = g_strdup_printf("{\"send_ticket\":{" - "\"recipient\":\"%s\"," - "\"file_name\":\"%s\"," - "\"file_size\":\"%u\"" - "}}", - purple_xfer_get_remote_user(xfer), - edisc_xfer->filename, - (int)purple_xfer_get_size(xfer)); - body = g_bytes_new_take(data, strlen(data)); - soup_message_set_request_body_from_bytes(msg, - "application/x-www-form-urlencoded; charset=UTF-8", - body); - g_bytes_unref(body); - - edisc_xfer->msg = msg; - soup_session_send_and_read_async(sdata->session, msg, G_PRIORITY_DEFAULT, - edisc_xfer->cancellable, - ggp_edisc_xfer_send_init_ticket_created, - xfer); -} - -static void -ggp_edisc_xfer_send_init(PurpleXfer *xfer) -{ - GGPXfer *edisc_xfer = GGP_XFER(xfer); - - purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_NOT_STARTED); - - edisc_xfer->filename = g_strdup(purple_xfer_get_filename(xfer)); - g_strcanon(edisc_xfer->filename, GGP_EDISC_FNAME_ALLOWED, '_'); - - ggp_ggdrive_auth(edisc_xfer->gc, ggp_edisc_xfer_send_init_authenticated, - xfer); -} - -static void -ggp_edisc_xfer_send_done(GObject *source, GAsyncResult *async_result, - gpointer data) -{ - PurpleXfer *xfer = data; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - GBytes *response_body = NULL; - JsonParser *parser = NULL; - JsonObject *result = NULL; - int result_status = -1; - GError *error = NULL; - - if(purple_xfer_is_cancelled(xfer)) { - return; - } - - g_return_if_fail(edisc_xfer != NULL); - - if(!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(edisc_xfer->msg))) { - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Error while sending a file")); - return; - } - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - async_result, &error); - if(response_body == NULL) { - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Error while sending a file")); - g_error_free(error); - return; - } - - parser = ggp_json_parse(g_bytes_get_data(response_body, NULL)); - result = json_node_get_object(json_parser_get_root(parser)); - result = json_object_get_object_member(result, "result"); - if(json_object_has_member(result, "status")) { - result_status = json_object_get_int_member(result, "status"); - } - g_object_unref(parser); - g_clear_pointer(&response_body, g_bytes_unref); - g_clear_object(&edisc_xfer->msg); - - if(result_status == 0) { - purple_xfer_set_completed(xfer, TRUE); - purple_xfer_end(xfer); - } else { - ggp_edisc_xfer_error(xfer, _("Error while sending a file")); - } -} - -static void -ggp_edisc_xfer_send_start_msg_cb(SoupMessage *msg, gpointer data) { - PurpleXfer *xfer = data; - GInputStream *stream = NULL; - /* TODO: Actually fill in stream with something. */ - soup_message_set_request_body(msg, NULL, stream, - purple_xfer_get_size(xfer)); -} - -static void ggp_edisc_xfer_send_start(PurpleXfer *xfer) -{ - ggp_edisc_session_data *sdata; - GGPXfer *edisc_xfer; - gchar *upload_url, *filename_e; - SoupMessage *msg; - SoupMessageHeaders *headers; - - g_return_if_fail(xfer != NULL); - edisc_xfer = GGP_XFER(xfer); - g_return_if_fail(edisc_xfer != NULL); - sdata = ggp_edisc_get_sdata(edisc_xfer->gc); - g_return_if_fail(sdata != NULL); - - filename_e = purple_strreplace(edisc_xfer->filename, " ", "%20"); - upload_url = g_strdup_printf("https://drive.mpa.gg.pl/me/file/outbox/" - "%s%%2C%s", edisc_xfer->ticket_id, filename_e); - g_free(filename_e); - msg = soup_message_new("PUT", upload_url); - g_free(upload_url); - - ggp_edisc_set_defaults(msg); - - headers = soup_message_get_request_headers(msg); - soup_message_headers_replace(headers, "X-gged-local-revision", "0"); - soup_message_headers_replace(headers, "X-gged-security-token", - sdata->security_token); - soup_message_headers_replace(headers, "X-gged-metadata", - "{\"node_type\": \"file\"}"); - - soup_message_headers_set_content_length(headers, - purple_xfer_get_size(xfer)); - edisc_xfer->msg = msg; - - g_signal_connect(msg, "starting", - G_CALLBACK(ggp_edisc_xfer_send_start_msg_cb), xfer); - g_signal_connect(msg, "restarted", - G_CALLBACK(ggp_edisc_xfer_send_start_msg_cb), xfer); - soup_session_send_and_read_async(sdata->session, msg, G_PRIORITY_DEFAULT, - edisc_xfer->cancellable, - ggp_edisc_xfer_send_done, xfer); -} - -PurpleXfer * -ggp_edisc_xfer_send_new(G_GNUC_UNUSED PurpleProtocolXfer *prplxfer, - PurpleConnection *gc, const char *who) -{ - GGPXfer *xfer; - - g_return_val_if_fail(gc != NULL, NULL); - g_return_val_if_fail(who != NULL, NULL); - - xfer = g_object_new( - GGP_TYPE_XFER, - "account", purple_connection_get_account(gc), - "type", PURPLE_XFER_TYPE_SEND, - "remote-user", who, - NULL - ); - - xfer->gc = gc; - - return PURPLE_XFER(xfer); -} - -void ggp_edisc_xfer_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, - const char *filename) -{ - PurpleXfer *xfer; - - g_return_if_fail(gc != NULL); - g_return_if_fail(who != NULL); - - /* Nothing interesting here, this code is common among protocols. - * See ggp_edisc_xfer_send_new. */ - - xfer = ggp_edisc_xfer_send_new(prplxfer, gc, who); - if (filename) - purple_xfer_request_accepted(xfer, filename); - else - purple_xfer_request(xfer); -} - -/******************************************************************************* - * Receiving a file. - ******************************************************************************/ - -static PurpleXfer * -ggp_edisc_xfer_recv_new(PurpleConnection *gc, const char *who) -{ - GGPXfer *xfer; - - g_return_val_if_fail(gc != NULL, NULL); - g_return_val_if_fail(who != NULL, NULL); - - xfer = g_object_new(GGP_TYPE_XFER, "account", - purple_connection_get_account(gc), "type", - PURPLE_XFER_TYPE_RECEIVE, "remote-user", who, NULL); - - xfer->gc = gc; - - return PURPLE_XFER(xfer); -} - -static void -ggp_edisc_xfer_recv_ack_done(GObject *source, GAsyncResult *result, - gpointer data) -{ - PurpleXfer *xfer = data; - GGPXfer *edisc_xfer = NULL; - GBytes *response_body = NULL; - const gchar *buffer = NULL; - gsize size = 0; - GError *error = NULL; - - if (purple_xfer_is_cancelled(xfer)) { - g_return_if_reached(); - } - - edisc_xfer = GGP_XFER(xfer); - - if(!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(edisc_xfer->msg))) { - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Cannot confirm file transfer.")); - return; - } - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - if(response_body == NULL) { - purple_debug_error("gg", "ggp_edisc_xfer_recv_ack_done: failed: %s", - error->message); - g_error_free(error); - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Cannot confirm file transfer.")); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - purple_debug_info("gg", "ggp_edisc_xfer_recv_ack_done: [%.*s]", (int)size, - buffer); - - g_bytes_unref(response_body); - g_clear_object(&edisc_xfer->msg); -} - -static void ggp_edisc_xfer_recv_ack(PurpleXfer *xfer, gboolean accept) -{ - GGPXfer *edisc_xfer = GGP_XFER(xfer); - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(edisc_xfer->gc); - SoupMessage *msg; - SoupMessageHeaders *headers; - - g_return_if_fail(sdata != NULL); - - edisc_xfer->allowed = accept; - - msg = soup_message_new("PUT", - ggp_edisc_xfer_ticket_url(edisc_xfer->ticket_id)); - ggp_edisc_set_defaults(msg); - - headers = soup_message_get_request_headers(msg); - soup_message_headers_replace(headers, "X-gged-security-token", - sdata->security_token); - soup_message_headers_replace(headers, "X-gged-ack-status", - accept ? "allow" : "reject"); - - if(accept) { - edisc_xfer->msg = msg; - soup_session_send_and_read_async(sdata->session, msg, - G_PRIORITY_DEFAULT, - edisc_xfer->cancellable, - ggp_edisc_xfer_recv_ack_done, xfer); - } else { - edisc_xfer->msg = NULL; - soup_session_send_and_read_async(sdata->session, msg, - G_PRIORITY_DEFAULT, - edisc_xfer->cancellable, NULL, NULL); - g_object_unref(msg); - } -} - -static void -ggp_edisc_xfer_recv_reject(PurpleXfer *xfer) -{ - ggp_edisc_xfer_recv_ack(xfer, FALSE); -} - -static void -ggp_edisc_xfer_recv_accept(PurpleXfer *xfer) -{ - ggp_edisc_xfer_recv_ack(xfer, TRUE); -} - -static void ggp_edisc_xfer_recv_ticket_completed(PurpleXfer *xfer) -{ - GGPXfer *edisc_xfer = GGP_XFER(xfer); - - if (edisc_xfer->ready) - return; - edisc_xfer->ready = TRUE; - - purple_xfer_start(xfer, -1, NULL, 0); -} - -static gboolean -ggp_edisc_xfer_recv_pollable_source_cb(GObject *pollable_stream, gpointer data) -{ - PurpleXfer *xfer = data; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - guchar buf[4096]; - gssize len; - gboolean stored; - GError *error = NULL; - - do { - len = g_pollable_input_stream_read_nonblocking( - G_POLLABLE_INPUT_STREAM(pollable_stream), buf, sizeof(buf), - edisc_xfer->cancellable, &error); - if(len == 0) { - /* End of file */ - if(purple_xfer_get_bytes_remaining(xfer) == 0) { - purple_xfer_set_completed(xfer, TRUE); - purple_xfer_end(xfer); - } else { - purple_debug_warning("gg", "ggp_edisc_xfer_recv_done: didn't " - "receive everything"); - ggp_edisc_xfer_error(xfer, _("Error while receiving a file")); - } - edisc_xfer->handler = 0; - return G_SOURCE_REMOVE; - - } else if(len < 0) { - /* Errors occurred */ - if(error->code == G_IO_ERROR_WOULD_BLOCK) { - g_error_free(error); - return G_SOURCE_CONTINUE; - } else if(error->code == G_IO_ERROR_CANCELLED) { - g_error_free(error); - } else { - purple_debug_warning("gg", "ggp_edisc_xfer_recv_done: lost " - "connection with server: %s", - error->message); - ggp_edisc_xfer_error(xfer, _("Error while receiving a file")); - g_error_free(error); - } - edisc_xfer->handler = 0; - return G_SOURCE_REMOVE; - } - - if(len > purple_xfer_get_bytes_remaining(xfer)) { - purple_debug_error("gg", "ggp_edisc_xfer_recv_writer: saved too " - "much (%" G_GSIZE_FORMAT - " > %" G_GOFFSET_FORMAT ")", - len, purple_xfer_get_bytes_remaining(xfer)); - ggp_edisc_xfer_error(xfer, _("Error while receiving a file")); - edisc_xfer->handler = 0; - return G_SOURCE_REMOVE; - } - - stored = purple_xfer_write_file(xfer, buf, len); - if(!stored) { - purple_debug_error("gg", "ggp_edisc_xfer_recv_writer: failed to save"); - ggp_edisc_xfer_error(xfer, _("Error while receiving a file")); - edisc_xfer->handler = 0; - return G_SOURCE_REMOVE; - } - } while(len > 0); - - return G_SOURCE_CONTINUE; -} - -static void -ggp_edisc_xfer_recv_done_cb(GObject *source, GAsyncResult *result, - gpointer data) -{ - PurpleXfer *xfer = data; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - GInputStream *input = NULL; - GSource *poll = NULL; - GError *error = NULL; - - if(!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(edisc_xfer->msg))) { - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Error while receiving a file")); - return; - } - - input = soup_session_send_finish(SOUP_SESSION(source), result, &error); - if(input == NULL) { - purple_debug_warning("gg", "ggp_edisc_xfer_recv_done_cb: error " - "receiving file: %s", error->message); - g_error_free(error); - g_clear_object(&edisc_xfer->msg); - ggp_edisc_xfer_error(xfer, _("Error while receiving a file")); - return; - } - - poll = g_pollable_input_stream_create_source(G_POLLABLE_INPUT_STREAM(input), - edisc_xfer->cancellable); - g_source_set_callback(poll, - G_SOURCE_FUNC(ggp_edisc_xfer_recv_pollable_source_cb), - xfer, NULL); - edisc_xfer->handler = g_source_attach(poll, NULL); - g_source_unref(poll); - g_clear_object(&edisc_xfer->msg); -} - -static void -ggp_edisc_xfer_recv_start(PurpleXfer *xfer) -{ - ggp_edisc_session_data *sdata; - GGPXfer *edisc_xfer; - gchar *upload_url; - SoupMessage *msg; - - g_return_if_fail(xfer != NULL); - edisc_xfer = GGP_XFER(xfer); - g_return_if_fail(edisc_xfer != NULL); - sdata = ggp_edisc_get_sdata(edisc_xfer->gc); - g_return_if_fail(sdata != NULL); - - upload_url = - g_strdup_printf("https://drive.mpa.gg.pl/me/file/inbox/" - "%s,%s?api_version=%s&security_token=%s", - edisc_xfer->ticket_id, - purple_url_encode(purple_xfer_get_filename(xfer)), - GGP_EDISC_API, sdata->security_token); - msg = soup_message_new("GET", upload_url); - g_free(upload_url); - - ggp_edisc_set_defaults(msg); - // purple_http_request_set_max_len(msg, purple_xfer_get_size(xfer) + 1); - - edisc_xfer->msg = msg; - soup_session_send_async(sdata->session, msg, G_PRIORITY_DEFAULT, - edisc_xfer->cancellable, - ggp_edisc_xfer_recv_done_cb, xfer); -} - -static void -ggp_edisc_xfer_recv_ticket_update_got(GObject *source, - GAsyncResult *async_result, - gpointer data) -{ - SoupMessage *msg = data; - PurpleConnection *gc = NULL; - GBytes *response_body = NULL; - PurpleXfer *xfer; - GGPXfer *edisc_xfer; - const char *buffer = NULL; - gsize size = 0; - JsonParser *parser; - JsonObject *result; - int status = -1; - ggp_edisc_session_data *sdata; - - const gchar *ticket_id, *file_name, *send_mode_str; - uin_t sender, recipient; - int file_size; - SoupStatus status_code; - GError *error = NULL; - - status_code = soup_message_get_status(msg); - if (!SOUP_STATUS_IS_SUCCESSFUL(status_code)) { - purple_debug_error("gg", - "ggp_edisc_xfer_recv_ticket_update_got: cannot " - "fetch update for ticket (code=%d)", - status_code); - g_object_unref(msg); - return; - } - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - async_result, &error); - if(response_body == NULL) { - purple_debug_error("gg", - "ggp_edisc_xfer_recv_ticket_update_got: cannot " - "fetch update for ticket (%s)", - error->message); - g_error_free(error); - g_object_unref(msg); - return; - } - - gc = g_object_get_data(G_OBJECT(msg), "purple-connection"); - sdata = ggp_edisc_get_sdata(gc); - if(sdata == NULL) { - g_bytes_unref(response_body); - g_object_unref(msg); - g_return_if_reached(); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - parser = ggp_json_parse(buffer); - g_clear_pointer(&response_body, g_bytes_unref); - g_clear_object(&msg); - - result = json_node_get_object(json_parser_get_root(parser)); - result = json_object_get_object_member(result, "result"); - if (json_object_has_member(result, "status")) - status = json_object_get_int_member(result, "status"); - result = json_object_get_object_member(result, "send_ticket"); - - if (status != 0) { - purple_debug_warning("gg", - "ggp_edisc_xfer_recv_ticket_update_got: failed to " - "get update (status=%d)", - status); - g_object_unref(parser); - return; - } - - ticket_id = json_object_get_string_member(result, "id"); - sender = ggp_str_to_uin(json_object_get_string_member(result, "sender")); - recipient = - ggp_str_to_uin(json_object_get_string_member(result, "recipient")); - file_size = g_ascii_strtoll( - json_object_get_string_member(result, "file_size"), NULL, 10); - file_name = json_object_get_string_member(result, "file_name"); - - /* GG11: normal - * AQQ 2.4.2.10: direct_inbox - */ - send_mode_str = json_object_get_string_member(result, "send_mode"); - - /* more fields: - * send_progress (float), ack_status, send_status - */ - - if (purple_debug_is_verbose() && purple_debug_is_unsafe()) { - purple_debug_info("gg", - "Got ticket update: id=%s, sender=%u, recipient=%u, " - "file name=\"%s\", file size=%d, send mode=%s)", - ticket_id, sender, recipient, file_name, file_size, - send_mode_str); - } - - xfer = g_hash_table_lookup(sdata->xfers_initialized, ticket_id); - if (xfer != NULL) { - purple_debug_misc("gg", - "ggp_edisc_xfer_recv_ticket_update_got: ticket %s " - "already updated", - purple_debug_is_unsafe() ? ticket_id : ""); - g_object_unref(parser); - return; - } - - if (recipient != ggp_get_my_uin(gc)) { - purple_debug_misc("gg", - "ggp_edisc_xfer_recv_ticket_update_got: ticket %s is " - "not for incoming transfer (its from %u to %u)", - purple_debug_is_unsafe() ? ticket_id : "", sender, - recipient); - g_object_unref(parser); - return; - } - - xfer = ggp_edisc_xfer_recv_new(gc, ggp_uin_to_str(sender)); - purple_xfer_set_filename(xfer, file_name); - purple_xfer_set_size(xfer, file_size); - purple_xfer_request(xfer); - edisc_xfer = GGP_XFER(xfer); - edisc_xfer->ticket_id = g_strdup(ticket_id); - g_hash_table_insert(sdata->xfers_initialized, edisc_xfer->ticket_id, xfer); - g_hash_table_add(sdata->xfers_history, g_strdup(ticket_id)); - - g_object_unref(parser); -} - -static void -ggp_edisc_xfer_recv_ticket_update_authenticated(PurpleConnection *gc, - gboolean success, - gpointer _ticket) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - SoupMessage *msg; - gchar *ticket = _ticket; - - g_return_if_fail(sdata != NULL); - - if (!success) { - purple_debug_warning( - "gg", - "ggp_edisc_xfer_recv_ticket_update_authenticated: update of " - "ticket %s aborted due to authentication failure", - ticket); - g_free(ticket); - return; - } - - msg = soup_message_new("GET", ggp_edisc_xfer_ticket_url(ticket)); - g_free(ticket); - - ggp_edisc_set_defaults(msg); - - soup_message_headers_replace(soup_message_get_request_headers(msg), - "X-gged-security-token", - sdata->security_token); - - g_object_set_data(G_OBJECT(msg), "purple-connection", gc); - soup_session_send_and_read_async(sdata->session, msg, G_PRIORITY_DEFAULT, - NULL, - ggp_edisc_xfer_recv_ticket_update_got, - msg); -} - -static void -ggp_edisc_xfer_recv_ticket_got(PurpleConnection *gc, const gchar *ticket_id) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - - g_return_if_fail(sdata != NULL); - - if (g_hash_table_contains(sdata->xfers_history, ticket_id)) { - return; - } - - ggp_ggdrive_auth(gc, ggp_edisc_xfer_recv_ticket_update_authenticated, - g_strdup(ticket_id)); -} - -void -ggp_edisc_xfer_ticket_changed(PurpleConnection *gc, const char *data) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - PurpleXfer *xfer; - JsonParser *parser; - JsonObject *ticket; - const gchar *ticket_id, *send_status; - ggp_edisc_xfer_ack_status ack_status; - gboolean is_completed; - - g_return_if_fail(sdata != NULL); - - parser = ggp_json_parse(data); - ticket = json_node_get_object(json_parser_get_root(parser)); - ticket_id = json_object_get_string_member(ticket, "id"); - ack_status = ggp_edisc_xfer_parse_ack_status( - json_object_get_string_member(ticket, "ack_status")); - send_status = json_object_get_string_member(ticket, "send_status"); - - if (ticket_id == NULL) { - ticket_id = ""; - } - xfer = g_hash_table_lookup(sdata->xfers_initialized, ticket_id); - if (xfer == NULL) { - purple_debug_misc("gg", - "ggp_edisc_event_ticket_changed: ticket %s not " - "found, updating it...", - purple_debug_is_unsafe() ? ticket_id : ""); - ggp_edisc_xfer_recv_ticket_got(gc, ticket_id); - g_object_unref(parser); - return; - } - - is_completed = FALSE; - if (g_strcmp0("in_progress", send_status) == 0) { - /* do nothing */ - } else if (g_strcmp0("completed", send_status) == 0) { - is_completed = TRUE; - } else if (g_strcmp0("expired", send_status) == 0) - ggp_edisc_xfer_error(xfer, _("File transfer expired.")); - else { - purple_debug_warning( - "gg", "ggp_edisc_event_ticket_changed: unknown send_status=%s", - send_status); - g_object_unref(parser); - return; - } - - g_object_unref(parser); - - if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) { - if (is_completed) { - ggp_edisc_xfer_recv_ticket_completed(xfer); - } - } else { - if (ack_status != GGP_EDISC_XFER_ACK_STATUS_UNKNOWN) { - ggp_edisc_xfer_send_ticket_changed( - gc, xfer, ack_status == GGP_EDISC_XFER_ACK_STATUS_ALLOWED); - } - } -} - -/******************************************************************************* - * GObject implementation - ******************************************************************************/ - -G_DEFINE_DYNAMIC_TYPE_EXTENDED(GGPXfer, ggp_xfer, PURPLE_TYPE_XFER, - G_TYPE_FLAG_FINAL, {}) - -static void -ggp_xfer_init_xfer(PurpleXfer *xfer) { - PurpleXferType type = purple_xfer_get_xfer_type(xfer); - - if(type == PURPLE_XFER_TYPE_SEND) { - ggp_edisc_xfer_send_init(xfer); - } else if(type == PURPLE_XFER_TYPE_RECEIVE) { - ggp_edisc_xfer_recv_accept(xfer); - } -} - -static void -ggp_xfer_start(PurpleXfer *xfer) { - PurpleXferType type = purple_xfer_get_xfer_type(xfer); - - if(type == PURPLE_XFER_TYPE_SEND) { - ggp_edisc_xfer_send_start(xfer); - } else if(type == PURPLE_XFER_TYPE_RECEIVE) { - ggp_edisc_xfer_recv_start(xfer); - } -} - -static void -ggp_xfer_init(GGPXfer *xfer) { - xfer->cancellable = g_cancellable_new(); -} - -static void -ggp_xfer_finalize(GObject *obj) { - GGPXfer *edisc_xfer = GGP_XFER(obj); - ggp_edisc_session_data *sdata; - - sdata = ggp_edisc_get_sdata(edisc_xfer->gc); - - g_free(edisc_xfer->filename); - g_cancellable_cancel(edisc_xfer->cancellable); - g_clear_object(&edisc_xfer->cancellable); - g_clear_object(&edisc_xfer->msg); - - g_clear_handle_id(&edisc_xfer->handler, g_source_remove); - - if (edisc_xfer->ticket_id != NULL) { - g_hash_table_remove(sdata->xfers_initialized, - edisc_xfer->ticket_id); - } - - G_OBJECT_CLASS(ggp_xfer_parent_class)->finalize(obj); -} - -static void -ggp_xfer_class_finalize(G_GNUC_UNUSED GGPXferClass *klass) { -} - -static void -ggp_xfer_class_init(GGPXferClass *klass) { - GObjectClass *obj_class = G_OBJECT_CLASS(klass); - PurpleXferClass *xfer_class = PURPLE_XFER_CLASS(klass); - - obj_class->finalize = ggp_xfer_finalize; - - xfer_class->init = ggp_xfer_init_xfer; - xfer_class->start = ggp_xfer_start; - xfer_class->request_denied = ggp_edisc_xfer_recv_reject; -} - -void -ggp_xfer_register(GTypeModule *module) { - ggp_xfer_register_type(module); -}
--- a/libpurple/protocols/gg/edisc.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_EDISC_H -#define PURPLE_GG_EDISC_H - -#include <purple.h> - -typedef struct _ggp_edisc_session_data ggp_edisc_session_data; - -G_BEGIN_DECLS - -#define GGP_TYPE_XFER (ggp_xfer_get_type()) -G_DECLARE_FINAL_TYPE(GGPXfer, ggp_xfer, GGP, XFER, PurpleXfer); - -void ggp_xfer_register(GTypeModule *module); - -/* Setting up. */ -void ggp_edisc_setup(PurpleConnection *gc, GProxyResolver *resolver); -void ggp_edisc_cleanup(PurpleConnection *gc); - -/* General xfer functions. */ -void ggp_edisc_xfer_ticket_changed(PurpleConnection *gc, - const char *data); - -/* Sending a file. */ -gboolean ggp_edisc_xfer_can_receive_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who); -void ggp_edisc_xfer_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, - const char *filename); -PurpleXfer * ggp_edisc_xfer_send_new(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who); - -G_END_DECLS - -#endif /* PURPLE_GG_EDISC_H */
--- a/libpurple/protocols/gg/gg.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1452 +0,0 @@ -/** - * @file gg.c Gadu-Gadu protocol plugin - * - * purple - * - * Copyright (C) 2005 Bartosz Oler <bartosz@bzimage.us> - * - * Some parts of the code are adapted or taken from the previous implementation - * of this plugin written by Arkadiusz Miskiewicz <misiek@pld.org.pl> - * Some parts Copyright (C) 2009 Krzysztof Klinikowski <grommasher@gmail.com> - * - * Thanks to Google's Summer of Code Program. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include <gplugin.h> -#include <gplugin-native.h> - -#include <purple.h> - -#include "gg.h" -#include "chat.h" -#include "search.h" -#include "blist.h" -#include "utils.h" -#include "resolver-purple.h" -#include "purplew.h" -#include "libgadu-events.h" -#include "multilogon.h" -#include "status.h" -#include "servconn.h" -#include "tcpsocket.h" -#include "pubdir-prpl.h" -#include "message-prpl.h" -#include "html.h" -#include "libgaduw.h" - -struct _GGPProtocol { - PurpleProtocol parent; -}; - -/* ---------------------------------------------------------------------- */ -static PurpleProtocol *my_protocol = NULL; - -/* ---------------------------------------------------------------------- */ - -ggp_buddy_data * ggp_buddy_get_data(PurpleBuddy *buddy) -{ - ggp_buddy_data *buddy_data = purple_buddy_get_protocol_data(buddy); - if (buddy_data) - return buddy_data; - - buddy_data = g_new0(ggp_buddy_data, 1); /* TODO: leak */ - purple_buddy_set_protocol_data(buddy, buddy_data); - return buddy_data; -} - -static void -ggp_buddy_free(G_GNUC_UNUSED PurpleProtocolClient *client, PurpleBuddy *buddy) -{ - ggp_buddy_data *buddy_data = purple_buddy_get_protocol_data(buddy); - - if (!buddy_data) { - return; - } - - g_free(buddy_data); - purple_buddy_set_protocol_data(buddy, NULL); -} - -const gchar * ggp_get_imtoken(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - - if (accdata->imtoken) - return accdata->imtoken; - - if (accdata->imtoken_warned) - return NULL; - accdata->imtoken_warned = TRUE; - - purple_notify_error(gc, _("Authentication failed"), - _("IMToken value has not been received."), - _("Some features will be disabled. " - "You may try again after a while."), - purple_request_cpar_from_connection(gc)); - return NULL; -} - -uin_t -ggp_own_uin(PurpleConnection *gc) { - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - - return ggp_str_to_uin(purple_contact_info_get_username(info)); -} - -/* ---------------------------------------------------------------------- */ -/* buddy list import/export from/to file */ - -static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *filename) -{ - PurpleAccount *account = purple_connection_get_account(gc); - - char *buddylist = ggp_buddylist_dump(account); - - purple_debug_info("gg", "Saving...\n"); - purple_debug_info("gg", "file = %s\n", filename); - - if (buddylist == NULL) { - purple_notify_info(account, _("Save Buddylist..."), _("Your " - "buddylist is empty, nothing was written to the file."), - NULL, purple_request_cpar_from_connection(gc)); - return; - } - - if (g_file_set_contents(filename, buddylist, -1, NULL)) { - purple_notify_info(account, _("Save Buddylist..."), - _("Buddylist saved successfully!"), NULL, - purple_request_cpar_from_connection(gc)); - } else { - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - gchar *primary = NULL; - - primary = g_strdup_printf(_("Couldn't write buddy list for %s to %s"), - purple_contact_info_get_username(info), - filename); - purple_notify_error(account, _("Save Buddylist..."), - primary, NULL, purple_request_cpar_from_connection(gc)); - g_free(primary); - } - - g_free(buddylist); -} - -static void ggp_callback_buddylist_load_ok(PurpleConnection *gc, gchar *file) -{ - PurpleAccount *account = purple_connection_get_account(gc); - GError *error = NULL; - char *buddylist = NULL; - gsize length; - - purple_debug_info("gg", "file_name = %s\n", file); - - if (!g_file_get_contents(file, &buddylist, &length, &error)) { - purple_notify_error(account, _("Couldn't load buddylist"), - _("Couldn't load buddylist"), error->message, - purple_request_cpar_from_connection(gc)); - - purple_debug_error("gg", - "Couldn't load buddylist. file = %s; error = %s\n", - file, error->message); - - g_error_free(error); - - return; - } - - ggp_buddylist_load(gc, buddylist); - g_free(buddylist); - - purple_notify_info(account, _("Load Buddylist..."), - _("Buddylist loaded successfully!"), NULL, - purple_request_cpar_from_connection(gc)); -} -/* }}} */ - -static void -ggp_action_buddylist_save(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *connection = NULL; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("GG save buddylist action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - connection = purple_account_get_connection(account); - - purple_request_file(action, _("Save buddylist..."), NULL, TRUE, - G_CALLBACK(ggp_callback_buddylist_save_ok), NULL, - purple_request_cpar_from_connection(connection), connection); - - g_clear_object(&account); -} - -static void -ggp_action_buddylist_load(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *connection = NULL; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("GG load buddylist action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - connection = purple_account_get_connection(account); - - purple_request_file(action, _("Load buddylist from file..."), NULL, - FALSE, G_CALLBACK(ggp_callback_buddylist_load_ok), NULL, - purple_request_cpar_from_connection(connection), connection); - - g_clear_object(&account); -} - -/* ----- BLOCK BUDDIES -------------------------------------------------- */ - -#if 0 -static void ggp_add_deny(PurpleProtocolPrivacy *privacy, PurpleConnection *gc, - const char *who) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - uin_t uin = ggp_str_to_uin(who); - - purple_debug_info("gg", "ggp_add_deny: %u\n", uin); - - gg_remove_notify_ex(info->session, uin, GG_USER_NORMAL); - gg_add_notify_ex(info->session, uin, GG_USER_BLOCKED); -} - -static void ggp_remove_deny(PurpleProtocolPrivacy *privacy, - PurpleConnection *gc, const char *who) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - uin_t uin = ggp_str_to_uin(who); - - purple_debug_info("gg", "ggp_rem_deny: %u\n", uin); - - gg_remove_notify_ex(info->session, uin, GG_USER_BLOCKED); - gg_add_notify_ex(info->session, uin, GG_USER_NORMAL); -} -#endif - -/* ---------------------------------------------------------------------- */ -/* ----- INTERNAL CALLBACKS --------------------------------------------- */ -/* ---------------------------------------------------------------------- */ - -static void ggp_typing_notification_handler(PurpleConnection *gc, uin_t uin, int length) { - gchar *from; - - from = g_strdup_printf("%u", uin); - if (length) - purple_serv_got_typing(gc, from, 0, PURPLE_IM_TYPING); - else - purple_serv_got_typing_stopped(gc, from); - g_free(from); -} - -/** - * Handling of XML events. - * - * @param gc PurpleConnection. - * @param data Raw XML contents. - * - * @see http://toxygen.net/libgadu/protocol/#ch1.13 - * @todo: this may not be necessary anymore - */ -static void -ggp_xml_event_handler(G_GNUC_UNUSED PurpleConnection *gc, char *data) -{ - PurpleXmlNode *xml = NULL; - PurpleXmlNode *xmlnode_next_event; - - xml = purple_xmlnode_from_str(data, -1); - if (xml == NULL) { - purple_debug_error("gg", "ggp_xml_event_handler: " - "invalid xml: [%s]\n", data); - goto out; - } - - xmlnode_next_event = purple_xmlnode_get_child(xml, "event"); - while (xmlnode_next_event != NULL) { - PurpleXmlNode *xmlnode_current_event = xmlnode_next_event; - - PurpleXmlNode *xmlnode_type; - char *event_type_raw; - int event_type = 0; - - PurpleXmlNode *xmlnode_sender; - char *event_sender_raw; - uin_t event_sender = 0; - - xmlnode_next_event = purple_xmlnode_get_next_twin(xmlnode_next_event); - - xmlnode_type = purple_xmlnode_get_child(xmlnode_current_event, "type"); - if (xmlnode_type == NULL) - continue; - event_type_raw = purple_xmlnode_get_data(xmlnode_type); - if (event_type_raw != NULL) - event_type = atoi(event_type_raw); - g_free(event_type_raw); - - xmlnode_sender = purple_xmlnode_get_child(xmlnode_current_event, "sender"); - if (xmlnode_sender != NULL) { - event_sender_raw = purple_xmlnode_get_data(xmlnode_sender); - if (event_sender_raw != NULL) - event_sender = ggp_str_to_uin(event_sender_raw); - g_free(event_sender_raw); - } - - switch (event_type) - { - case 28: /* avatar update */ - purple_debug_info("gg", - "ggp_xml_event_handler: avatar updated (uid: %u)\n", - event_sender); - break; - default: - purple_debug_error("gg", - "ggp_xml_event_handler: unsupported event type=%d from=%u\n", - event_type, event_sender); - } - } - - out: - if (xml) - purple_xmlnode_free(xml); -} - -static void -ggp_callback_recv(gpointer _gc, G_GNUC_UNUSED gint fd, - G_GNUC_UNUSED PurpleInputCondition cond) -{ - PurpleConnection *gc = _gc; - GGPInfo *info = purple_connection_get_protocol_data(gc); - struct gg_event *ev; - - if (!(ev = gg_watch_fd(info->session))) { - purple_debug_error("gg", - "ggp_callback_recv: gg_watch_fd failed -- CRITICAL!\n"); - purple_connection_error (gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to read from socket")); - return; - } - - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_callback_recv: got event %s", - gg_debug_event(ev->type)); - } - - g_source_remove(info->inpa); - info->inpa = purple_input_add(info->session->fd, - ggp_tcpsocket_inputcond_gg_to_purple(info->session->check), - ggp_callback_recv, gc); - - switch (ev->type) { - case GG_EVENT_NONE: - /* Nothing happened. */ - break; - case GG_EVENT_CONN_FAILED: - purple_connection_error (gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Server disconnected")); - break; - case GG_EVENT_MSG: - ggp_message_got(gc, &ev->event.msg); - break; - case GG_EVENT_ACK: - case GG_EVENT_ACK110: - break; - case GG_EVENT_IMAGE_REPLY: - ggp_image_recv(gc, &ev->event.image_reply); - break; - case GG_EVENT_IMAGE_REQUEST: - ggp_image_send(gc, &ev->event.image_request); - break; - case GG_EVENT_NOTIFY60: - case GG_EVENT_STATUS60: - ggp_status_got_others(gc, ev); - break; - case GG_EVENT_TYPING_NOTIFICATION: - ggp_typing_notification_handler(gc, ev->event.typing_notification.uin, - ev->event.typing_notification.length); - break; - case GG_EVENT_XML_EVENT: - purple_debug_info("gg", "GG_EVENT_XML_EVENT\n"); - ggp_xml_event_handler(gc, ev->event.xml_event.data); - break; - case GG_EVENT_USER_DATA: - ggp_events_user_data(gc, &ev->event.user_data); - break; - case GG_EVENT_JSON_EVENT: - ggp_events_json(gc, &ev->event.json_event); - break; - case GG_EVENT_USERLIST100_VERSION: - ggp_roster_version(gc, &ev->event.userlist100_version); - break; - case GG_EVENT_USERLIST100_REPLY: - ggp_roster_reply(gc, &ev->event.userlist100_reply); - break; - case GG_EVENT_MULTILOGON_MSG: - ggp_message_got_multilogon(gc, &ev->event.multilogon_msg); - break; - case GG_EVENT_MULTILOGON_INFO: - ggp_multilogon_info(gc, &ev->event.multilogon_info); - break; - case GG_EVENT_IMTOKEN: - purple_debug_info("gg", "gg11: got IMTOKEN\n"); - g_free(info->imtoken); - info->imtoken = g_strdup(ev->event.imtoken.imtoken); - break; - case GG_EVENT_PONG110: - purple_debug_info("gg", "gg11: got PONG110 %lu\n", - (long unsigned)ev->event.pong110.time); - break; - case GG_EVENT_CHAT_INFO: - case GG_EVENT_CHAT_INFO_GOT_ALL: - case GG_EVENT_CHAT_INFO_UPDATE: - case GG_EVENT_CHAT_CREATED: - case GG_EVENT_CHAT_INVITE_ACK: - ggp_chat_got_event(gc, ev); - break; - case GG_EVENT_DISCONNECT: - ggp_servconn_remote_disconnect(gc); - break; - default: - purple_debug_warning("gg", - "unsupported event type=%d\n", ev->type); - break; - } - - gg_free_event(ev); -} - -void -ggp_async_login_handler(gpointer _gc, G_GNUC_UNUSED gint fd, - G_GNUC_UNUSED PurpleInputCondition cond) -{ - PurpleConnection *gc = _gc; - GGPInfo *info; - struct gg_event *ev; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - info = purple_connection_get_protocol_data(gc); - - purple_debug_info("gg", "login_handler: session: check = %d; state = %d;\n", - info->session->check, info->session->state); - - switch (info->session->state) { - case GG_STATE_ERROR: - purple_debug_info("gg", "GG_STATE_ERROR\n"); - break; - case GG_STATE_RESOLVING: - purple_debug_info("gg", "GG_STATE_RESOLVING\n"); - break; - case GG_STATE_RESOLVING_GG: - purple_debug_info("gg", "GG_STATE_RESOLVING_GG\n"); - break; - case GG_STATE_CONNECTING_HUB: - purple_debug_info("gg", "GG_STATE_CONNECTING_HUB\n"); - break; - case GG_STATE_READING_DATA: - purple_debug_info("gg", "GG_STATE_READING_DATA\n"); - break; - case GG_STATE_CONNECTING_GG: - purple_debug_info("gg", "GG_STATE_CONNECTING_GG\n"); - break; - case GG_STATE_READING_KEY: - purple_debug_info("gg", "GG_STATE_READING_KEY\n"); - break; - case GG_STATE_READING_REPLY: - purple_debug_info("gg", "GG_STATE_READING_REPLY\n"); - break; - case GG_STATE_TLS_NEGOTIATION: - purple_debug_info("gg", "GG_STATE_TLS_NEGOTIATION\n"); - break; - case GG_STATE_RESOLVING_HUB: - purple_debug_info("gg", "GG_STATE_RESOLVING_HUB\n"); - break; - case GG_STATE_READING_HUB: - purple_debug_info("gg", "GG_STATE_READING_HUB\n"); - break; - default: - purple_debug_error("gg", "unknown state = %d\n", - info->session->state); - break; - } - - if (!(ev = gg_watch_fd(info->session))) { - purple_debug_error("gg", "login_handler: gg_watch_fd failed!\n"); - purple_connection_error (gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to read from socket")); - return; - } - purple_debug_info("gg", "login_handler: session->fd = %d\n", info->session->fd); - purple_debug_info("gg", "login_handler: session: check = %d; state = %d;\n", - info->session->check, info->session->state); - - g_clear_handle_id(&info->inpa, g_source_remove); - - /** XXX I think that this shouldn't be done if ev->type is GG_EVENT_CONN_FAILED or GG_EVENT_CONN_SUCCESS -datallah */ - if (info->session->fd >= 0) - info->inpa = purple_input_add(info->session->fd, - (info->session->check == 1) ? PURPLE_INPUT_WRITE : - PURPLE_INPUT_READ, - ggp_async_login_handler, gc); - - switch (ev->type) { - case GG_EVENT_NONE: - /* Nothing happened. */ - purple_debug_info("gg", "GG_EVENT_NONE\n"); - break; - case GG_EVENT_CONN_SUCCESS: - { - purple_debug_info("gg", "GG_EVENT_CONN_SUCCESS:" - " successfully connected to %s\n", - info->session->connect_host); - ggp_servconn_add_server(info->session-> - connect_host); - g_source_remove(info->inpa); - info->inpa = purple_input_add(info->session->fd, - PURPLE_INPUT_READ, - ggp_callback_recv, gc); - - purple_connection_set_state(gc, PURPLE_CONNECTION_STATE_CONNECTED); - - ggp_buddylist_send(gc); - ggp_roster_request_update(gc); - } - break; - case GG_EVENT_CONN_FAILED: - g_clear_handle_id(&info->inpa, g_source_remove); - purple_debug_info("gg", "Connection failure: %d\n", - ev->event.failure); - switch (ev->event.failure) { - case GG_FAILURE_RESOLVING: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to resolve " - "hostname")); - break; - case GG_FAILURE_PASSWORD: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, - _("Incorrect password")); - break; - case GG_FAILURE_TLS: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, - _("SSL Connection Failed")); - break; - case GG_FAILURE_INTRUDER: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, - _("Your account has been " - "disabled because too many " - "incorrect passwords were " - "entered")); - break; - case GG_FAILURE_UNAVAILABLE: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Service temporarily " - "unavailable")); - break; - case GG_FAILURE_PROXY: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Error connecting to proxy " - "server")); - break; - case GG_FAILURE_HUB: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Error connecting to master " - "server")); - break; - case GG_FAILURE_INTERNAL: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_OTHER_ERROR, - _("Internal error")); - break; - default: - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Connection failed")); - } - break; - case GG_EVENT_MSG: - if (ev->event.msg.sender == 0) { - if (ev->event.msg.message == NULL) - break; - - /* system messages are mostly ads */ - purple_debug_info("gg", "System message:\n%s\n", - ev->event.msg.message); - } else { - purple_debug_warning("gg", "GG_EVENT_MSG: message from user %u " - "unexpected while connecting:\n%s\n", - ev->event.msg.sender, - ev->event.msg.message); - } - break; - default: - purple_debug_error("gg", "strange event: %d\n", ev->type); - break; - } - - gg_free_event(ev); -} - -static gboolean -gg_uri_handler_find_account(PurpleAccount *account, - G_GNUC_UNUSED gconstpointer data) -{ - const gchar *protocol_id; - - protocol_id = purple_account_get_protocol_id(account); - - return (purple_strequal(protocol_id, "prpl-gg") && - purple_account_is_connected(account)); -} - -static gboolean -gg_uri_handler(const gchar *scheme, const gchar *screenname, - G_GNUC_UNUSED GHashTable *params) -{ - PurpleAccountManager *manager = NULL; - PurpleAccount *account; - PurpleConversation *im; - - g_return_val_if_fail(screenname != NULL, FALSE); - - if (!purple_strequal(scheme, "gg")) { - return FALSE; - } - - if (screenname[0] == '\0') { - purple_debug_warning("gg", "Invalid empty screenname in URI"); - return FALSE; - } - - /* Find online Gadu-Gadu account */ - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_custom(manager, - (GEqualFunc)gg_uri_handler_find_account, - NULL); - - if (account == NULL) { - return FALSE; - } - - im = purple_im_conversation_new(account, screenname); - purple_conversation_present(im); - - g_clear_object(&account); - - return TRUE; -} - -/* ---------------------------------------------------------------------- */ -/* ----- PurpleProtocol ----------------------------------------- */ -/* ---------------------------------------------------------------------- */ - -static PurpleBuddyIconSpec * -ggp_protocol_get_buddy_icon_spec(G_GNUC_UNUSED PurpleProtocol *protocol) { - return purple_buddy_icon_spec_new("png", - 1, 1, 200, 200, 0, - PURPLE_ICON_SCALE_DISPLAY | - PURPLE_ICON_SCALE_SEND); -} - -static GList * -ggp_protocol_get_account_options(G_GNUC_UNUSED PurpleProtocol *protocol) { - PurpleAccountOption *option = NULL; - PurpleKeyValuePair *kvp = NULL; - GList *encryption_options = NULL; - GList *protocol_version = NULL; - GList *opts = NULL; - - option = purple_account_option_string_new(_("GG server"), "gg_server", ""); - opts = g_list_append(opts, option); - - /* setup encryption options */ - kvp = purple_key_value_pair_new(_("Use encryption if available"), - "opportunistic_tls"); - encryption_options = g_list_append(encryption_options, kvp); - - kvp = purple_key_value_pair_new(_("Require encryption"), "require_tls"); - encryption_options = g_list_append(encryption_options, kvp); - - kvp = purple_key_value_pair_new(_("Don't use encryption"), "none"); - encryption_options = g_list_append(encryption_options, kvp); - - option = purple_account_option_list_new(_("Connection security"), - "encryption", encryption_options); - opts = g_list_append(opts, option); - - /* setup the protocol version */ - kvp = purple_key_value_pair_new(_("Default"), "default"); - protocol_version = g_list_append(protocol_version, kvp); - - kvp = purple_key_value_pair_new("GG 10", "gg10"); - protocol_version = g_list_append(protocol_version, kvp); - - kvp = purple_key_value_pair_new("GG 11", "gg11"); - protocol_version = g_list_append(protocol_version, kvp); - - option = purple_account_option_list_new(_("Protocol version"), - "protocol_version", - protocol_version); - opts = g_list_append(opts, option); - - option = purple_account_option_bool_new(_("Show links from strangers"), - "show_links_from_strangers", 1); - opts = g_list_append(opts, option); - - return opts; -} - -static const char * -ggp_normalize(G_GNUC_UNUSED PurpleProtocolClient *client, - G_GNUC_UNUSED PurpleAccount *account, const char *who) -{ - static char normalized[21]; /* maximum unsigned long long int size */ - - uin_t uin = ggp_str_to_uin(who); - if(uin <= 0) { - return NULL; - } - - g_snprintf(normalized, sizeof(normalized), "%u", uin); - - return normalized; -} - -static void -ggp_login(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleAccount *account) { - PurpleConnection *gc = purple_account_get_connection(account); - PurpleContactInfo *contact_info = PURPLE_CONTACT_INFO(account); - struct gg_login_params *glp; - GGPInfo *info; - const char *address; - const gchar *encryption_type, *protocol_version; - GProxyResolver *resolver; - GError *error = NULL; - - purple_connection_set_flags(gc, - PURPLE_CONNECTION_FLAG_HTML | - PURPLE_CONNECTION_FLAG_NO_URLDESC); - - resolver = purple_proxy_get_proxy_resolver(account, &error); - if (resolver == NULL) { - purple_debug_error("gg", "Unable to get account proxy resolver: %s", - error->message); - purple_connection_take_error(gc, error); - return; - } - - glp = g_new0(struct gg_login_params, 1); - glp->struct_size = sizeof(struct gg_login_params); - info = g_new0(GGPInfo, 1); - - purple_connection_set_protocol_data(gc, info); - - info->http = soup_session_new_with_options("proxy-resolver", resolver, - NULL); - - ggp_tcpsocket_setup(gc, glp); - ggp_image_setup(gc); - ggp_avatar_setup(gc); - ggp_roster_setup(gc); - ggp_multilogon_setup(gc); - ggp_status_setup(gc); - ggp_chat_setup(gc); - ggp_message_setup(gc); - ggp_edisc_setup(gc, resolver); - g_object_unref(resolver); - - glp->uin = ggp_str_to_uin(purple_contact_info_get_username(contact_info)); - glp->password = - ggp_convert_to_cp1250(purple_connection_get_password(gc)); - - if (glp->uin == 0) { - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_INVALID_USERNAME, - _("The username specified is invalid.")); - purple_str_wipe(glp->password); - g_free(glp); - return; - } - - glp->image_size = 255; - glp->status_flags = GG_STATUS_FLAG_UNKNOWN; - - if (purple_account_get_bool(account, "show_links_from_strangers", 1)) - glp->status_flags |= GG_STATUS_FLAG_SPAM; - - glp->encoding = GG_ENCODING_UTF8; - glp->protocol_features = (GG_FEATURE_DND_FFC | - GG_FEATURE_TYPING_NOTIFICATION | GG_FEATURE_MULTILOGON | - GG_FEATURE_USER_DATA); - - glp->async = 1; - - encryption_type = purple_account_get_string(account, "encryption", - "opportunistic_tls"); - purple_debug_info("gg", "Requested encryption type: %s\n", - encryption_type); - if (purple_strequal(encryption_type, "opportunistic_tls")) - glp->tls = GG_SSL_ENABLED; - else if (purple_strequal(encryption_type, "require_tls")) { - if (gg_libgadu_check_feature(GG_LIBGADU_FEATURE_SSL)) - glp->tls = GG_SSL_REQUIRED; - else { - purple_connection_error(gc, - PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, - _("SSL support unavailable")); - purple_str_wipe(glp->password); - g_free(glp); - return; - } - } - else /* encryption_type == "none" */ - glp->tls = GG_SSL_DISABLED; - purple_debug_misc("gg", "TLS mode: %d\n", glp->tls); - - protocol_version = purple_account_get_string(account, - "protocol_version", "default"); - purple_debug_info("gg", "Requested protocol version: %s\n", - protocol_version); - if (purple_strequal(protocol_version, "gg10")) - glp->protocol_version = GG_PROTOCOL_VERSION_100; - else if (purple_strequal(protocol_version, "gg11")) - glp->protocol_version = GG_PROTOCOL_VERSION_110; - glp->compatibility = GG_COMPAT_1_12_0; - - ggp_status_set_initial(gc, glp); - - address = purple_account_get_string(account, "gg_server", ""); - if (address && *address) - glp->connect_host = g_strdup(address); - - info->session = gg_login(glp); - g_free(glp->connect_host); - purple_str_wipe(glp->password); - g_free(glp); - - if (info->session == NULL) { - purple_connection_error (gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Connection failed")); - return; - } - - if (info->session->fd > 0) { - info->inpa = purple_input_add(info->session->fd, - PURPLE_INPUT_READ, ggp_async_login_handler, gc); - } -} - -static void -ggp_close(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleConnection *gc) { - PurpleAccount *account; - GGPInfo *info;; - - g_return_if_fail(gc != NULL); - - account = purple_connection_get_account(gc); - info = purple_connection_get_protocol_data(gc); - - purple_notify_close_with_handle(gc); - - if (info) { - if (info->session != NULL) { - ggp_status_set_disconnected(account); - gg_logoff(info->session); - gg_free_session(info->session); - } - - ggp_image_cleanup(gc); - ggp_avatar_cleanup(gc); - ggp_roster_cleanup(gc); - ggp_multilogon_cleanup(gc); - ggp_status_cleanup(gc); - ggp_chat_cleanup(gc); - ggp_message_cleanup(gc); - ggp_edisc_cleanup(gc); - - g_clear_handle_id(&info->inpa, g_source_remove); - g_free(info->imtoken); - - if (info->http) { - soup_session_abort(info->http); - g_object_unref(info->http); - } - - purple_connection_set_protocol_data(gc, NULL); - g_free(info); - } - - purple_debug_info("gg", "Connection closed.\n"); -} - -static unsigned int -ggp_send_typing(G_GNUC_UNUSED PurpleProtocolIM *im, PurpleConnection *gc, - const char *name, PurpleIMTypingState state) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - int dummy_length; /* we don't send real length of typed message */ - - if (state == PURPLE_IM_TYPED) /* not supported */ - return 1; - - if (state == PURPLE_IM_TYPING) - dummy_length = (int)g_random_int(); - else /* PURPLE_IM_NOT_TYPING */ - dummy_length = 0; - - gg_typing_notification( - info->session, - ggp_str_to_uin(name), - dummy_length); - - return 1; /* wait 1 second before another notification */ -} - -static void -ggp_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, - PurpleBuddy *buddy, PurpleGroup *group, const gchar *message) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *contact_info = PURPLE_CONTACT_INFO(account); - GGPInfo *info = purple_connection_get_protocol_data(gc); - const gchar *name = purple_buddy_get_name(buddy); - - gg_add_notify(info->session, ggp_str_to_uin(name)); - - /* gg server won't tell us our status here */ - if(purple_strequal(purple_contact_info_get_username(contact_info), name)) { - ggp_status_fake_to_self(gc); - } - - ggp_roster_add_buddy(protocol_server, gc, buddy, group, message); - ggp_pubdir_request_buddy_alias(gc, buddy); -} - -static void -ggp_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, - PurpleBuddy *buddy, PurpleGroup *group) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - - gg_remove_notify(info->session, ggp_str_to_uin(purple_buddy_get_name(buddy))); - ggp_roster_remove_buddy(protocol_server, gc, buddy, group); -} - -static void -ggp_keepalive(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - - /* purple_debug_info("gg", "Keeping connection alive....\n"); */ - - if (gg_ping(info->session) < 0) { - purple_debug_info("gg", "Not connected to the server " - "or gg_session is not correct\n"); - purple_connection_error (gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Not connected to the server")); - } -} - -static void -ggp_action_multilogon(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *connection = NULL; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("GG multilogin action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - connection = purple_account_get_connection(account); - g_clear_object(&account); - - ggp_multilogon_dialog(connection); -} - -static void -ggp_action_status_broadcasting(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *connection = NULL; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("GG broadcast action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - connection = purple_account_get_connection(account); - g_clear_object(&account); - - ggp_status_broadcasting_dialog(connection); -} - -static void -ggp_action_search(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *connection = NULL; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("GG search action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - connection = purple_account_get_connection(account); - g_clear_object(&account); - - ggp_pubdir_search(connection, NULL); -} - -static void -ggp_action_set_info(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *connection = NULL; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("GG set info action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - connection = purple_account_get_connection(account); - g_clear_object(&account); - - ggp_pubdir_set_info(connection); -} - -static const gchar * -ggp_protocol_actions_get_prefix(G_GNUC_UNUSED PurpleProtocolActions *actions) { - return "prpl-gg"; -} - -static GActionGroup * -ggp_protocol_actions_get_action_group(G_GNUC_UNUSED PurpleProtocolActions *actions, - G_GNUC_UNUSED PurpleConnection *connection) -{ - GSimpleActionGroup *group = NULL; - GActionEntry entries[] = { - { - .name = "multilogon", - .activate = ggp_action_multilogon, - .parameter_type = "s", - }, - { - .name = "broadcasting", - .activate = ggp_action_status_broadcasting, - .parameter_type = "s", - }, - { - .name = "search", - .activate = ggp_action_search, - .parameter_type = "s", - }, - { - .name = "set-info", - .activate = ggp_action_set_info, - .parameter_type = "s", - }, - { - .name = "save-buddylist", - .activate = ggp_action_buddylist_save, - .parameter_type = "s", - }, - { - .name = "load-buddylist", - .activate = ggp_action_buddylist_load, - .parameter_type = "s", - }, - }; - gsize nentries = G_N_ELEMENTS(entries); - - group = g_simple_action_group_new(); - g_action_map_add_action_entries(G_ACTION_MAP(group), entries, nentries, - NULL); - - return G_ACTION_GROUP(group); -} - -static GMenu * -ggp_protocol_actions_get_menu(G_GNUC_UNUSED PurpleProtocolActions *actions, - G_GNUC_UNUSED PurpleConnection *connection) { - GMenu *menu = NULL, *submenu = NULL; - GMenuItem *item = NULL; - - menu = g_menu_new(); - - item = g_menu_item_new(_("Show other sessions"), "prpl-gg.multilogon"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - g_object_unref(item); - - item = g_menu_item_new(_("Show status only for buddies"), - "prpl-gg.broadcasting"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - g_object_unref(item); - - item = g_menu_item_new(_("Find buddies..."), "prpl-gg.search"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - g_object_unref(item); - - item = g_menu_item_new(_("Set User Info"), "prpl-gg.set-info"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - g_object_unref(item); - - /* Buddy list management. */ - submenu = g_menu_new(); - - item = g_menu_item_new(_("Save to file..."), "prpl-gg.save-buddylist"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - g_object_unref(item); - - item = g_menu_item_new(_("Load from file..."), "prpl-gg.load-buddylist"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - g_object_unref(item); - - g_menu_append_submenu(menu, _("Buddy list"), G_MENU_MODEL(submenu)); - g_object_unref(submenu); - - return menu; -} - -static const char * -ggp_list_emblem(G_GNUC_UNUSED PurpleProtocolClient *client, - PurpleBuddy *buddy) -{ - ggp_buddy_data *buddy_data = ggp_buddy_get_data(buddy); - - if (buddy_data->blocked) - return "not-authorized"; - if (buddy_data->not_a_friend) - return "unavailable"; - - return NULL; -} - -static gboolean -ggp_offline_message(G_GNUC_UNUSED PurpleProtocolClient *client, - G_GNUC_UNUSED PurpleBuddy *buddy) -{ - return TRUE; -} - -static GHashTable * -ggp_get_account_text_table(G_GNUC_UNUSED PurpleProtocolClient *client, - G_GNUC_UNUSED PurpleAccount *account) -{ - GHashTable *table; - table = g_hash_table_new(g_str_hash, g_str_equal); - g_hash_table_insert(table, "login_label", (gpointer)_("GG number...")); - return table; -} - -static gssize -ggp_get_max_message_size(G_GNUC_UNUSED PurpleProtocolClient *client, - G_GNUC_UNUSED PurpleConversation *conv) -{ - /* TODO: it may depend on protocol version or other factors */ - return 1200; /* no more than 1232 */ -} - -static void -ggp_protocol_init(G_GNUC_UNUSED GGPProtocol *self) { -} - -static void -ggp_protocol_class_init(GGPProtocolClass *klass) -{ - PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass); - - protocol_class->login = ggp_login; - protocol_class->close = ggp_close; - protocol_class->status_types = ggp_status_types; - - protocol_class->get_account_options = ggp_protocol_get_account_options; - protocol_class->get_buddy_icon_spec = ggp_protocol_get_buddy_icon_spec; -} - -static void -ggp_protocol_class_finalize(G_GNUC_UNUSED GGPProtocolClass *klass) -{ -} - -static void -ggp_protocol_actions_iface_init(PurpleProtocolActionsInterface *iface) -{ - iface->get_prefix = ggp_protocol_actions_get_prefix; - iface->get_action_group = ggp_protocol_actions_get_action_group; - iface->get_menu = ggp_protocol_actions_get_menu; -} - -static void -ggp_protocol_client_iface_init(PurpleProtocolClientInterface *client_iface) -{ - client_iface->list_emblem = ggp_list_emblem; - client_iface->buddy_free = ggp_buddy_free; - client_iface->normalize = ggp_normalize; - client_iface->offline_message = ggp_offline_message; - client_iface->get_account_text_table = ggp_get_account_text_table; - client_iface->get_max_message_size = ggp_get_max_message_size; -} - -static void -ggp_protocol_server_iface_init(PurpleProtocolServerInterface *server_iface) -{ - server_iface->get_info = ggp_pubdir_get_info_protocol; - server_iface->set_status = ggp_status_set_purplestatus; - server_iface->add_buddy = ggp_add_buddy; - server_iface->remove_buddy = ggp_remove_buddy; - server_iface->keepalive = ggp_keepalive; - server_iface->alias_buddy = ggp_roster_alias_buddy; - server_iface->group_buddy = ggp_roster_group_buddy; - server_iface->rename_group = ggp_roster_rename_group; - server_iface->set_buddy_icon = ggp_avatar_own_set; -} - -static void -ggp_protocol_im_iface_init(PurpleProtocolIMInterface *im_iface) -{ - im_iface->send = ggp_message_send_im; - im_iface->send_typing = ggp_send_typing; -} - -static void -ggp_protocol_chat_iface_init(PurpleProtocolChatInterface *chat_iface) -{ - chat_iface->info = ggp_chat_info; - chat_iface->info_defaults = ggp_chat_info_defaults; - chat_iface->join = ggp_chat_join; - chat_iface->get_name = ggp_chat_get_name; - chat_iface->invite = ggp_chat_invite; - chat_iface->leave = ggp_chat_leave; - chat_iface->send = ggp_chat_send; - - chat_iface->reject = NULL; /* TODO */ -} - -static void -ggp_protocol_roomlist_iface_init(PurpleProtocolRoomlistInterface *roomlist_iface) -{ - roomlist_iface->get_list = ggp_chat_roomlist_get_list; -} - -static void -ggp_protocol_xfer_iface_init(PurpleProtocolXferInterface *xfer_iface) -{ - xfer_iface->can_receive = ggp_edisc_xfer_can_receive_file; - xfer_iface->send_file = ggp_edisc_xfer_send_file; - xfer_iface->new_xfer = ggp_edisc_xfer_send_new; -} - -G_DEFINE_DYNAMIC_TYPE_EXTENDED( - GGPProtocol, - ggp_protocol, - PURPLE_TYPE_PROTOCOL, - G_TYPE_FLAG_FINAL, - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ACTIONS, - ggp_protocol_actions_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT, - ggp_protocol_client_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER, - ggp_protocol_server_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM, - ggp_protocol_im_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT, - ggp_protocol_chat_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ROOMLIST, - ggp_protocol_roomlist_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_XFER, - ggp_protocol_xfer_iface_init)) - -static PurpleProtocol * -ggp_protocol_new(void) { - return g_object_new( - GGP_TYPE_PROTOCOL, - "id", "prpl-gg", - "name", "Gadu-Gadu", - "description", _("Gadu-Gadu is a Polish instant messaging network."), - "icon-name", "im-gadu-gadu", - "icon-resource-path", "/im/pidgin/libpurple/gg/icons", - NULL); -} - -static GPluginPluginInfo * -gg_query(G_GNUC_UNUSED GError **error) -{ - GPluginPluginInfo *info = NULL; - gchar *description = NULL; - const gchar * const authors[] = { - "boler@sourceforge.net", - NULL - }; - - description = g_strdup_printf(N_("Polish popular IM\nlibgadu version %s"), - gg_libgadu_version()); - - info = purple_plugin_info_new( - "id", "prpl-gg", - "name", "Gadu-Gadu Protocol", - "version", DISPLAY_VERSION, - "category", N_("Protocol"), - "summary", N_("Gadu-Gadu Protocol Plugin"), - "description", description, - "authors", authors, - "website", PURPLE_WEBSITE, - "abi-version", PURPLE_ABI_VERSION, - "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL | - PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD, - NULL - ); - - g_free(description); - - return info; -} - -static gboolean -gg_load(GPluginPlugin *plugin, GError **error) -{ - PurpleProtocolManager *manager = purple_protocol_manager_get_default(); - - ggp_protocol_register_type(G_TYPE_MODULE(plugin)); - - ggp_xfer_register(G_TYPE_MODULE(plugin)); - - my_protocol = ggp_protocol_new(); - if(!purple_protocol_manager_register(manager, my_protocol, error)) { - g_clear_object(&my_protocol); - - return FALSE; - } - - purple_prefs_add_none("/plugins/prpl/gg"); - - purple_debug_info("gg", "Loading Gadu-Gadu protocol plugin with " - "libgadu %s...\n", gg_libgadu_version()); - - ggp_libgaduw_setup(); - ggp_resolver_purple_setup(); - ggp_servconn_setup(NULL); - ggp_html_setup(); - ggp_message_setup_global(); - - purple_signal_connect(purple_get_core(), "uri-handler", plugin, - G_CALLBACK(gg_uri_handler), NULL); - - return TRUE; -} - -static gboolean -gg_unload(GPluginPlugin *plugin, G_GNUC_UNUSED gboolean shutdown, - GError **error) -{ - PurpleProtocolManager *manager = purple_protocol_manager_get_default(); - - if(!purple_protocol_manager_unregister(manager, my_protocol, error)) { - return FALSE; - } - - purple_signal_disconnect(purple_get_core(), "uri-handler", plugin, - G_CALLBACK(gg_uri_handler)); - - ggp_servconn_cleanup(); - ggp_html_cleanup(); - ggp_message_cleanup_global(); - ggp_libgaduw_cleanup(); - - g_clear_object(&my_protocol); - - return TRUE; -} - -GPLUGIN_NATIVE_PLUGIN_DECLARE(gg) - -/* vim: set ts=8 sts=0 sw=8 noet: */
--- a/libpurple/protocols/gg/gg.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * @file gg.h - * - * purple - * - * Copyright (C) 2005 Bartosz Oler <bartosz@bzimage.us> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_GG_H -#define PURPLE_GG_GG_H - -#define GGP_UIN_LEN_MAX 10 - -#include <gmodule.h> -#include <libgadu.h> -#include <libsoup/soup.h> - -#include "search.h" - -#include <purple.h> - -#include "image-prpl.h" -#include "avatar.h" -#include "roster.h" -#include "multilogon.h" -#include "status.h" -#include "chat.h" -#include "message-prpl.h" -#include "edisc.h" - -#define GGP_TYPE_PROTOCOL (ggp_protocol_get_type()) - -G_MODULE_EXPORT -G_DECLARE_FINAL_TYPE(GGPProtocol, ggp_protocol, GGP, PROTOCOL, PurpleProtocol) - -typedef struct { - struct gg_session *session; - SoupSession *http; - guint inpa; - - gchar *imtoken; - gboolean imtoken_warned; - - ggp_image_session_data *image_data; - ggp_avatar_session_data *avatar_data; - ggp_roster_session_data roster_data; - ggp_multilogon_session_data *multilogon_data; - ggp_status_session_data *status_data; - ggp_chat_session_data *chat_data; - ggp_message_session_data *message_data; - ggp_edisc_session_data *edisc_data; -} GGPInfo; - -typedef struct -{ - gboolean blocked; - gboolean not_a_friend; -} ggp_buddy_data; - -ggp_buddy_data * ggp_buddy_get_data(PurpleBuddy *buddy); - -const gchar * ggp_get_imtoken(PurpleConnection *gc); - -uin_t ggp_own_uin(PurpleConnection *gc); - -void ggp_async_login_handler(gpointer _gc, gint fd, PurpleInputCondition cond); - -#endif /* PURPLE_GG_GG_H */
--- a/libpurple/protocols/gg/html.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "html.h" - -typedef struct -{ - GRegex *re_html_attr; - GRegex *re_css_attr; - GRegex *re_color_hex; - GRegex *re_color_rgb; -} ggp_html_global_data; - -static ggp_html_global_data global_data; - -void ggp_html_setup(void) -{ - global_data.re_html_attr = g_regex_new( - "([a-z-]+)=\"([^\"]+)\"", - G_REGEX_OPTIMIZE, 0, NULL); - global_data.re_css_attr = g_regex_new( - "([a-z-]+): *([^;]+)", - G_REGEX_OPTIMIZE, 0, NULL); - global_data.re_color_hex = g_regex_new( - "^#([0-9a-fA-F]+){6}$", - G_REGEX_OPTIMIZE, 0, NULL); - global_data.re_color_rgb = g_regex_new( - "^rgb\\(([0-9]+), *([0-9]+), *([0-9]+)\\)$", - G_REGEX_OPTIMIZE, 0, NULL); -} - -void ggp_html_cleanup(void) -{ - g_regex_unref(global_data.re_html_attr); - g_regex_unref(global_data.re_css_attr); - g_regex_unref(global_data.re_color_hex); - g_regex_unref(global_data.re_color_rgb); -} - -GHashTable * ggp_html_tag_attribs(const gchar *attribs_str) -{ - GMatchInfo *match; - GHashTable *attribs = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - - if (attribs_str == NULL) - return attribs; - - g_regex_match(global_data.re_html_attr, attribs_str, 0, &match); - while (g_match_info_matches(match)) { - g_hash_table_insert(attribs, - g_match_info_fetch(match, 1), - g_match_info_fetch(match, 2)); - - g_match_info_next(match, NULL); - } - g_match_info_free(match); - - return attribs; -} - -GHashTable * ggp_html_css_attribs(const gchar *attribs_str) -{ - GMatchInfo *match; - GHashTable *attribs = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - - if (attribs_str == NULL) - return attribs; - - g_regex_match(global_data.re_css_attr, attribs_str, 0, &match); - while (g_match_info_matches(match)) { - g_hash_table_insert(attribs, - g_match_info_fetch(match, 1), - g_match_info_fetch(match, 2)); - - g_match_info_next(match, NULL); - } - g_match_info_free(match); - - return attribs; -} - -int ggp_html_decode_color(const gchar *str) -{ - GMatchInfo *match; - int color = -1; - - g_regex_match(global_data.re_color_hex, str, 0, &match); - if (g_match_info_matches(match)) { - if (sscanf(str + 1, "%x", &color) != 1) - color = -1; - } - g_match_info_free(match); - if (color >= 0) - return color; - - g_regex_match(global_data.re_color_rgb, str, 0, &match); - if (g_match_info_matches(match)) { - int r = -1, g = -1, b = -1; - gchar *c_str; - - c_str = g_match_info_fetch(match, 1); - if (c_str) - r = atoi(c_str); - g_free(c_str); - - c_str = g_match_info_fetch(match, 2); - if (c_str) - g = atoi(c_str); - g_free(c_str); - - c_str = g_match_info_fetch(match, 3); - if (c_str) - b = atoi(c_str); - g_free(c_str); - - if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) - color = (r << 16) | (g << 8) | b; - } - g_match_info_free(match); - if (color >= 0) - return color; - - return -1; -} - -ggp_html_tag ggp_html_parse_tag(const gchar *tag_str) -{ - if (0 == g_ascii_strcasecmp(tag_str, "eom")) - return GGP_HTML_TAG_EOM; - if (0 == g_ascii_strcasecmp(tag_str, "span")) - return GGP_HTML_TAG_SPAN; - if (0 == g_ascii_strcasecmp(tag_str, "div")) - return GGP_HTML_TAG_DIV; - if (0 == g_ascii_strcasecmp(tag_str, "br")) - return GGP_HTML_TAG_BR; - if (0 == g_ascii_strcasecmp(tag_str, "a")) - return GGP_HTML_TAG_A; - if (0 == g_ascii_strcasecmp(tag_str, "b")) - return GGP_HTML_TAG_B; - if (0 == g_ascii_strcasecmp(tag_str, "i")) - return GGP_HTML_TAG_I; - if (0 == g_ascii_strcasecmp(tag_str, "u")) - return GGP_HTML_TAG_U; - if (0 == g_ascii_strcasecmp(tag_str, "s")) - return GGP_HTML_TAG_S; - if (0 == g_ascii_strcasecmp(tag_str, "img")) - return GGP_HTML_TAG_IMG; - if (0 == g_ascii_strcasecmp(tag_str, "font")) - return GGP_HTML_TAG_FONT; - if (0 == g_ascii_strcasecmp(tag_str, "hr")) - return GGP_HTML_TAG_HR; - return GGP_HTML_TAG_UNKNOWN; -}
--- a/libpurple/protocols/gg/html.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_HTML_H -#define PURPLE_GG_HTML_H - -#include <purple.h> - -typedef enum -{ - GGP_HTML_TAG_UNKNOWN, - GGP_HTML_TAG_EOM, - GGP_HTML_TAG_A, - GGP_HTML_TAG_B, - GGP_HTML_TAG_I, - GGP_HTML_TAG_U, - GGP_HTML_TAG_S, - GGP_HTML_TAG_IMG, - GGP_HTML_TAG_FONT, - GGP_HTML_TAG_SPAN, - GGP_HTML_TAG_DIV, - GGP_HTML_TAG_BR, - GGP_HTML_TAG_HR, -} ggp_html_tag; - -void ggp_html_setup(void); -void ggp_html_cleanup(void); - -GHashTable * ggp_html_tag_attribs(const gchar *attribs_str); -GHashTable * ggp_html_css_attribs(const gchar *attribs_str); -int ggp_html_decode_color(const gchar *str); -ggp_html_tag ggp_html_parse_tag(const gchar *tag_str); - -#endif /* PURPLE_GG_HTML_H */
--- a/libpurple/protocols/gg/image-prpl.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,262 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include "image-prpl.h" - -#include "gg.h" -#include "utils.h" - -#include <purple.h> - -struct _ggp_image_session_data -{ - GHashTable *recv_images; - GHashTable *sent_images; -}; - -typedef struct -{ - PurpleImage *image; - gchar *conv_name; /* TODO: callback */ -} ggp_image_sent; - -static void ggp_image_sent_free(gpointer _sent_image) -{ - ggp_image_sent *sent_image = _sent_image; - g_object_unref(sent_image->image); - g_free(sent_image->conv_name); - g_free(sent_image); -} - -static uint64_t ggp_image_params_to_id(uint32_t crc32, uint32_t size) -{ - return ((uint64_t)crc32 << 32) | size; -} - -static inline ggp_image_session_data * -ggp_image_get_sdata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return accdata->image_data; -} - -void ggp_image_setup(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_image_session_data *sdata = g_new0(ggp_image_session_data, 1); - - accdata->image_data = sdata; - - sdata->recv_images = g_hash_table_new_full( - g_int64_hash, g_int64_equal, g_free, g_object_unref); - sdata->sent_images = g_hash_table_new_full( - g_int64_hash, g_int64_equal, g_free, - ggp_image_sent_free); -} - -void ggp_image_cleanup(PurpleConnection *gc) -{ - ggp_image_session_data *sdata = ggp_image_get_sdata(gc); - - g_hash_table_destroy(sdata->recv_images); - g_hash_table_destroy(sdata->sent_images); - g_free(sdata); -} - -ggp_image_prepare_result -ggp_image_prepare(PurpleConversation *conv, PurpleImage *image, uint64_t *id) -{ - PurpleConnection *gc = purple_conversation_get_connection(conv); - ggp_image_session_data *sdata = ggp_image_get_sdata(gc); - size_t image_size; - gconstpointer image_data; - uint32_t image_crc; - ggp_image_sent *sent_image; - - g_return_val_if_fail(image, GGP_IMAGE_PREPARE_FAILURE); - - image_size = purple_image_get_data_size(image); - - if (image_size > GGP_IMAGE_SIZE_MAX) { - purple_debug_warning("gg", "ggp_image_prepare: image " - "is too big (max bytes: %d)\n", GGP_IMAGE_SIZE_MAX); - return GGP_IMAGE_PREPARE_TOO_BIG; - } - - g_object_ref(image); - image_data = purple_image_get_data(image); - image_crc = gg_crc32(0, image_data, image_size); - - purple_debug_info("gg", "ggp_image_prepare: image prepared " - "[crc=%u, size=%" G_GSIZE_FORMAT "]", - image_crc, image_size); - - *id = ggp_image_params_to_id(image_crc, image_size); - - g_object_ref(image); - sent_image = g_new(ggp_image_sent, 1); - sent_image->image = image; - sent_image->conv_name = g_strdup(purple_conversation_get_name(conv)); - g_hash_table_insert(sdata->sent_images, ggp_uint64dup(*id), - sent_image); - - return GGP_IMAGE_PREPARE_OK; -} - -void ggp_image_recv(PurpleConnection *gc, - const struct gg_event_image_reply *image_reply) -{ - ggp_image_session_data *sdata = ggp_image_get_sdata(gc); - PurpleImage *img; - uint64_t id; - - id = ggp_image_params_to_id(image_reply->crc32, image_reply->size); - img = g_hash_table_lookup(sdata->recv_images, &id); - if (!img) { - purple_debug_warning("gg", "ggp_image_recv: " - "image " GGP_IMAGE_ID_FORMAT " wasn't requested\n", - id); - return; - } - - purple_debug_info("gg", "ggp_image_recv: got image " - "[crc=%u, size=%u, filename=%s, id=" GGP_IMAGE_ID_FORMAT "]", - image_reply->crc32, image_reply->size, - image_reply->filename, id); - - img = purple_image_new_from_data( - (const guint8 *)image_reply->image, - image_reply->size - ); - purple_image_set_friendly_filename(img, image_reply->filename); - - g_hash_table_insert(sdata->recv_images, &id, img); -} - -void ggp_image_send(PurpleConnection *gc, - const struct gg_event_image_request *image_request) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_image_session_data *sdata = ggp_image_get_sdata(gc); - ggp_image_sent *sent_image; - PurpleConversation *conv; - PurpleConversationManager *manager; - uint64_t id; - uin_t sender; - gchar *gg_filename; - - purple_debug_info("gg", "ggp_image_send: got image request " - "[uin=%u, crc=%u, size=%u]\n", - image_request->sender, - image_request->crc32, - image_request->size); - - id = ggp_image_params_to_id(image_request->crc32, image_request->size); - - sent_image = g_hash_table_lookup(sdata->sent_images, &id); - - sender = ggp_str_to_uin(purple_contact_info_get_username(info)); - if (sent_image == NULL && image_request->sender == sender) { - purple_debug_misc("gg", "ggp_image_send: requested image " - "not found, but this may be another session request\n"); - return; - } - if (sent_image == NULL) { - purple_debug_warning("gg", "ggp_image_send: requested image " - "not found\n"); - return; - } - - purple_debug_misc("gg", "ggp_image_send: requested image found " - "[id=" GGP_IMAGE_ID_FORMAT ", conv=%s]\n", - id, sent_image->conv_name); - - g_return_if_fail(sent_image->image); - - /* TODO: check allowed recipients */ - gg_filename = g_strdup_printf(GGP_IMAGE_ID_FORMAT, id); - gg_image_reply(accdata->session, image_request->sender, - gg_filename, - purple_image_get_data(sent_image->image), - purple_image_get_data_size(sent_image->image)); - g_free(gg_filename); - - manager = purple_conversation_manager_get_default(); - conv = purple_conversation_manager_find(manager, - purple_connection_get_account(gc), - sent_image->conv_name); - if (conv != NULL) { - gchar *msg = g_strdup_printf(_("Image delivered to %u."), - image_request->sender); - purple_conversation_write_system_message(conv, msg, - PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_NOTIFY); - g_free(msg); - } -} - -PurpleImage * -ggp_image_request(PurpleConnection *gc, uin_t uin, uint64_t id) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_image_session_data *sdata = ggp_image_get_sdata(gc); - PurpleImage *img; - uint32_t crc = id >> 32; - uint32_t size = id; - - if (size > GGP_IMAGE_SIZE_MAX && crc <= GGP_IMAGE_SIZE_MAX) { - uint32_t tmp; - purple_debug_warning("gg", "ggp_image_request: " - "crc and size are swapped!\n"); - tmp = crc; - crc = size; - size = tmp; - id = ggp_image_params_to_id(crc, size); - } - - img = g_hash_table_lookup(sdata->recv_images, &id); - if (img) { - purple_debug_info("gg", "ggp_image_request: " - "image " GGP_IMAGE_ID_FORMAT " got from cache", id); - return img; - } - - - g_hash_table_insert(sdata->recv_images, ggp_uint64dup(id), NULL); - - purple_debug_info("gg", "ggp_image_request: requesting image " - GGP_IMAGE_ID_FORMAT, id); - if (gg_image_request(accdata->session, uin, size, crc) != 0) - purple_debug_error("gg", "ggp_image_request: failed"); - - return img; -}
--- a/libpurple/protocols/gg/image-prpl.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_IMAGE_PRPL_H -#define PURPLE_GG_IMAGE_PRPL_H - -#include <purple.h> -#include <libgadu.h> - -#define GGP_IMAGE_SIZE_MAX 255000 -#define GGP_IMAGE_ID_FORMAT "%016" G_GINT64_MODIFIER "x" - -typedef struct _ggp_image_session_data ggp_image_session_data; - -typedef enum -{ - GGP_IMAGE_PREPARE_OK = 0, - GGP_IMAGE_PREPARE_FAILURE, - GGP_IMAGE_PREPARE_TOO_BIG -} ggp_image_prepare_result; - -void -ggp_image_setup(PurpleConnection *gc); - -void -ggp_image_cleanup(PurpleConnection *gc); - -ggp_image_prepare_result -ggp_image_prepare(PurpleConversation *conv, PurpleImage *image, uint64_t *id); - -void -ggp_image_recv(PurpleConnection *gc, - const struct gg_event_image_reply *image_reply); - -void -ggp_image_send(PurpleConnection *gc, - const struct gg_event_image_request *image_request); - -PurpleImage * -ggp_image_request(PurpleConnection *gc, uin_t uin, uint64_t id); - -#endif /* PURPLE_GG_IMAGE_PRPL_H */
--- a/libpurple/protocols/gg/keymapper.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "keymapper.h" - -/* The problem: we want to convert 64-bit unique integers into unique gpointer - * keys (that may be 32-bit or 64-bit, or whatever else). We also want to - * convert it back. - * - * The idea: let's store every value in our internal memory. Then, its address - * can be also an unique key. We also need a map, to quickly figure out the - * address for any previously stored value. - * - * The naming problem: values becomes the keys and vice-versa. - */ - -/* TODO - * For a 64-bit gpointer, keymapper could just do nothing and return the value - * as a key. But it have to be figured out at a compile time. - */ - -struct _ggp_keymapper -{ - /* Table keys: pointers to 64-bit mapped *values*. - * Table values: keys (gpointers) corresponding to mapped values. - * - * Ultimately, both keys and values are the same pointers. - * - * Yes, it's hard to comment it well enough. - */ - GHashTable *val_to_key; -}; - -ggp_keymapper * -ggp_keymapper_new(void) -{ - ggp_keymapper *km; - - km = g_new0(ggp_keymapper, 1); - km->val_to_key = g_hash_table_new_full(g_int64_hash, g_int64_equal, - g_free, NULL); - - return km; -} - -void -ggp_keymapper_free(ggp_keymapper *km) -{ - if (km == NULL) - return; - - g_hash_table_destroy(km->val_to_key); - g_free(km); -} - -gpointer -ggp_keymapper_to_key(ggp_keymapper *km, guint64 val) -{ - guint64 *key; - - g_return_val_if_fail(km != NULL, NULL); - - key = g_hash_table_lookup(km->val_to_key, &val); - if (key) - return key; - - key = g_new(guint64, 1); - *key = val; - - g_hash_table_insert(km->val_to_key, key, key); - - return key; -} - -guint64 -ggp_keymapper_from_key(ggp_keymapper *km, gpointer key) -{ - g_return_val_if_fail(km != NULL, 0); - g_return_val_if_fail(key != NULL, 0); - - return *((guint64*)key); -}
--- a/libpurple/protocols/gg/keymapper.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_KEYMAPPER_H -#define PURPLE_GG_KEYMAPPER_H - -typedef struct _ggp_keymapper ggp_keymapper; - -#include <purple.h> - -ggp_keymapper * -ggp_keymapper_new(void); - -void -ggp_keymapper_free(ggp_keymapper *km); - -gpointer -ggp_keymapper_to_key(ggp_keymapper *km, guint64 val); - -/* The key have to be valid. */ -guint64 -ggp_keymapper_from_key(ggp_keymapper *km, gpointer key); - -#endif /* PURPLE_GG_KEYMAPPER_H */
--- a/libpurple/protocols/gg/libgadu-events.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "libgadu-events.h" - -#include "avatar.h" -#include "edisc.h" - -void ggp_events_user_data(PurpleConnection *gc, struct gg_event_user_data *data) -{ - guint user_idx; - gboolean is_update; - - purple_debug_info("gg", "GG_EVENT_USER_DATA [type=%d, user_count=%" - G_GSIZE_FORMAT "]\n", data->type, data->user_count); - - /* - type = - 1, 3: user information sent after connecting (divided by - 20 contacts; 3 - last one; 1 - rest of them) - 0: data update - */ - is_update = (data->type == 0); - - for (user_idx = 0; user_idx < data->user_count; user_idx++) { - struct gg_event_user_data_user *data_user = - &data->users[user_idx]; - uin_t uin = data_user->uin; - guint attr_idx; - gboolean got_avatar = FALSE; - for (attr_idx = 0; attr_idx < data_user->attr_count; attr_idx++) { - struct gg_event_user_data_attr *data_attr = - &data_user->attrs[attr_idx]; - if (strcmp(data_attr->key, "avatar") == 0) { - time_t timestamp; - if (data_attr->type == 0) { - ggp_avatar_buddy_remove(gc, uin); - continue; - } - - timestamp = atoi(data_attr->value); - if (timestamp <= 0) - continue; - got_avatar = TRUE; - ggp_avatar_buddy_update(gc, uin, timestamp); - } - } - - if (!is_update && !got_avatar) - ggp_avatar_buddy_remove(gc, uin); - } -} - -static void ggp_events_new_version(const gchar *data) -{ - /* data = {"severity":"download"} */ - purple_debug_info("gg", "Gadu-Gadu server reports new client version." - " %s", data); -} - -void ggp_events_json(PurpleConnection *gc, struct gg_event_json_event *ev) -{ - static const gchar *ignored_events[] = { - "edisc/scope_files_changed", - "notifications/state", - "invitations/list", - "notifications/list", /* gifts */ - NULL - }; - const gchar **it; - - if (g_strcmp0("edisc/send_ticket_changed", ev->type) == 0) { - ggp_edisc_xfer_ticket_changed(gc, ev->data); - return; - } - - if (g_strcmp0("updates/new-version", ev->type) == 0) { - ggp_events_new_version(ev->data); - return; - } - - for (it = ignored_events; *it != NULL; it++) { - if (g_strcmp0(*it, ev->type) == 0) - return; - } - - if (purple_debug_is_unsafe() && purple_debug_is_verbose()) - purple_debug_warning("gg", "ggp_events_json: " - "unhandled event \"%s\": %s\n", - ev->type, ev->data); - else - purple_debug_warning("gg", "ggp_events_json: " - "unhandled event \"%s\"\n", ev->type); -}
--- a/libpurple/protocols/gg/libgadu-events.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_LIBGADU_EVENTS_H -#define PURPLE_GG_LIBGADU_EVENTS_H - -#include <purple.h> -#include <libgadu.h> - -#include "gg.h" - -void ggp_events_user_data(PurpleConnection *gc, - struct gg_event_user_data *data); - -void ggp_events_json(PurpleConnection *gc, struct gg_event_json_event *ev); - -#endif /* PURPLE_GG_LIBGADU_EVENTS_H */
--- a/libpurple/protocols/gg/libgaduw.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "libgaduw.h" - -#include "purplew.h" -#include "gg.h" - -#include <ctype.h> - -static void ggp_libgaduw_debug_handler(int level, const char * format, - va_list args); - -/******************************************************************************* - * Setup/cleanup. - ******************************************************************************/ - -void ggp_libgaduw_setup(void) -{ - gg_debug_handler = ggp_libgaduw_debug_handler; -} - -void ggp_libgaduw_cleanup(void) -{ - gg_debug_handler = NULL; -} - -/******************************************************************************* - * General. - ******************************************************************************/ - -const gchar * ggp_libgaduw_version(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - const gchar *ver = accdata->session->client_version; - - if (ver != NULL && isdigit(ver[0])) - return ver; - return GG_DEFAULT_CLIENT_VERSION; -} - -static void ggp_libgaduw_debug_handler(int level, const char * format, - va_list args) -{ - PurpleDebugLevel purple_level; - char msgbuff[1000]; - int ret; - - if ((level & GG_DEBUG_NET) || (level & GG_DEBUG_FUNCTION) || - (level & GG_DEBUG_VERBOSE)) - { - if (!purple_debug_is_verbose()) - return; - } - - if ((level & GG_DEBUG_DUMP) || /* GG session protocol packets */ - (level & GG_DEBUG_TRAFFIC)) /* HTTP traffic */ - { - if (!purple_debug_is_verbose() || !purple_debug_is_unsafe()) - return; - } - - /* Don't use glib's printf family, since it might not support - * system-specific formatting modifiers (like %Iu for size on win32). */ - ret = vsnprintf(msgbuff, sizeof(msgbuff) / sizeof(char), format, args); - - if (ret <= 0) { - purple_debug_error("gg", - "failed to printf the following message: %s", - format ? format : "(null)"); - - return; - } - - if (level & GG_DEBUG_ERROR) - purple_level = PURPLE_DEBUG_ERROR; - else if (level & GG_DEBUG_WARNING) - purple_level = PURPLE_DEBUG_WARNING; - else - purple_level = PURPLE_DEBUG_MISC; - - purple_debug(purple_level, "gg", "%s", msgbuff); -} - -/******************************************************************************* - * HTTP requests. - ******************************************************************************/ - -static void ggp_libgaduw_http_processing_cancel(PurpleConnection *gc, - void *_req); - -static void ggp_libgaduw_http_handler(gpointer _req, gint fd, - PurpleInputCondition cond); - -static void ggp_libgaduw_http_finish(ggp_libgaduw_http_req *req, - gboolean success); - -/******************************************************************************/ - -ggp_libgaduw_http_req * ggp_libgaduw_http_watch(PurpleConnection *gc, - struct gg_http *h, ggp_libgaduw_http_cb cb, - gpointer user_data, gboolean show_processing) -{ - ggp_libgaduw_http_req *req; - purple_debug_misc("gg", "ggp_libgaduw_http_watch(h=%p, " - "show_processing=%d)\n", h, show_processing); - - req = g_new(ggp_libgaduw_http_req, 1); - req->user_data = user_data; - req->cb = cb; - req->cancelled = FALSE; - req->h = h; - req->processing = NULL; - if (show_processing) - req->processing = ggp_purplew_request_processing(gc, NULL, - req, ggp_libgaduw_http_processing_cancel); - req->inpa = ggp_purplew_http_input_add(h, ggp_libgaduw_http_handler, - req); - - return req; -} - -static void -ggp_libgaduw_http_processing_cancel(G_GNUC_UNUSED PurpleConnection *gc, - void *_req) -{ - ggp_libgaduw_http_req *req = _req; - req->processing = NULL; - ggp_libgaduw_http_cancel(req); -} - -static void -ggp_libgaduw_http_handler(gpointer _req, G_GNUC_UNUSED gint fd, - G_GNUC_UNUSED PurpleInputCondition cond) -{ - ggp_libgaduw_http_req *req = _req; - - if (req->h->callback(req->h) == -1 || req->h->state == GG_STATE_ERROR) { - purple_debug_error("gg", "ggp_libgaduw_http_handler: failed to " - "make http request: %d\n", req->h->error); - ggp_libgaduw_http_finish(req, FALSE); - return; - } - - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_libgaduw_http_handler: got fd " - "update [check=%d, state=%d]\n", req->h->check, - req->h->state); - } - - if (req->h->state != GG_STATE_DONE) { - g_source_remove(req->inpa); - req->inpa = ggp_purplew_http_input_add(req->h, - ggp_libgaduw_http_handler, req); - return; - } - - if (!req->h->data || !req->h->body) { - purple_debug_error("gg", "ggp_libgaduw_http_handler: got empty " - "http response: %d\n", req->h->error); - ggp_libgaduw_http_finish(req, FALSE); - return; - } - - ggp_libgaduw_http_finish(req, TRUE); -} - -void ggp_libgaduw_http_cancel(ggp_libgaduw_http_req *req) -{ - purple_debug_misc("gg", "ggp_libgaduw_http_cancel\n"); - req->cancelled = TRUE; - gg_http_stop(req->h); - ggp_libgaduw_http_finish(req, FALSE); -} - -static void ggp_libgaduw_http_finish(ggp_libgaduw_http_req *req, - gboolean success) -{ - purple_debug_misc("gg", "ggp_libgaduw_http_finish(h=%p, processing=%p):" - " success=%d\n", req->h, req->processing, success); - if (req->processing) { - ggp_purplew_request_processing_done(req->processing); - req->processing = NULL; - } - g_source_remove(req->inpa); - req->cb(req->h, success, req->cancelled, req->user_data); - req->h->destroy(req->h); - g_free(req); -}
--- a/libpurple/protocols/gg/libgaduw.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_LIBGADUW_H -#define PURPLE_GG_LIBGADUW_H - -#include <purple.h> -#include <libgadu.h> - -#include "purplew.h" - -typedef void (*ggp_libgaduw_http_cb)(struct gg_http *h, gboolean success, - gboolean cancelled, gpointer user_data); - -typedef struct -{ - gpointer user_data; - ggp_libgaduw_http_cb cb; - - gboolean cancelled; - struct gg_http *h; - ggp_purplew_request_processing_handle *processing; - guint inpa; -} ggp_libgaduw_http_req; - -void ggp_libgaduw_setup(void); -void ggp_libgaduw_cleanup(void); - -const gchar * ggp_libgaduw_version(PurpleConnection *gc); - -ggp_libgaduw_http_req * ggp_libgaduw_http_watch(PurpleConnection *gc, - struct gg_http *h, ggp_libgaduw_http_cb cb, gpointer user_data, - gboolean show_processing); -void ggp_libgaduw_http_cancel(ggp_libgaduw_http_req *req); - -#endif /* PURPLE_GG_LIBGADUW_H */
--- a/libpurple/protocols/gg/meson.build Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -GG_SOURCES = [ - 'avatar.c', - 'avatar.h', - 'blist.c', - 'blist.h', - 'chat.c', - 'chat.h', - 'edisc.c', - 'edisc.h', - 'gg.c', - 'gg.h', - 'html.c', - 'html.h', - 'image-prpl.c', - 'image-prpl.h', - 'keymapper.c', - 'keymapper.h', - 'libgadu-events.c', - 'libgadu-events.h', - 'libgaduw.c', - 'libgaduw.h', - 'message-prpl.c', - 'message-prpl.h', - 'multilogon.c', - 'multilogon.h', - 'pubdir-prpl.c', - 'pubdir-prpl.h', - 'purplew.c', - 'purplew.h', - 'resolver-purple.c', - 'resolver-purple.h', - 'roster.c', - 'roster.h', - 'servconn.c', - 'servconn.h', - 'status.c', - 'status.h', - 'tcpsocket.c', - 'tcpsocket.h', - 'utils.c', - 'utils.h', - 'validator.c', - 'validator.h', - 'xml.c', - 'xml.h', - 'oauth/oauth.c', - 'oauth/oauth.h', - 'oauth/oauth-purple.c', - 'oauth/oauth-purple.h' -] - -if DYNAMIC_GG - gg_resources = gnome.compile_resources('ggresource', - 'resources/gg.gresource.xml', - source_dir : 'resources', - c_name : 'gg') - GG_SOURCES += gg_resources - - shared_library('gg', GG_SOURCES, - c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-GaduGadu"'], - gnu_symbol_visibility : 'hidden', - dependencies : [libgadu, json, libpurple_dep, libsoup, glib], - install : true, install_dir : PURPLE_PLUGINDIR) - - devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) -endif
--- a/libpurple/protocols/gg/message-prpl.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,699 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include <errno.h> - -#include "message-prpl.h" - -#include "gg.h" -#include "chat.h" -#include "utils.h" -#include "html.h" - -#define GGP_GG10_DEFAULT_FORMAT "<span style=\"color:#000000; " \ - "font-family:'MS Shell Dlg 2'; font-size:9pt; \">" -#define GGP_GG10_DEFAULT_FORMAT_REPLACEMENT "<span>" -#define GGP_GG11_FORCE_COMPAT FALSE - -typedef struct -{ - enum - { - GGP_MESSAGE_GOT_TYPE_IM, - GGP_MESSAGE_GOT_TYPE_CHAT, - GGP_MESSAGE_GOT_TYPE_MULTILOGON - } type; - - uin_t user; - gchar *text; - time_t time; - uint64_t chat_id; - - PurpleConnection *gc; -} ggp_message_got_data; - -typedef struct -{ - GRegex *re_html_tag; - GRegex *re_gg_img; -} ggp_message_global_data; - -static ggp_message_global_data global_data; - -struct _ggp_message_session_data -{ -}; - -typedef struct -{ - int size; - gchar *face; - int color, bgcolor; - gboolean b, i, u, s; -} ggp_font; - -static ggp_font * ggp_font_new(void); -static ggp_font * ggp_font_clone(ggp_font *font); -static void ggp_font_free(gpointer font); - -static PurpleConversation * ggp_message_get_conv(PurpleConnection *gc, - uin_t uin); -static void ggp_message_got_data_free(ggp_message_got_data *msg); -static void ggp_message_got_display(PurpleConnection *gc, - ggp_message_got_data *msg); -static void ggp_message_format_from_gg(ggp_message_got_data *msg, - const gchar *text); - -/**************/ - -void ggp_message_setup_global(void) -{ - global_data.re_html_tag = g_regex_new( - "<(/)?([a-zA-Z]+)( [^>]+)?>", - G_REGEX_OPTIMIZE, 0, NULL); - global_data.re_gg_img = g_regex_new( - "<img name=\"([0-9a-fA-F]+)\"/?>", - G_REGEX_OPTIMIZE, 0, NULL); -} - -void ggp_message_cleanup_global(void) -{ - g_regex_unref(global_data.re_html_tag); - g_regex_unref(global_data.re_gg_img); -} - -static inline ggp_message_session_data * -ggp_message_get_sdata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return accdata->message_data; -} - -void ggp_message_setup(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_message_session_data *sdata = g_new0(ggp_message_session_data, 1); - - accdata->message_data = sdata; -} - -void ggp_message_cleanup(PurpleConnection *gc) -{ - ggp_message_session_data *sdata = ggp_message_get_sdata(gc); - - g_free(sdata); -} - -static ggp_font * ggp_font_new(void) -{ - ggp_font *font; - - font = g_new0(ggp_font, 1); - font->color = -1; - font->bgcolor = -1; - - return font; -} - -static ggp_font * ggp_font_clone(ggp_font * font) -{ - ggp_font *clone = g_new0(ggp_font, 1); - - *clone = *font; - clone->face = g_strdup(font->face); - - return clone; -} - -static void ggp_font_free(gpointer _font) -{ - ggp_font *font = _font; - - g_free(font->face); - g_free(font); -} - -/**/ - -static PurpleConversation * ggp_message_get_conv(PurpleConnection *gc, - uin_t uin) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleConversation *im; - PurpleConversationManager *manager; - const gchar *who = ggp_uin_to_str(uin); - - manager = purple_conversation_manager_get_default(); - im = purple_conversation_manager_find_im(manager, account, who); - if (im) { - return im; - } - im = purple_im_conversation_new(account, who); - return im; -} - -static void ggp_message_got_data_free(ggp_message_got_data *msg) -{ - g_free(msg->text); - g_free(msg); -} - -void ggp_message_got(PurpleConnection *gc, const struct gg_event_msg *ev) -{ - ggp_message_got_data *msg = g_new0(ggp_message_got_data, 1); - - msg->gc = gc; - msg->time = ev->time; - msg->user = ev->sender; - - if (ev->chat_id != 0) { - msg->type = GGP_MESSAGE_GOT_TYPE_CHAT; - msg->chat_id = ev->chat_id; - } else { - msg->type = GGP_MESSAGE_GOT_TYPE_IM; - } - - ggp_message_format_from_gg(msg, ev->xhtml_message); - - ggp_message_got_display(gc, msg); - ggp_message_got_data_free(msg); -} - -void ggp_message_got_multilogon(PurpleConnection *gc, - const struct gg_event_msg *ev) -{ - ggp_message_got_data *msg = g_new0(ggp_message_got_data, 1); - - msg->gc = gc; - msg->time = ev->time; - msg->user = ev->sender; /* not really a sender*/ - - if (ev->chat_id != 0) { - msg->type = GGP_MESSAGE_GOT_TYPE_CHAT; - msg->chat_id = ev->chat_id; - } else { - msg->type = GGP_MESSAGE_GOT_TYPE_MULTILOGON; - } - - ggp_message_format_from_gg(msg, ev->xhtml_message); - - ggp_message_got_display(gc, msg); - ggp_message_got_data_free(msg); -} - -static void ggp_message_got_display(PurpleConnection *gc, - ggp_message_got_data *msg) -{ - if (msg->type == GGP_MESSAGE_GOT_TYPE_IM) { - purple_serv_got_im(gc, ggp_uin_to_str(msg->user), msg->text, - PURPLE_MESSAGE_RECV, msg->time); - } else if (msg->type == GGP_MESSAGE_GOT_TYPE_CHAT) { - ggp_chat_got_message(gc, msg->chat_id, msg->text, msg->time, - msg->user); - } else if (msg->type == GGP_MESSAGE_GOT_TYPE_MULTILOGON) { - GDateTime *dt = NULL; - PurpleAccount *account = NULL; - PurpleContactInfo *info = NULL; - PurpleConversation *im = ggp_message_get_conv(gc, msg->user); - PurpleMessage *pmsg; - const gchar *me = NULL; - - account = purple_connection_get_account(gc); - info = PURPLE_CONTACT_INFO(account); - me = purple_contact_info_get_name_for_display(info); - - pmsg = purple_message_new_outgoing(me, NULL, msg->text, 0); - - dt = g_date_time_new_from_unix_local((gint64)msg->time); - purple_message_set_timestamp(pmsg, dt); - g_date_time_unref(dt); - - purple_conversation_write_message(im, pmsg); - - g_object_unref(pmsg); - } else { - purple_debug_error("gg", "ggp_message_got_display: " - "unexpected message type: %d\n", msg->type); - } -} - -static gboolean ggp_message_format_from_gg_found_img(const GMatchInfo *info, - GString *res, gpointer data) -{ - ggp_message_got_data *msg = data; - gchar *name, *replacement; - int64_t id; - PurpleImage *image; - guint image_id; - - name = g_match_info_fetch(info, 1); - if (sscanf(name, "%" G_GINT64_MODIFIER "x", &id) != 1) - id = 0; - g_free(name); - if (!id) { - /* TODO: stock broken image? */ - g_string_append_printf(res, "[%s]", _("broken image")); - return FALSE; - } - - image = ggp_image_request(msg->gc, msg->user, id); - if (!image) { - purple_debug_warning("gg", "ggp_message_format_from_gg_" - "found_img: couldn't request image"); - g_string_append_printf(res, "[%s]", _("broken image")); - return FALSE; - } - - image_id = purple_image_store_add_weak(image); - replacement = g_strdup_printf("<img src=\"" - PURPLE_IMAGE_STORE_PROTOCOL "%u\">", image_id); - g_string_append(res, replacement); - g_free(replacement); - - return FALSE; -} - -static void ggp_message_format_from_gg(ggp_message_got_data *msg, - const gchar *text) -{ - gchar *text_new, *tmp; - - if (text == NULL) { - msg->text = g_strdup(""); - return; - } - - text_new = g_strdup(text); - purple_str_strip_char(text_new, '\r'); - - tmp = text_new; - text_new = purple_strreplace(text_new, GGP_GG10_DEFAULT_FORMAT, - GGP_GG10_DEFAULT_FORMAT_REPLACEMENT); - g_free(tmp); - - tmp = text_new; - text_new = g_regex_replace_eval(global_data.re_gg_img, text_new, -1, 0, - 0, ggp_message_format_from_gg_found_img, msg, NULL); - g_free(tmp); - - msg->text = text_new; -} - -gchar * -ggp_message_format_to_gg(PurpleConversation *conv, const gchar *text) -{ - gchar *text_new, *tmp; - GString *reformatted_text = NULL; - GMatchInfo *match; - guint pos = 0; - GString *pending_objects = NULL; - GList *font_stack = NULL; - static int html_sizes_pt[7] = { 7, 8, 9, 10, 12, 14, 16 }; - - ggp_font *font_new, *font_current, *font_base; - gboolean font_changed = FALSE; - gboolean in_any_tag = FALSE; - - if (purple_debug_is_verbose()) - purple_debug_info("gg", "ggp formatting text: [%s]", text); - - /* default font */ - font_base = ggp_font_new(); - font_current = ggp_font_new(); - font_new = ggp_font_new(); - - /* GG11 doesn't use nbsp, it just print spaces */ - text_new = purple_strreplace(text, " ", " "); - - /* add end-of-message tag */ - if (strstr(text_new, "<eom>") != NULL) { - tmp = text_new; - text_new = purple_strreplace(text_new, "<eom>", ""); - g_free(tmp); - purple_debug_warning("gg", "ggp_message_format_to_gg: " - "unexpected <eom> tag\n"); - } - tmp = text_new; - text_new = g_strdup_printf("%s<eom></eom>", text_new); - g_free(tmp); - - reformatted_text = g_string_new(NULL); - pending_objects = g_string_new(NULL); - g_regex_match(global_data.re_html_tag, text_new, 0, &match); - while (g_match_info_matches(match)) { - int m_start, m_end, m_pos; - gboolean tag_close; - gchar *tag_str, *attribs_str; - ggp_html_tag tag; - gboolean text_before; - - /* reading tag and its contents */ - g_match_info_fetch_pos(match, 0, &m_start, &m_end); - g_assert(m_start >= 0 && m_end >= 0); - text_before = ((guint)m_start > pos); - g_match_info_fetch_pos(match, 1, &m_pos, NULL); - tag_close = (m_pos >= 0); - tag_str = g_match_info_fetch(match, 2); - tag = ggp_html_parse_tag(tag_str); - attribs_str = g_match_info_fetch(match, 3); - g_match_info_next(match, NULL); - - if (tag == GGP_HTML_TAG_UNKNOWN) { - purple_debug_warning( - "gg", - "ggp_message_format_to_gg: unknown tag %s", - tag_str); - } - - /* closing *all* formatting-related tags (GG11 weirdness) - * and adding pending objects */ - if ((text_before && (font_changed || pending_objects->len > 0)) || - (tag == GGP_HTML_TAG_EOM && tag_close)) { - font_changed = FALSE; - if (in_any_tag) { - in_any_tag = FALSE; - if (font_current->s && !GGP_GG11_FORCE_COMPAT) { - g_string_append(reformatted_text, "</s>"); - } - if (font_current->u) { - g_string_append(reformatted_text, "</u>"); - } - if (font_current->i) { - g_string_append(reformatted_text, "</i>"); - } - if (font_current->b) { - g_string_append(reformatted_text, "</b>"); - } - g_string_append(reformatted_text, "</span>"); - } - if (pending_objects->len > 0) { - g_string_append(reformatted_text, pending_objects->str); - g_string_truncate(pending_objects, 0); - } - } - - /* opening formatting-related tags again */ - if (text_before && !in_any_tag) { - gboolean has_size = (font_new->size > 0 && - font_new->size <= 7 && font_new->size != 3); - gboolean has_style = - has_size || font_new->face || - (font_new->bgcolor >= 0 && !GGP_GG11_FORCE_COMPAT) || - font_new->color >= 0; - - if (has_style) { - g_string_append(reformatted_text, "<span style=\""); - - if (has_size) { - g_string_append_printf(reformatted_text, "font-size:%dpt;", - html_sizes_pt[font_new->size - 1]); - } - if (font_new->face) { - g_string_append_printf(reformatted_text, "font-family:%s;", - font_new->face); - } - if (font_new->bgcolor >= 0 && !GGP_GG11_FORCE_COMPAT) { - g_string_append_printf(reformatted_text, - "background-color:#%06x;", - font_new->bgcolor); - } - if (font_new->color >= 0) { - g_string_append_printf(reformatted_text, "color:#%06x;", - font_new->color); - } - - g_string_append(reformatted_text, "\">"); - } else { - g_string_append(reformatted_text, "<span>"); - } - - if (font_new->b) { - g_string_append(reformatted_text, "<b>"); - } - if (font_new->i) { - g_string_append(reformatted_text, "<i>"); - } - if (font_new->u) { - g_string_append(reformatted_text, "<u>"); - } - if (font_new->s && !GGP_GG11_FORCE_COMPAT) { - g_string_append(reformatted_text, "<s>"); - } - - ggp_font_free(font_current); - font_current = font_new; - font_new = ggp_font_clone(font_current); - - in_any_tag = TRUE; - } - if (text_before) { - g_string_append_len(reformatted_text, text_new + pos, - m_start - pos); - } - - /* set formatting of a following text */ - if (tag == GGP_HTML_TAG_B) { - font_changed |= (font_new->b != !tag_close); - font_new->b = !tag_close; - } else if (tag == GGP_HTML_TAG_I) { - font_changed |= (font_new->i != !tag_close); - font_new->i = !tag_close; - } else if (tag == GGP_HTML_TAG_U) { - font_changed |= (font_new->u != !tag_close); - font_new->u = !tag_close; - } else if (tag == GGP_HTML_TAG_S) { - font_changed |= (font_new->s != !tag_close); - font_new->s = !tag_close; - } else if (tag == GGP_HTML_TAG_IMG && !tag_close) { - GHashTable *attribs = ggp_html_tag_attribs(attribs_str); - gchar *val = NULL; - uint64_t id; - ggp_image_prepare_result res = -1; - PurpleImage *image = NULL; - - val = g_hash_table_lookup(attribs, "src"); - if (val) - image = purple_image_store_get_from_uri(val); - - if (image != NULL) - res = ggp_image_prepare(conv, image, &id); - - if (res == GGP_IMAGE_PREPARE_OK) { - g_string_append_printf(pending_objects, - "<img name=\"" GGP_IMAGE_ID_FORMAT "\">", - id); - } else if (res == GGP_IMAGE_PREPARE_TOO_BIG) { - purple_conversation_write_system_message(conv, - _("Image is too large, please try " - "smaller one."), PURPLE_MESSAGE_ERROR); - } else { - purple_conversation_write_system_message(conv, - _("Image cannot be sent."), - PURPLE_MESSAGE_ERROR); - } - - g_hash_table_destroy(attribs); - } else if (tag == GGP_HTML_TAG_FONT && !tag_close) { - GHashTable *attribs = ggp_html_tag_attribs(attribs_str); - gchar *val = NULL; - - font_stack = g_list_prepend(font_stack, - ggp_font_clone(font_new)); - - if ((val = g_hash_table_lookup(attribs, "size")) != NULL - && val[0] >= '1' && val[0] <= '7' && - val[1] == '\0') - { - int size = val[0] - '0'; - font_changed |= (font_new->size != size); - font_new->size = size; - } - - if ((val = g_hash_table_lookup(attribs, "face")) - != NULL) - { - font_changed |= - (g_strcmp0(font_new->face, val) != 0); - g_free(font_new->face); - font_new->face = g_strdup(val); - } - - if ((val = g_hash_table_lookup(attribs, "color")) - != NULL && val[0] == '#' && strlen(val) == 7) - { - int color = ggp_html_decode_color(val); - font_changed |= (font_new->color != color); - font_new->color = color; - } - - g_hash_table_destroy(attribs); - } - else if ((tag == GGP_HTML_TAG_SPAN || tag == GGP_HTML_TAG_DIV) - && !tag_close) - { - GHashTable *attribs, *styles = NULL; - gchar *style = NULL; - gchar *val = NULL; - - attribs = ggp_html_tag_attribs(attribs_str); - - font_stack = g_list_prepend(font_stack, - ggp_font_clone(font_new)); - if (tag == GGP_HTML_TAG_DIV) { - g_string_append(pending_objects, "<br>"); - } - - style = g_hash_table_lookup(attribs, "style"); - if (style) - styles = ggp_html_css_attribs(style); - - if (styles && (val = g_hash_table_lookup(styles, - "background-color")) != NULL) - { - int color = ggp_html_decode_color(val); - font_changed |= (font_new->bgcolor != color); - font_new->bgcolor = color; - } - - if (styles && (val = g_hash_table_lookup(styles, - "color")) != NULL) - { - int color = ggp_html_decode_color(val); - font_changed |= (font_new->color != color); - font_new->color = color; - } - - g_clear_pointer(&styles, g_hash_table_destroy); - g_hash_table_destroy(attribs); - } - else if ((tag == GGP_HTML_TAG_FONT || tag == GGP_HTML_TAG_SPAN - || tag == GGP_HTML_TAG_DIV) && tag_close) - { - font_changed = TRUE; - - ggp_font_free(font_new); - if (font_stack) { - font_new = (ggp_font*)font_stack->data; - font_stack = g_list_delete_link( - font_stack, font_stack); - } - else - font_new = ggp_font_clone(font_base); - } else if (tag == GGP_HTML_TAG_BR) { - g_string_append(pending_objects, "<br>"); - } else if (tag == GGP_HTML_TAG_HR) { - g_string_append(pending_objects, "<br><span>---</span><br>"); - } else if (tag == GGP_HTML_TAG_A || tag == GGP_HTML_TAG_EOM) { - /* do nothing */ - } else if (tag == GGP_HTML_TAG_UNKNOWN) { - purple_debug_warning( - "gg", - "ggp_message_format_to_gg: unknown tag %s", - tag_str); - } else { - purple_debug_error("gg", "ggp_message_format_to_gg: " - "not handled tag %s\n", tag_str); - } - - pos = m_end; - g_free(tag_str); - g_free(attribs_str); - } - g_match_info_free(match); - - if (pos < strlen(text_new) || in_any_tag) { - purple_debug_error( - "gg", - "ggp_message_format_to_gg: end of message not reached"); - } - - /* releasing fonts resources */ - ggp_font_free(font_new); - ggp_font_free(font_current); - ggp_font_free(font_base); - g_list_free_full(font_stack, ggp_font_free); - - /* combining reformatted text info one string */ - g_free(text_new); - g_string_free(pending_objects, TRUE); - text_new = g_string_free(reformatted_text, FALSE); - - if (purple_debug_is_verbose()) - purple_debug_info("gg", "reformatted text: [%s]", text_new); - - return text_new; -} - -int -ggp_message_send_im(G_GNUC_UNUSED PurpleProtocolIM *pim, - PurpleConnection *gc, - G_GNUC_UNUSED PurpleConversation *conversation, - PurpleMessage *msg) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - PurpleConversation *im; - PurpleConversationManager *manager; - ggp_buddy_data *buddy_data; - gchar *gg_msg; - gboolean succ; - const gchar *rcpt = purple_message_get_recipient(msg); - - /* TODO: return -ENOTCONN, if not connected */ - - if (purple_message_is_empty(msg)) - return 0; - - buddy_data = ggp_buddy_get_data(purple_blist_find_buddy( - purple_connection_get_account(gc), rcpt)); - - if (buddy_data->blocked) - return -1; - - manager = purple_conversation_manager_get_default(); - im = purple_conversation_manager_find_im(manager, - purple_connection_get_account(gc), - rcpt); - - gg_msg = ggp_message_format_to_gg(im, - purple_message_get_contents(msg)); - - /* TODO: splitting messages */ - if (strlen(gg_msg) > GG_MSG_MAXSIZE) { - g_free(gg_msg); - return -E2BIG; - } - - succ = (gg_send_message_html(info->session, GG_CLASS_CHAT, - ggp_str_to_uin(rcpt), (unsigned char *)gg_msg) >= 0); - - g_free(gg_msg); - - return succ ? 1 : -1; -}
--- a/libpurple/protocols/gg/message-prpl.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_MESSAGE_PRPL_H -#define PURPLE_GG_MESSAGE_PRPL_H - -#include <purple.h> -#include <libgadu.h> - -typedef struct _ggp_message_session_data ggp_message_session_data; - -void ggp_message_setup_global(void); -void ggp_message_cleanup_global(void); -void ggp_message_setup(PurpleConnection *gc); -void ggp_message_cleanup(PurpleConnection *gc); - -void ggp_message_got(PurpleConnection *gc, const struct gg_event_msg *ev); -void ggp_message_got_multilogon(PurpleConnection *gc, - const struct gg_event_msg *ev); - -int ggp_message_send_im(PurpleProtocolIM *im, PurpleConnection *gc, PurpleConversation *conversation, PurpleMessage *msg); -gchar * ggp_message_format_to_gg(PurpleConversation *conv, const gchar *text); - -#endif /* PURPLE_GG_MESSAGE_PRPL_H */
--- a/libpurple/protocols/gg/multilogon.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "multilogon.h" - -#include <glib/gi18n-lib.h> - -#include "gg.h" -#include "keymapper.h" -#include "utils.h" -#include "message-prpl.h" - -typedef struct -{ - uint64_t id; - uint32_t remote_addr; - gchar *name; - GDateTime *logon_time; -} ggp_multilogon_session_info; - -struct _ggp_multilogon_session_data -{ - int session_count; - ggp_multilogon_session_info *sessions; - PurpleRequestDatasheet *sheet_handle; - gpointer dialog_handle; - ggp_keymapper *sid_mapper; -}; - -static inline ggp_multilogon_session_data * -ggp_multilogon_get_mldata(PurpleConnection *gc); - - -static inline ggp_multilogon_session_data * -ggp_multilogon_get_mldata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return accdata->multilogon_data; -} - -void -ggp_multilogon_setup(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - - ggp_multilogon_session_data *mldata = - g_new0(ggp_multilogon_session_data, 1); - accdata->multilogon_data = mldata; - - mldata->sid_mapper = ggp_keymapper_new(); -} - -static void -ggp_multilogon_free_sessions(PurpleConnection *gc) -{ - ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc); - int i; - - for (i = 0; i < mldata->session_count; i++) { - g_free(mldata->sessions[i].name); - g_clear_pointer(&mldata->sessions[i].logon_time, g_date_time_unref); - } - g_free(mldata->sessions); - - mldata->sessions = NULL; - mldata->session_count = 0; -} - -void -ggp_multilogon_cleanup(PurpleConnection *gc) -{ - ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc); - - if (mldata->dialog_handle) { - purple_request_close(PURPLE_REQUEST_FIELDS, - mldata->dialog_handle); - mldata->dialog_handle = NULL; - } - - ggp_multilogon_free_sessions(gc); - ggp_keymapper_free(mldata->sid_mapper); - g_free(mldata); -} - -static uint64_t -ggp_multilogon_sid_from_libgadu(gg_multilogon_id_t lsid) -{ - uint64_t sid; - - memcpy(&sid, lsid.id, sizeof(uint64_t)); - - return sid; -} - -static void -ggp_multilogon_sid_to_libgadu(uint64_t sid, gg_multilogon_id_t *lsid) -{ - g_return_if_fail(lsid != NULL); - - memcpy(lsid->id, &sid, sizeof(uint64_t)); -} - -static void -ggp_multilogon_fill_sessions(PurpleRequestDatasheet *sheet, - PurpleConnection *gc) -{ - ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc); - ggp_keymapper *km = mldata->sid_mapper; - int i; - - purple_request_datasheet_record_mark_all_for_rem(sheet); - - for (i = 0; i < mldata->session_count; i++) { - ggp_multilogon_session_info *sess = &mldata->sessions[i]; - PurpleRequestDatasheetRecord *rec; - gchar *tmp = NULL; - - rec = purple_request_datasheet_record_add(sheet, - ggp_keymapper_to_key(km, sess->id)); - - purple_request_datasheet_record_set_string_data(rec, 0, - ggp_ipv4_to_str(sess->remote_addr)); - - tmp = g_date_time_format(sess->logon_time, "%c"); - purple_request_datasheet_record_set_string_data(rec, 1, tmp); - g_free(tmp); - - purple_request_datasheet_record_set_string_data(rec, 2, sess->name); - } - - purple_request_datasheet_record_remove_marked(sheet); -} - -void -ggp_multilogon_info(PurpleConnection *gc, struct gg_event_multilogon_info *info) -{ - ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc); - int i; - - ggp_multilogon_free_sessions(gc); - - purple_debug_info("gg", "ggp_multilogon_info: session list changed " - "(count now: %d)\n", info->count); - - mldata->sessions = g_new(ggp_multilogon_session_info, info->count); - for (i = 0; i < info->count; i++) { - struct gg_multilogon_session *lsess = &info->sessions[i]; - ggp_multilogon_session_info *psess = &mldata->sessions[i]; - - psess->id = ggp_multilogon_sid_from_libgadu(lsess->id); - psess->remote_addr = lsess->remote_addr; - psess->name = g_strdup(lsess->name); - psess->logon_time = g_date_time_new_from_unix_local(lsess->logon_time); - } - - mldata->session_count = info->count; - - if (mldata->sheet_handle != NULL) - ggp_multilogon_fill_sessions(mldata->sheet_handle, gc); -} - -static void -ggp_multilogon_disconnect(PurpleRequestDatasheetRecord *rec, gpointer _gc) -{ - PurpleConnection *gc = _gc; - ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc); - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - uint64_t sid; - gpointer key; - gg_multilogon_id_t lsid; - - key = purple_request_datasheet_record_get_key(rec); - sid = ggp_keymapper_from_key(mldata->sid_mapper, key); - - ggp_multilogon_sid_to_libgadu(sid, &lsid); - gg_multilogon_disconnect(accdata->session, lsid); - - purple_request_datasheet_record_remove( - purple_request_datasheet_record_get_datasheet(rec), key); -} - -static void -ggp_multilogin_close_request(ggp_multilogon_session_data *mldata) -{ - mldata->sheet_handle = NULL; - mldata->dialog_handle = NULL; -} - -void -ggp_multilogon_dialog(PurpleConnection *gc) -{ - ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc); - PurpleRequestField *field; - PurpleRequestPage *page; - PurpleRequestGroup *group; - PurpleRequestCommonParameters *cpar; - PurpleRequestDatasheet *sheet; - PurpleRequestDatasheetAction *action; - gpointer dialog_handle; - - if (mldata->dialog_handle != NULL) - return; - - page = purple_request_page_new(); - group = purple_request_group_new(NULL); - purple_request_page_add_group(page, group); - - sheet = purple_request_datasheet_new(); - purple_request_datasheet_add_column(sheet, - PURPLE_REQUEST_DATASHEET_COLUMN_STRING, _("IP")); - purple_request_datasheet_add_column(sheet, - PURPLE_REQUEST_DATASHEET_COLUMN_STRING, _("Logon time")); - purple_request_datasheet_add_column(sheet, - PURPLE_REQUEST_DATASHEET_COLUMN_STRING, _("Session")); - - action = purple_request_datasheet_action_new(); - purple_request_datasheet_action_set_label(action, _("Disconnect")); - purple_request_datasheet_action_set_cb(action, - ggp_multilogon_disconnect, gc); - purple_request_datasheet_add_action(sheet, action); - ggp_multilogon_fill_sessions(sheet, gc); - - field = purple_request_field_datasheet_new("sessions", NULL, sheet); - purple_request_group_add_field(group, field); - - cpar = purple_request_cpar_new(); - purple_request_cpar_set_icon(cpar, PURPLE_REQUEST_ICON_DIALOG); - - dialog_handle = purple_request_fields(gc, - _("Other Gadu-Gadu sessions"), NULL, NULL, page, - NULL, NULL, _("Close"), NULL, - cpar, NULL); - mldata->sheet_handle = sheet; - mldata->dialog_handle = dialog_handle; - - purple_request_add_close_notify(dialog_handle, - (GDestroyNotify)ggp_multilogin_close_request, mldata); -}
--- a/libpurple/protocols/gg/multilogon.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_MULTILOGON_H -#define PURPLE_GG_MULTILOGON_H - -#include <purple.h> -#include <libgadu.h> - -typedef struct _ggp_multilogon_session_data ggp_multilogon_session_data; - -void ggp_multilogon_setup(PurpleConnection *gc); -void ggp_multilogon_cleanup(PurpleConnection *gc); - -void ggp_multilogon_info(PurpleConnection *gc, - struct gg_event_multilogon_info *msg); - -void ggp_multilogon_dialog(PurpleConnection *gc); - -#endif /* PURPLE_GG_MULTILOGON_H */
--- a/libpurple/protocols/gg/oauth/oauth-purple.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,301 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "oauth-purple.h" -#include "gg.h" - -#include "oauth.h" -#include "../utils.h" -#include "../xml.h" - -#include <purple.h> - -#define GGP_OAUTH_RESPONSE_MAX 10240 - -typedef struct -{ - SoupMessage *msg; - PurpleConnection *gc; - ggp_oauth_request_cb callback; - gpointer user_data; - gchar *token; - gchar *token_secret; - - gchar *sign_method, *sign_url; -} ggp_oauth_data; - -static void ggp_oauth_data_free(ggp_oauth_data *data) -{ - g_object_unref(data->msg); - g_free(data->token); - g_free(data->token_secret); - g_free(data->sign_method); - g_free(data->sign_url); - g_free(data); -} - -static void -ggp_oauth_access_token_got(GObject *source, GAsyncResult *result, - gpointer user_data) -{ - ggp_oauth_data *data = user_data; - GBytes *response_body = NULL; - const char *buffer = NULL; - gsize size = 0; - gchar *token = NULL, *token_secret = NULL; - PurpleXmlNode *xml; - gboolean succ = TRUE; - GError *error = NULL; - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - if(response_body == NULL) { - purple_debug_error("gg", "ggp_oauth_access_token_got: failed: %s", - error->message); - ggp_oauth_data_free(data); - g_error_free(error); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - xml = purple_xmlnode_from_str(buffer, size); - g_bytes_unref(response_body); - - if (xml == NULL) { - purple_debug_error("gg", "ggp_oauth_access_token_got: invalid xml"); - ggp_oauth_data_free(data); - return; - } - - succ &= ggp_xml_get_string(xml, "oauth_token", &token); - succ &= ggp_xml_get_string(xml, "oauth_token_secret", &token_secret); - purple_xmlnode_free(xml); - if (!succ || strlen(token) < 10) { - purple_debug_error("gg", "ggp_oauth_access_token_got: invalid xml - " - "token is not present"); - g_free(token); - g_free(token_secret); - ggp_oauth_data_free(data); - return; - } - - if (data->sign_url) { - PurpleAccount *account; - PurpleContactInfo *info = NULL; - gchar *auth; - - purple_debug_misc("gg", "ggp_oauth_access_token_got: got access token, " - "returning signed url"); - - account = purple_connection_get_account(data->gc); - info = PURPLE_CONTACT_INFO(account); - auth = gg_oauth_generate_header( - data->sign_method, data->sign_url, - purple_contact_info_get_username(info), - purple_connection_get_password(data->gc), token, token_secret); - data->callback(data->gc, auth, data->user_data); - } else { - purple_debug_misc( - "gg", - "ggp_oauth_access_token_got: got access token, returning it"); - data->callback(data->gc, token, data->user_data); - } - - g_free(token); - g_free(token_secret); - ggp_oauth_data_free(data); -} - -static void -ggp_oauth_authorization_done(GObject *source, - G_GNUC_UNUSED GAsyncResult *result, - gpointer user_data) -{ - ggp_oauth_data *data = user_data; - PurpleAccount *account; - PurpleContactInfo *info = NULL; - SoupStatus status_code; - char *auth; - SoupMessage *msg = NULL; - const char *method = "POST"; - const char *url = "http://api.gadu-gadu.pl/access_token"; - - PURPLE_ASSERT_CONNECTION_IS_VALID(data->gc); - - account = purple_connection_get_account(data->gc); - info = PURPLE_CONTACT_INFO(account); - - status_code = soup_message_get_status(data->msg); - if (status_code != 302) { - purple_debug_error("gg", - "ggp_oauth_authorization_done: failed (code = %d)", - status_code); - ggp_oauth_data_free(data); - return; - } - - purple_debug_misc("gg", "ggp_oauth_authorization_done: authorization done, " - "requesting access token..."); - - auth = gg_oauth_generate_header(method, url, - purple_contact_info_get_username(info), - purple_connection_get_password(data->gc), - data->token, data->token_secret); - - g_clear_object(&data->msg); - data->msg = msg = soup_message_new(method, url); - // purple_http_request_set_max_len(req, GGP_OAUTH_RESPONSE_MAX); - soup_message_headers_replace(soup_message_get_request_headers(msg), - "Authorization", auth); - soup_session_send_and_read_async(SOUP_SESSION(source), msg, - G_PRIORITY_DEFAULT, NULL, - ggp_oauth_access_token_got, data); - - g_free(auth); -} - -static void -ggp_oauth_request_token_got(GObject *source, GAsyncResult *result, - gpointer user_data) -{ - SoupSession *session = SOUP_SESSION(source); - ggp_oauth_data *data = user_data; - GBytes *response_body = NULL; - const char *buffer = NULL; - gsize size = 0; - PurpleAccount *account; - PurpleXmlNode *xml; - SoupMessage *msg = NULL; - gchar *request_data; - GBytes *body = NULL; - gboolean succ = TRUE; - GError *error = NULL; - - PURPLE_ASSERT_CONNECTION_IS_VALID(data->gc); - - account = purple_connection_get_account(data->gc); - - if(!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(data->msg))) { - purple_debug_error("gg", "ggp_oauth_request_token_got: " - "requested token not received\n"); - ggp_oauth_data_free(data); - return; - } - - response_body = soup_session_send_and_read_finish(session, result, &error); - if(response_body == NULL) { - purple_debug_error("gg", "ggp_oauth_access_token_got: failed: %s", - error->message); - ggp_oauth_data_free(data); - g_error_free(error); - return; - } - - purple_debug_misc("gg", "ggp_oauth_request_token_got: " - "got request token, doing authorization...\n"); - - buffer = g_bytes_get_data(response_body, &size); - xml = purple_xmlnode_from_str(buffer, size); - g_bytes_unref(response_body); - - if (xml == NULL) { - purple_debug_error("gg", "ggp_oauth_request_token_got: " - "invalid xml\n"); - ggp_oauth_data_free(data); - return; - } - - succ &= ggp_xml_get_string(xml, "oauth_token", &data->token); - succ &= ggp_xml_get_string(xml, "oauth_token_secret", - &data->token_secret); - purple_xmlnode_free(xml); - if (!succ) { - purple_debug_error("gg", "ggp_oauth_request_token_got: " - "invalid xml - token is not present\n"); - ggp_oauth_data_free(data); - return; - } - - request_data = g_strdup_printf( - "callback_url=http://www.mojageneracja.pl&request_token=%s&" - "uin=%s&password=%s", data->token, - purple_contact_info_get_username(PURPLE_CONTACT_INFO(account)), - purple_connection_get_password(data->gc)); - - g_clear_object(&data->msg); - data->msg = msg = soup_message_new("POST", - "https://login.gadu-gadu.pl/authorize"); - // purple_http_request_set_max_len(msg, GGP_OAUTH_RESPONSE_MAX); - /* we don't need any results, nor 302 redirection */ - soup_message_set_flags(msg, SOUP_MESSAGE_NO_REDIRECT); - body = g_bytes_new_take(request_data, strlen(request_data)); - soup_message_set_request_body_from_bytes(msg, - "application/x-www-form-urlencoded", - body); - g_bytes_unref(body); - soup_session_send_and_read_async(session, msg, G_PRIORITY_DEFAULT, NULL, - ggp_oauth_authorization_done, data); -} - -void -ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback, - gpointer user_data, const gchar *sign_method, - const gchar *sign_url) -{ - GGPInfo *info = purple_connection_get_protocol_data(gc); - PurpleAccount *account = purple_connection_get_account(gc); - SoupMessage *msg; - char *auth; - const char *method = "POST"; - const char *url = "http://api.gadu-gadu.pl/request_token"; - ggp_oauth_data *data; - - purple_debug_misc("gg", "ggp_oauth_request: requesting token...\n"); - - auth = gg_oauth_generate_header( - method, url, - purple_contact_info_get_username(PURPLE_CONTACT_INFO(account)), - purple_connection_get_password(gc), NULL, NULL); - - data = g_new0(ggp_oauth_data, 1); - data->gc = gc; - data->callback = callback; - data->user_data = user_data; - data->sign_method = g_strdup(sign_method); - data->sign_url = g_strdup(sign_url); - - data->msg = msg = soup_message_new(method, url); - // purple_http_request_set_max_len(req, GGP_OAUTH_RESPONSE_MAX); - soup_message_headers_replace(soup_message_get_request_headers(msg), - "Authorization", auth); - soup_session_send_and_read_async(info->http, msg, G_PRIORITY_DEFAULT, NULL, - ggp_oauth_request_token_got, data); - - g_free(auth); -}
--- a/libpurple/protocols/gg/oauth/oauth-purple.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _GGP_OAUTH_PURPLE_H -#define _GGP_OAUTH_PURPLE_H - -#include <purple.h> -#include <libgadu.h> - -typedef void (*ggp_oauth_request_cb)(PurpleConnection *gc, const gchar *token, - gpointer user_data); - -void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback, - gpointer user_data, const gchar *sign_method, const gchar *sign_url); - -#endif /* _GGP_OAUTH_PURPLE_H */
--- a/libpurple/protocols/gg/oauth/oauth.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Code adapted from libgadu (C) 2008 Wojtek Kaniewski <wojtekka@irc.pl> - * (http://toxygen.net/libgadu/) during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "oauth.h" - -#include <time.h> - -#include <glib.h> - -char *gg_oauth_static_nonce; /* dla unit testów */ -char *gg_oauth_static_timestamp; /* dla unit testów */ - -static char *gg_oauth_generate_request(gboolean header, ...) G_GNUC_NULL_TERMINATED; - -static void gg_oauth_generate_nonce(char *buf, int len) -{ - const char charset[] = "0123456789"; - - if (buf == NULL || len < 1) - return; - - while (len > 1) { - *buf++ = charset[(unsigned) (((float) sizeof(charset) - 1.0) * g_random_int() / (RAND_MAX + 1.0))]; - len--; - } - - *buf = 0; -} - -/* Returns a comma separated header value if header is true, - * or a url-encoded request otherwise - */ -static char * -gg_oauth_generate_request(gboolean header, ...) -{ - GString *res = g_string_new(NULL); - va_list params; - const gchar *key; - gboolean truncate = FALSE; - - if(header) { - res = g_string_append(res, "OAuth "); - } - - va_start(params, header); - while((key = va_arg(params, const gchar *))) { - const gchar *value = va_arg(params, const gchar *); - gchar *escaped = g_uri_escape_string(value, NULL, FALSE); - - if(header) { - g_string_append_printf(res, "%s=\"%s\",", key, escaped); - } else { - g_string_append_printf(res, "%s=%s&", key, escaped); - } - - g_free(escaped); - - truncate = TRUE; - } - va_end(params); - - if(truncate) { - /* remove trailing separator */ - res = g_string_truncate(res, res->len - 1); - } - - return g_string_free(res, FALSE); -} - -static gchar *gg_hmac_sha1(const char *key, const char *message) -{ - GHmac *hmac; - guchar digest[20]; - gsize digest_len = 20; - - hmac = g_hmac_new(G_CHECKSUM_SHA1, (guchar *)key, strlen(key)); - g_hmac_update(hmac, (guchar *)message, -1); - g_hmac_get_digest(hmac, digest, &digest_len); - g_hmac_unref(hmac); - - return g_base64_encode(digest, sizeof(digest)); -} - -static char * -gg_oauth_generate_signature(const char *method, const char *url, - const char *request, const char *consumer_secret, - const char *token_secret) -{ - char *text, *key, *res; - gchar *url_e, *request_e, *consumer_secret_e, *token_secret_e; - - url_e = g_uri_escape_string(url, "?", FALSE); - g_strdelimit(url_e, "?", '\0'); - request_e = g_uri_escape_string(request, NULL, FALSE); - text = g_strdup_printf("%s&%s&%s", method, url_e, request_e); - g_free(url_e); - g_free(request_e); - - consumer_secret_e = g_uri_escape_string(consumer_secret, NULL, FALSE); - token_secret_e = token_secret ? g_uri_escape_string(token_secret, NULL, FALSE) : NULL; - key = g_strdup_printf("%s&%s", consumer_secret_e, token_secret ? token_secret_e : ""); - g_free(consumer_secret_e); - g_free(token_secret_e); - - res = gg_hmac_sha1(key, text); - - g_free(key); - g_free(text); - - return res; -} - -char * -gg_oauth_generate_header(const char *method, const char *url, - const char *consumer_key, const char *consumer_secret, - const char *token, const char *token_secret) -{ - char *request, *signature, *res; - char nonce[80], timestamp[16]; - - if (gg_oauth_static_nonce == NULL) - gg_oauth_generate_nonce(nonce, sizeof(nonce)); - else { - strncpy(nonce, gg_oauth_static_nonce, sizeof(nonce) - 1); - nonce[sizeof(nonce) - 1] = 0; - } - - if (gg_oauth_static_timestamp == NULL) { - g_snprintf(timestamp, sizeof(timestamp), "%ld", time(NULL)); - } else { - strncpy(timestamp, gg_oauth_static_timestamp, sizeof(timestamp) - 1); - timestamp[sizeof(timestamp) - 1] = 0; - } - - request = gg_oauth_generate_request(FALSE, - "oauth_consumer_key", consumer_key, - "oauth_nonce", nonce, - "oauth_signature_method", "HMAC-SHA1", - "oauth_timestamp", timestamp, - "oauth_token", token, - "oauth_version", "1.0", - NULL); - - signature = gg_oauth_generate_signature(method, url, request, consumer_secret, token_secret); - - g_free(request); - - if (signature == NULL) - return NULL; - - res = gg_oauth_generate_request(TRUE, - "oauth_version", "1.0", - "oauth_nonce", nonce, - "oauth_timestamp", timestamp, - "oauth_consumer_key", consumer_key, - "oauth_token", token, - "oauth_signature_method", "HMAC-SHA1", - "oauth_signature", signature, - NULL); - g_free(signature); - - return res; -}
--- a/libpurple/protocols/gg/oauth/oauth.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Code adapted from libgadu (C) 2008 Wojtek Kaniewski <wojtekka@irc.pl> - * (http://toxygen.net/libgadu/) during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _GGP_OAUTH_H -#define _GGP_OAUTH_H - -#include <libgadu.h> - -char * gg_oauth_generate_header(const char *method, const char *url, - const char *consumer_key, const char *consumer_secret, - const char *token, const char *token_secret); - -#endif /* _GGP_OAUTH_H */
--- a/libpurple/protocols/gg/pubdir-prpl.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1025 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include <purple.h> - -#include "pubdir-prpl.h" -#include "gg.h" - -#include "oauth/oauth-purple.h" -#include "xml.h" -#include "utils.h" -#include "status.h" - -typedef struct -{ - PurpleConnection *gc; - ggp_pubdir_request_cb cb; - void *user_data; - enum - { - GGP_PUBDIR_REQUEST_TYPE_INFO, - GGP_PUBDIR_REQUEST_TYPE_SEARCH, - } type; - union - { - struct - { - uin_t uin; - } user_info; - ggp_pubdir_search_form *search_form; - } params; -} ggp_pubdir_request; - -/* Searching for buddies. */ - -#define GGP_PUBDIR_SEARCH_TITLE _("Gadu-Gadu Public Directory") -#define GGP_PUBDIR_SEARCH_PER_PAGE 20 - -struct _ggp_pubdir_search_form -{ - gchar *nick, *city; - ggp_pubdir_gender gender; - int offset; - int limit; - - void *display_handle; -}; - -/* For ggp_pubdir_search_results_next, which is called by this. */ -static void ggp_pubdir_search_results_display(PurpleConnection *gc, - int records_count, const ggp_pubdir_record *records, int next_offset, - void *user_data); - -/******************************************************************************/ - -static const gchar *ggp_pubdir_provinces[] = -{ - N_("Not specified"), - "dolnośląskie", - "kujawsko-pomorskie", - "lubelskie", - "lubuskie", - "łódzkie", - "małopolskie", - "mazowieckie", - "opolskie", - "podkarpackie", - "podlaskie", - "pomorskie", - "śląskie", - "świętokrzyskie", - "warmińsko-mazurskie", - "wielkopolskie", - "zachodniopomorskie", -}; - -static gsize ggp_pubdir_provinces_count = sizeof(ggp_pubdir_provinces)/sizeof(gchar*); - -/******************************************************************************/ - -static void -ggp_pubdir_record_free(ggp_pubdir_record *records, int count) -{ - int i; - for (i = 0; i < count; i++) { - g_free(records[i].label); - g_free(records[i].nickname); - g_free(records[i].first_name); - g_free(records[i].last_name); - g_free(records[i].city); - g_date_time_unref(records[i].birth); - } - g_free(records); -} - -static void -ggp_pubdir_search_form_free(ggp_pubdir_search_form *form) -{ - g_free(form->nick); - g_free(form->city); - g_free(form); -} - -static void -ggp_pubdir_request_free(ggp_pubdir_request *request) -{ - if (request->type == GGP_PUBDIR_REQUEST_TYPE_SEARCH) - ggp_pubdir_search_form_free(request->params.search_form); - g_free(request); -} - -static void -ggp_pubdir_got_data(GObject *source, GAsyncResult *result, gpointer data) { - ggp_pubdir_request *request = data; - PurpleConnection *gc = request->gc; - GBytes *response_body = NULL; - gboolean succ = TRUE; - PurpleXmlNode *xml; - const char *xml_raw = NULL; - gsize xml_size = 0; - unsigned int status, next_offset; - int record_count, i; - ggp_pubdir_record *records; - GError *error = NULL; - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - if (response_body == NULL) { - purple_debug_error("gg", "ggp_pubdir_got_data: %s", error->message); - request->cb(gc, -1, NULL, 0, request->user_data); - ggp_pubdir_request_free(request); - g_error_free(error); - return; - } - - xml_raw = g_bytes_unref_to_data(response_body, &xml_size); - - if (purple_debug_is_verbose() && purple_debug_is_unsafe()) { - purple_debug_misc("gg", "ggp_pubdir_got_data: xml=[%.*s]", - (int)xml_size, xml_raw); - } - - xml = purple_xmlnode_from_str(xml_raw, xml_size); - if (xml == NULL) { - purple_debug_error("gg", "ggp_pubdir_got_data: " - "invalid xml\n"); - request->cb(gc, -1, NULL, 0, request->user_data); - ggp_pubdir_request_free(request); - return; - } - - succ &= ggp_xml_get_uint(xml, "status", &status); - if (!ggp_xml_get_uint(xml, "nextOffset", &next_offset)) - next_offset = 0; - xml = purple_xmlnode_get_child(xml, "users"); - if (!succ || status != 0 || !xml) { - purple_debug_error("gg", "ggp_pubdir_got_data: " - "invalid reply\n"); - request->cb(gc, -1, NULL, 0, request->user_data); - ggp_pubdir_request_free(request); - return; - } - - record_count = ggp_xml_child_count(xml, "user"); - records = g_new0(ggp_pubdir_record, record_count); - - xml = purple_xmlnode_get_child(xml, "user"); - i = 0; - while (xml) { - ggp_pubdir_record *record = &records[i++]; - gchar *city = NULL, *birth_s = NULL; - unsigned int gender = 0; - const gchar *uin_s; - - g_assert(i <= record_count); - - record->uin = ggp_str_to_uin(purple_xmlnode_get_attrib(xml, "uin")); - if (record->uin == 0) - ggp_xml_get_uint(xml, "uin", &record->uin); - if (record->uin == 0) - purple_debug_error("gg", "ggp_pubdir_got_data:" - " invalid uin\n"); - uin_s = ggp_uin_to_str(record->uin); - - ggp_xml_get_string(xml, "label", &record->label); - ggp_xml_get_string(xml, "nick", &record->nickname); - ggp_xml_get_string(xml, "name", &record->first_name); - ggp_xml_get_string(xml, "surname", &record->last_name); - ggp_xml_get_string(xml, "city", &city); - ggp_xml_get_string(xml, "birth", &birth_s); - ggp_xml_get_uint(xml, "gender", &gender); - ggp_xml_get_uint(xml, "age", &record->age); - ggp_xml_get_uint(xml, "province", &record->province); - - record->label = ggp_free_if_equal(record->label, uin_s); - record->label = ggp_free_if_equal(record->label, ""); - record->nickname = ggp_free_if_equal(record->nickname, uin_s); - record->nickname = ggp_free_if_equal(record->nickname, ""); - record->first_name = ggp_free_if_equal(record->first_name, ""); - record->last_name = ggp_free_if_equal(record->last_name, ""); - g_clear_pointer(&record->birth, g_date_time_unref); - - if (record->label) {} - else if (record->nickname) - record->label = g_strdup(record->nickname); - else if (record->first_name && record->last_name) - record->label = g_strdup_printf("%s %s", - record->first_name, record->last_name); - else if (record->first_name) - record->label = g_strdup(record->first_name); - else if (record->last_name) - record->label = g_strdup(record->last_name); - if (record->label) - g_strstrip(record->label); - if (record->nickname) - g_strstrip(record->nickname); - - if (gender == 1) - record->gender = GGP_PUBDIR_GENDER_FEMALE; - else if (gender == 2) - record->gender = GGP_PUBDIR_GENDER_MALE; - else - record->gender = GGP_PUBDIR_GENDER_UNSPECIFIED; - - if (city && city[0] != '\0') - record->city = g_strdup(city); - if (record->city) - g_strstrip(record->city); - if (!record->city) { - g_free(record->city); - record->city = NULL; - } - - record->birth = g_date_time_new_from_iso8601(birth_s, NULL); - /*TODO: calculate age from birth */ - - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_pubdir_got_data: [uin:%d] " - "[label:%s] [nick:%s] [first name:%s] " - "[last name:%s] [city:%s] [gender:%d] [age:%d] " - "[birth:%lu]\n", record->uin, record->label, - record->nickname, record->first_name, - record->last_name, record->city, record->gender, - record->age, g_date_time_to_unix(record->birth)); - } - - g_clear_pointer(&city, g_free); - g_clear_pointer(&birth_s, g_free); - - xml = purple_xmlnode_get_next_twin(xml); - } - - request->cb(gc, record_count, records, next_offset, request->user_data); - - ggp_pubdir_request_free(request); - ggp_pubdir_record_free(records, record_count); -} - -static void -ggp_pubdir_get_info_got_token(PurpleConnection *gc, const gchar *token, - gpointer _request) -{ - GGPInfo *info = NULL; - gchar *url; - SoupMessage *msg; - ggp_pubdir_request *request = _request; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - if (!token) { - request->cb(gc, -1, NULL, 0, request->user_data); - ggp_pubdir_request_free(request); - return; - } - - info = purple_connection_get_protocol_data(gc); - - url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u", - request->params.user_info.uin); - msg = soup_message_new("GET", url); - g_free(url); - soup_message_headers_replace(soup_message_get_request_headers(msg), - "Authorization", token); - soup_session_send_and_read_async(info->http, msg, G_PRIORITY_DEFAULT, NULL, - ggp_pubdir_got_data, request); - g_object_unref(msg); -} - -void -ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin, ggp_pubdir_request_cb cb, - void *user_data) -{ - ggp_pubdir_request *request = g_new0(ggp_pubdir_request, 1); - gchar *url; - - request->type = GGP_PUBDIR_REQUEST_TYPE_INFO; - request->gc = gc; - request->cb = cb; - request->user_data = user_data; - request->params.user_info.uin = uin; - - url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u", uin); - ggp_oauth_request(gc, ggp_pubdir_get_info_got_token, request, "GET", url); - g_free(url); -} - -static void -ggp_pubdir_get_info_protocol_got(PurpleConnection *gc, int records_count, - const ggp_pubdir_record *records, - G_GNUC_UNUSED int next_offset, void *_uin_p) -{ - uin_t uin = *((uin_t*)_uin_p); - PurpleNotifyUserInfo *info = purple_notify_user_info_new(); - const ggp_pubdir_record *record = &records[0]; - PurpleBuddy *buddy; - - g_free(_uin_p); - - if (records_count < 1) { - purple_debug_error("gg", "ggp_pubdir_get_info_protocol_got: " - "couldn't get info for %u\n", uin); - purple_notify_user_info_add_pair_plaintext(info, NULL, - _("Cannot get user information")); - purple_notify_userinfo(gc, ggp_uin_to_str(uin), info, - NULL, NULL); - purple_notify_user_info_destroy(info); - return; - } - - purple_debug_info("gg", "ggp_pubdir_get_info_protocol_got: %u\n", uin); - g_assert(uin == record->uin); - g_assert(records_count == 1); - - buddy = purple_blist_find_buddy(purple_connection_get_account(gc), - ggp_uin_to_str(uin)); - if (buddy) { - const char *alias; - PurpleStatus *status; - gchar *status_message; - - alias = purple_buddy_get_alias_only(buddy); - if (alias) - purple_notify_user_info_add_pair_plaintext(info, - _("Alias"), alias); - - status = purple_presence_get_active_status( - purple_buddy_get_presence(buddy)); - ggp_status_from_purplestatus(status, &status_message); - purple_notify_user_info_add_pair_plaintext(info, _("Status"), - purple_status_get_name(status)); - if (status_message) { - purple_notify_user_info_add_pair_plaintext(info, - _("Message"), status_message); - } - } - - if (record->nickname) { - purple_notify_user_info_add_pair_plaintext(info, - _("Nickname"), record->nickname); - } - if (record->first_name) { - purple_notify_user_info_add_pair_plaintext(info, - _("First name"), record->first_name); - } - if (record->last_name) { - purple_notify_user_info_add_pair_plaintext(info, - _("Last name"), record->last_name); - } - if (record->gender != GGP_PUBDIR_GENDER_UNSPECIFIED) { - purple_notify_user_info_add_pair_plaintext(info, _("Gender"), - record->gender == GGP_PUBDIR_GENDER_FEMALE ? - _("Female") : _("Male")); - } - if (record->city) { - purple_notify_user_info_add_pair_plaintext(info, _("City"), - record->city); - } - if (record->birth) { - gchar *bday = g_date_time_format(record->birth, "%Y-%m-%d"); - - purple_notify_user_info_add_pair_plaintext(info, _("Birthday"), bday); - - g_free(bday); - } else if (record->age) { - gchar *age_s = g_strdup_printf("%d", record->age); - purple_notify_user_info_add_pair_plaintext(info, _("Age"), - age_s); - g_free(age_s); - } - - purple_notify_userinfo(gc, ggp_uin_to_str(uin), info, NULL, NULL); - purple_notify_user_info_destroy(info); -} - -void -ggp_pubdir_get_info_protocol(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, const gchar *name) -{ - uin_t uin = ggp_str_to_uin(name); - uin_t *uin_p = g_new0(uin_t, 1); - - *uin_p = uin; - - purple_debug_info("gg", "ggp_pubdir_get_info_protocol: %u", uin); - - ggp_pubdir_get_info(gc, uin, ggp_pubdir_get_info_protocol_got, uin_p); -} - -static void -ggp_pubdir_request_buddy_alias_got(PurpleConnection *gc, int records_count, - const ggp_pubdir_record *records, - G_GNUC_UNUSED int next_offset, - G_GNUC_UNUSED gpointer data) -{ - uin_t uin; - const gchar *alias; - - if (records_count < 0) { - purple_debug_error("gg", "ggp_pubdir_request_buddy_alias_got: " - "couldn't get info for user\n"); - return; - } - uin = records[0].uin; - - alias = records[0].label; - if (!alias) { - purple_debug_info("gg", "ggp_pubdir_request_buddy_alias_got: " - "public alias for %u is not available\n", uin); - return; - } - - purple_debug_info("gg", "ggp_pubdir_request_buddy_alias_got: " - "public alias for %u is \"%s\"\n", uin, alias); - - purple_serv_got_alias(gc, ggp_uin_to_str(uin), alias); -} - -void -ggp_pubdir_request_buddy_alias(PurpleConnection *gc, PurpleBuddy *buddy) -{ - uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy)); - - purple_debug_info("gg", "ggp_pubdir_request_buddy_alias: %u", uin); - - ggp_pubdir_get_info(gc, uin, ggp_pubdir_request_buddy_alias_got, NULL); -} - -/******************************************************************************* - * Searching for buddies. - ******************************************************************************/ - -static ggp_pubdir_search_form * -ggp_pubdir_search_form_clone(const ggp_pubdir_search_form *form) -{ - ggp_pubdir_search_form *dup = g_new(ggp_pubdir_search_form, 1); - - dup->nick = g_strdup(form->nick); - dup->city = g_strdup(form->city); - dup->gender = form->gender; - dup->offset = form->offset; - dup->limit = form->limit; - - dup->display_handle = form->display_handle; - - return dup; -} - -static gchar * ggp_pubdir_search_make_query(const ggp_pubdir_search_form *form) -{ - gchar *nick, *city, *gender; - gchar *query; - - if (form->nick && form->nick[0] != '\0') { - gchar *nick_e = g_uri_escape_string(form->nick, NULL, FALSE); - nick = g_strdup_printf("&nick=%s", nick_e); - g_free(nick_e); - } else - nick = g_strdup(""); - - if (form->city && form->city[0] != '\0') { - gchar *city_e = g_uri_escape_string(form->city, NULL, FALSE); - city = g_strdup_printf("&city=%s", city_e); - g_free(city_e); - } else - city = g_strdup(""); - - if (form->gender != GGP_PUBDIR_GENDER_UNSPECIFIED) { - gender = g_strdup_printf("&gender=%d", - form->gender == GGP_PUBDIR_GENDER_MALE ? 2 : 1); - } else - gender = g_strdup(""); - - query = g_strdup_printf("/users.xml?offset=%d&limit=%d%s%s%s", - form->offset, form->limit, nick, city, gender); - - g_free(nick); - g_free(city); - g_free(gender); - - return query; -} - -static void ggp_pubdir_search_got_token(PurpleConnection *gc, - const gchar *token, gpointer _request) -{ - GGPInfo *info = NULL; - gchar *url; - SoupMessage *msg; - ggp_pubdir_request *request = _request; - gchar *query; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - if (!token) { - request->cb(gc, -1, NULL, 0, request->user_data); - ggp_pubdir_request_free(request); - return; - } - - purple_debug_misc("gg", "ggp_pubdir_search_got_token\n"); - - query = ggp_pubdir_search_make_query(request->params.search_form); - - info = purple_connection_get_protocol_data(gc); - - url = g_strdup_printf("http://api.gadu-gadu.pl%s", query); - msg = soup_message_new("GET", url); - soup_message_headers_replace(soup_message_get_request_headers(msg), - "Authorization", token); - soup_session_send_and_read_async(info->http, msg, G_PRIORITY_DEFAULT, NULL, - ggp_pubdir_got_data, request); - - g_object_unref(msg); - g_free(url); - g_free(query); -} - -static void -ggp_pubdir_search_execute(PurpleConnection *gc, - const ggp_pubdir_search_form *form, - ggp_pubdir_request_cb cb, void *user_data) -{ - ggp_pubdir_request *request = g_new0(ggp_pubdir_request, 1); - gchar *url; - ggp_pubdir_search_form *local_form = ggp_pubdir_search_form_clone(form); - gchar *query; - - request->type = GGP_PUBDIR_REQUEST_TYPE_SEARCH; - request->gc = gc; - request->cb = cb; - request->user_data = user_data; - request->params.search_form = local_form; - - query = ggp_pubdir_search_make_query(form); - purple_debug_misc("gg", "ggp_pubdir_search_execute: %s", query); - url = g_strdup_printf("http://api.gadu-gadu.pl%s", query); - ggp_oauth_request(gc, ggp_pubdir_search_got_token, request, "GET", url); - g_free(query); - g_free(url); -} - -static void -ggp_pubdir_search_results_new(PurpleConnection *gc, G_GNUC_UNUSED GList *row, - gpointer _form) -{ - ggp_pubdir_search_form *form = _form; - ggp_pubdir_search(gc, form); -} - -static void -ggp_pubdir_search_results_close(gpointer _form) -{ - ggp_pubdir_search_form *form = _form; - ggp_pubdir_search_form_free(form); -} - -static void -ggp_pubdir_search_results_next(PurpleConnection *gc, G_GNUC_UNUSED GList *row, - gpointer _form) -{ - ggp_pubdir_search_form *form = _form; - ggp_pubdir_search_execute(gc, form, ggp_pubdir_search_results_display, - form); -} - -static void -ggp_pubdir_search_results_add(PurpleConnection *gc, GList *row, - G_GNUC_UNUSED gpointer form) -{ - purple_blist_request_add_buddy(purple_connection_get_account(gc), - g_list_nth_data(row, 0), NULL, - g_list_nth_data(row, 1)); -} - -static void -ggp_pubdir_search_results_im(PurpleConnection *gc, GList *row, - G_GNUC_UNUSED gpointer form) -{ - purple_conversation_present(PURPLE_CONVERSATION(purple_im_conversation_new( - purple_connection_get_account(gc), g_list_nth_data(row, 0)))); -} - -static void -ggp_pubdir_search_results_info(PurpleConnection *gc, GList *row, - G_GNUC_UNUSED gpointer form) -{ - ggp_pubdir_get_info_protocol(NULL, gc, g_list_nth_data(row, 0)); -} - -static void -ggp_pubdir_search_results_display(PurpleConnection *gc, int records_count, - const ggp_pubdir_record *records, - int next_offset, void *_form) -{ - ggp_pubdir_search_form *form = _form; - PurpleNotifySearchResults *results; - int i; - - purple_debug_info("gg", "ggp_pubdir_search_results_display: " - "got %d records (next offset: %d)\n", - records_count, next_offset); - - if (records_count < 0 || - (records_count == 0 && form->offset != 0)) - { - purple_notify_error(gc, GGP_PUBDIR_SEARCH_TITLE, - _("Error while searching for buddies"), NULL, - purple_request_cpar_from_connection(gc)); - ggp_pubdir_search_form_free(form); - return; - } - - if (records_count == 0) { - purple_notify_info(gc, GGP_PUBDIR_SEARCH_TITLE, - _("No matching users found"), - _("There are no users matching your search criteria."), - purple_request_cpar_from_connection(gc)); - ggp_pubdir_search_form_free(form); - return; - } - - form->offset = next_offset; - - results = purple_notify_searchresults_new(); - - purple_notify_searchresults_column_add(results, - purple_notify_searchresults_column_new(_("GG Number"))); - purple_notify_searchresults_column_add(results, - purple_notify_searchresults_column_new(_("Name"))); - purple_notify_searchresults_column_add(results, - purple_notify_searchresults_column_new(_("City"))); - purple_notify_searchresults_column_add(results, - purple_notify_searchresults_column_new(_("Gender"))); - purple_notify_searchresults_column_add(results, - purple_notify_searchresults_column_new(_("Age"))); - - for (i = 0; i < records_count; i++) { - GList *row = NULL; - const ggp_pubdir_record *record = &records[i]; - gchar *gender = NULL, *age = NULL; - - if (record->gender == GGP_PUBDIR_GENDER_MALE) - gender = g_strdup("male"); - else if (record->gender == GGP_PUBDIR_GENDER_FEMALE) - gender = g_strdup("female"); - - if (record->age) - age = g_strdup_printf("%d", record->age); - - row = g_list_append(row, g_strdup(ggp_uin_to_str(record->uin))); - row = g_list_append(row, g_strdup(record->label)); - row = g_list_append(row, g_strdup(record->city)); - row = g_list_append(row, gender); - row = g_list_append(row, age); - purple_notify_searchresults_row_add(results, row); - } - - purple_notify_searchresults_button_add(results, - PURPLE_NOTIFY_BUTTON_ADD, ggp_pubdir_search_results_add); - purple_notify_searchresults_button_add(results, - PURPLE_NOTIFY_BUTTON_IM, ggp_pubdir_search_results_im); - purple_notify_searchresults_button_add(results, - PURPLE_NOTIFY_BUTTON_INFO, ggp_pubdir_search_results_info); - purple_notify_searchresults_button_add_labeled(results, _("New search"), - ggp_pubdir_search_results_new); - if (next_offset != 0) - purple_notify_searchresults_button_add(results, - PURPLE_NOTIFY_BUTTON_CONTINUE, - ggp_pubdir_search_results_next); - - if (!form->display_handle) - form->display_handle = purple_notify_searchresults(gc, - GGP_PUBDIR_SEARCH_TITLE, _("Search results"), NULL, - results, ggp_pubdir_search_results_close, form); - else - purple_notify_searchresults_new_rows(gc, results, - form->display_handle); - g_assert(form->display_handle); -} - -static void -ggp_pubdir_search_request(PurpleConnection *gc, PurpleRequestPage *page) { - ggp_pubdir_search_form *form = g_new0(ggp_pubdir_search_form, 1); - - purple_debug_info("gg", "ggp_pubdir_search_request"); - - form->nick = g_strdup(purple_request_page_get_string(page, "name")); - form->city = g_strdup(purple_request_page_get_string(page, "city")); - form->gender = - GPOINTER_TO_INT(purple_request_page_get_choice(page, "gender")); - form->offset = 0; - form->limit = GGP_PUBDIR_SEARCH_PER_PAGE; - - ggp_pubdir_search_execute(gc, form, ggp_pubdir_search_results_display, - form); -} - -void -ggp_pubdir_search(PurpleConnection *gc, const ggp_pubdir_search_form *form) -{ - PurpleRequestPage *page; - PurpleRequestGroup *group; - PurpleRequestField *field; - PurpleRequestFieldChoice *choice; - - purple_debug_info("gg", "ggp_pubdir_search"); - - page = purple_request_page_new(); - group = purple_request_group_new(NULL); - purple_request_page_add_group(page, group); - - field = purple_request_field_string_new("name", _("Name"), - form ? form->nick : NULL, FALSE); - purple_request_group_add_field(group, field); - - field = purple_request_field_string_new("city", _("City"), - form ? form->city : NULL, FALSE); - purple_request_group_add_field(group, field); - - field = purple_request_field_choice_new( - "gender", _("Gender"), form ? GINT_TO_POINTER(form->gender) : NULL); - choice = PURPLE_REQUEST_FIELD_CHOICE(field); - purple_request_field_choice_add(choice, _("Male or female"), NULL); - purple_request_field_choice_add(choice, _("Male"), - GINT_TO_POINTER(GGP_PUBDIR_GENDER_MALE)); - purple_request_field_choice_add(choice, _("Female"), - GINT_TO_POINTER(GGP_PUBDIR_GENDER_FEMALE)); - purple_request_group_add_field(group, field); - - purple_request_fields(gc, _("Find buddies"), _("Find buddies"), - _("Please, enter your search criteria below"), page, - _("OK"), G_CALLBACK(ggp_pubdir_search_request), - _("Cancel"), NULL, - purple_request_cpar_from_connection(gc), gc); -} - -/******************************************************************************* - * Own profile. - ******************************************************************************/ - -static void -ggp_pubdir_set_info_got_response(GObject *source, GAsyncResult *result, - gpointer data) -{ - SoupMessage *msg = data; - GBytes *response_body = NULL; - const char *buffer = NULL; - gsize size = 0; - GError *error = NULL; - - if (!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(msg))) { - purple_debug_error("gg", "ggp_pubdir_set_info_got_response: failed"); - g_object_unref(msg); - return; - } - g_clear_object(&msg); - - response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), - result, &error); - if (response_body == NULL) { - purple_debug_error("gg", - "ggp_pubdir_set_info_got_response: failed: %s", - error->message); - g_error_free(error); - return; - } - - buffer = g_bytes_get_data(response_body, &size); - purple_debug_info("gg", "ggp_pubdir_set_info_got_response: [%.*s]", - (int)size, buffer); - /* <result><status>0</status></result> */ - - /* TODO: notify about failure */ - - g_bytes_unref(response_body); -} - -static void ggp_pubdir_set_info_got_token(PurpleConnection *gc, - const gchar *token, gpointer _record) -{ - ggp_pubdir_record *record = _record; - GGPInfo *info = NULL; - SoupMessage *msg; - GBytes *body = NULL; - gchar *url; - gchar *request_data; - gchar *name, *surname, *city; - gchar *bday; - uin_t uin = record->uin; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - if (!token) { - /* TODO: notify about failure */ - ggp_pubdir_record_free(record, 1); - return; - } - - info = purple_connection_get_protocol_data(gc); - - name = g_uri_escape_string(record->first_name, NULL, FALSE); - surname = g_uri_escape_string(record->last_name, NULL, FALSE); - city = g_uri_escape_string(record->city, NULL, FALSE); - bday = g_date_time_format(record->birth, "%Y-%m-%d"); - - request_data = g_strdup_printf( - "name=%s&" - "surname=%s&" - "birth=%sT10:00:00%%2B00:00&" - "birth_priv=2&" - "gender=%d&" - "gender_priv=2&" - "city=%s&" - "province=%d", - name, surname, - bday, - record->gender, - city, - record->province); - - g_free(name); - g_free(surname); - g_free(city); - g_free(bday); - - if (purple_debug_is_verbose() && purple_debug_is_unsafe()) { - purple_debug_misc("gg", "ggp_pubdir_set_info_got_token: " - "query [%s]\n", request_data); - } - - url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u.xml", uin); - msg = soup_message_new("PUT", url); - soup_message_headers_replace(soup_message_get_request_headers(msg), - "Authorization", token); - body = g_bytes_new_take(request_data, strlen(request_data)); - soup_message_set_request_body_from_bytes(msg, - "application/x-www-form-urlencoded", - body); - g_bytes_unref(body); - soup_session_send_and_read_async(info->http, msg, G_PRIORITY_DEFAULT, NULL, - ggp_pubdir_set_info_got_response, msg); - - g_free(url); - ggp_pubdir_record_free(record, 1); -} - -static void -ggp_pubdir_set_info_request(PurpleConnection *gc, PurpleRequestPage *page) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - gchar *url; - uin_t uin = ggp_str_to_uin(purple_contact_info_get_username(info)); - ggp_pubdir_record *record = g_new0(ggp_pubdir_record, 1); - gchar *birth_s; - - purple_debug_info("gg", "ggp_pubdir_set_info_request"); - - record->uin = uin; - record->first_name = g_strdup(purple_request_page_get_string(page, - "first_name")); - record->last_name = g_strdup(purple_request_page_get_string(page, - "last_name")); - record->gender = GPOINTER_TO_INT(purple_request_page_get_choice(page, - "gender")); - record->city = g_strdup(purple_request_page_get_string(page, "city")); - record->province = GPOINTER_TO_INT(purple_request_page_get_choice(page, - "province")); - - birth_s = g_strdup_printf("%sT10:00:00+00:00", - purple_request_page_get_string(page, "birth_date")); - record->birth = g_date_time_new_from_iso8601(birth_s, NULL); - g_free(birth_s); - purple_debug_info("gg", "ggp_pubdir_set_info_request: birth [%lu][%s]", - g_date_time_to_unix(record->birth), - purple_request_page_get_string(page, "birth_date")); - - url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u.xml", uin); - ggp_oauth_request(gc, ggp_pubdir_set_info_got_token, record, "PUT", url); - g_free(url); -} - -static void -ggp_pubdir_set_info_dialog(PurpleConnection *gc, int records_count, - const ggp_pubdir_record *records, - G_GNUC_UNUSED int next_offset, - G_GNUC_UNUSED gpointer data) -{ - PurpleRequestPage *page; - PurpleRequestGroup *group; - PurpleRequestField *field; - PurpleRequestFieldChoice *choice; - gchar *bday = NULL; - gsize i; - const ggp_pubdir_record *record; - - purple_debug_info("gg", "ggp_pubdir_set_info_dialog (record: %d)", - records_count); - - record = (records_count == 1 ? &records[0] : NULL); - - page = purple_request_page_new(); - group = purple_request_group_new(NULL); - purple_request_page_add_group(page, group); - - field = purple_request_field_string_new("first_name", _("First name"), - record ? record->first_name : NULL, - FALSE); - purple_request_group_add_field(group, field); - - field = purple_request_field_string_new("last_name", _("Last name"), - record ? record->last_name : NULL, - FALSE); - purple_request_group_add_field(group, field); - - field = purple_request_field_choice_new( - "gender", _("Gender"), - record ? GINT_TO_POINTER(record->gender) - : GGP_PUBDIR_GENDER_UNSPECIFIED); - choice = PURPLE_REQUEST_FIELD_CHOICE(field); - purple_request_field_set_required(field, TRUE); - purple_request_field_choice_add(choice, _("Male"), - GINT_TO_POINTER(GGP_PUBDIR_GENDER_MALE)); - purple_request_field_choice_add(choice, _("Female"), - GINT_TO_POINTER(GGP_PUBDIR_GENDER_FEMALE)); - purple_request_group_add_field(group, field); - - if(record != NULL && record->birth != NULL) { - bday = g_date_time_format(record->birth, "%Y-%m-%d"); - } - - field = purple_request_field_string_new( - "birth_date", _("Birth Day"), bday, - FALSE); - g_free(bday); - purple_request_field_set_required(field, TRUE); - purple_request_group_add_field(group, field); - - field = purple_request_field_string_new( - "city", _("City"), record ? record->city : NULL, FALSE); - purple_request_group_add_field(group, field); - - /* Translators: This word is basically used to describe a Polish - province. Gadu-Gadu users outside of Poland might choose to enter some - equivalent value for themselves. For example, users in the USA might - use their state (e.g. New York). If there is an equivalent term for - your language, feel free to use it. Otherwise it's probably acceptable - to leave it changed or transliterate it into your alphabet. */ - field = purple_request_field_choice_new("province", _("Voivodeship"), 0); - choice = PURPLE_REQUEST_FIELD_CHOICE(field); - purple_request_group_add_field(group, field); - for (i = 0; i < ggp_pubdir_provinces_count; i++) { - purple_request_field_choice_add(choice, ggp_pubdir_provinces[i], - GINT_TO_POINTER(i)); - if (record && i == record->province) { - purple_request_field_choice_set_value(choice, GINT_TO_POINTER(i)); - purple_request_field_choice_set_default_value(choice, - GINT_TO_POINTER(i)); - } - } - - purple_request_fields(gc, _("Set User Info"), _("Set User Info"), NULL, - page, _("OK"), - G_CALLBACK(ggp_pubdir_set_info_request), _("Cancel"), - NULL, purple_request_cpar_from_connection(gc), gc); -} - -void -ggp_pubdir_set_info(PurpleConnection *gc) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - - ggp_pubdir_get_info(gc, - ggp_str_to_uin(purple_contact_info_get_username(info)), - ggp_pubdir_set_info_dialog, NULL); -}
--- a/libpurple/protocols/gg/pubdir-prpl.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_PUBDIR_PRPL_H -#define PURPLE_GG_PUBDIR_PRPL_H - -#include <purple.h> -#include <libgadu.h> - -typedef enum -{ - GGP_PUBDIR_GENDER_UNSPECIFIED, - GGP_PUBDIR_GENDER_FEMALE, - GGP_PUBDIR_GENDER_MALE, -} ggp_pubdir_gender; - -typedef struct -{ - uin_t uin; - gchar *label; - gchar *nickname; - gchar *first_name; - gchar *last_name; - ggp_pubdir_gender gender; - gchar *city; - unsigned int province; - GDateTime *birth; - unsigned int age; -} ggp_pubdir_record; - -typedef struct _ggp_pubdir_search_form ggp_pubdir_search_form; - -typedef void (*ggp_pubdir_request_cb)(PurpleConnection *gc, int records_count, - const ggp_pubdir_record *records, int next_offset, void *user_data); - -void ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin, - ggp_pubdir_request_cb cb, void *user_data); - -void ggp_pubdir_get_info_protocol(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *name); -void ggp_pubdir_request_buddy_alias(PurpleConnection *gc, PurpleBuddy *buddy); - -void ggp_pubdir_search(PurpleConnection *gc, - const ggp_pubdir_search_form *form); - -void ggp_pubdir_set_info(PurpleConnection *gc); - -#endif /* PURPLE_GG_PUBDIR_PRPL_H */
--- a/libpurple/protocols/gg/purplew.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "purplew.h" - -#include "tcpsocket.h" - -#include <glib/gi18n-lib.h> - -guint ggp_purplew_http_input_add(struct gg_http *http_req, - PurpleInputFunction func, gpointer user_data) -{ - if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_purplew_http_input_add: " - "[req=%p, fd=%d, cond=%d]\n", - http_req, http_req->fd, http_req->check); - } - return purple_input_add(http_req->fd, - ggp_tcpsocket_inputcond_gg_to_purple(http_req->check), - func, user_data); -} - -static void -ggp_purplew_request_processing_cancel(ggp_purplew_request_processing_handle *handle, - G_GNUC_UNUSED gint id) -{ - handle->cancel_cb(handle->gc, handle->user_data); - g_free(handle); -} - -ggp_purplew_request_processing_handle * ggp_purplew_request_processing( - PurpleConnection *gc, const gchar *msg, void *user_data, - ggp_purplew_request_processing_cancel_cb cancel_cb) -{ - ggp_purplew_request_processing_handle *handle = - g_new(ggp_purplew_request_processing_handle, 1); - - handle->gc = gc; - handle->cancel_cb = cancel_cb; - handle->user_data = user_data; - handle->request_handle = purple_request_action(gc, _("Please wait..."), - (msg ? msg : _("Please wait...")), NULL, - PURPLE_DEFAULT_ACTION_NONE, - purple_request_cpar_from_connection(gc), handle, 1, - _("Cancel"), G_CALLBACK(ggp_purplew_request_processing_cancel)); - - return handle; -} - -void ggp_purplew_request_processing_done( - ggp_purplew_request_processing_handle *handle) -{ - purple_request_close(PURPLE_REQUEST_ACTION, handle->request_handle); - g_free(handle); -} - -PurpleGroup * ggp_purplew_buddy_get_group_only(PurpleBuddy *buddy) -{ - PurpleGroup *group = purple_buddy_get_group(buddy); - if (!group) - return NULL; - if (0 == g_strcmp0(PURPLE_BLIST_DEFAULT_GROUP_NAME, - purple_group_get_name(group))) - { - return NULL; - } - if (0 == g_strcmp0("Buddies", purple_group_get_name(group))) - return NULL; - return group; -} - -GList * ggp_purplew_group_get_buddies(PurpleGroup *group, PurpleAccount *account) -{ - GList *buddies = NULL; - PurpleBlistNode *gnode, *cnode, *bnode; - - g_return_val_if_fail(group != NULL, NULL); - - gnode = PURPLE_BLIST_NODE(group); - for (cnode = gnode->child; cnode; cnode = cnode->next) { - if (!PURPLE_IS_META_CONTACT(cnode)) - continue; - for (bnode = cnode->child; bnode; bnode = bnode->next) { - PurpleBuddy *buddy; - if (!PURPLE_IS_BUDDY(bnode)) - continue; - - buddy = PURPLE_BUDDY(bnode); - if (account == NULL || - purple_buddy_get_account(buddy) == account) - { - buddies = g_list_append(buddies, buddy); - } - } - } - - return buddies; -} - -GList * ggp_purplew_account_get_groups(PurpleAccount *account, gboolean exclusive) -{ - PurpleBlistNode *bnode; - GList *groups = NULL; - for (bnode = purple_blist_get_default_root(); bnode; - bnode = bnode->next) { - PurpleGroup *group; - GSList *accounts; - gboolean have_specified = FALSE, have_others = FALSE; - - if (!PURPLE_IS_GROUP(bnode)) - continue; - - group = PURPLE_GROUP(bnode); - for (accounts = purple_group_get_accounts(group); accounts; - accounts = g_slist_delete_link(accounts, accounts)) - { - if (accounts->data == account) - have_specified = TRUE; - else - have_others = TRUE; - } - - if (have_specified && (!exclusive || !have_others)) - groups = g_list_append(groups, group); - } - return groups; -}
--- a/libpurple/protocols/gg/purplew.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_PURPLEW_H -#define PURPLE_GG_PURPLEW_H - -#include <purple.h> -#include <libgadu.h> - -/** - * Adds an input handler in purple event loop for http request. - * - * @see purple_input_add - * - * @param http_req Http connection to watch. - * @param func The callback function for data. - * @param user_data User-specified data. - * - * @return The resulting handle (will be greater than 0). - */ -guint ggp_purplew_http_input_add(struct gg_http *http_req, - PurpleInputFunction func, gpointer user_data); - -typedef void (*ggp_purplew_request_processing_cancel_cb)(PurpleConnection *gc, - void *user_data); - -typedef struct -{ - PurpleConnection *gc; - ggp_purplew_request_processing_cancel_cb cancel_cb; - void *request_handle; - void *user_data; -} ggp_purplew_request_processing_handle; - -ggp_purplew_request_processing_handle * ggp_purplew_request_processing( - PurpleConnection *gc, const gchar *msg, void *user_data, - ggp_purplew_request_processing_cancel_cb oncancel); - -void ggp_purplew_request_processing_done( - ggp_purplew_request_processing_handle *handle); - -/* ignores default group */ -PurpleGroup * ggp_purplew_buddy_get_group_only(PurpleBuddy *buddy); - -GList * ggp_purplew_group_get_buddies(PurpleGroup *group, PurpleAccount *account); - -/* you must g_free returned list */ -GList * ggp_purplew_account_get_groups(PurpleAccount *account, gboolean exclusive); - -#endif /* PURPLE_GG_PURPLEW_H */
--- a/libpurple/protocols/gg/resolver-purple.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,205 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <purple.h> -#include "libpurple/glibcompat.h" - -#include <libgadu.h> -#include "resolver-purple.h" - -#include <gio/gio.h> - -static int ggp_resolver_purple_start(int *fd, void **private_data, - const char *hostname); - -static void ggp_resolver_purple_cleanup(void **private_data, int force); - -static void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer data); - -typedef struct -{ - GCancellable *cancellable; - - /** - * File descriptors: - * pipes[0] - for reading - * pipes[1] - for writing - */ - int pipes[2]; -} ggp_resolver_purple_data; - - -extern void ggp_resolver_purple_setup(void) -{ - if (gg_global_set_custom_resolver(ggp_resolver_purple_start, - ggp_resolver_purple_cleanup) != 0) - { - purple_debug_error("gg", "failed to set custom resolver\n"); - } -} - -void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer cbdata) { - GList *addresses = NULL, *in_addrs = NULL, *l = NULL; - GError *error = NULL; - gsize native_size = 0; /* this is kind of dirty, but it'll be initialized before we use it */ - - ggp_resolver_purple_data *data = (ggp_resolver_purple_data*)cbdata; - const int fd = data->pipes[1]; - - addresses = g_resolver_lookup_by_name_finish(G_RESOLVER(sender), - res, &error); - if(addresses == NULL) { - purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n", - error->message); - - g_error_free(error); - } else { - purple_debug_misc("gg", "ggp_resolver_purple_cb succeeded: (%p, %p)\n", - addresses, cbdata); - } - - g_object_unref(data->cancellable); - data->cancellable = NULL; - - for(l = addresses; l; l = l->next) { - GInetAddress *inet_address = G_INET_ADDRESS(l->data); - GSocketFamily family = G_SOCKET_FAMILY_INVALID; - gchar *ip_address = g_inet_address_to_string(inet_address); - - family = g_inet_address_get_family(inet_address); - - switch(family) { - case G_SOCKET_FAMILY_IPV4: - purple_debug_misc("gg", "ggp_resolver_purple_cb " - "ipv4: %s\n", ip_address); - - native_size = g_inet_address_get_native_size(inet_address); - in_addrs = g_list_append(in_addrs, g_memdup2(g_inet_address_to_bytes(inet_address), native_size)); - - break; - case G_SOCKET_FAMILY_IPV6: - purple_debug_misc("gg", "ggp_resolver_purple_cb " - "ipv6 (ignore): %s\n", ip_address); - - break; - default: - purple_debug_warning("gg", "ggp_resolver_purple_cb " - "unexpected sa_family: %d\n", - family); - - break; - } - - g_free(ip_address); - } - - for(l = in_addrs; l; l = l->next) { - gint write_size = native_size; - if(write(fd, l->data, write_size) != write_size) { - purple_debug_error("gg", - "ggp_resolver_purple_cb write error on %p\n", l->data); - } - - g_free(l->data); - } - - g_list_free(in_addrs); - g_resolver_free_addresses(addresses); -} - -int ggp_resolver_purple_start(int *fd, void **private_data, - const char *hostname) -{ - ggp_resolver_purple_data *data; - GResolver *resolver; - - purple_debug_misc("gg", "ggp_resolver_purple_start(%p, %p, \"%s\")\n", - fd, private_data, hostname); - - data = g_new0(ggp_resolver_purple_data, 1); - *private_data = (void*)data; - data->cancellable = NULL; - data->pipes[0] = 0; - data->pipes[1] = 0; - - if (purple_input_pipe(data->pipes) != 0) { - purple_debug_error("gg", "ggp_resolver_purple_start: " - "unable to create pipe\n"); - ggp_resolver_purple_cleanup(private_data, 0); - return -1; - } - - *fd = data->pipes[0]; - - /* account and port is unknown in this context */ - data->cancellable = g_cancellable_new(); - - resolver = g_resolver_get_default(); - g_resolver_lookup_by_name_async(resolver, - hostname, - data->cancellable, - ggp_resolver_purple_cb, - (gpointer)data); - g_object_unref(resolver); - - if (!data->cancellable) { - purple_debug_error("gg", "ggp_resolver_purple_start: " - "unable to call purple_dnsquery_a\n"); - ggp_resolver_purple_cleanup(private_data, 0); - return -1; - } - - return 0; -} - -void ggp_resolver_purple_cleanup(void **private_data, int force) -{ - ggp_resolver_purple_data *data = - (ggp_resolver_purple_data*)(*private_data); - - purple_debug_misc("gg", "ggp_resolver_purple_cleanup(%p, %d)\n", - private_data, force); - - if (!data) - return; - *private_data = NULL; - - if (G_IS_CANCELLABLE(data->cancellable)) { - g_cancellable_cancel(data->cancellable); - - g_object_unref(data->cancellable); - } - - if (data->pipes[0]) - close(data->pipes[0]); - if (data->pipes[1]) - close(data->pipes[1]); - - g_free(data); -}
--- a/libpurple/protocols/gg/resolver-purple.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_RESOLVER_PURPLE_H -#define PURPLE_GG_RESOLVER_PURPLE_H - -/** - * Registers custom resolver for libgadu, that uses libpurple for DNS queries. - */ -void ggp_resolver_purple_setup(void); - -#endif /* PURPLE_GG_RESOLVER_PURPLE_H */
--- a/libpurple/protocols/gg/resources/gg.gresource.xml Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<gresources> - <gresource prefix="/im/pidgin/libpurple/gg"> - <file>icons/16x16/apps/im-gadu-gadu.png</file> - <file>icons/16x16/apps/scalable/im-gadu-gadu.svg</file> - <file>icons/22x22/apps/im-gadu-gadu.png</file> - <file>icons/22x22/apps/scalable/im-gadu-gadu.svg</file> - <file>icons/48x48/apps/im-gadu-gadu.png</file> - <file>icons/scalable/apps/im-gadu-gadu.svg</file> - </gresource> -</gresources>
--- a/libpurple/protocols/gg/resources/icons/16x16/apps/scalable/im-gadu-gadu.svg Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,365 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16px" - height="16px" - id="svg10335" - sodipodi:version="0.32" - inkscape:version="0.46" - sodipodi:docname="emote-select.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/hbons/Bureaublad/gadu-gadu.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs10337"> - <linearGradient - id="linearGradient8687" - inkscape:collect="always"> - <stop - id="stop8689" - offset="0" - style="stop-color:#f57575;stop-opacity:1" /> - <stop - id="stop8691" - offset="1" - style="stop-color:#fea523;stop-opacity:0;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient8653"> - <stop - style="stop-color:#a40000;stop-opacity:1;" - offset="0" - id="stop8655" /> - <stop - style="stop-color:#ef2929;stop-opacity:1" - offset="1" - id="stop8657" /> - </linearGradient> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 8 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="16 : 8 : 1" - inkscape:persp3d-origin="8 : 5.3333333 : 1" - id="perspective44" /> - <linearGradient - id="linearGradient11170" - inkscape:collect="always"> - <stop - id="stop11172" - offset="0" - style="stop-color:#000000;stop-opacity:1" /> - <stop - id="stop11174" - offset="1" - style="stop-color:#2e3436;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient11164" - inkscape:collect="always"> - <stop - id="stop11166" - offset="0" - style="stop-color:#000000;stop-opacity:1" /> - <stop - id="stop11168" - offset="1" - style="stop-color:#2e3436;stop-opacity:0;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient22870"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop22872" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop22874" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient22870" - id="linearGradient20933" - gradientUnits="userSpaceOnUse" - x1="-11.187567" - y1="-14.181667" - x2="31.90255" - y2="35.477989" /> - <linearGradient - id="linearGradient11461" - inkscape:collect="always"> - <stop - id="stop11463" - offset="0" - style="stop-color:#fbfeac;stop-opacity:1" /> - <stop - id="stop11465" - offset="1" - style="stop-color:#eedb3c;stop-opacity:0;" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient11461" - id="radialGradient20931" - gradientUnits="userSpaceOnUse" - cx="11.806158" - cy="10.04414" - fx="11.88395" - fy="6.1128922" - r="10.561975" - gradientTransform="matrix(1.9034559,3.0329373e-8,-4.2282289e-8,2.6533656,-10.666343,-17.069444)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient22526" - id="linearGradient20942" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.8000001,0,0,0.8980646,-0.6999993,-2.2354831)" - x1="8.5062485" - y1="9.7487373" - x2="8.7451591" - y2="10.765122" /> - <linearGradient - inkscape:collect="always" - id="linearGradient22526"> - <stop - style="stop-color:#f57575;stop-opacity:1" - offset="0" - id="stop22528" /> - <stop - style="stop-color:#fea523;stop-opacity:0;" - offset="1" - id="stop22530" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8687" - id="linearGradient20915" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(7.000002,1)" - x1="9.2937651" - y1="8.8493233" - x2="8.7171106" - y2="10" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient11164" - id="linearGradient11158" - gradientUnits="userSpaceOnUse" - x1="9.432662" - y1="9.6526775" - x2="10.732871" - y2="9.6526775" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient11170" - id="linearGradient11160" - gradientUnits="userSpaceOnUse" - x1="9.432662" - y1="9.6526775" - x2="10.732871" - y2="9.6526775" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8653" - id="linearGradient8659" - x1="14.605568" - y1="14.845765" - x2="9.3490162" - y2="3.9909718" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="31.392433" - inkscape:cx="15.513311" - inkscape:cy="8.506005" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - inkscape:snap-nodes="false" - inkscape:snap-bbox="true" - objecttolerance="10" - gridtolerance="10" - inkscape:window-width="1440" - inkscape:window-height="847" - inkscape:window-x="0" - inkscape:window-y="0"> - <inkscape:grid - type="xygrid" - id="grid10376" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata10340"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer"> - <rect - style="opacity:1;fill:#a40000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8683" - width="2.0000002" - height="2" - x="12" - y="12" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#a40000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8685" - width="2.0000002" - height="2" - x="2" - y="12" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8681" - width="2.0000002" - height="2" - x="12" - y="2" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8679" - width="2.0000002" - height="2" - x="1.9999998" - y="2" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#a40000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8675" - width="2.0000002" - height="2" - x="14" - y="7" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8671" - width="2.0000002" - height="2" - x="-2.3841858e-07" - y="7" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#a40000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8665" - width="2.0000002" - height="2" - x="7" - y="14" - rx="1" - ry="1" /> - <rect - style="opacity:1;fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect8663" - width="2.0000002" - height="2" - x="7" - y="0" - rx="1" - ry="1" /> - <rect - inkscape:label="22x22" - y="-0.90471238" - x="-0.90471238" - height="17.809425" - width="17.809425" - id="rect6749" - style="opacity:0;fill:#d3d7cf;fill-opacity:0;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - transform="matrix(0.651488,0,0,0.651488,0.30843,0.8446922)" - d="M 21.781414,10.983024 A 9.975256,9.975256 0 1 1 1.8309021,10.983024 A 9.975256,9.975256 0 1 1 21.781414,10.983024 z" - sodipodi:ry="9.975256" - sodipodi:rx="9.975256" - sodipodi:cy="10.983024" - sodipodi:cx="11.806158" - id="path17960" - style="opacity:1;fill:#fcaf3e;fill-opacity:1;stroke:url(#linearGradient8659);stroke-width:1.53875661000000008;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;enable-background:new" - sodipodi:type="arc" /> - <path - transform="matrix(0.5513643,0,0,0.5513643,1.490506,1.944353)" - d="M 21.781414,10.983024 A 9.975256,9.975256 0 1 1 1.8309021,10.983024 A 9.975256,9.975256 0 1 1 21.781414,10.983024 z" - sodipodi:ry="9.975256" - sodipodi:rx="9.975256" - sodipodi:cy="10.983024" - sodipodi:cx="11.806158" - id="path17964" - style="opacity:1;fill:url(#radialGradient20931);fill-opacity:1;stroke:url(#linearGradient20933);stroke-width:1.81368327;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;enable-background:new" - sodipodi:type="arc" /> - <path - id="path17966" - d="M 8.5000005,6.7451615 C 8.5000005,7.9844904 7.604002,8.9903231 6.500001,8.9903231 C 5.3959999,8.9903231 4.5000001,7.9844904 4.5000001,6.7451615 C 4.5000001,5.5058325 5.3959999,4.5000005 6.500001,4.5000005 C 7.604002,4.5000005 8.5000005,5.5058325 8.5000005,6.7451615 z" - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:url(#linearGradient20942);stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;display:inline;enable-background:new" /> - <path - sodipodi:nodetypes="cscsc" - id="path17974" - d="M 11,10 C 10.887023,11.226829 9.4422911,12 8.0000003,12 C 6.5577095,12 5.2085418,11.396721 5,10 C 5.6322481,10.739405 6.7426661,11.065616 8.0000003,11.065616 C 9.2573337,11.065616 10.367752,10.739405 11,10 z" - style="opacity:1;fill:#b40c0c;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;enable-background:new" /> - <a - style="opacity:1;display:inline;enable-background:new" - id="a22276" - transform="matrix(0.8295523,0,0,0.9130993,-3.698956,-3.261344)"> - <path - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:url(#linearGradient20915);stroke-width:1.14899766;stroke-miterlimit:4;stroke-opacity:1;display:inline;enable-background:new" - d="M 18.5,11 C 18.5,12.38 17.380001,13.5 16,13.5 C 14.62,13.5 13.5,12.38 13.5,11 C 13.5,9.62 14.62,8.5 16,8.5 C 17.380001,8.5 18.5,9.62 18.5,11 z" - id="path22835" /> - </a> - <path - transform="matrix(0.9747196,0,0,0.5150957,-2.4615398,2.0279474)" - d="M 10.732871,9.6526775 A 1.0259361,1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361,1.9413869 0 1 1 10.732871,9.6526775 z" - sodipodi:ry="1.9413869" - sodipodi:rx="1.0259361" - sodipodi:cy="9.6526775" - sodipodi:cx="9.7069349" - id="path17968" - style="opacity:1;fill:url(#linearGradient11160);fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;enable-background:new" - sodipodi:type="arc" /> - <path - transform="matrix(-0.9747196,0,0,0.5150957,18.46154,2.0279474)" - d="M 10.732871,9.6526775 A 1.0259361,1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361,1.9413869 0 1 1 10.732871,9.6526775 z" - sodipodi:ry="1.9413869" - sodipodi:rx="1.0259361" - sodipodi:cy="9.6526775" - sodipodi:cx="9.7069349" - id="path11156" - style="opacity:1;fill:url(#linearGradient11158);fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;enable-background:new" - sodipodi:type="arc" /> - </g> -</svg>
--- a/libpurple/protocols/gg/resources/icons/22x22/apps/scalable/im-gadu-gadu.svg Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="24" - height="24" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/protocols/22/scalable" - sodipodi:docname="gadu-gadu.svg" - inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/protocols/22/gadu-gadu.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4"> - <linearGradient - inkscape:collect="always" - id="linearGradient3150"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop3152" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop3154" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3150" - id="radialGradient3156" - cx="10.748654" - cy="10.457643" - fx="10.748654" - fy="10.457643" - r="6.6449099" - gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="24.007726" - inkscape:cx="16.146337" - inkscape:cy="13.950539" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - showguides="true" - inkscape:guide-bbox="true" - fill="#fce94f" - inkscape:window-width="1268" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="25" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1"> - <rect - style="opacity:1;fill:#c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2235" - width="2.0000005" - height="3.000001" - x="-0.29289341" - y="7.3639612" - transform="matrix(0.707107,-0.707107,0.707107,0.707107,-1,1)" /> - <rect - style="opacity:1;fill:#c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2239" - width="2.0000033" - height="3.0000048" - x="-17.970564" - y="8.0710697" - transform="matrix(-0.707107,-0.707107,0.707107,-0.707107,-1,1)" /> - <path - sodipodi:type="arc" - style="opacity:0.4;fill:url(#radialGradient3156);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3140" - sodipodi:cx="10.748654" - sodipodi:cy="10.457643" - sodipodi:rx="6.6449099" - sodipodi:ry="2.3675451" - d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1 4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1 17.393564 10.457643 z" - transform="matrix(1.429666,0,0,1.267135,-3.866981,6.748756)" /> - <rect - style="opacity:1;fill:#db2424;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2192" - width="1.9907103" - height="3" - x="12" - y="1" - transform="translate(-1,1)" /> - <rect - style="opacity:1;fill:#db2424;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2203" - width="2" - height="3" - x="12" - y="18" - transform="translate(-1,1)" /> - <rect - style="opacity:1;fill:#db2424;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2211" - width="2" - height="3.4306233" - x="-12" - y="3" - transform="matrix(0,-1,1,0,-1,1)" /> - <rect - style="opacity:1;fill:#db2424;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2213" - width="2" - height="3" - x="-12" - y="20" - transform="matrix(0,-1,1,0,-1,1)" /> - <rect - style="opacity:1;fill:#c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2237" - width="2.0000019" - height="3.0000029" - x="-0.29289412" - y="23.57716" - transform="matrix(0.707107,-0.707107,0.707107,0.707107,-1,1)" /> - <rect - style="opacity:1;fill:#c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2241" - width="2.0000048" - height="3.0000067" - x="-17.970566" - y="-8.24265" - transform="matrix(-0.707107,-0.707107,0.707107,-0.707107,-1,1)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#fce94f;fill-opacity:1;stroke:#c00;stroke-width:0.73921776;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2217" - sodipodi:cx="8.0702047" - sodipodi:cy="8.0363102" - sodipodi:rx="5.5372205" - sodipodi:ry="5.5372205" - d="M 13.607425 8.0363102 A 5.5372205 5.5372205 0 1 1 2.5329843,8.0363102 A 5.5372205 5.5372205 0 1 1 13.607425 8.0363102 z" - transform="matrix(1.354195,0,0,1.35137,1.070845,1.157102)" /> - <path - sodipodi:type="arc" - style="opacity:0.7;fill:none;fill-opacity:1;stroke:#c4a000;stroke-width:0.85407299;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.4848485" - id="path2222" - sodipodi:cx="8.0702047" - sodipodi:cy="8.0363102" - sodipodi:rx="5.5372205" - sodipodi:ry="5.5372205" - d="M 13.607425 8.0363102 A 5.5372205 5.5372205 0 1 1 2.5329843,8.0363102 A 5.5372205 5.5372205 0 1 1 13.607425 8.0363102 z" - transform="matrix(1.171277,0,0,1.170443,2.525066,2.61184)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2243" - sodipodi:cx="9.8489876" - sodipodi:cy="10.583912" - sodipodi:rx="1.2626907" - sodipodi:ry="1.0417198" - d="M 11.111678 10.583912 A 1.2626907 1.0417198 0 1 1 8.5862969,10.583912 A 1.2626907 1.0417198 0 1 1 11.111678 10.583912 z" - transform="matrix(0,1.18426,-0.959955,0,20.16009,-1.168408)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2245" - sodipodi:cx="9.8489876" - sodipodi:cy="10.583912" - sodipodi:rx="1.2626907" - sodipodi:ry="1.0417198" - d="M 11.111678 10.583912 A 1.2626907 1.0417198 0 1 1 8.5862969,10.583912 A 1.2626907 1.0417198 0 1 1 11.111678 10.583912 z" - transform="matrix(0,-1.187938,0.959951,0,3.839963,22.19998)" /> - <path - style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1.10482609;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 17.0113,10.955978 C 17.0113,13.182328 15.218558,14.007827 13,14.007827 C 10.819611,14.007827 9.0496187,13.101106 8.9887006,10.913915 L 8,10.942262 C 8.0756746,13.659262 10.29145,15 13,15 C 15.758926,15 17.999999,13.724591 18,10.955978 L 17.0113,10.955978 z " - id="path2247" - sodipodi:nodetypes="csccscc" - transform="translate(-1,1)" /> - </g> -</svg>
--- a/libpurple/protocols/gg/resources/icons/scalable/apps/im-gadu-gadu.svg Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="48px" - height="48px" - id="svg1307" - sodipodi:version="0.32" - inkscape:version="0.46" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/protocols/48/scalable" - sodipodi:docname="gadu-gadu.svg" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/protocols/48/gadu-gadu.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs1309"> - <linearGradient - inkscape:collect="always" - id="linearGradient2447"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop2449" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop2451" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3150"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop3152" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop3154" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3150" - id="radialGradient3156" - cx="10.748654" - cy="10.457643" - fx="10.748654" - fy="10.457643" - r="6.6449099" - gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient2233"> - <stop - style="stop-color:#eeeeec;stop-opacity:1;" - offset="0" - id="stop2235" /> - <stop - style="stop-color:#eeeeec;stop-opacity:0;" - offset="1" - id="stop2237" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2233" - id="linearGradient2279" - gradientUnits="userSpaceOnUse" - x1="24.450865" - y1="5.1375499" - x2="24.450865" - y2="31.487988" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2447" - id="linearGradient2453" - x1="24.5" - y1="0.33943355" - x2="24.5" - y2="19.724688" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="15.004828" - inkscape:cx="40.53287" - inkscape:cy="23.900599" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - fill="#ef2929" - showguides="true" - inkscape:guide-bbox="true" - inkscape:window-width="1268" - inkscape:window-height="972" - inkscape:window-x="6" - inkscape:window-y="21" /> - <metadata - id="metadata1312"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer"> - <path - sodipodi:type="arc" - style="opacity:0.5;fill:url(#radialGradient3156);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3140" - sodipodi:cx="10.748654" - sodipodi:cy="10.457643" - sodipodi:rx="6.6449099" - sodipodi:ry="2.3675451" - d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1 4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1 17.393564 10.457643 z" - transform="matrix(3.160314,0,0,2.745459,-9.969125,9.788968)" /> - <path - style="opacity:1;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:0.9999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 22.5,4.5130623 L 22.5,8.6366327 C 19.782905,9.0005399 17.277282,10.079925 15.21875,11.698071 L 12.0625,8.5116761 L 9.5,11.073287 L 12.6875,14.259683 C 11.068793,16.317502 9.9577835,18.791017 9.59375,21.50717 L 5.5,21.50717 L 5.5,25.505784 L 9.59375,25.505784 C 9.9535644,28.234089 11.062591,30.718808 12.6875,32.78451 L 9.5,35.970906 L 12.0625,38.501278 L 15.21875,35.346123 C 17.277282,36.964269 19.782905,38.043654 22.5,38.407561 L 22.5,42.499891 L 26.5,42.499891 L 26.5,38.407561 C 29.229107,38.042044 31.717452,36.944842 33.78125,35.314883 L 36.96875,38.501278 L 39.5,35.970906 L 36.3125,32.78451 C 37.936789,30.719597 39.014761,28.232873 39.375,25.505784 L 43.5,25.505784 L 43.5,21.50717 L 39.375,21.50717 C 39.010966,18.791018 37.931208,16.317502 36.3125,14.259683 L 39.5,11.073287 L 36.96875,8.5116761 L 33.78125,11.698071 L 33.75,11.698071 C 31.691468,10.079924 29.217095,9.0005401 26.5,8.6366327 L 26.5,4.5130623 L 22.5,4.5130623 z M 23.8125,11.354441 C 24.033452,11.344807 24.274977,11.354441 24.5,11.354441 C 31.700731,11.354441 36.65625,16.339482 36.65625,23.537717 C 36.656248,30.735953 31.700731,35.689753 24.5,35.689753 C 17.29927,35.689754 12.502002,30.735951 12.502002,23.537717 C 12.502002,16.564428 16.962974,11.653081 23.8125,11.354441 z " - id="path2394" - sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccssssc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1" - inkscape:original="M 22.5 4.5 L 22.5 8.625 C 19.782905 8.988907 17.277282 10.069354 15.21875 11.6875 L 12.0625 8.5 L 9.5 11.0625 L 12.6875 14.25 C 11.068793 16.307819 9.9577835 18.783847 9.59375 21.5 L 5.5 21.5 L 5.5 25.5 L 9.59375 25.5 C 9.9535644 28.228306 11.062591 30.715548 12.6875 32.78125 L 9.5 35.96875 L 12.0625 38.5 L 15.21875 35.34375 C 17.277282 36.961896 19.782905 38.042343 22.5 38.40625 L 22.5 42.5 L 26.5 42.5 L 26.5 38.40625 C 29.229107 38.040732 31.717452 36.942459 33.78125 35.3125 L 36.96875 38.5 L 39.5 35.96875 L 36.3125 32.78125 C 37.936789 30.716335 39.014761 28.227089 39.375 25.5 L 43.5 25.5 L 43.5 21.5 L 39.375 21.5 C 39.010966 18.783848 37.931208 16.307819 36.3125 14.25 L 39.5 11.0625 L 36.96875 8.5 L 33.78125 11.6875 L 33.75 11.6875 C 31.691468 10.069353 29.217095 8.9889074 26.5 8.625 L 26.5 4.5 L 22.5 4.5 z M 23.8125 11.34375 C 24.033452 11.334116 24.274977 11.34375 24.5 11.34375 C 31.700731 11.34375 36.65625 16.333015 36.65625 23.53125 C 36.656248 30.729485 31.700731 35.6875 24.5 35.6875 C 17.29927 35.6875 12.5 30.729484 12.5 23.53125 C 12.5 16.55796 16.962974 11.64239 23.8125 11.34375 z " - xlink:href="#path2394" - style="opacity:0.2;fill:url(#linearGradient2453);fill-opacity:1.0;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.9999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2445" - inkscape:href="#path2394" - d="M 23.5,5.5 L 23.5,8.625 C 23.503929,9.1319208 23.127956,9.5616039 22.625,9.625 C 20.085855,9.9650737 17.762357,10.960594 15.84375,12.46875 C 15.44664,12.797268 14.864902,12.77021 14.5,12.40625 L 12.0625,9.9375 L 10.9375,11.0625 L 13.40625,13.53125 C 13.77021,13.896152 13.797268,14.47789 13.46875,14.875 C 11.953567,16.801212 10.932828,19.095048 10.59375,21.625 C 10.530354,22.127956 10.100671,22.503929 9.59375,22.5 L 6.5,22.5 L 6.5,24.5 L 9.59375,24.5 C 10.100671,24.496071 10.530354,24.872044 10.59375,25.375 C 10.929039,27.917339 11.948302,30.223346 13.46875,32.15625 C 13.797268,32.55336 13.77021,33.135098 13.40625,33.5 L 10.9375,35.96875 L 12.03125,37.09375 L 14.5,34.625 C 14.864902,34.26104 15.44664,34.233982 15.84375,34.5625 C 17.762357,36.070656 20.085855,37.066176 22.625,37.40625 C 23.127956,37.469646 23.503929,37.899329 23.5,38.40625 L 23.5,41.5 L 25.5,41.5 L 25.5,38.40625 C 25.496071,37.899329 25.872044,37.469646 26.375,37.40625 C 28.92215,37.065102 31.227806,36.054308 33.15625,34.53125 C 33.55336,34.202732 34.135098,34.22979 34.5,34.59375 L 36.96875,37.0625 L 38.0625,35.96875 L 35.59375,33.5 C 35.22979,33.135098 35.202732,32.55336 35.53125,32.15625 C 37.047015,30.229299 38.038333,27.923642 38.375,25.375 C 38.438396,24.872044 38.868079,24.496071 39.375,24.5 L 42.5,24.5 L 42.5,22.5 L 39.375,22.5 C 38.868079,22.503929 38.438396,22.127956 38.375,21.625 C 38.034921,19.087581 37.042567,16.796296 35.53125,14.875 C 35.202732,14.47789 35.22979,13.896152 35.59375,13.53125 L 38.09375,11.03125 L 36.96875,9.9375 L 34.5,12.40625 C 34.307701,12.592396 34.048815,12.693699 33.78125,12.6875 L 33.75,12.6875 C 33.522871,12.68767 33.302449,12.610522 33.125,12.46875 C 31.202527,10.957555 28.913145,9.9649402 26.375,9.625 C 25.872044,9.5616039 25.496071,9.1319208 25.5,8.625 L 25.5,5.5 L 23.5,5.5 z M 23.78125,10.34375 C 24.062872,10.331471 24.303519,10.34375 24.5,10.34375 C 32.162653,10.34375 37.65625,15.874058 37.65625,23.53125 C 37.656248,31.188442 32.15976,36.6875 24.5,36.6875 C 20.67012,36.6875 17.391923,35.341265 15.09375,33 C 12.795577,30.658735 11.5,27.35261 11.5,23.53125 C 11.5,16.131287 16.473536,10.662367 23.78125,10.34375 z " /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#edd400;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.08146787;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2198" - sodipodi:cx="24.450865" - sodipodi:cy="23.959385" - sodipodi:rx="14.03053" - sodipodi:ry="14.03053" - d="M 38.481395 23.959385 A 14.03053 14.03053 0 1 1 10.420335,23.959385 A 14.03053 14.03053 0 1 1 38.481395 23.959385 z" - transform="matrix(0.924879,0,0,0.924459,1.889957,1.34006)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:url(#linearGradient2279);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.12198293;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2277" - sodipodi:cx="24.450865" - sodipodi:cy="23.959385" - sodipodi:rx="14.03053" - sodipodi:ry="14.03053" - d="M 38.481395 23.959385 A 14.03053 14.03053 0 1 1 10.420335,23.959385 A 14.03053 14.03053 0 1 1 38.481395 23.959385 z" - transform="matrix(0.890914,0,0,0.891279,2.716374,2.14037)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2200" - sodipodi:cx="10.54341" - sodipodi:cy="-2.7068274" - sodipodi:rx="2.4204714" - sodipodi:ry="1.7230475" - d="M 12.963882 -2.7068274 A 2.4204714 1.7230475 0 1 1 8.1229389,-2.7068274 A 2.4204714 1.7230475 0 1 1 12.963882 -2.7068274 z" - transform="matrix(0.827565,0,0,0.87352,11.27774,22.85935)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2202" - sodipodi:cx="10.54341" - sodipodi:cy="-2.7068274" - sodipodi:rx="2.4204714" - sodipodi:ry="1.7230475" - d="M 12.963882 -2.7068274 A 2.4204714 1.7230475 0 1 1 8.1229389,-2.7068274 A 2.4204714 1.7230475 0 1 1 12.963882 -2.7068274 z" - transform="matrix(0.827567,0,0,0.87352,20.27772,22.86958)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:4.5851903;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2204" - sodipodi:cx="24.450865" - sodipodi:cy="23.959385" - sodipodi:rx="14.03053" - sodipodi:ry="14.03053" - d="M 36.657066,30.877796 A 14.03053,14.03053 0 0 1 11.928959,30.288496" - transform="matrix(0.453563,0,0,0.419476,13.51464,14.26249)" - sodipodi:start="0.51564596" - sodipodi:end="2.6736" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="opacity:0.5;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.75245398;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2465" - sodipodi:cx="26.658085" - sodipodi:cy="20.675463" - sodipodi:rx="9.863492" - sodipodi:ry="8.2640066" - d="M 36.521577 20.675463 A 9.863492 8.2640066 0 1 1 16.794593,20.675463 A 9.863492 8.2640066 0 1 1 36.521577 20.675463 z" - transform="matrix(1.216989,0,0,1.451287,-7.948546,-6.503855)" /> - </g> -</svg>
--- a/libpurple/protocols/gg/roster.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1092 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "roster.h" - -#include <glib/gi18n-lib.h> - -#include "gg.h" -#include "xml.h" -#include "utils.h" -#include "purplew.h" - -#define GGP_ROSTER_SYNC_SETT "gg-synchronized" -#define GGP_ROSTER_DEBUG 0 -#define GGP_ROSTER_GROUPID_DEFAULT "00000000-0000-0000-0000-000000000000" -#define GGP_ROSTER_GROUPID_BOTS "0b345af6-0001-0000-0000-000000000004" - -/* TODO: ignored contacts synchronization (?) */ - -typedef struct -{ - int version; - - PurpleXmlNode *xml; - - PurpleXmlNode *groups_node, *contacts_node; - - /** - * Key: (uin_t) user identifier - * Value: (PurpleXmlNode*) xml node for contact - */ - GHashTable *contact_nodes; - - /** - * Key: (gchar*) group id - * Value: (PurpleXmlNode*) xml node for group - */ - GHashTable *group_nodes; - - /** - * Key: (gchar*) group name - * Value: (gchar*) group id - */ - GHashTable *group_ids; - - /** - * Key: (gchar*) group id - * Value: (gchar*) group name - */ - GHashTable *group_names; - - gchar *bots_group_id; - - gboolean needs_update; -} ggp_roster_content; - -typedef struct -{ - enum - { - GGP_ROSTER_CHANGE_CONTACT_UPDATE, - GGP_ROSTER_CHANGE_CONTACT_REMOVE, - GGP_ROSTER_CHANGE_GROUP_RENAME, - } type; - union - { - uin_t uin; - struct - { - gchar *old_name; - gchar *new_name; - } group_rename; - } data; -} ggp_roster_change; - -static inline ggp_roster_session_data * -ggp_roster_get_rdata(PurpleConnection *gc); -static void ggp_roster_content_free(ggp_roster_content *content); -static void ggp_roster_change_free(gpointer change); -static int ggp_roster_get_version(PurpleConnection *gc); -static gboolean ggp_roster_timer_cb(gpointer _gc); -#if GGP_ROSTER_DEBUG -static void ggp_roster_dump(ggp_roster_content *content); -#endif - -/* synchronization control */ -static gboolean ggp_roster_is_synchronized(PurpleBuddy *buddy); -static void ggp_roster_set_synchronized(PurpleConnection *gc, - PurpleBuddy *buddy, gboolean synchronized); - -/* buddy list import */ -static gboolean ggp_roster_reply_list_read_group(PurpleXmlNode *node, - ggp_roster_content *content); -static gboolean ggp_roster_reply_list_read_buddy(PurpleConnection *gc, - PurpleXmlNode *node, ggp_roster_content *content, GHashTable *remove_buddies); -static void ggp_roster_reply_list(PurpleConnection *gc, uint32_t version, - const char *reply); - -/* buddy list export */ -static const gchar * ggp_roster_send_update_group_add( - ggp_roster_content *content, PurpleGroup *group); -static gboolean ggp_roster_send_update_contact_update(PurpleConnection *gc, - ggp_roster_change *change); -static gboolean ggp_roster_send_update_contact_remove(PurpleConnection *gc, - ggp_roster_change *change); -static gboolean ggp_roster_send_update_group_rename(PurpleConnection *gc, - ggp_roster_change *change); -static void ggp_roster_send_update(PurpleConnection *gc); -static void ggp_roster_reply_ack(PurpleConnection *gc, uint32_t version); -static void ggp_roster_reply_reject(PurpleConnection *gc, uint32_t version); - -/******************************************************************************/ - -static inline ggp_roster_session_data * -ggp_roster_get_rdata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return &accdata->roster_data; -} - -static void ggp_roster_content_free(ggp_roster_content *content) -{ - if (content == NULL) - return; - g_clear_pointer(&content->xml, purple_xmlnode_free); - g_clear_pointer(&content->contact_nodes, g_hash_table_destroy); - g_clear_pointer(&content->group_nodes, g_hash_table_destroy); - g_clear_pointer(&content->group_ids, g_hash_table_destroy); - g_clear_pointer(&content->group_names, g_hash_table_destroy); - g_free(content->bots_group_id); - g_free(content); -} - -static void ggp_roster_change_free(gpointer _change) -{ - ggp_roster_change *change = _change; - - if (change->type == GGP_ROSTER_CHANGE_GROUP_RENAME) { - g_free(change->data.group_rename.old_name); - g_free(change->data.group_rename.new_name); - } - - g_free(change); -} - -static int ggp_roster_get_version(PurpleConnection *gc) -{ - ggp_roster_content *content = ggp_roster_get_rdata(gc)->content; - if (content == NULL) - return 0; - return content->version; -} - -static gboolean ggp_roster_timer_cb(gpointer _gc) -{ - PurpleConnection *gc = _gc; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - ggp_roster_send_update(gc); - - return TRUE; -} - -#if GGP_ROSTER_DEBUG -static void ggp_roster_dump(ggp_roster_content *content) -{ - char *str; - int len; - - g_return_if_fail(content != NULL); - g_return_if_fail(content->xml != NULL); - - str = purple_xmlnode_to_formatted_str(content->xml, &len); - purple_debug_misc("gg", "ggp_roster_dump: [%s]\n", str); - g_free(str); -} -#endif - -/******************************************************************************* - * Setup. - ******************************************************************************/ - -gboolean ggp_roster_enabled(void) -{ - static gboolean checked = FALSE; - static gboolean enabled; - - if (!checked) { - enabled = gg_libgadu_check_feature( - GG_LIBGADU_FEATURE_USERLIST100); - checked = TRUE; - } - return enabled; -} - -void ggp_roster_setup(PurpleConnection *gc) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - - rdata->content = NULL; - rdata->sent_updates = NULL; - rdata->pending_updates = NULL; - rdata->timer = 0; - rdata->is_updating = FALSE; - - if (ggp_roster_enabled()) - rdata->timer = g_timeout_add_seconds(2, - ggp_roster_timer_cb, gc); -} - -void ggp_roster_cleanup(PurpleConnection *gc) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - - g_clear_handle_id(&rdata->timer, g_source_remove); - ggp_roster_content_free(rdata->content); - g_list_free_full(rdata->sent_updates, ggp_roster_change_free); - g_list_free_full(rdata->pending_updates, ggp_roster_change_free); -} - -/******************************************************************************* - * Synchronization control. - ******************************************************************************/ - -static gboolean ggp_roster_is_synchronized(PurpleBuddy *buddy) -{ - gboolean ret = purple_blist_node_get_bool(PURPLE_BLIST_NODE(buddy), - GGP_ROSTER_SYNC_SETT); - return ret; -} - -static void ggp_roster_set_synchronized(PurpleConnection *gc, - PurpleBuddy *buddy, gboolean synchronized) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy)); - ggp_roster_change *change; - - purple_blist_node_set_bool(PURPLE_BLIST_NODE(buddy), - GGP_ROSTER_SYNC_SETT, synchronized); - if (!synchronized) { - change = g_new0(ggp_roster_change, 1); - change->type = GGP_ROSTER_CHANGE_CONTACT_UPDATE; - change->data.uin = uin; - rdata->pending_updates = - g_list_append(rdata->pending_updates, change); - } -} - -void ggp_roster_request_update(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - int local_version = ggp_roster_get_version(gc); - - if (!ggp_roster_enabled()) { - purple_debug_warning("gg", "ggp_roster_request_update: " - "feature disabled\n"); - return; - } - - purple_debug_info("gg", "ggp_roster_request_update: local=%u\n", - local_version); - - gg_userlist100_request(accdata->session, GG_USERLIST100_GET, - local_version, GG_USERLIST100_FORMAT_TYPE_GG100, NULL); -} - -/******************************************************************************* - * Libgadu callbacks. - ******************************************************************************/ - -void ggp_roster_reply(PurpleConnection *gc, - struct gg_event_userlist100_reply *reply) -{ - if (GG_USERLIST100_FORMAT_TYPE_GG100 != reply->format_type) { - purple_debug_warning("gg", "ggp_roster_reply: " - "unsupported format type (%x)\n", reply->format_type); - return; - } - - if (reply->type == GG_USERLIST100_REPLY_LIST) - ggp_roster_reply_list(gc, reply->version, reply->reply); - else if (reply->type == 0x01) /* list up to date (TODO: push to libgadu) */ - purple_debug_info("gg", "ggp_roster_reply: list up to date\n"); - else if (reply->type == GG_USERLIST100_REPLY_ACK) - ggp_roster_reply_ack(gc, reply->version); - else if (reply->type == GG_USERLIST100_REPLY_REJECT) - ggp_roster_reply_reject(gc, reply->version); - else - purple_debug_error("gg", "ggp_roster_reply: " - "unsupported reply (%x)\n", reply->type); -} - -void ggp_roster_version(PurpleConnection *gc, - struct gg_event_userlist100_version *version) -{ - int local_version = ggp_roster_get_version(gc); - int remote_version = version->version; - - purple_debug_info("gg", "ggp_roster_version: local=%u, remote=%u\n", - local_version, remote_version); - - if (local_version < remote_version) - ggp_roster_request_update(gc); -} - -/******************************************************************************* - * Libpurple callbacks. - ******************************************************************************/ - -void -ggp_roster_alias_buddy(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, const gchar *who, - const gchar *alias) -{ - PurpleBuddy *buddy; - - g_return_if_fail(who != NULL); - - if (!ggp_roster_enabled()) - return; - - purple_debug_misc("gg", "ggp_roster_alias_buddy(\"%s\", \"%s\")\n", - who, alias); - - buddy = purple_blist_find_buddy(purple_connection_get_account(gc), who); - g_return_if_fail(buddy != NULL); - - ggp_roster_set_synchronized(gc, buddy, FALSE); -} - -void -ggp_roster_group_buddy(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, const gchar *who, - const gchar *old_group, const gchar *new_group) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - ggp_roster_change *change; - - if (!ggp_roster_enabled()) - return; - if (rdata->is_updating) - return; - - purple_debug_misc("gg", "ggp_roster_group_buddy: " - "who=\"%s\", group=\"%s\" -> \"%s\")\n", - who, old_group, new_group); - - /* purple_blist_find_buddy(..., who) is not accessible at this moment */ - change = g_new0(ggp_roster_change, 1); - change->type = GGP_ROSTER_CHANGE_CONTACT_UPDATE; - change->data.uin = ggp_str_to_uin(who); - rdata->pending_updates = g_list_append(rdata->pending_updates, change); -} - -void -ggp_roster_rename_group(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, const gchar *old_name, - PurpleGroup *group, G_GNUC_UNUSED GList *moved_buddies) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - ggp_roster_change *change; - - if (!ggp_roster_enabled()) - return; - - change = g_new0(ggp_roster_change, 1); - change->type = GGP_ROSTER_CHANGE_GROUP_RENAME; - change->data.group_rename.old_name = g_strdup(old_name); - change->data.group_rename.new_name = - g_strdup(purple_group_get_name(group)); - rdata->pending_updates = g_list_append(rdata->pending_updates, change); -} - -void -ggp_roster_add_buddy(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, PurpleBuddy *buddy, - G_GNUC_UNUSED PurpleGroup *group, - G_GNUC_UNUSED const gchar *message) -{ - g_return_if_fail(gc != NULL); - g_return_if_fail(buddy != NULL); - - if (!ggp_roster_enabled()) - return; - - ggp_roster_set_synchronized(gc, buddy, FALSE); -} - -void -ggp_roster_remove_buddy(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, PurpleBuddy *buddy, - G_GNUC_UNUSED PurpleGroup *group) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - ggp_roster_change *change; - - if (!ggp_roster_enabled()) - return; - - change = g_new0(ggp_roster_change, 1); - change->type = GGP_ROSTER_CHANGE_CONTACT_REMOVE; - change->data.uin = ggp_str_to_uin(purple_buddy_get_name(buddy)); - rdata->pending_updates = g_list_append(rdata->pending_updates, change); -} - -/******************************************************************************* - * Buddy list import. - ******************************************************************************/ - -static gboolean ggp_roster_reply_list_read_group(PurpleXmlNode *node, - ggp_roster_content *content) -{ - char *name, *id; - gboolean removable; - gboolean succ = TRUE, is_bot, is_default; - - succ &= ggp_xml_get_string(node, "Id", &id); - succ &= ggp_xml_get_string(node, "Name", &name); - succ &= ggp_xml_get_bool(node, "IsRemovable", &removable); - - if (!succ) { - g_free(id); - g_free(name); - g_return_val_if_reached(FALSE); - } - - is_bot = (strcmp(id, GGP_ROSTER_GROUPID_BOTS) == 0 || - g_strcmp0(name, "Pomocnicy") == 0); - is_default = (strcmp(id, GGP_ROSTER_GROUPID_DEFAULT) == 0 || - g_strcmp0(name, PURPLE_BLIST_DEFAULT_GROUP_NAME) == 0 || - g_strcmp0(name, "[default]") == 0); - - if (!content->bots_group_id && is_bot) - content->bots_group_id = g_strdup(id); - - if (!removable || is_bot || is_default) { - g_free(id); - g_free(name); - return TRUE; - } - - g_hash_table_insert(content->group_nodes, g_strdup(id), node); - g_hash_table_insert(content->group_ids, g_strdup(name), g_strdup(id)); - g_hash_table_insert(content->group_names, id, name); - - return TRUE; -} - -static gboolean ggp_roster_reply_list_read_buddy(PurpleConnection *gc, - PurpleXmlNode *node, ggp_roster_content *content, GHashTable *remove_buddies) -{ - gchar *alias, *group_name = NULL; - uin_t uin; - gboolean succ = TRUE; - PurpleXmlNode *group_list, *group_elem; - PurpleBuddy *buddy = NULL; - PurpleGroup *group = NULL; - PurpleGroup *currentGroup; - gboolean alias_changed; - PurpleAccount *account = purple_connection_get_account(gc); - - succ &= ggp_xml_get_string(node, "ShowName", &alias); - succ &= ggp_xml_get_uint(node, "GGNumber", &uin); - - group_list = purple_xmlnode_get_child(node, "Groups"); - succ &= (group_list != NULL); - - if (!succ) { - g_free(alias); - g_return_val_if_reached(FALSE); - } - - g_hash_table_insert(content->contact_nodes, GINT_TO_POINTER(uin), node); - - /* check, if alias is set */ - if (*alias == '\0' || - strcmp(alias, ggp_uin_to_str(uin)) == 0) - { - g_free(alias); - alias = NULL; - } - - /* getting (eventually creating) group */ - group_elem = purple_xmlnode_get_child(group_list, "GroupId"); - while (group_elem != NULL) { - gchar *id; - gboolean isbot; - - if (!ggp_xml_get_string(group_elem, NULL, &id)) - continue; - isbot = (0 == g_strcmp0(id, content->bots_group_id)); - group_name = g_hash_table_lookup(content->group_names, id); - g_free(id); - - /* we don't want to import bots; - * they are inserted to roster by default - */ - if (isbot) { - g_free(alias); - return TRUE; - } - - if (group_name != NULL) - break; - - group_elem = purple_xmlnode_get_next_twin(group_elem); - } - if (group_name) { - group = purple_blist_find_group(group_name); - if (!group) { - group = purple_group_new(group_name); - purple_blist_add_group(group, NULL); - } - } - - /* add buddy, if doesn't exists */ - buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); - g_hash_table_remove(remove_buddies, GINT_TO_POINTER(uin)); - if (!buddy) { - purple_debug_info("gg", "ggp_roster_reply_list_read_buddy: " - "adding %u (%s) to buddy list\n", uin, alias); - buddy = purple_buddy_new(account, ggp_uin_to_str(uin), alias); - purple_blist_add_buddy(buddy, NULL, group, NULL); - ggp_roster_set_synchronized(gc, buddy, TRUE); - - g_free(alias); - return TRUE; - } - - /* buddy exists, but is not synchronized - local list has priority */ - if (!ggp_roster_is_synchronized(buddy)) { - purple_debug_misc("gg", "ggp_roster_reply_list_read_buddy: " - "ignoring not synchronized %u (%s)\n", - uin, purple_buddy_get_name(buddy)); - g_free(alias); - return TRUE; - } - - currentGroup = ggp_purplew_buddy_get_group_only(buddy); - alias_changed = - (0 != g_strcmp0(alias, purple_buddy_get_alias_only(buddy))); - - if (currentGroup == group && !alias_changed) { - g_free(alias); - return TRUE; - } - - purple_debug_misc("gg", "ggp_roster_reply_list_read_buddy: " - "updating %u (%s) - alias=\"%s\"->\"%s\", group=%p->%p (%s)\n", - uin, purple_buddy_get_name(buddy), - purple_buddy_get_alias(buddy), alias, - currentGroup, group, group_name); - if (alias_changed) - purple_buddy_set_local_alias(buddy, alias); - if (currentGroup != group) - purple_blist_add_buddy(buddy, NULL, group, NULL); - - g_free(alias); - return TRUE; -} - -static void ggp_roster_reply_list(PurpleConnection *gc, uint32_t version, - const char *data) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - PurpleXmlNode *xml, *xml_it; - PurpleAccount *account; - GSList *local_buddies; - GHashTable *remove_buddies; - GList *update_buddies = NULL, *local_groups, *it, *table_values; - ggp_roster_content *content; - - g_return_if_fail(gc != NULL); - g_return_if_fail(data != NULL); - - account = purple_connection_get_account(gc); - - purple_debug_info("gg", "ggp_roster_reply_list: got list, version=%u\n", - version); - - xml = purple_xmlnode_from_str(data, -1); - if (xml == NULL) { - purple_debug_warning("gg", "ggp_roster_reply_list: " - "invalid xml\n"); - return; - } - - ggp_roster_content_free(rdata->content); - rdata->content = NULL; - rdata->is_updating = TRUE; - content = g_new0(ggp_roster_content, 1); - content->version = version; - content->xml = xml; - content->contact_nodes = g_hash_table_new(NULL, NULL); - content->group_nodes = g_hash_table_new_full( - g_str_hash, g_str_equal, g_free, NULL); - content->group_ids = g_hash_table_new_full( - g_str_hash, g_str_equal, g_free, g_free); - content->group_names = g_hash_table_new_full( - g_str_hash, g_str_equal, g_free, g_free); - -#if GGP_ROSTER_DEBUG - ggp_roster_dump(content); -#endif - - /* reading groups */ - content->groups_node = purple_xmlnode_get_child(xml, "Groups"); - if (content->groups_node == NULL) { - ggp_roster_content_free(content); - g_return_if_reached(); - } - xml_it = purple_xmlnode_get_child(content->groups_node, "Group"); - while (xml_it != NULL) { - if (!ggp_roster_reply_list_read_group(xml_it, content)) { - ggp_roster_content_free(content); - g_return_if_reached(); - } - - xml_it = purple_xmlnode_get_next_twin(xml_it); - } - - /* dumping current group list */ - local_groups = ggp_purplew_account_get_groups(account, TRUE); - - /* dumping current buddy list - * we will: - * - remove synchronized ones, if not found in list at server - * - upload not synchronized ones - */ - local_buddies = purple_blist_find_buddies(account, NULL); - remove_buddies = g_hash_table_new(g_direct_hash, g_direct_equal); - while (local_buddies) { - PurpleBuddy *buddy = local_buddies->data; - uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy)); - local_buddies = - g_slist_delete_link(local_buddies, local_buddies); - - if (!uin) - continue; - - if (ggp_roster_is_synchronized(buddy)) - g_hash_table_insert(remove_buddies, - GINT_TO_POINTER(uin), buddy); - else - update_buddies = g_list_append(update_buddies, buddy); - } - - /* reading buddies */ - content->contacts_node = purple_xmlnode_get_child(xml, "Contacts"); - if (content->contacts_node == NULL) { - g_hash_table_destroy(remove_buddies); - g_list_free(update_buddies); - ggp_roster_content_free(content); - g_return_if_reached(); - } - xml_it = purple_xmlnode_get_child(content->contacts_node, "Contact"); - while (xml_it != NULL) { - if (!ggp_roster_reply_list_read_buddy(gc, xml_it, content, - remove_buddies)) - { - g_hash_table_destroy(remove_buddies); - g_list_free(update_buddies); - ggp_roster_content_free(content); - g_return_if_reached(); - } - - xml_it = purple_xmlnode_get_next_twin(xml_it); - } - - /* removing buddies, which are not present in roster */ - table_values = g_hash_table_get_values(remove_buddies); - it = g_list_first(table_values); - while (it) { - PurpleBuddy *buddy = it->data; - it = g_list_next(it); - if (!ggp_roster_is_synchronized(buddy)) - continue; - purple_debug_info("gg", "ggp_roster_reply_list: " - "removing %s from buddy list\n", - purple_buddy_get_name(buddy)); - purple_blist_remove_buddy(buddy); - } - g_list_free(table_values); - g_hash_table_destroy(remove_buddies); - - /* remove groups, which are empty, but had contacts before - * synchronization - */ - it = g_list_first(local_groups); - while (it) { - PurpleGroup *group = it->data; - it = g_list_next(it); - if (purple_counting_node_get_total_size(PURPLE_COUNTING_NODE(group)) != 0) - continue; - purple_debug_info("gg", "ggp_roster_reply_list: " - "removing group %s\n", purple_group_get_name(group)); - purple_blist_remove_group(group); - } - g_list_free(local_groups); - - /* adding not synchronized buddies */ - it = g_list_first(update_buddies); - while (it) { - PurpleBuddy *buddy = it->data; - uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy)); - ggp_roster_change *change; - - it = g_list_next(it); - g_assert(uin > 0); - - purple_debug_misc("gg", "ggp_roster_reply_list: " - "adding change of %u for roster\n", uin); - change = g_new0(ggp_roster_change, 1); - change->type = GGP_ROSTER_CHANGE_CONTACT_UPDATE; - change->data.uin = uin; - rdata->pending_updates = - g_list_append(rdata->pending_updates, change); - } - g_list_free(update_buddies); - - rdata->content = content; - rdata->is_updating = FALSE; - purple_debug_info("gg", "ggp_roster_reply_list: " - "import done, version=%u\n", version); -} - -/******************************************************************************* - * Buddy list export. - ******************************************************************************/ - -static const gchar * ggp_roster_send_update_group_add( - ggp_roster_content *content, PurpleGroup *group) -{ - gchar *id; - const char *id_existing, *group_name; - PurpleXmlNode *group_node; - gboolean succ = TRUE; - - if (group) { - group_name = purple_group_get_name(group); - id_existing = - g_hash_table_lookup(content->group_ids, group_name); - } else - id_existing = GGP_ROSTER_GROUPID_DEFAULT; - if (id_existing) - return id_existing; - - purple_debug_info("gg", "ggp_roster_send_update_group_add: adding %s\n", - purple_group_get_name(group)); - - id = g_uuid_string_random(); - - group_node = purple_xmlnode_new_child(content->groups_node, "Group"); - succ &= ggp_xml_set_string(group_node, "Id", id); - succ &= ggp_xml_set_string(group_node, "Name", group_name); - succ &= ggp_xml_set_string(group_node, "IsExpanded", "true"); - succ &= ggp_xml_set_string(group_node, "IsRemovable", "true"); - content->needs_update = TRUE; - - g_hash_table_insert(content->group_ids, g_strdup(group_name), - g_strdup(id)); - g_hash_table_replace(content->group_nodes, id, group_node); - - g_return_val_if_fail(succ, NULL); - - return id; -} - -static gboolean ggp_roster_send_update_contact_update(PurpleConnection *gc, - ggp_roster_change *change) -{ - PurpleAccount *account = purple_connection_get_account(gc); - ggp_roster_content *content = ggp_roster_get_rdata(gc)->content; - uin_t uin = change->data.uin; - PurpleBuddy *buddy; - PurpleXmlNode *buddy_node, *contact_groups; - gboolean succ = TRUE; - const gchar *group_id; - gchar *guid; - - g_return_val_if_fail(change->type == GGP_ROSTER_CHANGE_CONTACT_UPDATE, - FALSE); - - buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); - if (!buddy) - return TRUE; - buddy_node = g_hash_table_lookup(content->contact_nodes, - GINT_TO_POINTER(uin)); - - group_id = ggp_roster_send_update_group_add(content, - ggp_purplew_buddy_get_group_only(buddy)); - - if (buddy_node) { /* update existing */ - purple_debug_misc("gg", "ggp_roster_send_update_contact_update:" - " updating %u...\n", uin); - - succ &= ggp_xml_set_string(buddy_node, "ShowName", - purple_buddy_get_alias(buddy)); - - contact_groups = purple_xmlnode_get_child(buddy_node, "Groups"); - g_assert(contact_groups); - ggp_xmlnode_remove_children(contact_groups); - succ &= ggp_xml_set_string(contact_groups, "GroupId", group_id); - - g_return_val_if_fail(succ, FALSE); - - return TRUE; - } - - /* add new */ - guid = g_uuid_string_random(); - purple_debug_misc("gg", "ggp_roster_send_update_contact_update: " - "adding %u...\n", uin); - buddy_node = purple_xmlnode_new_child(content->contacts_node, "Contact"); - succ &= ggp_xml_set_string(buddy_node, "Guid", guid); - succ &= ggp_xml_set_uint(buddy_node, "GGNumber", uin); - succ &= ggp_xml_set_string(buddy_node, "ShowName", - purple_buddy_get_alias(buddy)); - - contact_groups = purple_xmlnode_new_child(buddy_node, "Groups"); - g_assert(contact_groups); - succ &= ggp_xml_set_string(contact_groups, "GroupId", group_id); - - purple_xmlnode_new_child(buddy_node, "Avatars"); - succ &= ggp_xml_set_bool(buddy_node, "FlagBuddy", TRUE); - succ &= ggp_xml_set_bool(buddy_node, "FlagNormal", TRUE); - succ &= ggp_xml_set_bool(buddy_node, "FlagFriend", TRUE); - - /* we don't use Guid, so update is not needed - * content->needs_update = TRUE; - */ - g_free(guid); - - g_hash_table_insert(content->contact_nodes, GINT_TO_POINTER(uin), - buddy_node); - - g_return_val_if_fail(succ, FALSE); - - return TRUE; -} - -static gboolean ggp_roster_send_update_contact_remove(PurpleConnection *gc, - ggp_roster_change *change) -{ - PurpleAccount *account = purple_connection_get_account(gc); - ggp_roster_content *content = ggp_roster_get_rdata(gc)->content; - uin_t uin = change->data.uin; - PurpleBuddy *buddy; - PurpleXmlNode *buddy_node; - - g_return_val_if_fail(change->type == GGP_ROSTER_CHANGE_CONTACT_REMOVE, - FALSE); - - buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); - if (buddy) { - purple_debug_info("gg", "ggp_roster_send_update_contact_remove:" - " contact %u re-added\n", uin); - return TRUE; - } - - buddy_node = g_hash_table_lookup(content->contact_nodes, - GINT_TO_POINTER(uin)); - if (!buddy_node) /* already removed */ - return TRUE; - - purple_debug_info("gg", "ggp_roster_send_update_contact_remove: " - "removing %u\n", uin); - purple_xmlnode_free(buddy_node); - g_hash_table_remove(content->contact_nodes, GINT_TO_POINTER(uin)); - - return TRUE; -} - -static gboolean ggp_roster_send_update_group_rename(PurpleConnection *gc, - ggp_roster_change *change) -{ - PurpleAccount *account = purple_connection_get_account(gc); - ggp_roster_content *content = ggp_roster_get_rdata(gc)->content; - const char *old_name = change->data.group_rename.old_name; - const char *new_name = change->data.group_rename.new_name; - PurpleXmlNode *group_node; - const char *group_id; - - g_return_val_if_fail(change->type == GGP_ROSTER_CHANGE_GROUP_RENAME, - FALSE); - - purple_debug_misc("gg", "ggp_roster_send_update_group_rename: " - "\"%s\"->\"%s\"\n", old_name, new_name); - - /* moving to or from default group instead of renaming it */ - if (0 == g_strcmp0(old_name, PURPLE_BLIST_DEFAULT_GROUP_NAME) || - 0 == g_strcmp0(new_name, PURPLE_BLIST_DEFAULT_GROUP_NAME)) - { - PurpleGroup *group; - GList *group_buddies; - group = purple_blist_find_group(new_name); - if (!group) - return TRUE; - purple_debug_info("gg", "ggp_roster_send_update_group_rename: " - "invalidating buddies in default group\n"); - group_buddies = ggp_purplew_group_get_buddies(group, account); - while (group_buddies) { - ggp_roster_set_synchronized(gc, group_buddies->data, - FALSE); - group_buddies = g_list_delete_link(group_buddies, - group_buddies); - } - return TRUE; - } - group_id = g_hash_table_lookup(content->group_ids, old_name); - if (!group_id) { - purple_debug_info("gg", "ggp_roster_send_update_group_rename: " - "%s is not present at roster\n", old_name); - return TRUE; - } - - group_node = g_hash_table_lookup(content->group_nodes, group_id); - if (!group_node) { - purple_debug_error("gg", "ggp_roster_send_update_group_rename: " - "node for %s not found, id=%s\n", old_name, group_id); - g_hash_table_remove(content->group_ids, old_name); - return TRUE; - } - - g_hash_table_remove(content->group_ids, old_name); - g_hash_table_insert(content->group_ids, g_strdup(new_name), - g_strdup(group_id)); - g_hash_table_insert(content->group_nodes, g_strdup(group_id), - group_node); - return ggp_xml_set_string(group_node, "Name", new_name); -} - -static void ggp_roster_send_update(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - ggp_roster_content *content = rdata->content; - GList *updates_it; - gchar *str; - int len; - - /* an update is running now */ - if (rdata->sent_updates) - return; - - /* no pending updates found */ - if (!rdata->pending_updates) - return; - - /* not initialized */ - if (!content) - return; - - purple_debug_info("gg", "ggp_roster_send_update: " - "pending updates found\n"); - - rdata->sent_updates = rdata->pending_updates; - rdata->pending_updates = NULL; - - updates_it = g_list_first(rdata->sent_updates); - while (updates_it) { - ggp_roster_change *change = updates_it->data; - gboolean succ = FALSE; - updates_it = g_list_next(updates_it); - - if (change->type == GGP_ROSTER_CHANGE_CONTACT_UPDATE) { - succ = ggp_roster_send_update_contact_update(gc, change); - } else if (change->type == GGP_ROSTER_CHANGE_CONTACT_REMOVE) { - succ = ggp_roster_send_update_contact_remove(gc, change); - } else if (change->type == GGP_ROSTER_CHANGE_GROUP_RENAME) { - succ = ggp_roster_send_update_group_rename(gc, change); - } else { - purple_debug_error("gg", "ggp_roster_send_update: not handled"); - } - g_return_if_fail(succ); - } - -#if GGP_ROSTER_DEBUG - ggp_roster_dump(content); -#endif - - str = purple_xmlnode_to_str(content->xml, &len); - gg_userlist100_request(accdata->session, GG_USERLIST100_PUT, - content->version, GG_USERLIST100_FORMAT_TYPE_GG100, str); - g_free(str); -} - -static void ggp_roster_reply_ack(PurpleConnection *gc, uint32_t version) -{ - PurpleAccount *account = purple_connection_get_account(gc); - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - ggp_roster_content *content = rdata->content; - GList *updates_it; - - purple_debug_info("gg", "ggp_roster_reply_ack: version=%u\n", version); - - /* set synchronization flag for all buddies, that were updated at roster */ - updates_it = g_list_first(rdata->sent_updates); - while (updates_it) { - ggp_roster_change *change = updates_it->data; - PurpleBuddy *buddy; - updates_it = g_list_next(updates_it); - - if (change->type != GGP_ROSTER_CHANGE_CONTACT_UPDATE) - continue; - - buddy = purple_blist_find_buddy(account, - ggp_uin_to_str(change->data.uin)); - if (buddy) - ggp_roster_set_synchronized(gc, buddy, TRUE); - } - - /* we need to remove "synchronized" flag for all contacts, that have - * been modified between roster update start and now - */ - updates_it = g_list_first(rdata->pending_updates); - while (updates_it) { - ggp_roster_change *change = updates_it->data; - PurpleBuddy *buddy; - updates_it = g_list_next(updates_it); - - if (change->type != GGP_ROSTER_CHANGE_CONTACT_UPDATE) - continue; - - buddy = purple_blist_find_buddy(account, - ggp_uin_to_str(change->data.uin)); - if (buddy && ggp_roster_is_synchronized(buddy)) - ggp_roster_set_synchronized(gc, buddy, FALSE); - } - - g_clear_list(&rdata->sent_updates, ggp_roster_change_free); - - /* bump roster version or update it, if needed */ - g_return_if_fail(content != NULL); - if (content->needs_update) { - ggp_roster_content_free(rdata->content); - rdata->content = NULL; - /* we have to wait for gg_event_userlist100_version - * ggp_roster_request_update(gc); - */ - } - else - content->version = version; -} - -static void ggp_roster_reply_reject(PurpleConnection *gc, uint32_t version) -{ - ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc); - - purple_debug_info("gg", "ggp_roster_reply_reject: version=%u\n", - version); - - g_return_if_fail(rdata->sent_updates); - - rdata->pending_updates = g_list_concat(rdata->pending_updates, - rdata->sent_updates); - rdata->sent_updates = NULL; - - ggp_roster_content_free(rdata->content); - rdata->content = NULL; - ggp_roster_request_update(gc); -} - -/******************************************************************************/
--- a/libpurple/protocols/gg/roster.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_ROSTER_H -#define PURPLE_GG_ROSTER_H - -#include <purple.h> -#include <libgadu.h> - -typedef struct -{ - gpointer content; - gboolean is_updating; - - GList *sent_updates; - GList *pending_updates; - - guint timer; -} ggp_roster_session_data; - -/* setup */ -gboolean ggp_roster_enabled(void); -void ggp_roster_setup(PurpleConnection *gc); -void ggp_roster_cleanup(PurpleConnection *gc); - -/* synchronization control */ -void ggp_roster_request_update(PurpleConnection *gc); - -/* libgadu callbacks */ -void ggp_roster_reply(PurpleConnection *gc, - struct gg_event_userlist100_reply *reply); -void ggp_roster_version(PurpleConnection *gc, - struct gg_event_userlist100_version *version); - -/* libpurple callbacks */ -void ggp_roster_alias_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who, - const char *alias); -void ggp_roster_group_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who, - const char *old_group, const char *new_group); -void ggp_roster_rename_group(PurpleProtocolServer *protocol_server, PurpleConnection *, const char *old_name, - PurpleGroup *group, GList *moved_buddies); -void ggp_roster_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy, - PurpleGroup *group, const char *message); -void ggp_roster_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy, - PurpleGroup *group); - -#endif /* PURPLE_GG_ROSTER_H */
--- a/libpurple/protocols/gg/servconn.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "servconn.h" - -#include "utils.h" - -#define GGP_SERVCONN_HISTORY_PREF "/plugins/prpl/gg/server_history" -#define GGP_SERVCONN_HISTORY_MAXLEN 15 - -typedef struct -{ - GList *server_history; - PurpleAccountOption *server_option; -} ggp_servconn_global_data; - -static ggp_servconn_global_data global_data; - -void ggp_servconn_setup(PurpleAccountOption *server_option) -{ - GList *extra; - purple_prefs_add_string_list(GGP_SERVCONN_HISTORY_PREF, NULL); - - global_data.server_option = server_option; - global_data.server_history = - purple_prefs_get_string_list(GGP_SERVCONN_HISTORY_PREF); - extra = g_list_nth(global_data.server_history, GGP_SERVCONN_HISTORY_MAXLEN); - if (extra != NULL) { - /* Truncate the list to the maximum. */ - extra->prev->next = NULL; - g_list_free_full(extra, g_free); - } - - if(server_option != NULL) { - purple_account_option_string_set_hints(global_data.server_option, - ggp_servconn_get_servers()); - } -} - -void ggp_servconn_cleanup(void) -{ - g_clear_list(&global_data.server_history, g_free); -} - -void ggp_servconn_add_server(const gchar *server) -{ - GList *old_entry; - - old_entry = g_list_find_custom(global_data.server_history, server, - (GCompareFunc)g_strcmp0); - if (old_entry) { - g_free(old_entry->data); - global_data.server_history = g_list_delete_link( - global_data.server_history, old_entry); - } - - global_data.server_history = g_list_prepend(global_data.server_history, - g_strdup(server)); - old_entry = - g_list_nth(global_data.server_history, GGP_SERVCONN_HISTORY_MAXLEN); - if (old_entry != NULL) { - /* Truncate the list to the maximum. */ - old_entry->prev->next = NULL; - g_list_free_full(old_entry, g_free); - } - - purple_prefs_set_string_list(GGP_SERVCONN_HISTORY_PREF, - global_data.server_history); - purple_account_option_string_set_hints(global_data.server_option, - ggp_servconn_get_servers()); -} - -GSList * -ggp_servconn_get_servers(void) -{ - GSList *new_list = NULL; - GList *it; - - it = g_list_first(global_data.server_history); - while (it) { - new_list = g_slist_append(new_list, g_strdup(it->data)); - it = g_list_next(it); - } - return new_list; -} - -void -ggp_servconn_remote_disconnect(PurpleConnection *gc) -{ - purple_debug_info("gg", "Server remotely closes connection"); - purple_account_disconnect(purple_connection_get_account(gc)); -}
--- a/libpurple/protocols/gg/servconn.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_SERVCONN_H -#define PURPLE_GG_SERVCONN_H - -#include <purple.h> - -void ggp_servconn_setup(PurpleAccountOption *server_option); -void ggp_servconn_cleanup(void); - -void ggp_servconn_add_server(const gchar *server); -GSList * ggp_servconn_get_servers(void); -void ggp_servconn_remote_disconnect(PurpleConnection *gc); - -#endif /* PURPLE_GG_SERVCONN_H */
--- a/libpurple/protocols/gg/status.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,449 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include <libgadu.h> - -#include "status.h" - -#include "gg.h" -#include "utils.h" - -struct _ggp_status_session_data -{ - gboolean status_broadcasting; - gchar *current_description; -}; - -static inline ggp_status_session_data * -ggp_status_get_ssdata(PurpleConnection *gc); - -static gchar * ggp_status_validate_description(const gchar* msg); - -static inline ggp_status_session_data * -ggp_status_get_ssdata(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - return accdata->status_data; -} - -void ggp_status_setup(PurpleConnection *gc) -{ - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - PurpleAccount *account = purple_connection_get_account(gc); - - ggp_status_session_data *ssdata = g_new0(ggp_status_session_data, 1); - accdata->status_data = ssdata; - - ssdata->status_broadcasting = - purple_account_get_bool(account, "status_broadcasting", TRUE); -} - -void ggp_status_cleanup(PurpleConnection *gc) -{ - ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc); - g_free(ssdata->current_description); - g_free(ssdata); -} - -static gchar * ggp_status_validate_description(const gchar* msg) -{ - if (msg == NULL || msg[0] == '\0') - return NULL; - - return ggp_utf8_strndup(msg, GG_STATUS_DESCR_MAXSIZE); -} - -GList * -ggp_status_types(G_GNUC_UNUSED PurpleProtocol *protocol, - G_GNUC_UNUSED PurpleAccount *account) -{ - GList *types = NULL; - - types = g_list_append(types, purple_status_type_new_with_attrs( - PURPLE_STATUS_AVAILABLE, NULL, NULL, - TRUE, TRUE, FALSE, "message", _("Message"), - purple_value_new(G_TYPE_STRING), NULL)); - - types = g_list_append(types, purple_status_type_new_with_attrs( - PURPLE_STATUS_AVAILABLE, "freeforchat", _("Chatty"), - TRUE, TRUE, FALSE, "message", _("Message"), - purple_value_new(G_TYPE_STRING), NULL)); - - types = g_list_append(types, purple_status_type_new_with_attrs( - PURPLE_STATUS_AWAY, NULL, NULL, - TRUE, TRUE, FALSE, "message", _("Message"), - purple_value_new(G_TYPE_STRING), NULL)); - - types = g_list_append(types, purple_status_type_new_with_attrs( - PURPLE_STATUS_UNAVAILABLE, NULL, NULL, - TRUE, TRUE, FALSE, "message", _("Message"), - purple_value_new(G_TYPE_STRING), NULL)); - - types = g_list_append(types, purple_status_type_new_with_attrs( - PURPLE_STATUS_INVISIBLE, NULL, NULL, - TRUE, TRUE, FALSE, "message", _("Message"), - purple_value_new(G_TYPE_STRING), NULL)); - - types = g_list_append(types, purple_status_type_new_with_attrs( - PURPLE_STATUS_OFFLINE, NULL, NULL, - TRUE, TRUE, FALSE, "message", _("Message"), - purple_value_new(G_TYPE_STRING), NULL)); - - return types; -} - -int ggp_status_from_purplestatus(PurpleStatus *status, gchar **message) -{ - const char *status_id = purple_status_get_id(status); - const char *status_message = - purple_status_get_attr_string(status, "message"); - - g_return_val_if_fail(message != NULL, 0); - - *message = NULL; - if (status_message) { - gchar *stripped = purple_markup_strip_html(status_message); - g_strstrip(stripped); - *message = ggp_status_validate_description(stripped); - g_free(stripped); - } - - if (0 == strcmp(status_id, "available")) - return status_message ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL; - if (0 == strcmp(status_id, "freeforchat")) - return status_message ? GG_STATUS_FFC_DESCR : GG_STATUS_FFC; - if (0 == strcmp(status_id, "away")) - return status_message ? GG_STATUS_BUSY_DESCR : GG_STATUS_BUSY; - if (0 == strcmp(status_id, "unavailable")) - return status_message ? GG_STATUS_DND_DESCR : GG_STATUS_DND; - if (0 == strcmp(status_id, "invisible")) - return status_message ? - GG_STATUS_INVISIBLE_DESCR : GG_STATUS_INVISIBLE; - if (0 == strcmp(status_id, "offline")) - return status_message ? - GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL; - - purple_debug_error("gg", "ggp_status_from_purplestatus: " - "unknown status requested (%s)\n", status_id); - return status_message ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL; -} - -const gchar * ggp_status_to_purplestatus(int status) -{ - switch (status) - { - case GG_STATUS_NOT_AVAIL: - case GG_STATUS_NOT_AVAIL_DESCR: - case GG_STATUS_BLOCKED: - case GG_STATUS_UNKNOWN: - return purple_primitive_get_id_from_type( - PURPLE_STATUS_OFFLINE); - case GG_STATUS_FFC: - case GG_STATUS_FFC_DESCR: - return "freeforchat"; - case GG_STATUS_AVAIL: - case GG_STATUS_AVAIL_DESCR: - return purple_primitive_get_id_from_type( - PURPLE_STATUS_AVAILABLE); - case GG_STATUS_BUSY: - case GG_STATUS_BUSY_DESCR: - return purple_primitive_get_id_from_type( - PURPLE_STATUS_AWAY); - case GG_STATUS_INVISIBLE: - case GG_STATUS_INVISIBLE_DESCR: - return purple_primitive_get_id_from_type( - PURPLE_STATUS_INVISIBLE); - case GG_STATUS_DND: - case GG_STATUS_DND_DESCR: - return purple_primitive_get_id_from_type( - PURPLE_STATUS_UNAVAILABLE); - default: - purple_debug_warning("gg", "ggp_status_to_purplestatus: unknown status %#02x\n", status); - return purple_primitive_get_id_from_type( - PURPLE_STATUS_AVAILABLE); - } -} - -const gchar * ggp_status_get_name(const gchar *purple_status) -{ - if (g_strcmp0(purple_status, "freeforchat") == 0) - return _("Chatty"); - return purple_primitive_get_name_from_type( - purple_primitive_get_type_from_id(purple_status)); -} - -/******************************************************************************* - * Own status. - ******************************************************************************/ - -void ggp_status_set_initial(PurpleConnection *gc, struct gg_login_params *glp) -{ - ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc); - PurpleAccount *account = purple_connection_get_account(gc); - - glp->status = ggp_status_from_purplestatus( - purple_account_get_active_status(account), &glp->status_descr); - if (!ggp_status_get_status_broadcasting(gc)) - glp->status |= GG_STATUS_FRIENDS_MASK; - ssdata->current_description = g_strdup(glp->status_descr); -} - -gboolean ggp_status_set(PurpleAccount *account, int status, const gchar* msg) -{ - PurpleConnection *gc = purple_account_get_connection(account); - ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc); - GGPInfo *accdata = purple_connection_get_protocol_data(gc); - gchar *new_description = ggp_status_validate_description(msg); - - if (!ssdata->status_broadcasting) - status |= GG_STATUS_FRIENDS_MASK; - - if ((status == GG_STATUS_NOT_AVAIL || - status == GG_STATUS_NOT_AVAIL_DESCR) && - 0 == g_strcmp0(ssdata->current_description, new_description)) - { - purple_debug_info("gg", "ggp_status_set: new status doesn't " - "differ when closing connection - ignore\n"); - g_free(new_description); - return FALSE; - } - g_free(ssdata->current_description); - ssdata->current_description = new_description; - - if (msg == NULL) - gg_change_status(accdata->session, status); - else - gg_change_status_descr(accdata->session, status, new_description); - - return TRUE; -} - -void -ggp_status_set_purplestatus(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleAccount *account, PurpleStatus *status) -{ - int status_gg; - gchar *msg = NULL; - - if (!purple_status_is_active(status)) - return; - - status_gg = ggp_status_from_purplestatus(status, &msg); - ggp_status_set(account, status_gg, msg); - g_free(msg); -} - -void ggp_status_set_disconnected(PurpleAccount *account) -{ - gchar *msg = NULL; - - ggp_status_from_purplestatus(purple_account_get_active_status(account), - &msg); - if (!ggp_status_set(account, - msg ? GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL, msg)) - { - g_free(msg); - return; - } - - /* - struct gg_event *ev; - guint64 wait_start = ggp_microtime(), now; - int sleep_time = 5000; - while ((ev = gg_watch_fd(info->session)) != NULL) - { - if (ev->type == GG_EVENT_DISCONNECT_ACK) - break; - now = ggp_microtime(); - if (now - wait_start + sleep_time >= 100000) - break; - usleep(sleep_time); - sleep_time *= 2; - } - */ - g_usleep(100000); - - g_free(msg); -} - -void ggp_status_fake_to_self(PurpleConnection *gc) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - PurpleStatus *status = purple_presence_get_active_status( - purple_account_get_presence(account)); - const char *status_msg = purple_status_get_attr_string(status, - "message"); - gchar *status_msg_gg = NULL; - - if (status_msg != NULL && status_msg[0] != '\0') { - status_msg_gg = g_new0(gchar, GG_STATUS_DESCR_MAXSIZE + 1); - g_utf8_strncpy(status_msg_gg, status_msg, - GG_STATUS_DESCR_MAXSIZE); - } - - purple_protocol_got_user_status(account, - purple_contact_info_get_username(info), - purple_status_get_id(status), - status_msg_gg ? "message" : NULL, status_msg_gg, NULL); - - g_free(status_msg_gg); -} - -gboolean ggp_status_get_status_broadcasting(PurpleConnection *gc) -{ - return ggp_status_get_ssdata(gc)->status_broadcasting; -} - -void ggp_status_set_status_broadcasting(PurpleConnection *gc, - gboolean broadcasting) -{ - PurpleAccount *account = purple_connection_get_account(gc); - - ggp_status_get_ssdata(gc)->status_broadcasting = broadcasting; - purple_account_set_bool(account, "status_broadcasting", broadcasting); - ggp_status_set_purplestatus(NULL, account, - purple_account_get_active_status(account)); -} - -static void -ggp_status_broadcasting_dialog_ok(PurpleConnection *gc, - PurpleRequestPage *page) -{ - gboolean buddies_only = purple_request_page_get_bool(page, "buddies_only"); - ggp_status_set_status_broadcasting(gc, !buddies_only); -} - -void ggp_status_broadcasting_dialog(PurpleConnection *gc) -{ - PurpleRequestPage *page; - PurpleRequestGroup *group; - PurpleRequestField *field; - - page = purple_request_page_new(); - group = purple_request_group_new(NULL); - purple_request_page_add_group(page, group); - - field = purple_request_field_bool_new("buddies_only", - _("Show status only for buddies"), - !ggp_status_get_status_broadcasting(gc)); - purple_request_group_add_field(group, field); - - purple_request_fields(gc, - _("Change status broadcasting"), - _("Please, select who can see your status"), - NULL, - page, - _("OK"), G_CALLBACK(ggp_status_broadcasting_dialog_ok), - _("Cancel"), NULL, - purple_request_cpar_from_connection(gc), gc); -} - -/******************************************************************************* - * Buddy status. - ******************************************************************************/ - -void ggp_status_got_others_buddy(PurpleConnection *gc, uin_t uin, int status, - const char *descr); - -/******************************************************************************/ - -void ggp_status_got_others(PurpleConnection *gc, struct gg_event *ev) -{ - if (ev->type == GG_EVENT_NOTIFY60) { - struct gg_event_notify60 *notify = ev->event.notify60; - int i; - for (i = 0; notify[i].uin; i++) - ggp_status_got_others_buddy(gc, notify[i].uin, - GG_S(notify[i].status), notify[i].descr); - } else if (ev->type == GG_EVENT_STATUS60) { - struct gg_event_status60 *notify = &ev->event.status60; - ggp_status_got_others_buddy(gc, notify->uin, - GG_S(notify->status), notify->descr); - } else { - purple_debug_error("gg", "ggp_status_got_others: unexpected event %d", - ev->type); - } -} - -void ggp_status_got_others_buddy(PurpleConnection *gc, uin_t uin, int status, - const char *descr) -{ - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - PurpleBuddy *buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); - const gchar *purple_status = ggp_status_to_purplestatus(status); - gchar *status_message = NULL; - gboolean is_own; - - is_own = (!g_strcmp0(ggp_uin_to_str(uin), - purple_contact_info_get_username(info))); - - if (!buddy) { - if (!is_own) { - purple_debug_warning("gg", - "ggp_status_got_others_buddy: " - "buddy %u not found\n", uin); - } - return; - } - ggp_buddy_get_data(buddy)->blocked = (status == GG_STATUS_BLOCKED); - ggp_buddy_get_data(buddy)->not_a_friend = (status == GG_STATUS_UNKNOWN); - - if (descr != NULL) { - status_message = g_strdup(descr); - g_strstrip(status_message); - if (status_message[0] == '\0') { - g_free(status_message); - status_message = NULL; - } - } - - if (uin == ggp_str_to_uin(purple_contact_info_get_username(info))) { - purple_debug_info("gg", "ggp_status_got_others_buddy: " - "own status changed to %s [%s]\n", - purple_status, status_message ? status_message : ""); - } else if (purple_debug_is_verbose()) { - purple_debug_misc("gg", "ggp_status_got_others_buddy: " - "status of %u changed to %s [%s]\n", uin, - purple_status, status_message ? status_message : ""); - } - - if (status_message) { - purple_protocol_got_user_status(account, ggp_uin_to_str(uin), - purple_status, "message", status_message, NULL); - } else { - purple_protocol_got_user_status(account, ggp_uin_to_str(uin), - purple_status, NULL); - } - - g_free(status_message); -}
--- a/libpurple/protocols/gg/status.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_STATUS_H -#define PURPLE_GG_STATUS_H - -#include <purple.h> -#include <libgadu.h> - -typedef struct _ggp_status_session_data ggp_status_session_data; - -void ggp_status_setup(PurpleConnection *gc); -void ggp_status_cleanup(PurpleConnection *gc); - -GList *ggp_status_types(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleAccount *account); -int ggp_status_from_purplestatus(PurpleStatus *status, gchar **message); -const gchar * ggp_status_to_purplestatus(int status); -const gchar * ggp_status_get_name(const gchar *purple_status); - -/* own status */ - -void ggp_status_set_initial(PurpleConnection *gc, struct gg_login_params *glp); - -gboolean ggp_status_set(PurpleAccount *account, int status, const gchar* msg); -void ggp_status_set_purplestatus(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleStatus *status); -void ggp_status_set_disconnected(PurpleAccount *account); -void ggp_status_fake_to_self(PurpleConnection *gc); - -gboolean ggp_status_get_status_broadcasting(PurpleConnection *gc); -void ggp_status_set_status_broadcasting(PurpleConnection *gc, - gboolean broadcasting); -void ggp_status_broadcasting_dialog(PurpleConnection *gc); - -/* buddy status */ - -void ggp_status_got_others(PurpleConnection *gc, struct gg_event *ev); - -#endif /* PURPLE_GG_STATUS_H */
--- a/libpurple/protocols/gg/tcpsocket.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <errno.h> - -#include <purple.h> - -#include "tcpsocket.h" - -#include "gg.h" - - -typedef struct { - GSocketConnection *conn; - GCancellable *cancellable; - PurpleConnection *gc; - gpointer priv_gg; -} GGPTcpSocketData; - -static void -ggp_tcp_socket_data_free(GGPTcpSocketData *data) -{ - g_return_if_fail(data != NULL); - - if (data->cancellable != NULL) { - g_cancellable_cancel(data->cancellable); - g_clear_object(&data->cancellable); - } - - if (data->conn != NULL) { - purple_gio_graceful_close(G_IO_STREAM(data->conn), NULL, NULL); - g_clear_object(&data->conn); - } - - g_free(data); -} - -static void -ggp_tcpsocket_connected(GObject *source, GAsyncResult *res, gpointer user_data) -{ - GGPTcpSocketData *data = user_data; - GSocketConnection *conn; - GSocket *socket; - int fd = -1; - GGPInfo *info; - GError *error = NULL; - - conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), - res, &error); - - if (conn == NULL) { - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - /* The connection was already closed, return now */ - g_clear_error(&error); - return; - } - - purple_debug_error("gg", "socket failed to connect: %s", - error->message); - g_clear_error(&error); - } else { - data->conn = conn; - - socket = g_socket_connection_get_socket(data->conn); - - if (socket != NULL) { - fd = g_socket_get_fd(socket); - } - } - - /* XXX: For some reason if you try to connect and then immediately - * disconnect, this gets into a state where ggp_tcpsocket_close() - * isn't called. The cancellable is therefore not cancelled, and - * the connection is never closed. Guard against that state here. - */ - if (data->gc == NULL || - !g_list_find(purple_connections_get_all(), data->gc)) { - purple_debug_error("gg", - "disconnected without closing connection: %p", - data); - ggp_tcp_socket_data_free(data); - return; - } - - if (!gg_socket_manager_connected(data, data->priv_gg, fd)) { - purple_debug_error("gg", "socket not handled"); - ggp_tcp_socket_data_free(data); - return; - } - - info = purple_connection_get_protocol_data(data->gc); - - g_clear_handle_id(&info->inpa, g_source_remove); - - if (info->session->fd < 0) - return; - - /* XXX: This works, but not recommended to use GSocket FDs directly */ - info->inpa = purple_input_add(info->session->fd, - ggp_tcpsocket_inputcond_gg_to_purple(info->session->check), - ggp_async_login_handler, data->gc); -} - -static void* -ggp_tcpsocket_connect(void *_gc, const char *host, int port, int is_tls, - int is_async, void *priv) -{ - PurpleConnection *gc = _gc; - GGPTcpSocketData *data; - GSocketClient *client; - GError *error = NULL; - - PURPLE_ASSERT_CONNECTION_IS_VALID(gc); - - g_return_val_if_fail(host != NULL, NULL); - g_return_val_if_fail(is_async, NULL); - - purple_debug_misc("gg", "ggp_tcpsocket_connect(%p, %s:%d, %s, %p)", - gc, host, port, is_tls ? "tls" : "tcp", priv); - - client = purple_gio_socket_client_new( - purple_connection_get_account(gc), &error); - - if (client == NULL) { - purple_debug_error("gg", "unable to connect: %s", - error->message); - g_clear_error(&error); - return NULL; - } - - g_socket_client_set_tls(client, is_tls); - - data = g_new0(GGPTcpSocketData, 1); - data->cancellable = g_cancellable_new(); - data->gc = gc; - data->priv_gg = priv; - - g_socket_client_connect_to_host_async(client, host, port, - data->cancellable, ggp_tcpsocket_connected, data); - g_object_unref(client); - - return data; -} - -static void -ggp_tcpsocket_close(G_GNUC_UNUSED void *_gc, void *_data) { - GGPTcpSocketData *data = _data; - - ggp_tcp_socket_data_free(data); -} - -static ssize_t -ggp_tcpsocket_read(G_GNUC_UNUSED void *_gc, void *_data, - unsigned char *buffer, size_t bufsize) -{ - GGPTcpSocketData *data = _data; - GPollableInputStream *input; - gssize ret; - GError *error = NULL; - - if (data->conn == NULL) { - return -1; - } - - input = G_POLLABLE_INPUT_STREAM( - g_io_stream_get_input_stream(G_IO_STREAM(data->conn))); - ret = g_pollable_input_stream_read_nonblocking(input, - buffer, bufsize, NULL, &error); - - if (ret < 0) { - if (g_error_matches(error, - G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - errno = EAGAIN; - } else { - purple_debug_error("gg", "socket read error: %s", - error->message); - } - - g_clear_error(&error); - } - - return ret; -} - -static ssize_t -ggp_tcpsocket_write(G_GNUC_UNUSED void *_gc, void *_data, - const unsigned char *data_buf, size_t len) -{ - GGPTcpSocketData *data = _data; - GPollableOutputStream *output; - gssize ret; - GError *error = NULL; - - if (data->conn == NULL) { - return -1; - } - - output = G_POLLABLE_OUTPUT_STREAM( - g_io_stream_get_output_stream(G_IO_STREAM(data->conn))); - ret = g_pollable_output_stream_write_nonblocking(output, - data_buf, len, NULL, &error); - - if (ret < 0) { - if (g_error_matches(error, - G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - errno = EAGAIN; - } else { - purple_debug_error("gg", "socket write error: %s", - error->message); - } - - g_clear_error(&error); - } - - return ret; -} - -void -ggp_tcpsocket_setup(PurpleConnection *gc, struct gg_login_params *glp) -{ - glp->socket_manager_type = GG_SOCKET_MANAGER_TYPE_TLS; - glp->socket_manager.cb_data = gc; - glp->socket_manager.connect_cb = ggp_tcpsocket_connect; - glp->socket_manager.close_cb = ggp_tcpsocket_close; - glp->socket_manager.read_cb = ggp_tcpsocket_read; - glp->socket_manager.write_cb = ggp_tcpsocket_write; -} - -PurpleInputCondition -ggp_tcpsocket_inputcond_gg_to_purple(enum gg_check_t check) -{ - PurpleInputCondition cond = 0; - - if (check & GG_CHECK_READ) - cond |= PURPLE_INPUT_READ; - if (check & GG_CHECK_WRITE) - cond |= PURPLE_INPUT_WRITE; - - return cond; -}
--- a/libpurple/protocols/gg/tcpsocket.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. - * As a recipient of this file you may choose, which license to receive the - * code under. As a contributor, you have to ensure the new code is - * compatible with both. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_TCPSOCKET_H -#define PURPLE_GG_TCPSOCKET_H - -#include <purple.h> -#include <libgadu.h> - -void -ggp_tcpsocket_setup(PurpleConnection *gc, struct gg_login_params *glp); - -PurpleInputCondition -ggp_tcpsocket_inputcond_gg_to_purple(enum gg_check_t check); - -#endif /* PURPLE_GG_TCPSOCKET_H */
--- a/libpurple/protocols/gg/utils.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <errno.h> -#include <netinet/in.h> - -#include <purple.h> - -#include "utils.h" - -#include "gg.h" - -uin_t ggp_str_to_uin(const char *str) -{ - char *endptr; - uin_t uin; - - if (!str || str[0] < '0' || str[0] > '9') - return 0; - - errno = 0; - uin = strtoul(str, &endptr, 10); - - if (errno == ERANGE || endptr[0] != '\0') - return 0; - - return uin; -} - -const char * ggp_uin_to_str(uin_t uin) -{ - static char buff[GGP_UIN_LEN_MAX + 1]; - - g_snprintf(buff, GGP_UIN_LEN_MAX + 1, "%u", uin); - - return buff; -} - -uin_t -ggp_get_my_uin(PurpleConnection *gc) { - PurpleAccount *account = purple_connection_get_account(gc); - PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); - - g_return_val_if_fail(gc != NULL, 0); - - return ggp_str_to_uin(purple_contact_info_get_username(info)); -} - -static gchar * ggp_convert(const gchar *src, const char *srcenc, - const char *dstenc) -{ - gchar *dst; - GError *err = NULL; - - if (src == NULL) - return NULL; - - dst = g_convert_with_fallback(src, strlen(src), dstenc, srcenc, "?", - NULL, NULL, &err); - if (err != NULL) { - purple_debug_error("gg", "error converting from %s to %s: %s\n", - srcenc, dstenc, err->message); - g_error_free(err); - } - - if (dst == NULL) - dst = g_strdup(src); - - return dst; -} - -gchar * ggp_convert_to_cp1250(const gchar *src) -{ - return ggp_convert(src, "UTF-8", "CP1250"); -} - -gchar * ggp_convert_from_cp1250(const gchar *src) -{ - return ggp_convert(src, "CP1250", "UTF-8"); -} - -gchar * ggp_utf8_strndup(const gchar *str, gsize n) -{ - size_t raw_len; - gchar *end_ptr; - if (str == NULL) - return NULL; - raw_len = strlen(str); - if (raw_len <= n) - return g_strdup(str); - - end_ptr = g_utf8_offset_to_pointer(str, g_utf8_pointer_to_offset(str, &str[n])); - raw_len = end_ptr - str; - - if (raw_len > n) { - end_ptr = g_utf8_prev_char(end_ptr); - raw_len = end_ptr - str; - } - - g_assert(raw_len <= n); - - return g_strndup(str, raw_len); -} - -const gchar * ggp_ipv4_to_str(uint32_t raw_ip) -{ - static gchar buff[INET_ADDRSTRLEN]; - buff[0] = '\0'; - - g_snprintf(buff, sizeof(buff), "%d.%d.%d.%d", - ((raw_ip >> 0) & 0xFF), - ((raw_ip >> 8) & 0xFF), - ((raw_ip >> 16) & 0xFF), - ((raw_ip >> 24) & 0xFF)); - - return buff; -} - -gchar * ggp_free_if_equal(gchar *str, const gchar *pattern) -{ - if (g_strcmp0(str, pattern) == 0) { - g_free(str); - return NULL; - } - return str; -} - -uint64_t * ggp_uint64dup(uint64_t val) -{ - uint64_t *ptr = g_new(uint64_t, 1); - *ptr = val; - return ptr; -} - -JsonParser * ggp_json_parse(const gchar *data) -{ - JsonParser *parser; - - parser = json_parser_new(); - if (json_parser_load_from_data(parser, data, -1, NULL)) - return parser; - - if (purple_debug_is_unsafe()) - purple_debug_warning("gg", "Invalid JSON: %s\n", data); - return NULL; -}
--- a/libpurple/protocols/gg/utils.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_UTILS_H -#define PURPLE_GG_UTILS_H - -#include <libgadu.h> -#include <json-glib/json-glib.h> - -#include <purple.h> - -/** - * Converts stringified UIN to uin_t. - * - * @param str The string to convert. - * - * @return Converted UIN or 0 if an error occurred. - */ -uin_t ggp_str_to_uin(const char *str); - -/** - * Stringifies UIN. - * - * @param uin UIN to stringify. - * - * @return Stringified UIN. - */ -const char * ggp_uin_to_str(uin_t uin); - -/** - * Gets UIN for the account. - * - * @param gc The connection, in which account is connected. - * @return UIN for this account. - */ -uin_t ggp_get_my_uin(PurpleConnection *gc); - -/** - * Converts encoding of a given string from UTF-8 to CP1250. - * - * @param src Input string. - * - * @return Converted string (must be freed with g_free). If src is NULL, - * then NULL is returned. - */ -gchar * ggp_convert_to_cp1250(const gchar *src); - -/** - * Converts encoding of a given string from CP1250 to UTF-8. - * - * @param src Input string. - * - * @return Converted string (must be freed with g_free). If src is NULL, - * then NULL is returned. - */ -gchar * ggp_convert_from_cp1250(const gchar *src); - -gchar * ggp_utf8_strndup(const gchar *str, gsize n); - -const gchar * ggp_ipv4_to_str(uint32_t raw_ip); - -gchar * ggp_free_if_equal(gchar *str, const gchar *pattern); - -uint64_t * ggp_uint64dup(uint64_t val); - -JsonParser * ggp_json_parse(const gchar *data); - -#endif /* PURPLE_GG_UTILS_H */
--- a/libpurple/protocols/gg/validator.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "validator.h" - -#include "utils.h" - -#include <glib/gi18n-lib.h> - -gboolean -ggp_validator_password(PurpleRequestField *field, gchar **errmsg, - G_GNUC_UNUSED gpointer data) -{ - const char *value; - - g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE); - - value = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field)); - - if (value != NULL) { - size_t len = strlen(value); - if (6 <= len && len <= 15) { - if (g_regex_match_simple( - "^[ a-zA-Z0-9~`!@#$%^&*()_+=[\\]{};':\",./?<>\\\\|-]+$", - value, 0, 0)) { - return TRUE; - } - } - } - - if (errmsg) - *errmsg = g_strdup(_("Password can contain 6-15 alphanumeric characters")); - return FALSE; -} - -gboolean ggp_validator_password_equal(PurpleRequestField *field, gchar **errmsg, - void *field2_p) -{ - const char *value1, *value2; - PurpleRequestField *field2 = field2_p; - - g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE); - g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field2), FALSE); - - value1 = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field)); - value2 = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field2)); - - if (g_strcmp0(value1, value2) == 0) - return TRUE; - - if (errmsg) - *errmsg = g_strdup(_("Passwords do not match")); - return FALSE; -}
--- a/libpurple/protocols/gg/validator.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_VALIDATOR_H -#define PURPLE_GG_VALIDATOR_H - -#include <purple.h> - -gboolean ggp_validator_password(PurpleRequestField *field, gchar **errmsg, - void *user_data); - -gboolean ggp_validator_password_equal(PurpleRequestField *field, gchar **errmsg, - void *field2); - -#endif /* PURPLE_GG_VALIDATOR_H */
--- a/libpurple/protocols/gg/xml.c Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <errno.h> - -#include "xml.h" - -gboolean -ggp_xml_get_string(const PurpleXmlNode *xml, const gchar *childName, gchar **var) -{ - char *str; - - g_return_val_if_fail(xml != NULL, FALSE); - g_return_val_if_fail(var != NULL, FALSE); - - if (childName != NULL) { - xml = purple_xmlnode_get_child(xml, childName); - if (xml == NULL) - return FALSE; - } - - str = purple_xmlnode_get_data(xml); - if (str == NULL) - return FALSE; - - *var = str; - return TRUE; -} - -gboolean -ggp_xml_get_bool(const PurpleXmlNode *xml, const gchar *childName, gboolean *var) -{ - char *str; - gboolean succ; - - succ = ggp_xml_get_string(xml, childName, &str); - if (!succ) - return FALSE; - - *var = (strcmp(str, "true") == 0 || - strcmp(str, "True") == 0 || - strcmp(str, "TRUE") == 0 || - strcmp(str, "1") == 0); - g_free(str); - - return TRUE; -} - -gboolean -ggp_xml_get_uint(const PurpleXmlNode *xml, const gchar *childName, unsigned int *var) -{ - char *str, *endptr; - gboolean succ; - unsigned int val; - - succ = ggp_xml_get_string(xml, childName, &str); - if (!succ) - return FALSE; - - errno = 0; - val = strtoul(str, &endptr, 10); - - succ = (errno != ERANGE && endptr[0] == '\0'); - g_free(str); - - if (succ) - *var = val; - return succ; -} - -gboolean -ggp_xml_set_string(PurpleXmlNode *xml, const gchar *childName, const gchar *val) -{ - g_return_val_if_fail(xml != NULL, FALSE); - g_return_val_if_fail(val != NULL, FALSE); - - if (childName != NULL) { - PurpleXmlNode *child = purple_xmlnode_get_child(xml, childName); - if (child == NULL) - child = purple_xmlnode_new_child(xml, childName); - xml = child; - } - - ggp_xmlnode_remove_children(xml); - purple_xmlnode_insert_data(xml, val, -1); - - return TRUE; -} - -gboolean -ggp_xml_set_bool(PurpleXmlNode *xml, const gchar *childName, gboolean val) -{ - return ggp_xml_set_string(xml, childName, val ? "true" : "false"); -} - -gboolean -ggp_xml_set_uint(PurpleXmlNode *xml, const gchar *childName, unsigned int val) -{ - gchar buff[20]; - g_snprintf(buff, sizeof(buff), "%u", val); - return ggp_xml_set_string(xml, childName, buff); -} - -void ggp_xmlnode_remove_children(PurpleXmlNode *xml) -{ - PurpleXmlNode *child = xml->child; - while (child) { - PurpleXmlNode *next = child->next; - if (child->type != PURPLE_XMLNODE_TYPE_ATTRIB) - purple_xmlnode_free(child); - child = next; - } -} - -unsigned int ggp_xml_child_count(PurpleXmlNode *xml, const gchar *childName) -{ - PurpleXmlNode *child; - unsigned int count = 0; - - g_return_val_if_fail(xml != NULL, 0); - - if (childName) { - child = purple_xmlnode_get_child(xml, childName); - while (child) { - child = purple_xmlnode_get_next_twin(child); - count++; - } - } else { - child = xml->child; - while (child) { - child = child->next; - count++; - } - } - - return count; -}
--- a/libpurple/protocols/gg/xml.h Tue Apr 09 21:50:31 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * Rewritten from scratch during Google Summer of Code 2012 - * by Tomek Wasilczyk (http://www.wasilczyk.pl). - * - * Previously implemented by: - * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); - * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; - * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_GG_XML_H -#define PURPLE_GG_XML_H - -#include <purple.h> - -gboolean ggp_xml_get_string(const PurpleXmlNode *xml, const gchar *childName, gchar **var); -gboolean ggp_xml_get_bool(const PurpleXmlNode *xml, const gchar *childName, gboolean *var); -gboolean ggp_xml_get_uint(const PurpleXmlNode *xml, const gchar *childName, unsigned int *var); - -gboolean ggp_xml_set_string(PurpleXmlNode *xml, const gchar *childName, const gchar *val); -gboolean ggp_xml_set_bool(PurpleXmlNode *xml, const gchar *childName, gboolean val); -gboolean ggp_xml_set_uint(PurpleXmlNode *xml, const gchar *childName, unsigned int val); - -void ggp_xmlnode_remove_children(PurpleXmlNode *xml); - -unsigned int ggp_xml_child_count(PurpleXmlNode *xml, const gchar *childName); - -#endif /* PURPLE_GG_XML_H */
--- a/libpurple/protocols/meson.build Tue Apr 09 21:50:31 2024 -0500 +++ b/libpurple/protocols/meson.build Tue Apr 09 21:55:54 2024 -0500 @@ -1,3 +1,2 @@ subdir('bonjour') -subdir('gg') subdir('jabber')
--- a/meson.build Tue Apr 09 21:50:31 2024 -0500 +++ b/meson.build Tue Apr 09 21:55:54 2024 -0500 @@ -276,35 +276,13 @@ endif ####################################################################### -# Check for Gadu-Gadu protocol library (libgadu) -####################################################################### - -libgadu = dependency('libgadu', version : '>= 1.12.0', required : get_option('libgadu')) - -if libgadu.found() - if not compiler.has_function('gg_is_gpl_compliant', dependencies : libgadu) - if get_option('libgadu').auto() - libgadu = disabler() - else - message(''' -libgadu is not compatible with the GPL when compiled with OpenSSL support. - -To link against libgadu, please recompile it using: -./configure --with-openssl=no -Then rerun this Meson build - ''') - endif - endif -endif - -####################################################################### # Check for Xeme XMPP Library ####################################################################### xeme = dependency('xeme') dependency('shoes', required : false) -DEFAULT_PRPLS = ['bonjour', 'demo', 'gg', 'ircv3', 'jabber', 'xmpp'] +DEFAULT_PRPLS = ['bonjour', 'demo', 'ircv3', 'jabber', 'xmpp'] dynamic_list = get_option('dynamic-prpls').split(',') if dynamic_list == ['all'] @@ -316,8 +294,6 @@ # The list was empty; do nothing. elif prpl == 'bonjour' and not enable_avahi # Do nothing. - elif prpl == 'gg' and not libgadu.found() - # Do nothing. elif prpl == 'xmpp' and not xeme.found() # Do nothing. else @@ -327,7 +303,6 @@ DYNAMIC_BONJOUR = DYNAMIC_PRPLS.contains('bonjour') DYNAMIC_DEMO = DYNAMIC_PRPLS.contains('demo') -DYNAMIC_GG = DYNAMIC_PRPLS.contains('gg') DYNAMIC_IRCV3 = DYNAMIC_PRPLS.contains('ircv3') DYNAMIC_JABBER = DYNAMIC_PRPLS.contains('jabber') DYNAMIC_XMPP = DYNAMIC_PRPLS.contains('xmpp')