1.1 --- a/configure.ac
1.2 +++ b/configure.ac
1.3 @@ -816,6 +816,19 @@
1.4 AC_SUBST(LIBXML_LIBS)
1.5
1.6 dnl #######################################################################
1.7 +dnl # Check for zlib (required)
1.8 +dnl #######################################################################
1.9 +
1.10 +PKG_CHECK_MODULES(ZLIB, [zlib >= 1.2.0], , [
1.11 + AC_MSG_RESULT(no)
1.12 + AC_MSG_ERROR([
1.13 +You must have zlib >= 1.2.0 development headers installed to build.
1.14 +])])
1.15 +
1.16 +AC_SUBST(ZLIB_CFLAGS)
1.17 +AC_SUBST(ZLIB_LIBS)
1.18 +
1.19 +dnl #######################################################################
1.20 dnl # GConf schemas
1.21 dnl #######################################################################
1.22 AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
1.23 @@ -1069,13 +1082,14 @@
1.24 AC_ARG_WITH(gadu-libs, [AC_HELP_STRING([--with-gadu-libs=DIR], [compile the Gadu-Gadu plugin against the libs in DIR])], [ac_gadu_libs="$withval"], [ac_gadu_libs="no"])
1.25 GADU_CFLAGS=""
1.26 GADU_LIBS=""
1.27 +GADU_LIBGADU_VERSION=1.11.2
1.28 if test -n "$with_gadu_includes" || test -n "$with_gadu_libs"; then
1.29 gadu_manual_check="yes"
1.30 else
1.31 gadu_manual_check="no"
1.32 fi
1.33 if test "x$gadu_manual_check" = "xno"; then
1.34 - PKG_CHECK_MODULES(GADU, [libgadu >= 1.11.0], [
1.35 + PKG_CHECK_MODULES(GADU, [libgadu >= $GADU_LIBGADU_VERSION], [
1.36 gadu_includes="yes"
1.37 gadu_libs="yes"
1.38 ], [
1.39 @@ -1107,28 +1121,7 @@
1.40 #error "libgadu is not compatible with the GPL when compiled with OpenSSL support."
1.41 #endif
1.42 ]])], [
1.43 - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libgadu.h>]], [[
1.44 -#if GG_DEFAULT_PROTOCOL_VERSION < 0x2e
1.45 -#error "Your libgadu version is too old. libpurple requires 1.11.0 or higher."
1.46 -#endif
1.47 - ]])], [
1.48 - AC_MSG_RESULT(yes)
1.49 - AC_DEFINE([HAVE_LIBGADU], [1],
1.50 - [Define to 1 if you have libgadu.])
1.51 - ], [
1.52 - AC_MSG_RESULT(no)
1.53 - echo
1.54 - echo
1.55 - echo "Your supplied copy of libgadu is too old."
1.56 - echo "Install version 1.11.0 or newer."
1.57 - echo "Then rerun this ./configure"
1.58 - echo
1.59 - echo "Falling back to using our own copy of libgadu"
1.60 - echo
1.61 - GADU_LIBS=""
1.62 - GADU_CFLAGS=""
1.63 - gadu_libs=no
1.64 - ])
1.65 + AC_MSG_RESULT(yes)
1.66 ], [
1.67 AC_MSG_RESULT(no)
1.68 echo
1.69 @@ -1147,6 +1140,35 @@
1.70 CPPFLAGS="$CPPFLAGS_save"
1.71 fi
1.72
1.73 +if test "x$gadu_libs" = "xyes" -a "x$gadu_manual_check" = "xyes"; then
1.74 + AC_MSG_CHECKING(for supplied libgadu compatibility)
1.75 + CPPFLAGS_save="$CPPFLAGS"
1.76 + CPPFLAGS="$CPPFLAGS $GADU_CFLAGS"
1.77 +
1.78 + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libgadu.h>]], [[
1.79 +#if GG_DEFAULT_PROTOCOL_VERSION < 0x2e
1.80 +#error "Your libgadu version is too old."
1.81 +#endif
1.82 + ]])], [
1.83 + AC_MSG_RESULT(yes)
1.84 + ], [
1.85 + AC_MSG_RESULT(no)
1.86 + echo
1.87 + echo "Your supplied copy of libgadu is too old."
1.88 + echo "Install version $GADU_LIBGADU_VERSION or newer."
1.89 + echo "Then rerun this ./configure"
1.90 + echo
1.91 + echo "Falling back to using our own copy of libgadu"
1.92 + echo
1.93 + GADU_LIBS=""
1.94 + GADU_CFLAGS=""
1.95 + gadu_libs=no
1.96 + ])
1.97 +
1.98 + CPPFLAGS="$CPPFLAGS_save"
1.99 +fi
1.100 +
1.101 +AM_CONDITIONAL(HAVE_LIBGADU, test "x$gadu_libs" = "xyes")
1.102 AM_CONDITIONAL(USE_INTERNAL_LIBGADU, test "x$gadu_libs" != "xyes")
1.103
1.104 if test "x$gadu_libs" = "x"; then
1.105 @@ -1155,6 +1177,7 @@
1.106
1.107 AC_SUBST(GADU_LIBS)
1.108 AC_SUBST(GADU_CFLAGS)
1.109 +AC_SUBST(GADU_LIBGADU_VERSION)
1.110
1.111 AC_ARG_ENABLE(distrib,,,enable_distrib=no)
1.112 AM_CONDITIONAL(DISTRIB, test "x$enable_distrib" = "xyes")
2.1 --- a/libpurple/eventloop.c
2.2 +++ b/libpurple/eventloop.c
2.3 @@ -91,6 +91,16 @@
2.4 }
2.5 }
2.6
2.7 +int
2.8 +purple_input_pipe(int pipefd[2])
2.9 +{
2.10 +#ifdef _WIN32
2.11 + return wpurple_input_pipe(pipefd);
2.12 +#else
2.13 + return pipe(pipefd);
2.14 +#endif
2.15 +}
2.16 +
2.17 void
2.18 purple_eventloop_set_ui_ops(PurpleEventLoopUiOps *ops)
2.19 {
3.1 --- a/libpurple/eventloop.h
3.2 +++ b/libpurple/eventloop.h
3.3 @@ -240,6 +240,24 @@
3.4 int
3.5 purple_input_get_error(int fd, int *error);
3.6
3.7 +/**
3.8 + * Creates a pipe - an unidirectional data channel that can be used for
3.9 + * interprocess communication.
3.10 + *
3.11 + * File descriptors for both ends of pipe will be written into provided array.
3.12 + * The first one (pipefd[0]) can be used for reading, the second one (pipefd[1])
3.13 + * for writing.
3.14 + *
3.15 + * On Windows it's simulated by creating a pair of connected sockets, on other
3.16 + * systems pipe() is used.
3.17 + *
3.18 + * @param pipefd Array used to return file descriptors for both ends of pipe.
3.19 + *
3.20 + * @return @c 0 on success, @c -1 on error.
3.21 + */
3.22 +int
3.23 +purple_input_pipe(int pipefd[2]);
3.24 +
3.25
3.26 /*@}*/
3.27
4.1 --- a/libpurple/protocols/gg/Makefile.am
4.2 +++ b/libpurple/protocols/gg/Makefile.am
4.3 @@ -1,13 +1,20 @@
4.4 +V=0
4.5 +
4.6 +pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
4.7 +
4.8 EXTRA_DIST = \
4.9 Makefile.mingw \
4.10 - win32-resolver.c \
4.11 - win32-resolver.h \
4.12 + lib/COPYING
4.13 +
4.14 +if USE_INTERNAL_LIBGADU
4.15 +INTGGSOURCES = \
4.16 lib/common.c \
4.17 lib/compat.h \
4.18 - lib/COPYING \
4.19 + lib/config.h \
4.20 lib/dcc.c \
4.21 lib/dcc7.c \
4.22 lib/debug.c \
4.23 + lib/debug.h \
4.24 lib/deflate.c \
4.25 lib/deflate.h \
4.26 lib/encoding.c \
4.27 @@ -15,11 +22,9 @@
4.28 lib/events.c \
4.29 lib/handlers.c \
4.30 lib/http.c \
4.31 + lib/internal.h \
4.32 + lib/libgadu.c \
4.33 lib/libgadu.h \
4.34 - lib/libgadu.c \
4.35 - lib/libgadu-config.h \
4.36 - lib/libgadu-debug.h \
4.37 - lib/libgadu-internal.h \
4.38 lib/message.c \
4.39 lib/message.h \
4.40 lib/obsolete.c \
4.41 @@ -31,38 +36,11 @@
4.42 lib/session.h \
4.43 lib/sha1.c
4.44
4.45 -pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
4.46 -
4.47 -if USE_INTERNAL_LIBGADU
4.48 -INTGGSOURCES = \
4.49 - lib/common.c \
4.50 - lib/compat.h \
4.51 - lib/dcc.c \
4.52 - lib/dcc7.c \
4.53 - lib/debug.c \
4.54 - lib/deflate.c \
4.55 - lib/deflate.h \
4.56 - lib/encoding.c \
4.57 - lib/encoding.h \
4.58 - lib/events.c \
4.59 - lib/handlers.c \
4.60 - lib/http.c \
4.61 - lib/libgadu.h \
4.62 - lib/libgadu.c \
4.63 - lib/libgadu-config.h \
4.64 - lib/libgadu-internal.h \
4.65 - lib/message.c \
4.66 - lib/message.h \
4.67 - lib/obsolete.c \
4.68 - lib/protocol.h \
4.69 - lib/pubdir.c \
4.70 - lib/pubdir50.c \
4.71 - lib/resolver.c \
4.72 - lib/resolver.h \
4.73 - lib/session.h \
4.74 - lib/sha1.c
4.75 -
4.76 -INTGG_CFLAGS = -I$(top_srcdir)/libpurple/protocols/gg/lib -DGG_IGNORE_DEPRECATED -DUSE_INTERNAL_LIBGADU
4.77 +INTGG_CFLAGS = -I$(top_srcdir)/libpurple/protocols/gg/lib \
4.78 + $(ZLIB_CFLAGS) \
4.79 + -DGG_IGNORE_DEPRECATED \
4.80 + -DGG_INTERNAL_LIBGADU_VERSION=$(GADU_LIBGADU_VERSION)
4.81 +GADU_LIBS += $(ZLIB_LIBS)
4.82 endif
4.83
4.84 if USE_GNUTLS
4.85 @@ -72,16 +50,50 @@
4.86
4.87 GGSOURCES = \
4.88 $(INTGGSOURCES) \
4.89 - gg-utils.h \
4.90 - gg-utils.c \
4.91 + utils.h \
4.92 + utils.c \
4.93 confer.h \
4.94 confer.c \
4.95 - search.h \
4.96 - search.c \
4.97 buddylist.h \
4.98 buddylist.c \
4.99 gg.h \
4.100 - gg.c
4.101 + gg.c \
4.102 + resolver-purple.h \
4.103 + resolver-purple.c \
4.104 + image.h \
4.105 + image.c \
4.106 + account.h \
4.107 + account.c \
4.108 + deprecated.h \
4.109 + deprecated.c \
4.110 + purplew.h \
4.111 + purplew.c \
4.112 + libgaduw.h \
4.113 + libgaduw.c \
4.114 + avatar.h \
4.115 + avatar.c \
4.116 + libgadu-events.h \
4.117 + libgadu-events.c \
4.118 + roster.c \
4.119 + roster.h \
4.120 + validator.c \
4.121 + validator.h \
4.122 + xml.c \
4.123 + xml.h \
4.124 + multilogon.c \
4.125 + multilogon.h \
4.126 + status.c \
4.127 + status.h \
4.128 + servconn.c \
4.129 + servconn.h \
4.130 + pubdir-prpl.c \
4.131 + pubdir-prpl.h \
4.132 + oauth/oauth.c \
4.133 + oauth/oauth.h \
4.134 + oauth/oauth-parameter.c \
4.135 + oauth/oauth-parameter.h \
4.136 + oauth/oauth-purple.c \
4.137 + oauth/oauth-purple.h
4.138
4.139 AM_CFLAGS = $(st)
4.140
4.141 @@ -105,9 +117,9 @@
4.142 endif
4.143
4.144 AM_CPPFLAGS = \
4.145 + -Wall -Wextra -Werror \
4.146 -I$(top_srcdir)/libpurple \
4.147 -I$(top_builddir)/libpurple \
4.148 $(INTGG_CFLAGS) \
4.149 $(GLIB_CFLAGS) \
4.150 $(DEBUG_CFLAGS)
4.151 -
5.1 --- a/libpurple/protocols/gg/Makefile.mingw
5.2 +++ b/libpurple/protocols/gg/Makefile.mingw
5.3 @@ -24,14 +24,14 @@
5.4 ##
5.5 ## INCLUDE PATHS
5.6 ##
5.7 -INCLUDE_PATHS += -I. \
5.8 +INCLUDE_PATHS +=\
5.9 + -I$(PIDGIN_TREE_TOP) \
5.10 + -I$(PURPLE_TOP) \
5.11 + -I$(PURPLE_TOP)/win32 \
5.12 -I./lib \
5.13 -I$(GTK_TOP)/include \
5.14 -I$(GTK_TOP)/include/glib-2.0 \
5.15 - -I$(GTK_TOP)/lib/glib-2.0/include \
5.16 - -I$(PURPLE_TOP) \
5.17 - -I$(PURPLE_TOP)/win32 \
5.18 - -I$(PIDGIN_TREE_TOP)
5.19 + -I$(GTK_TOP)/lib/glib-2.0/include
5.20
5.21 LIB_PATHS += -L$(GTK_TOP)/lib \
5.22 -L$(PURPLE_TOP) \
5.23 @@ -60,8 +60,8 @@
5.24 confer.c \
5.25 gg.c \
5.26 search.c \
5.27 - gg-utils.c \
5.28 - win32-resolver.c
5.29 + utils.c \
5.30 + resolver-purple.c
5.31
5.32 OBJECTS = $(C_SRC:%.c=%.o)
5.33
6.1 new file mode 100644
6.2 --- /dev/null
6.3 +++ b/libpurple/protocols/gg/account.c
6.4 @@ -0,0 +1,649 @@
6.5 +/* purple
6.6 + *
6.7 + * Purple is the legal property of its developers, whose names are too numerous
6.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
6.9 + * source distribution.
6.10 + *
6.11 + * Rewritten from scratch during Google Summer of Code 2012
6.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
6.13 + *
6.14 + * Previously implemented by:
6.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
6.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
6.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
6.18 + *
6.19 + * This program is free software; you can redistribute it and/or modify
6.20 + * it under the terms of the GNU General Public License as published by
6.21 + * the Free Software Foundation; either version 2 of the License, or
6.22 + * (at your option) any later version.
6.23 + *
6.24 + * This program is distributed in the hope that it will be useful,
6.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.27 + * GNU General Public License for more details.
6.28 + *
6.29 + * You should have received a copy of the GNU General Public License
6.30 + * along with this program; if not, write to the Free Software
6.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
6.32 + */
6.33 +
6.34 +#include "account.h"
6.35 +
6.36 +#include <libgadu.h>
6.37 +#include <debug.h>
6.38 +
6.39 +#include "deprecated.h"
6.40 +#include "purplew.h"
6.41 +#include "utils.h"
6.42 +#include "libgaduw.h"
6.43 +#include "validator.h"
6.44 +
6.45 +/*******************************************************************************
6.46 + * Token requesting.
6.47 + ******************************************************************************/
6.48 +
6.49 +typedef struct
6.50 +{
6.51 + ggp_account_token_cb callback;
6.52 + PurpleConnection *gc;
6.53 + void *user_data;
6.54 +} ggp_account_token_reqdata;
6.55 +
6.56 +static void ggp_account_token_response(struct gg_http *h, gboolean success,
6.57 + gboolean cancelled, gpointer _reqdata);
6.58 +
6.59 +/******************************************************************************/
6.60 +
6.61 +void ggp_account_token_free(ggp_account_token *token)
6.62 +{
6.63 + if (!token)
6.64 + return;
6.65 + g_free(token->id);
6.66 + g_free(token->data);
6.67 + g_free(token);
6.68 +}
6.69 +
6.70 +void ggp_account_token_request(PurpleConnection *gc,
6.71 + ggp_account_token_cb callback, void *user_data)
6.72 +{
6.73 + struct gg_http *h;
6.74 + ggp_account_token_reqdata *reqdata;
6.75 +
6.76 + purple_debug_info("gg", "ggp_account_token_request: "
6.77 + "requesting token...\n");
6.78 +
6.79 + if (!ggp_deprecated_setup_proxy(gc))
6.80 + {
6.81 + callback(gc, NULL, user_data);
6.82 + return;
6.83 + }
6.84 +
6.85 + h = gg_token(TRUE);
6.86 +
6.87 + if (!h)
6.88 + {
6.89 + callback(gc, NULL, user_data);
6.90 + return;
6.91 + }
6.92 +
6.93 + reqdata = g_new(ggp_account_token_reqdata, 1);
6.94 + reqdata->callback = callback;
6.95 + reqdata->gc = gc;
6.96 + reqdata->user_data = user_data;
6.97 + ggp_libgaduw_http_watch(gc, h, ggp_account_token_response, reqdata,
6.98 + TRUE);
6.99 +}
6.100 +
6.101 +static void ggp_account_token_response(struct gg_http *h, gboolean success,
6.102 + gboolean cancelled, gpointer _reqdata)
6.103 +{
6.104 + ggp_account_token_reqdata *reqdata = _reqdata;
6.105 + struct gg_token *token_info;
6.106 + ggp_account_token *token = NULL;
6.107 +
6.108 + g_assert(!(success && cancelled));
6.109 +
6.110 + if (cancelled)
6.111 + purple_debug_info("gg", "ggp_account_token_handler: "
6.112 + "cancelled\n");
6.113 + else if (success)
6.114 + {
6.115 + purple_debug_info("gg", "ggp_account_token_handler: "
6.116 + "got token\n");
6.117 +
6.118 + token = g_new(ggp_account_token, 1);
6.119 +
6.120 + token_info = h->data;
6.121 + token->id = g_strdup(token_info->tokenid);
6.122 + token->size = h->body_size;
6.123 + token->data = g_memdup(h->body, token->size);
6.124 + token->length = token_info->length;
6.125 + }
6.126 + else
6.127 + {
6.128 + purple_debug_error("gg", "ggp_account_token_handler: error\n");
6.129 + purple_notify_error(
6.130 + purple_connection_get_account(reqdata->gc),
6.131 + _("Token Error"),
6.132 + _("Unable to fetch the token."), NULL);
6.133 + }
6.134 +
6.135 + reqdata->callback(reqdata->gc, token, reqdata->user_data);
6.136 + g_free(reqdata);
6.137 +}
6.138 +
6.139 +gboolean ggp_account_token_validate(ggp_account_token *token,
6.140 + const gchar *value)
6.141 +{
6.142 + if (strlen(value) != token->length)
6.143 + return FALSE;
6.144 + return g_regex_match_simple("^[a-zA-Z0-9]+$", value, 0, 0);
6.145 +}
6.146 +
6.147 +/*******************************************************************************
6.148 + * New account registration.
6.149 + ******************************************************************************/
6.150 +
6.151 +typedef struct
6.152 +{
6.153 + ggp_account_token *token;
6.154 + PurpleConnection *gc;
6.155 +
6.156 + gchar *email;
6.157 + gchar *password;
6.158 + gchar *token_value;
6.159 + gboolean password_remember;
6.160 +} ggp_account_register_data;
6.161 +
6.162 +static void ggp_account_register_dialog(PurpleConnection *gc,
6.163 + ggp_account_token *token, gpointer _register_data);
6.164 +static void ggp_account_register_dialog_ok(
6.165 + ggp_account_register_data *register_data, PurpleRequestFields *fields);
6.166 +#if 0
6.167 +static void ggp_account_register_dialog_invalid(
6.168 + ggp_account_register_data *register_data, const gchar *message);
6.169 +#endif
6.170 +static void ggp_account_register_dialog_cancel(
6.171 + ggp_account_register_data *register_data, PurpleRequestFields *fields);
6.172 +static void ggp_account_register_response(struct gg_http *h, gboolean success,
6.173 + gboolean cancelled, gpointer _reqdata);
6.174 +static void ggp_account_register_completed(
6.175 + ggp_account_register_data *register_data, gboolean success);
6.176 +
6.177 +#define GGP_ACCOUNT_REGISTER_TITLE _("Register New Gadu-Gadu Account")
6.178 +
6.179 +/******************************************************************************/
6.180 +
6.181 +void ggp_account_register(PurpleAccount *account)
6.182 +{
6.183 + PurpleConnection *gc = purple_account_get_connection(account);
6.184 + ggp_account_register_data *register_data;
6.185 +
6.186 + purple_debug_info("gg", "ggp_account_register\n");
6.187 +
6.188 + register_data = g_new0(ggp_account_register_data, 1);
6.189 + register_data->gc = gc;
6.190 + register_data->password_remember = TRUE;
6.191 +
6.192 + ggp_account_token_request(gc, ggp_account_register_dialog,
6.193 + register_data);
6.194 +}
6.195 +
6.196 +static void ggp_account_register_dialog(PurpleConnection *gc,
6.197 + ggp_account_token *token, gpointer _register_data)
6.198 +{
6.199 + PurpleRequestFields *fields;
6.200 + PurpleRequestFieldGroup *main_group, *password_group, *token_group;
6.201 + PurpleRequestField *field, *field_password;
6.202 + ggp_account_register_data *register_data = _register_data;
6.203 +
6.204 + purple_debug_info("gg", "ggp_account_register_dialog(%x, %x, %x)\n",
6.205 + (unsigned int)gc, (unsigned int)token,
6.206 + (unsigned int)_register_data);
6.207 + if (!token)
6.208 + {
6.209 + ggp_account_register_completed(register_data, FALSE);
6.210 + return;
6.211 + }
6.212 +
6.213 + fields = purple_request_fields_new();
6.214 + main_group = purple_request_field_group_new(NULL);
6.215 + purple_request_fields_add_group(fields, main_group);
6.216 +
6.217 + field = purple_request_field_string_new("email", _("Email"),
6.218 + register_data->email, FALSE);
6.219 + purple_request_field_set_required(field, TRUE);
6.220 + purple_request_field_set_validator(field,
6.221 + purple_request_field_email_validator, NULL);
6.222 + purple_request_field_group_add_field(main_group, field);
6.223 +
6.224 + password_group = purple_request_field_group_new(_("Password"));
6.225 + purple_request_fields_add_group(fields, password_group);
6.226 +
6.227 + field = purple_request_field_string_new("password1", _("Password"),
6.228 + register_data->password, FALSE);
6.229 + purple_request_field_set_required(field, TRUE);
6.230 + purple_request_field_string_set_masked(field, TRUE);
6.231 + purple_request_field_set_validator(field, ggp_validator_password, NULL);
6.232 + purple_request_field_group_add_field(password_group, field);
6.233 + field_password = field;
6.234 +
6.235 + field = purple_request_field_string_new("password2",
6.236 + _("Password (again)"), register_data->password, FALSE);
6.237 + purple_request_field_set_required(field, TRUE);
6.238 + purple_request_field_string_set_masked(field, TRUE);
6.239 + purple_request_field_set_validator(field, ggp_validator_password_equal,
6.240 + field_password);
6.241 + purple_request_field_group_add_field(password_group, field);
6.242 +
6.243 + field = purple_request_field_bool_new("password_remember",
6.244 + _("Remember password"), register_data->password_remember);
6.245 + purple_request_field_group_add_field(password_group, field);
6.246 +
6.247 + token_group = purple_request_field_group_new(_("Captcha"));
6.248 + purple_request_fields_add_group(fields, token_group);
6.249 +
6.250 + field = purple_request_field_string_new("token_value",
6.251 + _("Enter text from image below"), register_data->token_value,
6.252 + FALSE);
6.253 + purple_request_field_set_required(field, TRUE);
6.254 + purple_request_field_set_validator(field, ggp_validator_token, token);
6.255 + purple_request_field_group_add_field(token_group, field);
6.256 + purple_debug_info("gg", "token set %p\n", register_data->token);
6.257 +
6.258 + field = purple_request_field_image_new("token_image", _("Captcha"),
6.259 + token->data, token->size);
6.260 + purple_request_field_group_add_field(token_group, field);
6.261 +
6.262 + register_data->token = token;
6.263 +
6.264 + purple_request_fields(gc,
6.265 + GGP_ACCOUNT_REGISTER_TITLE,
6.266 + GGP_ACCOUNT_REGISTER_TITLE,
6.267 + _("Please, fill in the following fields"), fields,
6.268 + _("OK"), G_CALLBACK(ggp_account_register_dialog_ok),
6.269 + _("Cancel"), G_CALLBACK(ggp_account_register_dialog_cancel),
6.270 + purple_connection_get_account(gc), NULL, NULL, register_data);
6.271 +}
6.272 +
6.273 +static void ggp_account_register_dialog_cancel(
6.274 + ggp_account_register_data *register_data, PurpleRequestFields *fields)
6.275 +{
6.276 + purple_debug_info("gg", "ggp_account_register_dialog_cancel(%x, %x)\n",
6.277 + (unsigned int)register_data, (unsigned int)fields);
6.278 +
6.279 + ggp_account_register_completed(register_data, FALSE);
6.280 +}
6.281 +
6.282 +static void ggp_account_register_dialog_ok(
6.283 + ggp_account_register_data *register_data, PurpleRequestFields *fields)
6.284 +{
6.285 + struct gg_http *h;
6.286 +
6.287 + purple_debug_misc("gg", "ggp_account_register_dialog_ok(%x, %x)\n",
6.288 + (unsigned int)register_data, (unsigned int)fields);
6.289 +
6.290 + g_free(register_data->email);
6.291 + g_free(register_data->password);
6.292 + g_free(register_data->token_value);
6.293 +
6.294 + register_data->email = g_strdup(
6.295 + purple_request_fields_get_string(fields, "email"));
6.296 + register_data->password = g_strdup(
6.297 + purple_request_fields_get_string(fields, "password1"));
6.298 + register_data->password_remember =
6.299 + purple_request_fields_get_bool(fields, "password_remember");
6.300 + register_data->token_value = g_strdup(
6.301 + purple_request_fields_get_string(fields, "token_value"));
6.302 +
6.303 + g_assert(register_data->email != NULL);
6.304 + g_assert(register_data->password != NULL);
6.305 + g_assert(register_data->token_value != NULL);
6.306 +
6.307 + h = gg_register3(register_data->email, register_data->password,
6.308 + register_data->token->id, register_data->token_value, TRUE);
6.309 +
6.310 + ggp_libgaduw_http_watch(register_data->gc, h,
6.311 + ggp_account_register_response, register_data, TRUE);
6.312 +}
6.313 +
6.314 +#if 0
6.315 +// libgadu 1.12.x: use it for invalid token
6.316 +static void ggp_account_register_dialog_invalid(
6.317 + ggp_account_register_data *register_data, const gchar *message)
6.318 +{
6.319 + purple_debug_warning("gg", "ggp_account_register_dialog_invalid: %s\n",
6.320 + message);
6.321 + ggp_account_register_dialog(register_data->gc, register_data->token,
6.322 + register_data);
6.323 + purple_notify_error(purple_connection_get_account(register_data->gc),
6.324 + GGP_ACCOUNT_REGISTER_TITLE, message, NULL);
6.325 +}
6.326 +#endif
6.327 +
6.328 +static void ggp_account_register_response(struct gg_http *h, gboolean success,
6.329 + gboolean cancelled, gpointer _register_data)
6.330 +{
6.331 + ggp_account_register_data *register_data = _register_data;
6.332 + PurpleAccount *account =
6.333 + purple_connection_get_account(register_data->gc);
6.334 + struct gg_pubdir *register_result = h->data;
6.335 + uin_t uin;
6.336 + gchar *tmp;
6.337 +
6.338 + g_assert(!(success && cancelled));
6.339 +
6.340 + if (cancelled)
6.341 + {
6.342 + purple_debug_info("gg", "ggp_account_register_response: "
6.343 + "cancelled\n");
6.344 + ggp_account_register_completed(register_data, FALSE);
6.345 + return;
6.346 + }
6.347 + if (!success || !register_result->success)
6.348 + {
6.349 + //TODO (libgadu 1.12.x): check register_result->error
6.350 + purple_debug_error("gg", "ggp_account_register_response: "
6.351 + "error\n");
6.352 + purple_notify_error(NULL,
6.353 + GGP_ACCOUNT_REGISTER_TITLE,
6.354 + _("Unable to register new account. "
6.355 + "An unknown error occurred."), NULL);
6.356 + ggp_account_register_completed(register_data, FALSE);
6.357 + return;
6.358 + }
6.359 +
6.360 + uin = register_result->uin;
6.361 + purple_debug_info("gg", "ggp_account_register_response: "
6.362 + "registered uin %u\n", uin);
6.363 +
6.364 + purple_account_set_username(account, ggp_uin_to_str(uin));
6.365 + purple_account_set_remember_password(account,
6.366 + register_data->password_remember);
6.367 + purple_account_set_password(account, register_data->password);
6.368 +
6.369 + tmp = g_strdup_printf(_("Your new GG number: %u."), uin);
6.370 + purple_notify_info(account, GGP_ACCOUNT_REGISTER_TITLE,
6.371 + _("Registration completed successfully!"), tmp);
6.372 + g_free(tmp);
6.373 +
6.374 + ggp_account_register_completed(register_data, TRUE);
6.375 +}
6.376 +
6.377 +static void ggp_account_register_completed(
6.378 + ggp_account_register_data *register_data, gboolean success)
6.379 +{
6.380 + PurpleAccount *account =
6.381 + purple_connection_get_account(register_data->gc);
6.382 +
6.383 + purple_debug_misc("gg", "ggp_account_register_completed: %d\n",
6.384 + success);
6.385 +
6.386 + g_free(register_data->email);
6.387 + g_free(register_data->password);
6.388 + g_free(register_data->token_value);
6.389 + ggp_account_token_free(register_data->token);
6.390 + g_free(register_data);
6.391 +
6.392 + purple_account_disconnect(account);
6.393 + purple_account_register_completed(account, success);
6.394 +}
6.395 +
6.396 +/*******************************************************************************
6.397 + * Password change.
6.398 + ******************************************************************************/
6.399 +
6.400 +typedef struct
6.401 +{
6.402 + ggp_account_token *token;
6.403 + PurpleConnection *gc;
6.404 +
6.405 + gchar *email;
6.406 + gchar *password_current;
6.407 + gchar *password_new;
6.408 + gchar *token_value;
6.409 +} ggp_account_chpass_data;
6.410 +
6.411 +static void ggp_account_chpass_data_free(ggp_account_chpass_data *chpass_data);
6.412 +static void ggp_account_chpass_dialog(PurpleConnection *gc,
6.413 + ggp_account_token *token, gpointer _chpass_data);
6.414 +static void ggp_account_chpass_dialog_ok(
6.415 + ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields);
6.416 +static void ggp_account_chpass_dialog_invalid(
6.417 + ggp_account_chpass_data *chpass_data, const gchar *message);
6.418 +static void ggp_account_chpass_dialog_cancel(
6.419 + ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields);
6.420 +static void ggp_account_chpass_response(struct gg_http *h, gboolean success,
6.421 + gboolean cancelled, gpointer _chpass_data);
6.422 +
6.423 +#define GGP_ACCOUNT_CHPASS_TITLE _("Password change")
6.424 +
6.425 +/******************************************************************************/
6.426 +
6.427 +static void ggp_account_chpass_data_free(ggp_account_chpass_data *chpass_data)
6.428 +{
6.429 + g_free(chpass_data->email);
6.430 + g_free(chpass_data->password_current);
6.431 + g_free(chpass_data->password_new);
6.432 + g_free(chpass_data->token_value);
6.433 + ggp_account_token_free(chpass_data->token);
6.434 + g_free(chpass_data);
6.435 +}
6.436 +
6.437 +void ggp_account_chpass(PurpleConnection *gc)
6.438 +{
6.439 + ggp_account_chpass_data *chpass_data;
6.440 + void ggp_account_change_passwd(PurpleConnection *gc);
6.441 + purple_debug_info("gg", "ggp_account_chpass\n");
6.442 +
6.443 + chpass_data = g_new0(ggp_account_chpass_data, 1);
6.444 + chpass_data->gc = gc;
6.445 +
6.446 + ggp_account_token_request(gc, ggp_account_chpass_dialog, chpass_data);
6.447 +}
6.448 +
6.449 +static void ggp_account_chpass_dialog(PurpleConnection *gc,
6.450 + ggp_account_token *token, gpointer _chpass_data)
6.451 +{
6.452 + ggp_account_chpass_data *chpass_data = _chpass_data;
6.453 + PurpleAccount *account = purple_connection_get_account(chpass_data->gc);
6.454 + PurpleRequestFields *fields;
6.455 + PurpleRequestFieldGroup *main_group, *password_group, *token_group;
6.456 + PurpleRequestField *field, *field_password;
6.457 + gchar *primary;
6.458 +
6.459 + purple_debug_info("gg", "ggp_account_chpass_dialog(%p, %p, %p)\n",
6.460 + gc, token, _chpass_data);
6.461 + if (!token)
6.462 + {
6.463 + ggp_account_chpass_data_free(chpass_data);
6.464 + return;
6.465 + }
6.466 +
6.467 + fields = purple_request_fields_new();
6.468 + main_group = purple_request_field_group_new(NULL);
6.469 + purple_request_fields_add_group(fields, main_group);
6.470 +
6.471 + field = purple_request_field_string_new("email",
6.472 + _("New email address"), chpass_data->email, FALSE);
6.473 + purple_request_field_set_required(field, TRUE);
6.474 + purple_request_field_set_validator(field,
6.475 + purple_request_field_email_validator, NULL);
6.476 + purple_request_field_group_add_field(main_group, field);
6.477 +
6.478 + password_group = purple_request_field_group_new(_("Password"));
6.479 + purple_request_fields_add_group(fields, password_group);
6.480 +
6.481 + field = purple_request_field_string_new("password_current",
6.482 + _("Current password"), chpass_data->password_current, FALSE);
6.483 + purple_request_field_set_required(field, TRUE);
6.484 + purple_request_field_string_set_masked(field, TRUE);
6.485 + purple_request_field_group_add_field(password_group, field);
6.486 +
6.487 + field = purple_request_field_string_new("password_new1",
6.488 + _("Password"), chpass_data->password_new, FALSE);
6.489 + purple_request_field_set_required(field, TRUE);
6.490 + purple_request_field_string_set_masked(field, TRUE);
6.491 + purple_request_field_set_validator(field, ggp_validator_password, NULL);
6.492 + purple_request_field_group_add_field(password_group, field);
6.493 + field_password = field;
6.494 +
6.495 + field = purple_request_field_string_new("password_new2",
6.496 + _("Password (retype)"), chpass_data->password_new, FALSE);
6.497 + purple_request_field_set_required(field, TRUE);
6.498 + purple_request_field_string_set_masked(field, TRUE);
6.499 + purple_request_field_set_validator(field, ggp_validator_password_equal,
6.500 + field_password);
6.501 + purple_request_field_group_add_field(password_group, field);
6.502 +
6.503 + token_group = purple_request_field_group_new(_("Captcha"));
6.504 + purple_request_fields_add_group(fields, token_group);
6.505 +
6.506 + field = purple_request_field_string_new("token_value",
6.507 + _("Enter text from image below"), chpass_data->token_value,
6.508 + FALSE);
6.509 + purple_request_field_set_required(field, TRUE);
6.510 + purple_request_field_set_validator(field, ggp_validator_token, token);
6.511 + purple_request_field_group_add_field(token_group, field);
6.512 +
6.513 + field = purple_request_field_image_new("token_image", _("Captcha"),
6.514 + token->data, token->size);
6.515 + purple_request_field_group_add_field(token_group, field);
6.516 +
6.517 + chpass_data->token = token;
6.518 +
6.519 + primary = g_strdup_printf(_("Change password for %s"),
6.520 + purple_account_get_username(account));
6.521 +
6.522 + purple_request_fields(gc, GGP_ACCOUNT_CHPASS_TITLE, primary,
6.523 + _("Please enter your current password and your new password."),
6.524 + fields,
6.525 + _("OK"), G_CALLBACK(ggp_account_chpass_dialog_ok),
6.526 + _("Cancel"), G_CALLBACK(ggp_account_chpass_dialog_cancel),
6.527 + account, NULL, NULL, chpass_data);
6.528 +
6.529 + g_free(primary);
6.530 +}
6.531 +
6.532 +static void ggp_account_chpass_dialog_ok(
6.533 + ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields)
6.534 +{
6.535 + PurpleAccount *account = purple_connection_get_account(chpass_data->gc);
6.536 + struct gg_http *h;
6.537 + uin_t uin;
6.538 +
6.539 + purple_debug_misc("gg", "ggp_account_chpass_dialog_ok(%p, %p)\n",
6.540 + chpass_data, fields);
6.541 +
6.542 + g_free(chpass_data->email);
6.543 + g_free(chpass_data->password_current);
6.544 + g_free(chpass_data->password_new);
6.545 + g_free(chpass_data->token_value);
6.546 +
6.547 + chpass_data->email = g_strdup(
6.548 + purple_request_fields_get_string(fields, "email"));
6.549 + chpass_data->password_current = g_strdup(
6.550 + purple_request_fields_get_string(fields, "password_current"));
6.551 + chpass_data->password_new = g_strdup(
6.552 + purple_request_fields_get_string(fields, "password_new1"));
6.553 + chpass_data->token_value = g_strdup(
6.554 + purple_request_fields_get_string(fields, "token_value"));
6.555 +
6.556 + g_assert(chpass_data->email != NULL);
6.557 + g_assert(chpass_data->password_current != NULL);
6.558 + g_assert(chpass_data->password_new != NULL);
6.559 + g_assert(chpass_data->token_value != NULL);
6.560 +
6.561 + if (g_utf8_collate(chpass_data->password_current,
6.562 + purple_account_get_password(account)) != 0)
6.563 + {
6.564 + g_free(chpass_data->password_current);
6.565 + chpass_data->password_current = NULL;
6.566 + ggp_account_chpass_dialog_invalid(chpass_data,
6.567 + _("Your current password is different from the one that"
6.568 + " you specified."));
6.569 + return;
6.570 + }
6.571 + if (g_utf8_collate(chpass_data->password_current,
6.572 + chpass_data->password_new) == 0)
6.573 + {
6.574 + g_free(chpass_data->password_new);
6.575 + chpass_data->password_new = NULL;
6.576 + ggp_account_chpass_dialog_invalid(chpass_data,
6.577 + _("New password have to be different from the current "
6.578 + "one."));
6.579 + return;
6.580 + }
6.581 +
6.582 + uin = ggp_str_to_uin(purple_account_get_username(account));
6.583 + purple_debug_info("gg", "ggp_account_chpass_dialog_ok: validation ok "
6.584 + "[token id=%s, value=%s]\n",
6.585 + chpass_data->token->id, chpass_data->token_value);
6.586 + h = gg_change_passwd4(uin, chpass_data->email,
6.587 + chpass_data->password_current, chpass_data->password_new,
6.588 + chpass_data->token->id, chpass_data->token_value, TRUE);
6.589 +
6.590 + ggp_libgaduw_http_watch(chpass_data->gc, h,
6.591 + ggp_account_chpass_response, chpass_data, TRUE);
6.592 +}
6.593 +
6.594 +static void ggp_account_chpass_dialog_invalid(
6.595 + ggp_account_chpass_data *chpass_data, const gchar *message)
6.596 +{
6.597 + purple_debug_warning("gg", "ggp_account_chpass_dialog_invalid: %s\n",
6.598 + message);
6.599 + ggp_account_chpass_dialog(chpass_data->gc, chpass_data->token,
6.600 + chpass_data);
6.601 + purple_notify_error(purple_connection_get_account(chpass_data->gc),
6.602 + GGP_ACCOUNT_CHPASS_TITLE, message, NULL);
6.603 +}
6.604 +
6.605 +static void ggp_account_chpass_dialog_cancel(
6.606 + ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields)
6.607 +{
6.608 + ggp_account_chpass_data_free(chpass_data);
6.609 +}
6.610 +
6.611 +static void ggp_account_chpass_response(struct gg_http *h, gboolean success,
6.612 + gboolean cancelled, gpointer _chpass_data)
6.613 +{
6.614 + ggp_account_chpass_data *chpass_data = _chpass_data;
6.615 + PurpleAccount *account =
6.616 + purple_connection_get_account(chpass_data->gc);
6.617 + struct gg_pubdir *chpass_result = h->data;
6.618 +
6.619 + g_assert(!(success && cancelled));
6.620 +
6.621 + if (cancelled)
6.622 + {
6.623 + purple_debug_info("gg", "ggp_account_chpass_response: "
6.624 + "cancelled\n");
6.625 + ggp_account_chpass_data_free(chpass_data);
6.626 + return;
6.627 + }
6.628 + if (!success || !chpass_result->success)
6.629 + {
6.630 + //TODO (libgadu 1.12.x): check chpass_result->error
6.631 + purple_debug_error("gg", "ggp_account_chpass_response: "
6.632 + "error\n");
6.633 + purple_notify_error(NULL,
6.634 + GGP_ACCOUNT_CHPASS_TITLE,
6.635 + _("Unable to change password. "
6.636 + "An unknown error occurred."), NULL);
6.637 + ggp_account_chpass_data_free(chpass_data);
6.638 + return;
6.639 + }
6.640 +
6.641 + purple_debug_info("gg", "ggp_account_chpass_response: "
6.642 + "password changed\n");
6.643 +
6.644 + purple_account_set_password(account, chpass_data->password_new);
6.645 +
6.646 + purple_notify_info(account, GGP_ACCOUNT_CHPASS_TITLE,
6.647 + _("Your password has been changed."), NULL);
6.648 +
6.649 + ggp_account_chpass_data_free(chpass_data);
6.650 +
6.651 + //TODO: reconnect / check how it is done in original client
6.652 + purple_account_disconnect(account);
6.653 +}
7.1 new file mode 100644
7.2 --- /dev/null
7.3 +++ b/libpurple/protocols/gg/account.h
7.4 @@ -0,0 +1,60 @@
7.5 +/* purple
7.6 + *
7.7 + * Purple is the legal property of its developers, whose names are too numerous
7.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
7.9 + * source distribution.
7.10 + *
7.11 + * Rewritten from scratch during Google Summer of Code 2012
7.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
7.13 + *
7.14 + * Previously implemented by:
7.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
7.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
7.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
7.18 + *
7.19 + * This program is free software; you can redistribute it and/or modify
7.20 + * it under the terms of the GNU General Public License as published by
7.21 + * the Free Software Foundation; either version 2 of the License, or
7.22 + * (at your option) any later version.
7.23 + *
7.24 + * This program is distributed in the hope that it will be useful,
7.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.27 + * GNU General Public License for more details.
7.28 + *
7.29 + * You should have received a copy of the GNU General Public License
7.30 + * along with this program; if not, write to the Free Software
7.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
7.32 + */
7.33 +
7.34 +#ifndef _GGP_ACCOUNT_H
7.35 +#define _GGP_ACCOUNT_H
7.36 +
7.37 +#include <internal.h>
7.38 +
7.39 +typedef struct
7.40 +{
7.41 + gchar *id;
7.42 + gpointer data;
7.43 + size_t size;
7.44 + int length;
7.45 +} ggp_account_token;
7.46 +
7.47 +/**
7.48 + * token must be free'd with ggp_account_token_free
7.49 + */
7.50 +typedef void (*ggp_account_token_cb)(PurpleConnection *gc,
7.51 + ggp_account_token *token, gpointer user_data);
7.52 +
7.53 +void ggp_account_token_request(PurpleConnection *gc,
7.54 + ggp_account_token_cb callback, void *user_data);
7.55 +gboolean ggp_account_token_validate(ggp_account_token *token,
7.56 + const gchar *value);
7.57 +void ggp_account_token_free(ggp_account_token *token);
7.58 +
7.59 +
7.60 +void ggp_account_register(PurpleAccount *account);
7.61 +
7.62 +void ggp_account_chpass(PurpleConnection *gc);
7.63 +
7.64 +#endif /* _GGP_ACCOUNT_H */
8.1 new file mode 100644
8.2 --- /dev/null
8.3 +++ b/libpurple/protocols/gg/avatar.c
8.4 @@ -0,0 +1,392 @@
8.5 +/* purple
8.6 + *
8.7 + * Purple is the legal property of its developers, whose names are too numerous
8.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
8.9 + * source distribution.
8.10 + *
8.11 + * Rewritten from scratch during Google Summer of Code 2012
8.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
8.13 + *
8.14 + * Previously implemented by:
8.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
8.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
8.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
8.18 + *
8.19 + * This program is free software; you can redistribute it and/or modify
8.20 + * it under the terms of the GNU General Public License as published by
8.21 + * the Free Software Foundation; either version 2 of the License, or
8.22 + * (at your option) any later version.
8.23 + *
8.24 + * This program is distributed in the hope that it will be useful,
8.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.27 + * GNU General Public License for more details.
8.28 + *
8.29 + * You should have received a copy of the GNU General Public License
8.30 + * along with this program; if not, write to the Free Software
8.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
8.32 + */
8.33 +
8.34 +#include "avatar.h"
8.35 +
8.36 +#include <debug.h>
8.37 +
8.38 +#include "gg.h"
8.39 +#include "utils.h"
8.40 +#include "oauth/oauth-purple.h"
8.41 +
8.42 +// Common
8.43 +
8.44 +static inline ggp_avatar_session_data *
8.45 +ggp_avatar_get_avdata(PurpleConnection *gc);
8.46 +
8.47 +static gboolean ggp_avatar_timer_cb(gpointer _gc);
8.48 +
8.49 +#define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562"
8.50 +#define GGP_AVATAR_SIZE_MAX 1048576
8.51 +
8.52 +// Buddy avatars updating
8.53 +
8.54 +typedef struct
8.55 +{
8.56 + uin_t uin;
8.57 + time_t timestamp;
8.58 +
8.59 + PurpleConnection *gc;
8.60 + PurpleUtilFetchUrlData *request;
8.61 +} ggp_avatar_buddy_update_req;
8.62 +
8.63 +static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc);
8.64 +static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
8.65 + gpointer _pending_update, const gchar *url_text, gsize len,
8.66 + const gchar *error_message);
8.67 +
8.68 +#define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big"
8.69 +
8.70 +// Own avatar setting
8.71 +
8.72 +typedef struct
8.73 +{
8.74 + PurpleStoredImage *img;
8.75 +} ggp_avatar_own_data;
8.76 +
8.77 +static void ggp_avatar_own_got_token(PurpleConnection *gc, const gchar *token,
8.78 + gpointer img);
8.79 +static void ggp_avatar_own_sent(PurpleUtilFetchUrlData *url_data,
8.80 + gpointer user_data, const gchar *url_text, gsize len,
8.81 + const gchar *error_message);
8.82 +
8.83 +#define GGP_AVATAR_RESPONSE_MAX 10240
8.84 +
8.85 +/*******************************************************************************
8.86 + * Common.
8.87 + ******************************************************************************/
8.88 +
8.89 +void ggp_avatar_setup(PurpleConnection *gc)
8.90 +{
8.91 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
8.92 +
8.93 + avdata->pending_updates = NULL;
8.94 + avdata->current_update = NULL;
8.95 + avdata->own_data = g_new0(ggp_avatar_own_data, 1);
8.96 +
8.97 + avdata->timer = purple_timeout_add_seconds(1, ggp_avatar_timer_cb, gc);
8.98 +}
8.99 +
8.100 +void ggp_avatar_cleanup(PurpleConnection *gc)
8.101 +{
8.102 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
8.103 +
8.104 + purple_timeout_remove(avdata->timer);
8.105 +
8.106 + if (avdata->current_update != NULL)
8.107 + {
8.108 + ggp_avatar_buddy_update_req *current_update =
8.109 + avdata->current_update;
8.110 +
8.111 + purple_util_fetch_url_cancel(current_update->request);
8.112 + g_free(current_update);
8.113 + }
8.114 + avdata->current_update = NULL;
8.115 +
8.116 + g_free(avdata->own_data);
8.117 +
8.118 + g_list_free_full(avdata->pending_updates, &g_free);
8.119 + avdata->pending_updates = NULL;
8.120 +}
8.121 +
8.122 +static inline ggp_avatar_session_data *
8.123 +ggp_avatar_get_avdata(PurpleConnection *gc)
8.124 +{
8.125 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
8.126 + return &accdata->avatar_data;
8.127 +}
8.128 +
8.129 +static gboolean ggp_avatar_timer_cb(gpointer _gc)
8.130 +{
8.131 + PurpleConnection *gc = _gc;
8.132 + ggp_avatar_session_data *avdata;
8.133 +
8.134 + g_return_val_if_fail(PURPLE_CONNECTION_IS_VALID(gc), FALSE);
8.135 +
8.136 + avdata = ggp_avatar_get_avdata(gc);
8.137 + if (avdata->current_update != NULL)
8.138 + {
8.139 + //TODO: verbose mode
8.140 + //purple_debug_misc("gg", "ggp_avatar_timer_cb(%p): there is "
8.141 + // "already an update running\n", gc);
8.142 + return TRUE;
8.143 + }
8.144 +
8.145 + while (!ggp_avatar_buddy_update_next(gc));
8.146 +
8.147 + return TRUE;
8.148 +}
8.149 +
8.150 +/*******************************************************************************
8.151 + * Buddy avatars updating.
8.152 + ******************************************************************************/
8.153 +
8.154 +void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp)
8.155 +{
8.156 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
8.157 + ggp_avatar_buddy_update_req *pending_update =
8.158 + g_new(ggp_avatar_buddy_update_req, 1);
8.159 +
8.160 + purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)\n", gc,
8.161 + uin, timestamp);
8.162 +
8.163 + pending_update->uin = uin;
8.164 + pending_update->timestamp = timestamp;
8.165 +
8.166 + avdata->pending_updates = g_list_append(avdata->pending_updates,
8.167 + pending_update);
8.168 +}
8.169 +
8.170 +void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin)
8.171 +{
8.172 + purple_debug_info("gg", "ggp_avatar_buddy_remove(%p, %u)\n", gc, uin);
8.173 +
8.174 + purple_buddy_icons_set_for_user(purple_connection_get_account(gc),
8.175 + ggp_uin_to_str(uin), NULL, 0, NULL);
8.176 +}
8.177 +
8.178 +/* return TRUE if avatar update was performed or there is no new requests,
8.179 + FALSE if we can request another one immediately */
8.180 +static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc)
8.181 +{
8.182 + ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
8.183 + GList *pending_update_it;
8.184 + ggp_avatar_buddy_update_req *pending_update;
8.185 + PurpleBuddy *buddy;
8.186 + PurpleAccount *account = purple_connection_get_account(gc);
8.187 + time_t old_timestamp;
8.188 + const char *old_timestamp_str;
8.189 + gchar *avatar_url;
8.190 +
8.191 + pending_update_it = g_list_first(avdata->pending_updates);
8.192 + if (pending_update_it == NULL)
8.193 + return TRUE;
8.194 +
8.195 + pending_update = pending_update_it->data;
8.196 + avdata->pending_updates = g_list_remove(avdata->pending_updates,
8.197 + pending_update);
8.198 + buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
8.199 +
8.200 + if (!buddy)
8.201 + {
8.202 + if (ggp_str_to_uin(purple_account_get_username(account)) ==
8.203 + pending_update->uin)
8.204 + {
8.205 + purple_debug_misc("gg",
8.206 + "ggp_avatar_buddy_update_next(%p): own "
8.207 + "avatar update requested, but we don't have "
8.208 + "ourselves on buddy list\n", gc);
8.209 + }
8.210 + else
8.211 + {
8.212 + purple_debug_warning("gg",
8.213 + "ggp_avatar_buddy_update_next(%p): "
8.214 + "%u update requested, but he's not on buddy "
8.215 + "list\n", gc, pending_update->uin);
8.216 + }
8.217 + return FALSE;
8.218 + }
8.219 +
8.220 + old_timestamp_str = purple_buddy_icons_get_checksum_for_user(buddy);
8.221 + old_timestamp = old_timestamp_str ? g_ascii_strtoull(
8.222 + old_timestamp_str, NULL, 10) : 0;
8.223 + if (old_timestamp == pending_update->timestamp)
8.224 + {
8.225 + purple_debug_misc("gg",
8.226 + "ggp_avatar_buddy_update_next(%p): "
8.227 + "%u have up to date avatar with ts=%lu\n", gc,
8.228 + pending_update->uin, pending_update->timestamp);
8.229 + return FALSE;
8.230 + }
8.231 + if (old_timestamp > pending_update->timestamp)
8.232 + {
8.233 + purple_debug_warning("gg",
8.234 + "ggp_avatar_buddy_update_next(%p): "
8.235 + "saved timestamp for %u is newer than received "
8.236 + "(%lu > %lu)\n", gc, pending_update->uin, old_timestamp,
8.237 + pending_update->timestamp);
8.238 + }
8.239 +
8.240 + purple_debug_info("gg",
8.241 + "ggp_avatar_buddy_update_next(%p): "
8.242 + "updating %u with ts=%lu...\n", gc, pending_update->uin,
8.243 + pending_update->timestamp);
8.244 +
8.245 + pending_update->gc = gc;
8.246 + avdata->current_update = pending_update;
8.247 + avatar_url = g_strdup_printf(GGP_AVATAR_BUDDY_URL, pending_update->uin);
8.248 + pending_update->request = purple_util_fetch_url_request(account,
8.249 + avatar_url, FALSE, GGP_AVATAR_USERAGENT, TRUE, NULL, FALSE,
8.250 + GGP_AVATAR_SIZE_MAX, ggp_avatar_buddy_update_received,
8.251 + pending_update);
8.252 + g_free(avatar_url);
8.253 +
8.254 + return TRUE;
8.255 +}
8.256 +
8.257 +static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
8.258 + gpointer _pending_update, const gchar *url_text, gsize len,
8.259 + const gchar *error_message)
8.260 +{
8.261 + ggp_avatar_buddy_update_req *pending_update = _pending_update;
8.262 + PurpleBuddy *buddy;
8.263 + PurpleAccount *account;
8.264 + PurpleConnection *gc = pending_update->gc;
8.265 + ggp_avatar_session_data *avdata;
8.266 + gchar timestamp_str[20];
8.267 +
8.268 + if (!PURPLE_CONNECTION_IS_VALID(gc))
8.269 + {
8.270 + g_free(pending_update);
8.271 + return;
8.272 + }
8.273 +
8.274 + avdata = ggp_avatar_get_avdata(gc);
8.275 + g_assert(pending_update == avdata->current_update);
8.276 + avdata->current_update = NULL;
8.277 +
8.278 + if (len == 0)
8.279 + {
8.280 + purple_debug_error("gg", "ggp_avatar_buddy_update_received: bad"
8.281 + " response while getting avatar for %u: %s\n",
8.282 + pending_update->uin, error_message);
8.283 + g_free(pending_update);
8.284 + return;
8.285 + }
8.286 +
8.287 + account = purple_connection_get_account(gc);
8.288 + buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
8.289 +
8.290 + if (!buddy)
8.291 + {
8.292 + purple_debug_warning("gg", "ggp_avatar_buddy_update_received: "
8.293 + "buddy %u disappeared\n", pending_update->uin);
8.294 + g_free(pending_update);
8.295 + return;
8.296 + }
8.297 +
8.298 + g_snprintf(timestamp_str, sizeof(timestamp_str), "%lu",
8.299 + pending_update->timestamp);
8.300 + purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy),
8.301 + g_memdup(url_text, len), len, timestamp_str);
8.302 +
8.303 + purple_debug_info("gg", "ggp_avatar_buddy_update_received: "
8.304 + "got avatar for buddy %u [ts=%lu]\n", pending_update->uin,
8.305 + pending_update->timestamp);
8.306 + g_free(pending_update);
8.307 +}
8.308 +
8.309 +/*******************************************************************************
8.310 + * Own avatar setting.
8.311 + ******************************************************************************/
8.312 +
8.313 +/**
8.314 + * TODO: use new, GG11 method, when IMToken will be provided by libgadu.
8.315 + *
8.316 + * POST https://avatars.mpa.gg.pl/avatars/user,<uin>/0
8.317 + * Authorization: IMToken 0123456789abcdef0123456789abcdef01234567
8.318 + * photo=<avatar content>
8.319 + */
8.320 +
8.321 +void ggp_avatar_own_set(PurpleConnection *gc, PurpleStoredImage *img)
8.322 +{
8.323 + ggp_avatar_own_data *own_data = ggp_avatar_get_avdata(gc)->own_data;
8.324 +
8.325 + purple_debug_info("gg", "ggp_avatar_own_set(%p, %p)", gc, img);
8.326 +
8.327 + if (img == NULL)
8.328 + {
8.329 + purple_debug_warning("gg", "ggp_avatar_own_set: avatar removing"
8.330 + " is probably not possible within old protocol");
8.331 + return;
8.332 + }
8.333 +
8.334 + own_data->img = img;
8.335 +
8.336 + ggp_oauth_request(gc, ggp_avatar_own_got_token, img, NULL, NULL);
8.337 +}
8.338 +
8.339 +static void ggp_avatar_own_got_token(PurpleConnection *gc, const gchar *token,
8.340 + gpointer img)
8.341 +{
8.342 + ggp_avatar_own_data *own_data = ggp_avatar_get_avdata(gc)->own_data;
8.343 + gchar *img_data, *img_data_e, *request, *request_data;
8.344 + PurpleAccount *account = purple_connection_get_account(gc);
8.345 + uin_t uin = ggp_str_to_uin(purple_account_get_username(account));
8.346 +
8.347 + if (img != own_data->img)
8.348 + {
8.349 + purple_debug_warning("gg", "ggp_avatar_own_got_token: "
8.350 + "avatar was changed in meantime\n");
8.351 + return;
8.352 + }
8.353 + own_data->img = NULL;
8.354 +
8.355 + img_data = purple_base64_encode(purple_imgstore_get_data(img),
8.356 + purple_imgstore_get_size(img));
8.357 + img_data_e = g_uri_escape_string(img_data, NULL, FALSE);
8.358 + g_free(img_data);
8.359 + request_data = g_strdup_printf("uin=%d&photo=%s", uin, img_data_e);
8.360 + g_free(img_data_e);
8.361 +
8.362 + request = g_strdup_printf(
8.363 + "POST /upload HTTP/1.1\r\n"
8.364 + "Host: avatars.nowe.gg\r\n"
8.365 + "Authorization: %s\r\n"
8.366 + "From: avatars to avatars\r\n"
8.367 + "Content-Length: %u\r\n"
8.368 + "Content-Type: application/x-www-form-urlencoded\r\n"
8.369 + "\r\n%s",
8.370 + token, strlen(request_data), request_data);
8.371 + g_free(request_data);
8.372 +
8.373 + purple_debug_misc("gg", "ggp_avatar_own_got_token: "
8.374 + "uploading new avatar...\n");
8.375 + purple_util_fetch_url_request(account, "http://avatars.nowe.gg/upload",
8.376 + FALSE, NULL, TRUE, request, FALSE, GGP_AVATAR_RESPONSE_MAX,
8.377 + ggp_avatar_own_sent, gc);
8.378 +
8.379 + g_free(request);
8.380 +}
8.381 +
8.382 +static void ggp_avatar_own_sent(PurpleUtilFetchUrlData *url_data,
8.383 + gpointer user_data, const gchar *url_text, gsize len,
8.384 + const gchar *error_message)
8.385 +{
8.386 + PurpleConnection *gc = user_data;
8.387 +
8.388 + if (!PURPLE_CONNECTION_IS_VALID(gc))
8.389 + return;
8.390 +
8.391 + if (len == 0)
8.392 + purple_debug_error("gg", "ggp_avatar_own_sent: "
8.393 + "avatar not sent. %s\n", error_message);
8.394 + else
8.395 + purple_debug_info("gg", "ggp_avatar_own_sent: %s\n", url_text);
8.396 +}
9.1 new file mode 100644
9.2 --- /dev/null
9.3 +++ b/libpurple/protocols/gg/avatar.h
9.4 @@ -0,0 +1,53 @@
9.5 +/* purple
9.6 + *
9.7 + * Purple is the legal property of its developers, whose names are too numerous
9.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
9.9 + * source distribution.
9.10 + *
9.11 + * Rewritten from scratch during Google Summer of Code 2012
9.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
9.13 + *
9.14 + * Previously implemented by:
9.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
9.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
9.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
9.18 + *
9.19 + * This program is free software; you can redistribute it and/or modify
9.20 + * it under the terms of the GNU General Public License as published by
9.21 + * the Free Software Foundation; either version 2 of the License, or
9.22 + * (at your option) any later version.
9.23 + *
9.24 + * This program is distributed in the hope that it will be useful,
9.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.27 + * GNU General Public License for more details.
9.28 + *
9.29 + * You should have received a copy of the GNU General Public License
9.30 + * along with this program; if not, write to the Free Software
9.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
9.32 + */
9.33 +
9.34 +#ifndef _GGP_AVATAR_H
9.35 +#define _GGP_AVATAR_H
9.36 +
9.37 +#include <internal.h>
9.38 +#include <libgadu.h>
9.39 +
9.40 +typedef struct
9.41 +{
9.42 + guint timer;
9.43 + GList *pending_updates;
9.44 +
9.45 + gpointer current_update;
9.46 + gpointer own_data;
9.47 +} ggp_avatar_session_data;
9.48 +
9.49 +void ggp_avatar_setup(PurpleConnection *gc);
9.50 +void ggp_avatar_cleanup(PurpleConnection *gc);
9.51 +
9.52 +void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp);
9.53 +void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin);
9.54 +
9.55 +void ggp_avatar_own_set(PurpleConnection *gc, PurpleStoredImage *img);
9.56 +
9.57 +#endif /* _GGP_AVATAR_H */
10.1 --- a/libpurple/protocols/gg/buddylist.c
10.2 +++ b/libpurple/protocols/gg/buddylist.c
10.3 @@ -22,9 +22,10 @@
10.4
10.5
10.6 #include <libgadu.h>
10.7 +#include <debug.h>
10.8
10.9 #include "gg.h"
10.10 -#include "gg-utils.h"
10.11 +#include "utils.h"
10.12 #include "buddylist.h"
10.13
10.14 #define F_FIRSTNAME 0
10.15 @@ -36,6 +37,7 @@
10.16 #define F_UIN 6
10.17
10.18 /* void ggp_buddylist_send(PurpleConnection *gc) {{{ */
10.19 +// this is for for notify purposes, not synchronizing buddy list
10.20 void ggp_buddylist_send(PurpleConnection *gc)
10.21 {
10.22 GGPInfo *info = purple_connection_get_protocol_data(gc);
10.23 @@ -81,7 +83,7 @@
10.24 PurpleGroup *group;
10.25 gchar **users_tbl;
10.26 int i;
10.27 - char *utf8buddylist = charset_convert(buddylist, "CP1250", "UTF-8");
10.28 + char *utf8buddylist = ggp_convert_from_cp1250(buddylist);
10.29
10.30 /* Don't limit the number of records in a buddylist. */
10.31 users_tbl = g_strsplit(utf8buddylist, "\r\n", -1);
10.32 @@ -94,7 +96,7 @@
10.33 continue;
10.34
10.35 data_tbl = g_strsplit(users_tbl[i], ";", 8);
10.36 - if (ggp_array_size(data_tbl) < 8) {
10.37 + if (g_strv_length(data_tbl) < 8) {
10.38 purple_debug_warning("gg",
10.39 "Something is wrong on line %d of the buddylist. Skipping.\n",
10.40 i + 1);
10.41 @@ -127,7 +129,7 @@
10.42 /* XXX: Probably buddy should be added to all the groups. */
10.43 /* Hard limit to at most 50 groups */
10.44 gchar **group_tbl = g_strsplit(data_tbl[F_GROUP], ",", 50);
10.45 - if (ggp_array_size(group_tbl) > 0) {
10.46 + if (g_strv_length(group_tbl) > 0) {
10.47 g_free(g);
10.48 g = g_strdup(group_tbl[0]);
10.49 }
10.50 @@ -178,11 +180,22 @@
10.51 "", gname, bname, "", "");
10.52 }
10.53
10.54 - ptr = charset_convert(buddylist->str, "UTF-8", "CP1250");
10.55 + ptr = ggp_convert_to_cp1250(buddylist->str);
10.56 g_string_free(buddylist, TRUE);
10.57 return ptr;
10.58 }
10.59 /* }}} */
10.60
10.61 +const char * ggp_buddylist_get_buddy_name(PurpleConnection *gc, const uin_t uin)
10.62 +{
10.63 + const char *uin_s = ggp_uin_to_str(uin);
10.64 + PurpleBuddy *buddy = purple_find_buddy(
10.65 + purple_connection_get_account(gc), uin_s);
10.66 +
10.67 + if (buddy != NULL)
10.68 + return purple_buddy_get_alias(buddy);
10.69 + else
10.70 + return uin_s;
10.71 +}
10.72
10.73 /* vim: set ts=8 sts=0 sw=8 noet: */
11.1 --- a/libpurple/protocols/gg/buddylist.h
11.2 +++ b/libpurple/protocols/gg/buddylist.h
11.3 @@ -50,6 +50,16 @@
11.4 char *
11.5 ggp_buddylist_dump(PurpleAccount *account);
11.6
11.7 +/**
11.8 + * Returns the best name of a buddy from the buddylist.
11.9 + *
11.10 + * @param gc PurpleConnection instance.
11.11 + * @param uin UIN of the buddy.
11.12 + *
11.13 + * @return Name of the buddy, or UIN converted to string, if there is no such
11.14 + * user on the list.
11.15 + */
11.16 +const char * ggp_buddylist_get_buddy_name(PurpleConnection *gc, const uin_t uin);
11.17
11.18 #endif /* _PURPLE_GG_BUDDYLIST_H */
11.19
12.1 --- a/libpurple/protocols/gg/confer.c
12.2 +++ b/libpurple/protocols/gg/confer.c
12.3 @@ -23,7 +23,7 @@
12.4
12.5 #include <libgadu.h>
12.6 #include "gg.h"
12.7 -#include "gg-utils.h"
12.8 +#include "utils.h"
12.9 #include "confer.h"
12.10
12.11 /* PurpleConversation *ggp_confer_find_by_name(PurpleConnection *gc, const gchar *name) {{{ */
13.1 new file mode 100644
13.2 --- /dev/null
13.3 +++ b/libpurple/protocols/gg/deprecated.c
13.4 @@ -0,0 +1,62 @@
13.5 +/* purple
13.6 + *
13.7 + * Purple is the legal property of its developers, whose names are too numerous
13.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
13.9 + * source distribution.
13.10 + *
13.11 + * Rewritten from scratch during Google Summer of Code 2012
13.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
13.13 + *
13.14 + * Previously implemented by:
13.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
13.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
13.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
13.18 + *
13.19 + * This program is free software; you can redistribute it and/or modify
13.20 + * it under the terms of the GNU General Public License as published by
13.21 + * the Free Software Foundation; either version 2 of the License, or
13.22 + * (at your option) any later version.
13.23 + *
13.24 + * This program is distributed in the hope that it will be useful,
13.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13.27 + * GNU General Public License for more details.
13.28 + *
13.29 + * You should have received a copy of the GNU General Public License
13.30 + * along with this program; if not, write to the Free Software
13.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
13.32 + */
13.33 +
13.34 +#include "deprecated.h"
13.35 +
13.36 +#include <libgadu.h>
13.37 +
13.38 +gboolean ggp_deprecated_setup_proxy(PurpleConnection *gc)
13.39 +{
13.40 + PurpleProxyInfo *gpi = purple_proxy_get_setup(purple_connection_get_account(gc));
13.41 +
13.42 + if ((purple_proxy_info_get_type(gpi) != PURPLE_PROXY_NONE) &&
13.43 + (purple_proxy_info_get_host(gpi) == NULL ||
13.44 + purple_proxy_info_get_port(gpi) <= 0))
13.45 + {
13.46 + gg_proxy_enabled = 0;
13.47 + purple_notify_error(NULL, NULL, _("Invalid proxy settings"),
13.48 + _("Either the host name or port number specified for your given proxy type is invalid."));
13.49 + return FALSE;
13.50 + }
13.51 +
13.52 + if (purple_proxy_info_get_type(gpi) == PURPLE_PROXY_NONE)
13.53 + {
13.54 + gg_proxy_enabled = 0;
13.55 + return TRUE;
13.56 + }
13.57 +
13.58 + gg_proxy_enabled = 1;
13.59 + //TODO: memleak
13.60 + gg_proxy_host = g_strdup(purple_proxy_info_get_host(gpi));
13.61 + gg_proxy_port = purple_proxy_info_get_port(gpi);
13.62 + gg_proxy_username = g_strdup(purple_proxy_info_get_username(gpi));
13.63 + gg_proxy_password = g_strdup(purple_proxy_info_get_password(gpi));
13.64 +
13.65 + return TRUE;
13.66 +}
14.1 new file mode 100644
14.2 --- /dev/null
14.3 +++ b/libpurple/protocols/gg/deprecated.h
14.4 @@ -0,0 +1,37 @@
14.5 +/* purple
14.6 + *
14.7 + * Purple is the legal property of its developers, whose names are too numerous
14.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
14.9 + * source distribution.
14.10 + *
14.11 + * Rewritten from scratch during Google Summer of Code 2012
14.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
14.13 + *
14.14 + * Previously implemented by:
14.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
14.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
14.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
14.18 + *
14.19 + * This program is free software; you can redistribute it and/or modify
14.20 + * it under the terms of the GNU General Public License as published by
14.21 + * the Free Software Foundation; either version 2 of the License, or
14.22 + * (at your option) any later version.
14.23 + *
14.24 + * This program is distributed in the hope that it will be useful,
14.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
14.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14.27 + * GNU General Public License for more details.
14.28 + *
14.29 + * You should have received a copy of the GNU General Public License
14.30 + * along with this program; if not, write to the Free Software
14.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
14.32 + */
14.33 +
14.34 +#ifndef _GGP_DEPRECATED_H
14.35 +#define _GGP_DEPRECATED_H
14.36 +
14.37 +#include <internal.h>
14.38 +
14.39 +gboolean ggp_deprecated_setup_proxy(PurpleConnection *gc);
14.40 +
14.41 +#endif /* _GGP_DEPRECATED_H */
15.1 --- a/libpurple/protocols/gg/gg.c
15.2 +++ b/libpurple/protocols/gg/gg.c
15.3 @@ -26,12 +26,11 @@
15.4 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
15.5 */
15.6
15.7 -#include "internal.h"
15.8 +#include <internal.h>
15.9
15.10 #include "plugin.h"
15.11 #include "version.h"
15.12 #include "notify.h"
15.13 -#include "status.h"
15.14 #include "blist.h"
15.15 #include "accountopt.h"
15.16 #include "debug.h"
15.17 @@ -43,206 +42,43 @@
15.18 #include "confer.h"
15.19 #include "search.h"
15.20 #include "buddylist.h"
15.21 -#include "gg-utils.h"
15.22 -
15.23 -#ifdef _WIN32
15.24 -# include "win32-resolver.h"
15.25 -#endif
15.26 -
15.27 -static PurplePlugin *my_protocol = NULL;
15.28 -
15.29 -/* Prototypes */
15.30 -static void ggp_set_status(PurpleAccount *account, PurpleStatus *status);
15.31 -static int ggp_to_gg_status(PurpleStatus *status, char **msg);
15.32 -
15.33 -/* ---------------------------------------------------------------------- */
15.34 -/* ----- EXTERNAL CALLBACKS --------------------------------------------- */
15.35 -/* ---------------------------------------------------------------------- */
15.36 -
15.37 -
15.38 -/* ----- HELPERS -------------------------------------------------------- */
15.39 -
15.40 -/**
15.41 - * Set up libgadu's proxy.
15.42 - *
15.43 - * @param account Account for which to set up the proxy.
15.44 - *
15.45 - * @return Zero if proxy setup is valid, otherwise -1.
15.46 - */
15.47 -static int ggp_setup_proxy(PurpleAccount *account)
15.48 -{
15.49 - PurpleProxyInfo *gpi;
15.50 -
15.51 - gpi = purple_proxy_get_setup(account);
15.52 -
15.53 - if ((purple_proxy_info_get_type(gpi) != PURPLE_PROXY_NONE) &&
15.54 - (purple_proxy_info_get_host(gpi) == NULL ||
15.55 - purple_proxy_info_get_port(gpi) <= 0)) {
15.56 -
15.57 - gg_proxy_enabled = 0;
15.58 - purple_notify_error(NULL, NULL, _("Invalid proxy settings"),
15.59 - _("Either the host name or port number specified for your given proxy type is invalid."));
15.60 - return -1;
15.61 - } else if (purple_proxy_info_get_type(gpi) != PURPLE_PROXY_NONE) {
15.62 - gg_proxy_enabled = 1;
15.63 - gg_proxy_host = g_strdup(purple_proxy_info_get_host(gpi));
15.64 - gg_proxy_port = purple_proxy_info_get_port(gpi);
15.65 - gg_proxy_username = g_strdup(purple_proxy_info_get_username(gpi));
15.66 - gg_proxy_password = g_strdup(purple_proxy_info_get_password(gpi));
15.67 - } else {
15.68 - gg_proxy_enabled = 0;
15.69 - }
15.70 -
15.71 - return 0;
15.72 -}
15.73 -
15.74 -static void ggp_async_token_handler(gpointer _gc, gint fd, PurpleInputCondition cond)
15.75 -{
15.76 - PurpleConnection *gc = _gc;
15.77 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.78 - GGPToken *token = info->token;
15.79 - GGPTokenCallback cb;
15.80 -
15.81 - struct gg_token *t = NULL;
15.82 -
15.83 - purple_debug_info("gg", "token_handler: token->req: check = %d; state = %d;\n",
15.84 - token->req->check, token->req->state);
15.85 -
15.86 - if (gg_token_watch_fd(token->req) == -1 || token->req->state == GG_STATE_ERROR) {
15.87 - purple_debug_error("gg", "token error (1): %d\n", token->req->error);
15.88 - purple_input_remove(token->inpa);
15.89 - gg_token_free(token->req);
15.90 - token->req = NULL;
15.91 -
15.92 - purple_notify_error(purple_connection_get_account(gc),
15.93 - _("Token Error"),
15.94 - _("Unable to fetch the token.\n"), NULL);
15.95 - return;
15.96 - }
15.97 -
15.98 - if (token->req->state != GG_STATE_DONE) {
15.99 - purple_input_remove(token->inpa);
15.100 - token->inpa = purple_input_add(token->req->fd,
15.101 - (token->req->check == 1)
15.102 - ? PURPLE_INPUT_WRITE
15.103 - : PURPLE_INPUT_READ,
15.104 - ggp_async_token_handler, gc);
15.105 - return;
15.106 - }
15.107 -
15.108 - if (!(t = token->req->data) || !token->req->body) {
15.109 - purple_debug_error("gg", "token error (2): %d\n", token->req->error);
15.110 - purple_input_remove(token->inpa);
15.111 - gg_token_free(token->req);
15.112 - token->req = NULL;
15.113 -
15.114 - purple_notify_error(purple_connection_get_account(gc),
15.115 - _("Token Error"),
15.116 - _("Unable to fetch the token.\n"), NULL);
15.117 - return;
15.118 - }
15.119 -
15.120 - purple_input_remove(token->inpa);
15.121 -
15.122 - token->id = g_strdup(t->tokenid);
15.123 - token->size = token->req->body_size;
15.124 - token->data = g_new0(char, token->size);
15.125 - memcpy(token->data, token->req->body, token->size);
15.126 -
15.127 - purple_debug_info("gg", "TOKEN! tokenid = %s; size = %d\n",
15.128 - token->id, token->size);
15.129 -
15.130 - gg_token_free(token->req);
15.131 - token->req = NULL;
15.132 - token->inpa = 0;
15.133 -
15.134 - cb = token->cb;
15.135 - token->cb = NULL;
15.136 - cb(gc);
15.137 -}
15.138 -
15.139 -static void ggp_token_request(PurpleConnection *gc, GGPTokenCallback cb)
15.140 -{
15.141 - PurpleAccount *account;
15.142 - struct gg_http *req;
15.143 - GGPInfo *info;
15.144 -
15.145 - account = purple_connection_get_account(gc);
15.146 -
15.147 - if (ggp_setup_proxy(account) == -1)
15.148 - return;
15.149 -
15.150 - info = purple_connection_get_protocol_data(gc);
15.151 -
15.152 - if ((req = gg_token(1)) == NULL) {
15.153 - purple_notify_error(account,
15.154 - _("Token Error"),
15.155 - _("Unable to fetch the token.\n"), NULL);
15.156 - return;
15.157 - }
15.158 -
15.159 - info->token = g_new(GGPToken, 1);
15.160 - info->token->cb = cb;
15.161 -
15.162 - info->token->req = req;
15.163 - info->token->inpa = purple_input_add(req->fd, PURPLE_INPUT_READ,
15.164 - ggp_async_token_handler, gc);
15.165 -}
15.166 -/* }}} */
15.167 +#include "utils.h"
15.168 +#include "resolver-purple.h"
15.169 +#include "account.h"
15.170 +#include "deprecated.h"
15.171 +#include "purplew.h"
15.172 +#include "libgadu-events.h"
15.173 +#include "multilogon.h"
15.174 +#include "status.h"
15.175 +#include "servconn.h"
15.176 +#include "pubdir-prpl.h"
15.177
15.178 /* ---------------------------------------------------------------------- */
15.179
15.180 -/**
15.181 - * Request buddylist from the server.
15.182 - * Buddylist is received in the ggp_callback_recv().
15.183 - *
15.184 - * @param Current action handler.
15.185 - */
15.186 -static void ggp_action_buddylist_get(PurplePluginAction *action)
15.187 +ggp_buddy_data * ggp_buddy_get_data(PurpleBuddy *buddy)
15.188 {
15.189 - PurpleConnection *gc = (PurpleConnection *)action->context;
15.190 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.191 -
15.192 - purple_debug_info("gg", "Downloading...\n");
15.193 -
15.194 - gg_userlist_request(info->session, GG_USERLIST_GET, NULL);
15.195 + ggp_buddy_data *buddy_data = purple_buddy_get_protocol_data(buddy);
15.196 + if (buddy_data)
15.197 + return buddy_data;
15.198 +
15.199 + buddy_data = g_new0(ggp_buddy_data, 1);
15.200 + purple_buddy_set_protocol_data(buddy, buddy_data);
15.201 + return buddy_data;
15.202 }
15.203
15.204 -/**
15.205 - * Upload the buddylist to the server.
15.206 - *
15.207 - * @param action Current action handler.
15.208 - */
15.209 -static void ggp_action_buddylist_put(PurplePluginAction *action)
15.210 +static void ggp_buddy_free(PurpleBuddy *buddy)
15.211 {
15.212 - PurpleConnection *gc = (PurpleConnection *)action->context;
15.213 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.214 + ggp_buddy_data *buddy_data = purple_buddy_get_protocol_data(buddy);
15.215
15.216 - char *buddylist = ggp_buddylist_dump(purple_connection_get_account(gc));
15.217 -
15.218 - purple_debug_info("gg", "Uploading...\n");
15.219 -
15.220 - if (buddylist == NULL)
15.221 + if (!buddy_data)
15.222 return;
15.223
15.224 - gg_userlist_request(info->session, GG_USERLIST_PUT, buddylist);
15.225 - g_free(buddylist);
15.226 + g_free(buddy_data);
15.227 + purple_buddy_set_protocol_data(buddy, NULL);
15.228 }
15.229
15.230 -/**
15.231 - * Delete buddylist from the server.
15.232 - *
15.233 - * @param action Current action handler.
15.234 - */
15.235 -static void ggp_action_buddylist_delete(PurplePluginAction *action)
15.236 -{
15.237 - PurpleConnection *gc = (PurpleConnection *)action->context;
15.238 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.239 -
15.240 - purple_debug_info("gg", "Deleting...\n");
15.241 -
15.242 - gg_userlist_request(info->session, GG_USERLIST_PUT, NULL);
15.243 -}
15.244 +/* ---------------------------------------------------------------------- */
15.245 +// buddy list import/export from/to file
15.246
15.247 static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *filename)
15.248 {
15.249 @@ -332,550 +168,6 @@
15.250 gc);
15.251 }
15.252
15.253 -static void ggp_callback_register_account_ok(PurpleConnection *gc,
15.254 - PurpleRequestFields *fields)
15.255 -{
15.256 - PurpleAccount *account;
15.257 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.258 - struct gg_http *h = NULL;
15.259 - struct gg_pubdir *s;
15.260 - uin_t uin;
15.261 - gchar *email, *p1, *p2, *t;
15.262 - GGPToken *token = info->token;
15.263 -
15.264 - email = charset_convert(purple_request_fields_get_string(fields, "email"),
15.265 - "UTF-8", "CP1250");
15.266 - p1 = charset_convert(purple_request_fields_get_string(fields, "password1"),
15.267 - "UTF-8", "CP1250");
15.268 - p2 = charset_convert(purple_request_fields_get_string(fields, "password2"),
15.269 - "UTF-8", "CP1250");
15.270 - t = charset_convert(purple_request_fields_get_string(fields, "token"),
15.271 - "UTF-8", "CP1250");
15.272 -
15.273 - account = purple_connection_get_account(gc);
15.274 -
15.275 - if (email == NULL || p1 == NULL || p2 == NULL || t == NULL ||
15.276 - *email == '\0' || *p1 == '\0' || *p2 == '\0' || *t == '\0') {
15.277 - purple_connection_error (gc,
15.278 - PURPLE_CONNECTION_ERROR_OTHER_ERROR,
15.279 - _("You must fill in all registration fields"));
15.280 - goto exit_err;
15.281 - }
15.282 -
15.283 - if (g_utf8_collate(p1, p2) != 0) {
15.284 - purple_connection_error (gc,
15.285 - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
15.286 - _("Passwords do not match"));
15.287 - goto exit_err;
15.288 - }
15.289 -
15.290 - purple_debug_info("gg", "register_account_ok: token_id = %s; t = %s\n",
15.291 - token->id, t);
15.292 - h = gg_register3(email, p1, token->id, t, 0);
15.293 - if (h == NULL || !(s = h->data) || !s->success) {
15.294 - purple_connection_error (gc,
15.295 - PURPLE_CONNECTION_ERROR_OTHER_ERROR,
15.296 - _("Unable to register new account. An unknown error occurred."));
15.297 - goto exit_err;
15.298 - }
15.299 -
15.300 - uin = s->uin;
15.301 - purple_debug_info("gg", "registered uin: %d\n", uin);
15.302 -
15.303 - g_free(t);
15.304 - t = g_strdup_printf("%u", uin);
15.305 - purple_account_set_username(account, t);
15.306 - /* Save the password if remembering passwords for the account */
15.307 - purple_account_set_password(account, p1);
15.308 -
15.309 - purple_notify_info(NULL, _("New Gadu-Gadu Account Registered"),
15.310 - _("Registration completed successfully!"), NULL);
15.311 -
15.312 - purple_account_register_completed(account, TRUE);
15.313 -
15.314 - /* TODO: the currently open Accounts Window will not be updated withthe
15.315 - * new username and etc, we need to somehow have it refresh at this
15.316 - * point
15.317 - */
15.318 -
15.319 - /* Need to disconnect or actually log in. For now, we disconnect. */
15.320 - purple_account_disconnect(account);
15.321 -
15.322 -exit_err:
15.323 - purple_account_register_completed(account, FALSE);
15.324 -
15.325 - gg_register_free(h);
15.326 - g_free(email);
15.327 - g_free(p1);
15.328 - g_free(p2);
15.329 - g_free(t);
15.330 - g_free(token->id);
15.331 - g_free(token);
15.332 -}
15.333 -
15.334 -static void ggp_callback_register_account_cancel(PurpleConnection *gc,
15.335 - PurpleRequestFields *fields)
15.336 -{
15.337 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.338 - GGPToken *token = info->token;
15.339 -
15.340 - purple_account_disconnect(purple_connection_get_account(gc));
15.341 -
15.342 - g_free(token->id);
15.343 - g_free(token->data);
15.344 - g_free(token);
15.345 -
15.346 -}
15.347 -
15.348 -static void ggp_register_user_dialog(PurpleConnection *gc)
15.349 -{
15.350 - PurpleAccount *account;
15.351 - PurpleRequestFields *fields;
15.352 - PurpleRequestFieldGroup *group;
15.353 - PurpleRequestField *field;
15.354 -
15.355 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.356 - GGPToken *token = info->token;
15.357 -
15.358 -
15.359 - account = purple_connection_get_account(gc);
15.360 -
15.361 - fields = purple_request_fields_new();
15.362 - group = purple_request_field_group_new(NULL);
15.363 - purple_request_fields_add_group(fields, group);
15.364 -
15.365 - field = purple_request_field_string_new("email",
15.366 - _("Email"), "", FALSE);
15.367 - purple_request_field_string_set_masked(field, FALSE);
15.368 - purple_request_field_group_add_field(group, field);
15.369 -
15.370 - field = purple_request_field_string_new("password1",
15.371 - _("Password"), "", FALSE);
15.372 - purple_request_field_string_set_masked(field, TRUE);
15.373 - purple_request_field_group_add_field(group, field);
15.374 -
15.375 - field = purple_request_field_string_new("password2",
15.376 - _("Password (again)"), "", FALSE);
15.377 - purple_request_field_string_set_masked(field, TRUE);
15.378 - purple_request_field_group_add_field(group, field);
15.379 -
15.380 - field = purple_request_field_string_new("token",
15.381 - _("Enter captcha text"), "", FALSE);
15.382 - purple_request_field_string_set_masked(field, FALSE);
15.383 - purple_request_field_group_add_field(group, field);
15.384 -
15.385 - /* original size: 60x24 */
15.386 - field = purple_request_field_image_new("token_img",
15.387 - _("Captcha"), token->data, token->size);
15.388 - purple_request_field_group_add_field(group, field);
15.389 -
15.390 - purple_request_fields(account,
15.391 - _("Register New Gadu-Gadu Account"),
15.392 - _("Register New Gadu-Gadu Account"),
15.393 - _("Please, fill in the following fields"),
15.394 - fields,
15.395 - _("OK"), G_CALLBACK(ggp_callback_register_account_ok),
15.396 - _("Cancel"), G_CALLBACK(ggp_callback_register_account_cancel),
15.397 - purple_connection_get_account(gc), NULL, NULL,
15.398 - gc);
15.399 -}
15.400 -
15.401 -/* ----- PUBLIC DIRECTORY SEARCH ---------------------------------------- */
15.402 -
15.403 -static void ggp_callback_show_next(PurpleConnection *gc, GList *row, gpointer user_data)
15.404 -{
15.405 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.406 - GGPSearchForm *form = user_data;
15.407 - guint32 seq;
15.408 -
15.409 - form->page_number++;
15.410 -
15.411 - ggp_search_remove(info->searches, form->seq);
15.412 - purple_debug_info("gg", "ggp_callback_show_next(): Removed seq %u\n",
15.413 - form->seq);
15.414 -
15.415 - seq = ggp_search_start(gc, form);
15.416 - ggp_search_add(info->searches, seq, form);
15.417 - purple_debug_info("gg", "ggp_callback_show_next(): Added seq %u\n",
15.418 - seq);
15.419 -}
15.420 -
15.421 -static void ggp_callback_add_buddy(PurpleConnection *gc, GList *row, gpointer user_data)
15.422 -{
15.423 - purple_blist_request_add_buddy(purple_connection_get_account(gc),
15.424 - g_list_nth_data(row, 0), NULL, NULL);
15.425 -}
15.426 -
15.427 -static void ggp_callback_im(PurpleConnection *gc, GList *row, gpointer user_data)
15.428 -{
15.429 - PurpleAccount *account;
15.430 - PurpleConversation *conv;
15.431 - char *name;
15.432 -
15.433 - account = purple_connection_get_account(gc);
15.434 -
15.435 - name = g_list_nth_data(row, 0);
15.436 - conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
15.437 - purple_conversation_present(conv);
15.438 -}
15.439 -
15.440 -static void ggp_callback_find_buddies(PurpleConnection *gc, PurpleRequestFields *fields)
15.441 -{
15.442 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.443 - GGPSearchForm *form;
15.444 - guint32 seq;
15.445 -
15.446 - form = ggp_search_form_new(GGP_SEARCH_TYPE_FULL);
15.447 -
15.448 - form->user_data = info;
15.449 - form->lastname = g_strdup(
15.450 - purple_request_fields_get_string(fields, "lastname"));
15.451 - form->firstname = g_strdup(
15.452 - purple_request_fields_get_string(fields, "firstname"));
15.453 - form->nickname = g_strdup(
15.454 - purple_request_fields_get_string(fields, "nickname"));
15.455 - form->city = g_strdup(
15.456 - purple_request_fields_get_string(fields, "city"));
15.457 - form->birthyear = g_strdup(
15.458 - purple_request_fields_get_string(fields, "year"));
15.459 -
15.460 - switch (purple_request_fields_get_choice(fields, "gender")) {
15.461 - case 1:
15.462 - form->gender = g_strdup(GG_PUBDIR50_GENDER_MALE);
15.463 - break;
15.464 - case 2:
15.465 - form->gender = g_strdup(GG_PUBDIR50_GENDER_FEMALE);
15.466 - break;
15.467 - default:
15.468 - form->gender = NULL;
15.469 - break;
15.470 - }
15.471 -
15.472 - form->active = purple_request_fields_get_bool(fields, "active")
15.473 - ? g_strdup(GG_PUBDIR50_ACTIVE_TRUE) : NULL;
15.474 -
15.475 - seq = ggp_search_start(gc, form);
15.476 - ggp_search_add(info->searches, seq, form);
15.477 - purple_debug_info("gg", "ggp_callback_find_buddies(): Added seq %u\n",
15.478 - seq);
15.479 -}
15.480 -
15.481 -static void ggp_find_buddies(PurplePluginAction *action)
15.482 -{
15.483 - PurpleConnection *gc = (PurpleConnection *)action->context;
15.484 -
15.485 - PurpleRequestFields *fields;
15.486 - PurpleRequestFieldGroup *group;
15.487 - PurpleRequestField *field;
15.488 -
15.489 - fields = purple_request_fields_new();
15.490 - group = purple_request_field_group_new(NULL);
15.491 - purple_request_fields_add_group(fields, group);
15.492 -
15.493 - field = purple_request_field_string_new("lastname",
15.494 - _("Last name"), NULL, FALSE);
15.495 - purple_request_field_string_set_masked(field, FALSE);
15.496 - purple_request_field_group_add_field(group, field);
15.497 -
15.498 - field = purple_request_field_string_new("firstname",
15.499 - _("First name"), NULL, FALSE);
15.500 - purple_request_field_string_set_masked(field, FALSE);
15.501 - purple_request_field_group_add_field(group, field);
15.502 -
15.503 - field = purple_request_field_string_new("nickname",
15.504 - _("Nickname"), NULL, FALSE);
15.505 - purple_request_field_string_set_masked(field, FALSE);
15.506 - purple_request_field_group_add_field(group, field);
15.507 -
15.508 - field = purple_request_field_string_new("city",
15.509 - _("City"), NULL, FALSE);
15.510 - purple_request_field_string_set_masked(field, FALSE);
15.511 - purple_request_field_group_add_field(group, field);
15.512 -
15.513 - field = purple_request_field_string_new("year",
15.514 - _("Year of birth"), NULL, FALSE);
15.515 - purple_request_field_group_add_field(group, field);
15.516 -
15.517 - field = purple_request_field_choice_new("gender", _("Gender"), 0);
15.518 - purple_request_field_choice_add(field, _("Male or female"));
15.519 - purple_request_field_choice_add(field, _("Male"));
15.520 - purple_request_field_choice_add(field, _("Female"));
15.521 - purple_request_field_group_add_field(group, field);
15.522 -
15.523 - field = purple_request_field_bool_new("active",
15.524 - _("Only online"), FALSE);
15.525 - purple_request_field_group_add_field(group, field);
15.526 -
15.527 - purple_request_fields(gc,
15.528 - _("Find buddies"),
15.529 - _("Find buddies"),
15.530 - _("Please, enter your search criteria below"),
15.531 - fields,
15.532 - _("OK"), G_CALLBACK(ggp_callback_find_buddies),
15.533 - _("Cancel"), NULL,
15.534 - purple_connection_get_account(gc), NULL, NULL,
15.535 - gc);
15.536 -}
15.537 -
15.538 -/* ----- CHANGE PASSWORD ---------------------------------------------------- */
15.539 -
15.540 -typedef struct
15.541 -{
15.542 - guint inpa;
15.543 - struct gg_http *http_req;
15.544 - gchar *new_password;
15.545 - PurpleAccount *account;
15.546 -} ggp_change_passwd_request;
15.547 -
15.548 -static void ggp_callback_change_passwd_handler(gpointer _req, gint fd,
15.549 - PurpleInputCondition cond)
15.550 -{
15.551 - ggp_change_passwd_request *req = _req;
15.552 - const char *messagesTitle =
15.553 - _("Change password for the Gadu-Gadu account");
15.554 -
15.555 - purple_input_remove(req->inpa);
15.556 -
15.557 - if (gg_change_passwd_watch_fd(req->http_req) == -1 ||
15.558 - req->http_req->state == GG_STATE_ERROR)
15.559 - goto exit_error;
15.560 -
15.561 - if (req->http_req->state != GG_STATE_DONE)
15.562 - {
15.563 - req->inpa = ggp_http_input_add(req->http_req,
15.564 - ggp_callback_change_passwd_handler, req);
15.565 - return;
15.566 - }
15.567 -
15.568 - if (req->http_req->data != NULL &&
15.569 - ((struct gg_pubdir*)req->http_req->data)->success == 1)
15.570 - {
15.571 - purple_account_set_password(req->account, req->new_password);
15.572 - purple_notify_info(req->account, messagesTitle,
15.573 - _("Password was changed successfully!"), NULL);
15.574 - goto exit_cleanup;
15.575 - }
15.576 -
15.577 -exit_error:
15.578 - purple_notify_error(req->account, messagesTitle,
15.579 - _("Unable to change password. Error occurred.\n"), NULL);
15.580 -
15.581 -exit_cleanup:
15.582 - gg_change_passwd_free(req->http_req);
15.583 - g_free(req->new_password);
15.584 - g_free(req);
15.585 -}
15.586 -
15.587 -static void ggp_callback_change_passwd_ok(PurpleConnection *gc,
15.588 - PurpleRequestFields *fields)
15.589 -{
15.590 - PurpleAccount *account;
15.591 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.592 - struct gg_http *h;
15.593 - gchar *cur, *p1, *p2, *t, *mail;
15.594 - const char *messagesTitle =
15.595 - _("Change password for the Gadu-Gadu account");
15.596 -
15.597 - cur = g_strdup(purple_request_fields_get_string(fields,
15.598 - "password_cur"));
15.599 - p1 = g_strdup(purple_request_fields_get_string(fields, "password1"));
15.600 - p2 = g_strdup(purple_request_fields_get_string(fields, "password2"));
15.601 - t = g_strdup(purple_request_fields_get_string(fields, "token"));
15.602 - mail = g_strdup(purple_request_fields_get_string(fields, "email"));
15.603 -
15.604 - account = purple_connection_get_account(gc);
15.605 -
15.606 - if (cur == NULL || p1 == NULL || p2 == NULL || t == NULL ||
15.607 - mail == NULL || *cur == '\0' || *p1 == '\0' || *p2 == '\0' ||
15.608 - *t == '\0' || *mail == '\0') {
15.609 - purple_notify_error(account, messagesTitle,
15.610 - _("Fill in the fields."), NULL);
15.611 - goto exit_err;
15.612 - }
15.613 -
15.614 - if (g_utf8_collate(p1, p2) != 0) {
15.615 - purple_notify_error(account, messagesTitle,
15.616 - _("New passwords do not match."), NULL);
15.617 - goto exit_err;
15.618 - }
15.619 -
15.620 - if (strlen(p1) > 15) {
15.621 - purple_notify_error(account, messagesTitle,
15.622 - _("New password should be at most 15 characters long."),
15.623 - NULL);
15.624 - goto exit_err;
15.625 - }
15.626 -
15.627 - if (g_utf8_collate(cur, purple_account_get_password(account)) != 0) {
15.628 - purple_notify_error(account, messagesTitle,
15.629 - _("Your current password is different from the one that"
15.630 - " you specified."), NULL);
15.631 - goto exit_err;
15.632 - }
15.633 -
15.634 - if (!purple_email_is_valid(mail)) {
15.635 - purple_notify_error(account, messagesTitle,
15.636 - _("Invalid email address"), NULL);
15.637 - goto exit_err;
15.638 - }
15.639 -
15.640 - purple_debug_info("gg", "Changing password with email \"%s\"...\n",
15.641 - mail);
15.642 -
15.643 - h = gg_change_passwd4(ggp_get_uin(account), mail,
15.644 - purple_account_get_password(account), p1, info->token->id, t,
15.645 - 1);
15.646 -
15.647 - if (h == NULL)
15.648 - purple_notify_error(account, messagesTitle,
15.649 - _("Unable to change password. Error occurred.\n"),
15.650 - NULL);
15.651 - else
15.652 - {
15.653 - ggp_change_passwd_request *req =
15.654 - g_new(ggp_change_passwd_request, 1);
15.655 - req->http_req = h;
15.656 - req->new_password = g_strdup(p1);
15.657 - req->account = account;
15.658 -
15.659 - req->inpa = ggp_http_input_add(h,
15.660 - ggp_callback_change_passwd_handler, req);
15.661 - }
15.662 -
15.663 -exit_err:
15.664 - g_free(cur);
15.665 - g_free(p1);
15.666 - g_free(p2);
15.667 - g_free(t);
15.668 - g_free(mail);
15.669 - g_free(info->token->id);
15.670 - g_free(info->token->data);
15.671 - g_free(info->token);
15.672 -}
15.673 -
15.674 -static void ggp_change_passwd_dialog(PurpleConnection *gc)
15.675 -{
15.676 - PurpleRequestFields *fields;
15.677 - PurpleRequestFieldGroup *group;
15.678 - PurpleRequestField *field;
15.679 -
15.680 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.681 - GGPToken *token = info->token;
15.682 -
15.683 - char *msg;
15.684 -
15.685 - fields = purple_request_fields_new();
15.686 - group = purple_request_field_group_new(NULL);
15.687 - purple_request_fields_add_group(fields, group);
15.688 -
15.689 - field = purple_request_field_string_new("password_cur",
15.690 - _("Current password"), "", FALSE);
15.691 - purple_request_field_string_set_masked(field, TRUE);
15.692 - purple_request_field_group_add_field(group, field);
15.693 -
15.694 - field = purple_request_field_string_new("password1",
15.695 - _("Password"), "", FALSE);
15.696 - purple_request_field_string_set_masked(field, TRUE);
15.697 - purple_request_field_group_add_field(group, field);
15.698 -
15.699 - field = purple_request_field_string_new("password2",
15.700 - _("Password (retype)"), "", FALSE);
15.701 - purple_request_field_string_set_masked(field, TRUE);
15.702 - purple_request_field_group_add_field(group, field);
15.703 -
15.704 - field = purple_request_field_string_new("email",
15.705 - _("Email Address"), "", FALSE);
15.706 - purple_request_field_string_set_masked(field, FALSE);
15.707 - purple_request_field_group_add_field(group, field);
15.708 -
15.709 - field = purple_request_field_string_new("token",
15.710 - _("Enter current token"), "", FALSE);
15.711 - purple_request_field_string_set_masked(field, FALSE);
15.712 - purple_request_field_group_add_field(group, field);
15.713 -
15.714 - /* original size: 60x24 */
15.715 - field = purple_request_field_image_new("token_img",
15.716 - _("Current token"), token->data, token->size);
15.717 - purple_request_field_group_add_field(group, field);
15.718 -
15.719 - msg = g_strdup_printf("%s %d",
15.720 - _("Please, enter your current password and your new password "
15.721 - "for UIN: "), ggp_get_uin(purple_connection_get_account(gc)));
15.722 -
15.723 - purple_request_fields(gc,
15.724 - _("Change Gadu-Gadu Password"),
15.725 - _("Change Gadu-Gadu Password"),
15.726 - msg,
15.727 - fields, _("OK"), G_CALLBACK(ggp_callback_change_passwd_ok),
15.728 - _("Cancel"), NULL,
15.729 - purple_connection_get_account(gc), NULL, NULL,
15.730 - gc);
15.731 -
15.732 - g_free(msg);
15.733 -}
15.734 -
15.735 -static void ggp_change_passwd(PurplePluginAction *action)
15.736 -{
15.737 - PurpleConnection *gc = (PurpleConnection *)action->context;
15.738 -
15.739 - ggp_token_request(gc, ggp_change_passwd_dialog);
15.740 -}
15.741 -
15.742 -/* ----- CHANGE STATUS BROADCASTING ------------------------------------------------ */
15.743 -
15.744 -static void ggp_action_change_status_broadcasting_ok(PurpleConnection *gc, PurpleRequestFields *fields)
15.745 -{
15.746 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.747 - int selected_field;
15.748 - PurpleAccount *account = purple_connection_get_account(gc);
15.749 - PurpleStatus *status;
15.750 -
15.751 - selected_field = purple_request_fields_get_choice(fields, "status_broadcasting");
15.752 -
15.753 - if (selected_field == 0)
15.754 - info->status_broadcasting = TRUE;
15.755 - else
15.756 - info->status_broadcasting = FALSE;
15.757 -
15.758 - status = purple_account_get_active_status(account);
15.759 -
15.760 - ggp_set_status(account, status);
15.761 -}
15.762 -
15.763 -static void ggp_action_change_status_broadcasting(PurplePluginAction *action)
15.764 -{
15.765 - PurpleConnection *gc = (PurpleConnection *)action->context;
15.766 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.767 -
15.768 - PurpleRequestFields *fields;
15.769 - PurpleRequestFieldGroup *group;
15.770 - PurpleRequestField *field;
15.771 -
15.772 - fields = purple_request_fields_new();
15.773 - group = purple_request_field_group_new(NULL);
15.774 - purple_request_fields_add_group(fields, group);
15.775 -
15.776 - field = purple_request_field_choice_new("status_broadcasting", _("Show status to:"), 0);
15.777 - purple_request_field_choice_add(field, _("All people"));
15.778 - purple_request_field_choice_add(field, _("Only buddies"));
15.779 - purple_request_field_group_add_field(group, field);
15.780 -
15.781 - if (info->status_broadcasting)
15.782 - purple_request_field_choice_set_default_value(field, 0);
15.783 - else
15.784 - purple_request_field_choice_set_default_value(field, 1);
15.785 -
15.786 - purple_request_fields(gc,
15.787 - _("Change status broadcasting"),
15.788 - _("Change status broadcasting"),
15.789 - _("Please, select who can see your status"),
15.790 - fields,
15.791 - _("OK"), G_CALLBACK(ggp_action_change_status_broadcasting_ok),
15.792 - _("Cancel"), NULL,
15.793 - purple_connection_get_account(gc), NULL, NULL,
15.794 - gc);
15.795 -}
15.796 -
15.797 /* ----- CONFERENCES ---------------------------------------------------- */
15.798
15.799 static void ggp_callback_add_to_chat_ok(PurpleBuddy *buddy, PurpleRequestFields *fields)
15.800 @@ -970,538 +262,6 @@
15.801 /* ----- INTERNAL CALLBACKS --------------------------------------------- */
15.802 /* ---------------------------------------------------------------------- */
15.803
15.804 -struct gg_fetch_avatar_data
15.805 -{
15.806 - PurpleConnection *gc;
15.807 - gchar *uin;
15.808 - gchar *avatar_url;
15.809 -};
15.810 -
15.811 -
15.812 -static void gg_fetch_avatar_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
15.813 - const gchar *data, size_t len, const gchar *error_message) {
15.814 - struct gg_fetch_avatar_data *d = user_data;
15.815 - PurpleAccount *account;
15.816 - PurpleBuddy *buddy;
15.817 - gpointer buddy_icon_data;
15.818 -
15.819 - purple_debug_info("gg", "gg_fetch_avatar_cb: got avatar image for %s\n",
15.820 - d->uin);
15.821 -
15.822 - /* FIXME: This shouldn't be necessary */
15.823 - if (!PURPLE_CONNECTION_IS_VALID(d->gc)) {
15.824 - g_free(d->uin);
15.825 - g_free(d->avatar_url);
15.826 - g_free(d);
15.827 - g_return_if_reached();
15.828 - }
15.829 -
15.830 - account = purple_connection_get_account(d->gc);
15.831 - buddy = purple_find_buddy(account, d->uin);
15.832 -
15.833 - if (buddy == NULL)
15.834 - goto out;
15.835 -
15.836 - buddy_icon_data = g_memdup(data, len);
15.837 -
15.838 - purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy),
15.839 - buddy_icon_data, len, d->avatar_url);
15.840 - purple_debug_info("gg", "gg_fetch_avatar_cb: UIN %s should have avatar "
15.841 - "now\n", d->uin);
15.842 -
15.843 -out:
15.844 - g_free(d->uin);
15.845 - g_free(d->avatar_url);
15.846 - g_free(d);
15.847 -}
15.848 -
15.849 -static void gg_get_avatar_url_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
15.850 - const gchar *url_text, size_t len, const gchar *error_message) {
15.851 - struct gg_fetch_avatar_data *data;
15.852 - PurpleConnection *gc = user_data;
15.853 - PurpleAccount *account;
15.854 - PurpleBuddy *buddy;
15.855 - const char *uin;
15.856 - const char *is_blank;
15.857 - const char *checksum;
15.858 -
15.859 - gchar *bigavatar = NULL;
15.860 - xmlnode *xml = NULL;
15.861 - xmlnode *xmlnode_users;
15.862 - xmlnode *xmlnode_user;
15.863 - xmlnode *xmlnode_avatars;
15.864 - xmlnode *xmlnode_avatar;
15.865 - xmlnode *xmlnode_bigavatar;
15.866 -
15.867 - g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
15.868 - account = purple_connection_get_account(gc);
15.869 -
15.870 - if (error_message != NULL)
15.871 - purple_debug_error("gg", "gg_get_avatars_cb error: %s\n", error_message);
15.872 - else if (len > 0 && url_text && *url_text) {
15.873 - xml = xmlnode_from_str(url_text, -1);
15.874 - if (xml == NULL)
15.875 - goto out;
15.876 -
15.877 - xmlnode_users = xmlnode_get_child(xml, "users");
15.878 - if (xmlnode_users == NULL)
15.879 - goto out;
15.880 -
15.881 - xmlnode_user = xmlnode_get_child(xmlnode_users, "user");
15.882 - if (xmlnode_user == NULL)
15.883 - goto out;
15.884 -
15.885 - uin = xmlnode_get_attrib(xmlnode_user, "uin");
15.886 -
15.887 - xmlnode_avatars = xmlnode_get_child(xmlnode_user, "avatars");
15.888 - if (xmlnode_avatars == NULL)
15.889 - goto out;
15.890 -
15.891 - xmlnode_avatar = xmlnode_get_child(xmlnode_avatars, "avatar");
15.892 - if (xmlnode_avatar == NULL)
15.893 - goto out;
15.894 -
15.895 - xmlnode_bigavatar = xmlnode_get_child(xmlnode_avatar, "originBigAvatar");
15.896 - if (xmlnode_bigavatar == NULL)
15.897 - goto out;
15.898 -
15.899 - is_blank = xmlnode_get_attrib(xmlnode_avatar, "blank");
15.900 - bigavatar = xmlnode_get_data(xmlnode_bigavatar);
15.901 -
15.902 - purple_debug_info("gg", "gg_get_avatar_url_cb: UIN %s, IS_BLANK %s, "
15.903 - "URL %s\n",
15.904 - uin ? uin : "(null)", is_blank ? is_blank : "(null)",
15.905 - bigavatar ? bigavatar : "(null)");
15.906 -
15.907 - if (uin != NULL && bigavatar != NULL) {
15.908 - buddy = purple_find_buddy(account, uin);
15.909 - if (buddy == NULL)
15.910 - goto out;
15.911 -
15.912 - checksum = purple_buddy_icons_get_checksum_for_user(buddy);
15.913 -
15.914 - if (purple_strequal(is_blank, "1")) {
15.915 - purple_buddy_icons_set_for_user(account,
15.916 - purple_buddy_get_name(buddy), NULL, 0, NULL);
15.917 - } else if (!purple_strequal(checksum, bigavatar)) {
15.918 - data = g_new0(struct gg_fetch_avatar_data, 1);
15.919 - data->gc = gc;
15.920 - data->uin = g_strdup(uin);
15.921 - data->avatar_url = g_strdup(bigavatar);
15.922 -
15.923 - purple_debug_info("gg", "gg_get_avatar_url_cb: "
15.924 - "requesting avatar for %s\n", uin);
15.925 - /* FIXME: This should be cancelled somewhere if not needed. */
15.926 - url_data = purple_util_fetch_url_request(account,
15.927 - bigavatar, TRUE, "Mozilla/4.0 (compatible; MSIE 5.0)",
15.928 - FALSE, NULL, FALSE, -1, gg_fetch_avatar_cb, data);
15.929 - }
15.930 - }
15.931 - }
15.932 -
15.933 -out:
15.934 - if (xml)
15.935 - xmlnode_free(xml);
15.936 - g_free(bigavatar);
15.937 -}
15.938 -
15.939 -/**
15.940 - * Try to update avatar of the buddy.
15.941 - *
15.942 - * @param gc PurpleConnection
15.943 - * @param uin UIN of the buddy.
15.944 - */
15.945 -static void ggp_update_buddy_avatar(PurpleConnection *gc, uin_t uin)
15.946 -{
15.947 - gchar *avatarurl;
15.948 - PurpleUtilFetchUrlData *url_data;
15.949 -
15.950 - purple_debug_info("gg", "ggp_update_buddy_avatar(gc, %u)\n", uin);
15.951 -
15.952 - avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%u/0.xml", uin);
15.953 -
15.954 - /* FIXME: This should be cancelled somewhere if not needed. */
15.955 - url_data = purple_util_fetch_url_request(
15.956 - purple_connection_get_account(gc), avatarurl, TRUE,
15.957 - "Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1,
15.958 - gg_get_avatar_url_cb, gc);
15.959 -
15.960 - g_free(avatarurl);
15.961 -}
15.962 -
15.963 -/**
15.964 - * Handle change of the status of the buddy.
15.965 - *
15.966 - * @param gc PurpleConnection
15.967 - * @param uin UIN of the buddy.
15.968 - * @param status ID of the status.
15.969 - * @param descr Description.
15.970 - */
15.971 -static void ggp_generic_status_handler(PurpleConnection *gc, uin_t uin,
15.972 - int status, const char *descr)
15.973 -{
15.974 - gchar *from;
15.975 - const char *st;
15.976 - char *status_msg = NULL;
15.977 -
15.978 - ggp_update_buddy_avatar(gc, uin);
15.979 -
15.980 - from = g_strdup_printf("%u", uin);
15.981 -
15.982 - switch (status) {
15.983 - case GG_STATUS_NOT_AVAIL:
15.984 - case GG_STATUS_NOT_AVAIL_DESCR:
15.985 - st = purple_primitive_get_id_from_type(PURPLE_STATUS_OFFLINE);
15.986 - break;
15.987 - case GG_STATUS_FFC:
15.988 - case GG_STATUS_FFC_DESCR:
15.989 - st = "freeforchat";
15.990 - break;
15.991 - case GG_STATUS_AVAIL:
15.992 - case GG_STATUS_AVAIL_DESCR:
15.993 - st = purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE);
15.994 - break;
15.995 - case GG_STATUS_BUSY:
15.996 - case GG_STATUS_BUSY_DESCR:
15.997 - st = purple_primitive_get_id_from_type(PURPLE_STATUS_AWAY);
15.998 - break;
15.999 - case GG_STATUS_INVISIBLE:
15.1000 - case GG_STATUS_INVISIBLE_DESCR:
15.1001 - st = purple_primitive_get_id_from_type(PURPLE_STATUS_INVISIBLE);
15.1002 - break;
15.1003 - case GG_STATUS_DND:
15.1004 - case GG_STATUS_DND_DESCR:
15.1005 - st = purple_primitive_get_id_from_type(PURPLE_STATUS_UNAVAILABLE);
15.1006 - break;
15.1007 - case GG_STATUS_BLOCKED:
15.1008 - /* user is blocking us.... */
15.1009 - st = "blocked";
15.1010 - break;
15.1011 - default:
15.1012 - st = purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE);
15.1013 - purple_debug_info("gg",
15.1014 - "GG_EVENT_NOTIFY: Unknown status: %d\n", status);
15.1015 - break;
15.1016 - }
15.1017 -
15.1018 - if (descr != NULL) {
15.1019 - status_msg = g_strdup(descr);
15.1020 - g_strstrip(status_msg);
15.1021 - if (status_msg[0] == '\0') {
15.1022 - g_free(status_msg);
15.1023 - status_msg = NULL;
15.1024 - }
15.1025 - }
15.1026 -
15.1027 - purple_debug_info("gg", "status of %u is %s [%s]\n", uin, st,
15.1028 - status_msg ? status_msg : "");
15.1029 - if (status_msg == NULL) {
15.1030 - purple_prpl_got_user_status(purple_connection_get_account(gc),
15.1031 - from, st, NULL);
15.1032 - } else {
15.1033 - purple_prpl_got_user_status(purple_connection_get_account(gc),
15.1034 - from, st, "message", status_msg, NULL);
15.1035 - g_free(status_msg);
15.1036 - }
15.1037 - g_free(from);
15.1038 -}
15.1039 -
15.1040 -static void ggp_sr_close_cb(gpointer user_data)
15.1041 -{
15.1042 - GGPSearchForm *form = user_data;
15.1043 - GGPInfo *info = form->user_data;
15.1044 -
15.1045 - ggp_search_remove(info->searches, form->seq);
15.1046 - purple_debug_info("gg", "ggp_sr_close_cb(): Removed seq %u\n",
15.1047 - form->seq);
15.1048 - ggp_search_form_destroy(form);
15.1049 -}
15.1050 -
15.1051 -/**
15.1052 - * Translate a status' ID to a more user-friendly name.
15.1053 - *
15.1054 - * @param id The ID of the status.
15.1055 - *
15.1056 - * @return The user-friendly name of the status.
15.1057 - */
15.1058 -static const char *ggp_status_by_id(unsigned int id)
15.1059 -{
15.1060 - const char *st;
15.1061 -
15.1062 - purple_debug_info("gg", "ggp_status_by_id: %d\n", id);
15.1063 - switch (id) {
15.1064 - case GG_STATUS_NOT_AVAIL:
15.1065 - case GG_STATUS_NOT_AVAIL_DESCR:
15.1066 - st = _("Offline");
15.1067 - break;
15.1068 - case GG_STATUS_AVAIL:
15.1069 - case GG_STATUS_AVAIL_DESCR:
15.1070 - st = _("Available");
15.1071 - break;
15.1072 - case GG_STATUS_FFC:
15.1073 - case GG_STATUS_FFC_DESCR:
15.1074 - return _("Chatty");
15.1075 - case GG_STATUS_DND:
15.1076 - case GG_STATUS_DND_DESCR:
15.1077 - return _("Do Not Disturb");
15.1078 - case GG_STATUS_BUSY:
15.1079 - case GG_STATUS_BUSY_DESCR:
15.1080 - st = _("Away");
15.1081 - break;
15.1082 - default:
15.1083 - st = _("Unknown");
15.1084 - break;
15.1085 - }
15.1086 -
15.1087 - return st;
15.1088 -}
15.1089 -
15.1090 -static void ggp_pubdir_handle_info(PurpleConnection *gc, gg_pubdir50_t req,
15.1091 - GGPSearchForm *form)
15.1092 -{
15.1093 - PurpleNotifyUserInfo *user_info;
15.1094 - PurpleBuddy *buddy;
15.1095 - char *val, *who;
15.1096 -
15.1097 - user_info = purple_notify_user_info_new();
15.1098 -
15.1099 - val = ggp_search_get_result(req, 0, GG_PUBDIR50_STATUS);
15.1100 - /* XXX: Use of ggp_str_to_uin() is an ugly hack! */
15.1101 - purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), ggp_status_by_id(ggp_str_to_uin(val)));
15.1102 - g_free(val);
15.1103 -
15.1104 - who = ggp_search_get_result(req, 0, GG_PUBDIR50_UIN);
15.1105 - /* TODO: Check whether it's correct to call add_pair_html,
15.1106 - or if we should be using add_pair_plaintext */
15.1107 - purple_notify_user_info_add_pair_html(user_info, _("UIN"), who);
15.1108 -
15.1109 - val = ggp_search_get_result(req, 0, GG_PUBDIR50_FIRSTNAME);
15.1110 - /* TODO: Check whether it's correct to call add_pair_html,
15.1111 - or if we should be using add_pair_plaintext */
15.1112 - purple_notify_user_info_add_pair_html(user_info, _("First Name"), val);
15.1113 - g_free(val);
15.1114 -
15.1115 - val = ggp_search_get_result(req, 0, GG_PUBDIR50_NICKNAME);
15.1116 - /* TODO: Check whether it's correct to call add_pair_html,
15.1117 - or if we should be using add_pair_plaintext */
15.1118 - purple_notify_user_info_add_pair_html(user_info, _("Nickname"), val);
15.1119 - g_free(val);
15.1120 -
15.1121 - val = ggp_search_get_result(req, 0, GG_PUBDIR50_CITY);
15.1122 - /* TODO: Check whether it's correct to call add_pair_html,
15.1123 - or if we should be using add_pair_plaintext */
15.1124 - purple_notify_user_info_add_pair_html(user_info, _("City"), val);
15.1125 - g_free(val);
15.1126 -
15.1127 - val = ggp_search_get_result(req, 0, GG_PUBDIR50_BIRTHYEAR);
15.1128 - if (strncmp(val, "0", 1)) {
15.1129 - /* TODO: Check whether it's correct to call add_pair_html,
15.1130 - or if we should be using add_pair_plaintext */
15.1131 - purple_notify_user_info_add_pair_html(user_info, _("Birth Year"), val);
15.1132 - }
15.1133 - g_free(val);
15.1134 -
15.1135 - /*
15.1136 - * Include a status message, if exists and buddy is in the blist.
15.1137 - */
15.1138 - buddy = purple_find_buddy(purple_connection_get_account(gc), who);
15.1139 - if (NULL != buddy) {
15.1140 - PurpleStatus *status;
15.1141 - const char *msg;
15.1142 -
15.1143 - status = purple_presence_get_active_status(purple_buddy_get_presence(buddy));
15.1144 - msg = purple_status_get_attr_string(status, "message");
15.1145 -
15.1146 - if (msg != NULL) {
15.1147 - purple_notify_user_info_add_pair_plaintext(user_info, _("Message"), msg);
15.1148 - }
15.1149 - }
15.1150 -
15.1151 - purple_notify_userinfo(gc, who, user_info, ggp_sr_close_cb, form);
15.1152 - g_free(who);
15.1153 - purple_notify_user_info_destroy(user_info);
15.1154 -}
15.1155 -
15.1156 -static void ggp_pubdir_handle_full(PurpleConnection *gc, gg_pubdir50_t req,
15.1157 - GGPSearchForm *form)
15.1158 -{
15.1159 - PurpleNotifySearchResults *results;
15.1160 - PurpleNotifySearchColumn *column;
15.1161 - int res_count;
15.1162 - int start;
15.1163 - int i;
15.1164 -
15.1165 - g_return_if_fail(form != NULL);
15.1166 -
15.1167 - res_count = gg_pubdir50_count(req);
15.1168 - res_count = (res_count > PUBDIR_RESULTS_MAX) ? PUBDIR_RESULTS_MAX : res_count;
15.1169 - if (form->page_size == 0)
15.1170 - form->page_size = res_count;
15.1171 -
15.1172 - results = purple_notify_searchresults_new();
15.1173 -
15.1174 - if (results == NULL) {
15.1175 - purple_debug_error("gg", "ggp_pubdir_reply_handler: "
15.1176 - "Unable to display the search results.\n");
15.1177 - purple_notify_error(gc, NULL,
15.1178 - _("Unable to display the search results."),
15.1179 - NULL);
15.1180 - if (form->window == NULL)
15.1181 - ggp_sr_close_cb(form);
15.1182 - return;
15.1183 - }
15.1184 -
15.1185 - column = purple_notify_searchresults_column_new(_("UIN"));
15.1186 - purple_notify_searchresults_column_add(results, column);
15.1187 -
15.1188 - column = purple_notify_searchresults_column_new(_("First Name"));
15.1189 - purple_notify_searchresults_column_add(results, column);
15.1190 -
15.1191 - column = purple_notify_searchresults_column_new(_("Nickname"));
15.1192 - purple_notify_searchresults_column_add(results, column);
15.1193 -
15.1194 - column = purple_notify_searchresults_column_new(_("City"));
15.1195 - purple_notify_searchresults_column_add(results, column);
15.1196 -
15.1197 - column = purple_notify_searchresults_column_new(_("Birth Year"));
15.1198 - purple_notify_searchresults_column_add(results, column);
15.1199 -
15.1200 - purple_debug_info("gg", "Going with %d entries\n", res_count);
15.1201 -
15.1202 - start = (int)ggp_str_to_uin(gg_pubdir50_get(req, 0, GG_PUBDIR50_START));
15.1203 - purple_debug_info("gg", "start = %d\n", start);
15.1204 -
15.1205 - for (i = 0; i < res_count; i++) {
15.1206 - GList *row = NULL;
15.1207 - char *birth = ggp_search_get_result(req, i, GG_PUBDIR50_BIRTHYEAR);
15.1208 -
15.1209 - /* TODO: Status will be displayed as an icon. */
15.1210 - /* row = g_list_append(row, ggp_search_get_result(req, i, GG_PUBDIR50_STATUS)); */
15.1211 - row = g_list_append(row, ggp_search_get_result(req, i,
15.1212 - GG_PUBDIR50_UIN));
15.1213 - row = g_list_append(row, ggp_search_get_result(req, i,
15.1214 - GG_PUBDIR50_FIRSTNAME));
15.1215 - row = g_list_append(row, ggp_search_get_result(req, i,
15.1216 - GG_PUBDIR50_NICKNAME));
15.1217 - row = g_list_append(row, ggp_search_get_result(req, i,
15.1218 - GG_PUBDIR50_CITY));
15.1219 - row = g_list_append(row,
15.1220 - (birth && strncmp(birth, "0", 1)) ? birth : g_strdup("-"));
15.1221 -
15.1222 - purple_notify_searchresults_row_add(results, row);
15.1223 - }
15.1224 -
15.1225 - purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_CONTINUE,
15.1226 - ggp_callback_show_next);
15.1227 - purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_ADD,
15.1228 - ggp_callback_add_buddy);
15.1229 - purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_IM,
15.1230 - ggp_callback_im);
15.1231 -
15.1232 - if (form->window == NULL) {
15.1233 - void *h = purple_notify_searchresults(gc,
15.1234 - _("Gadu-Gadu Public Directory"),
15.1235 - _("Search results"), NULL, results,
15.1236 - (PurpleNotifyCloseCallback)ggp_sr_close_cb,
15.1237 - form);
15.1238 -
15.1239 - if (h == NULL) {
15.1240 - purple_debug_error("gg", "ggp_pubdir_reply_handler: "
15.1241 - "Unable to display the search results.\n");
15.1242 - purple_notify_error(gc, NULL,
15.1243 - _("Unable to display the search results."),
15.1244 - NULL);
15.1245 - return;
15.1246 - }
15.1247 -
15.1248 - form->window = h;
15.1249 - } else {
15.1250 - purple_notify_searchresults_new_rows(gc, results, form->window);
15.1251 - }
15.1252 -}
15.1253 -
15.1254 -static void ggp_pubdir_reply_handler(PurpleConnection *gc, gg_pubdir50_t req)
15.1255 -{
15.1256 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.1257 - GGPSearchForm *form;
15.1258 - int res_count;
15.1259 - guint32 seq;
15.1260 -
15.1261 - seq = gg_pubdir50_seq(req);
15.1262 - form = ggp_search_get(info->searches, seq);
15.1263 - purple_debug_info("gg",
15.1264 - "ggp_pubdir_reply_handler(): seq %u --> form %p\n", seq, form);
15.1265 - /*
15.1266 - * this can happen when user will request more results
15.1267 - * and close the results window before they arrive.
15.1268 - */
15.1269 - g_return_if_fail(form != NULL);
15.1270 -
15.1271 - res_count = gg_pubdir50_count(req);
15.1272 - if (res_count < 1) {
15.1273 - purple_debug_info("gg", "GG_EVENT_PUBDIR50_SEARCH_REPLY: Nothing found\n");
15.1274 - purple_notify_error(gc, NULL,
15.1275 - _("No matching users found"),
15.1276 - _("There are no users matching your search criteria."));
15.1277 - if (form->window == NULL)
15.1278 - ggp_sr_close_cb(form);
15.1279 - return;
15.1280 - }
15.1281 -
15.1282 - switch (form->search_type) {
15.1283 - case GGP_SEARCH_TYPE_INFO:
15.1284 - ggp_pubdir_handle_info(gc, req, form);
15.1285 - break;
15.1286 - case GGP_SEARCH_TYPE_FULL:
15.1287 - ggp_pubdir_handle_full(gc, req, form);
15.1288 - break;
15.1289 - default:
15.1290 - purple_debug_warning("gg", "Unknown search_type!\n");
15.1291 - break;
15.1292 - }
15.1293 -}
15.1294 -
15.1295 -static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev)
15.1296 -{
15.1297 - gint imgid = 0;
15.1298 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.1299 - GList *entry = g_list_first(info->pending_richtext_messages);
15.1300 - gchar *handlerid = g_strdup_printf("IMGID_HANDLER-%i", ev->event.image_reply.crc32);
15.1301 -
15.1302 - imgid = purple_imgstore_add_with_id(
15.1303 - g_memdup(ev->event.image_reply.image, ev->event.image_reply.size),
15.1304 - ev->event.image_reply.size,
15.1305 - ev->event.image_reply.filename);
15.1306 -
15.1307 - purple_debug_info("gg", "ggp_recv_image_handler: got image with crc32: %u\n", ev->event.image_reply.crc32);
15.1308 -
15.1309 - while(entry) {
15.1310 - if (strstr((gchar *)entry->data, handlerid) != NULL) {
15.1311 - gchar **split = g_strsplit((gchar *)entry->data, handlerid, 3);
15.1312 - gchar *text = g_strdup_printf("%s%i%s", split[0], imgid, split[1]);
15.1313 - purple_debug_info("gg", "ggp_recv_image_handler: found message matching crc32: %s\n", (gchar *)entry->data);
15.1314 - g_strfreev(split);
15.1315 - info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data);
15.1316 - /* We don't have any more images to download */
15.1317 - if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) {
15.1318 - gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.image_reply.sender);
15.1319 - serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, time(NULL));
15.1320 - g_free(buf);
15.1321 - purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text);
15.1322 - g_free(text);
15.1323 - break;
15.1324 - }
15.1325 - info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, text);
15.1326 - break;
15.1327 - }
15.1328 - entry = g_list_next(entry);
15.1329 - }
15.1330 - g_free(handlerid);
15.1331 -
15.1332 - return;
15.1333 -}
15.1334 -
15.1335 -
15.1336 /**
15.1337 * Dispatch a message received from a buddy.
15.1338 *
15.1339 @@ -1510,7 +270,7 @@
15.1340 *
15.1341 * Image receiving, some code borrowed from Kadu http://www.kadu.net
15.1342 */
15.1343 -static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev)
15.1344 +void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event_msg *ev, gboolean multilogon)
15.1345 {
15.1346 GGPInfo *info = purple_connection_get_protocol_data(gc);
15.1347 PurpleConversation *conv;
15.1348 @@ -1518,37 +278,38 @@
15.1349 gchar *msg;
15.1350 gchar *tmp;
15.1351 time_t mtime;
15.1352 + uin_t sender = ev->sender;
15.1353
15.1354 - if (ev->event.msg.message == NULL)
15.1355 + if (ev->message == NULL)
15.1356 {
15.1357 purple_debug_warning("gg", "ggp_recv_message_handler: NULL as message pointer\n");
15.1358 return;
15.1359 }
15.1360
15.1361 - from = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender);
15.1362 + from = g_strdup_printf("%lu", (unsigned long int)ev->sender);
15.1363
15.1364 - /*
15.1365 - tmp = charset_convert((const char *)ev->event.msg.message,
15.1366 - "CP1250", "UTF-8");
15.1367 - */
15.1368 - tmp = g_strdup_printf("%s", ev->event.msg.message);
15.1369 + tmp = g_strdup_printf("%s", ev->message);
15.1370 purple_str_strip_char(tmp, '\r');
15.1371 msg = g_markup_escape_text(tmp, -1);
15.1372 g_free(tmp);
15.1373
15.1374 + if (ev->msgclass & GG_CLASS_QUEUED)
15.1375 + mtime = ev->time;
15.1376 + else
15.1377 + mtime = time(NULL);
15.1378 +
15.1379 /* We got richtext message */
15.1380 - if (ev->event.msg.formats_length)
15.1381 + if (ev->formats_length)
15.1382 {
15.1383 gboolean got_image = FALSE, bold = FALSE, italic = FALSE, under = FALSE;
15.1384 - char *cformats = (char *)ev->event.msg.formats;
15.1385 - char *cformats_end = cformats + ev->event.msg.formats_length;
15.1386 + char *cformats = (char *)ev->formats;
15.1387 + char *cformats_end = cformats + ev->formats_length;
15.1388 gint increased_len = 0;
15.1389 struct gg_msg_richtext_format *actformat;
15.1390 struct gg_msg_richtext_image *actimage;
15.1391 GString *message = g_string_new(msg);
15.1392 - gchar *handlerid;
15.1393
15.1394 - purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->event.msg.formats_length);
15.1395 + purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->formats_length);
15.1396
15.1397 while (cformats < cformats_end)
15.1398 {
15.1399 @@ -1569,7 +330,10 @@
15.1400 (actformat->font & GG_FONT_UNDERLINE) != 0,
15.1401 increased_len);
15.1402
15.1403 - if (actformat->font & GG_FONT_IMAGE) {
15.1404 + if (actformat->font & GG_FONT_IMAGE)
15.1405 + {
15.1406 + const char *placeholder;
15.1407 +
15.1408 got_image = TRUE;
15.1409 actimage = (struct gg_msg_richtext_image*)(cformats);
15.1410 cformats += sizeof(struct gg_msg_richtext_image);
15.1411 @@ -1582,13 +346,12 @@
15.1412 continue;
15.1413 }
15.1414
15.1415 - gg_image_request(info->session, ev->event.msg.sender,
15.1416 + gg_image_request(info->session, ev->sender,
15.1417 actimage->size, actimage->crc32);
15.1418
15.1419 - handlerid = g_strdup_printf("<IMG ID=\"IMGID_HANDLER-%i\">", actimage->crc32);
15.1420 - g_string_insert(message, byteoffset, handlerid);
15.1421 - increased_len += strlen(handlerid);
15.1422 - g_free(handlerid);
15.1423 + placeholder = ggp_image_pending_placeholder(actimage->crc32);
15.1424 + g_string_insert(message, byteoffset, placeholder);
15.1425 + increased_len += strlen(placeholder);
15.1426 continue;
15.1427 }
15.1428
15.1429 @@ -1636,80 +399,61 @@
15.1430 msg = message->str;
15.1431 g_string_free(message, FALSE);
15.1432
15.1433 - if (got_image) {
15.1434 - info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, msg);
15.1435 + if (got_image)
15.1436 + {
15.1437 + ggp_image_got_im(gc, sender, msg, mtime);
15.1438 return;
15.1439 }
15.1440 }
15.1441
15.1442 - purple_debug_info("gg", "ggp_recv_message_handler: msg from (%s): %s (class = %d; rcpt_count = %d)\n",
15.1443 - from, msg, ev->event.msg.msgclass,
15.1444 - ev->event.msg.recipients_count);
15.1445 + purple_debug_info("gg", "ggp_recv_message_handler: msg from (%s): %s (class = %d; rcpt_count = %d; multilogon = %d)\n",
15.1446 + from, msg, ev->msgclass,
15.1447 + ev->recipients_count,
15.1448 + multilogon);
15.1449
15.1450 - if (ev->event.msg.msgclass & GG_CLASS_QUEUED)
15.1451 - mtime = ev->event.msg.time;
15.1452 - else
15.1453 - mtime = time(NULL);
15.1454 -
15.1455 - if (ev->event.msg.recipients_count == 0) {
15.1456 + if (multilogon && ev->recipients_count != 0) {
15.1457 + purple_debug_warning("gg", "ggp_recv_message_handler: conference multilogon messages are not yet handled\n");
15.1458 + } else if (multilogon) {
15.1459 + PurpleAccount *account = purple_connection_get_account(gc);
15.1460 + PurpleConversation *conv;
15.1461 + const gchar *who = ggp_uin_to_str(ev->sender); // not really sender
15.1462 + conv = purple_find_conversation_with_account(
15.1463 + PURPLE_CONV_TYPE_IM, who, account);
15.1464 + if (conv == NULL)
15.1465 + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, who);
15.1466 + purple_conversation_write(conv, purple_account_get_username(account), msg, PURPLE_MESSAGE_SEND, mtime);
15.1467 + } else if (ev->recipients_count == 0) {
15.1468 serv_got_im(gc, from, msg, 0, mtime);
15.1469 } else {
15.1470 const char *chat_name;
15.1471 int chat_id;
15.1472 - char *buddy_name;
15.1473
15.1474 chat_name = ggp_confer_find_by_participants(gc,
15.1475 - ev->event.msg.recipients,
15.1476 - ev->event.msg.recipients_count);
15.1477 + ev->recipients,
15.1478 + ev->recipients_count);
15.1479
15.1480 if (chat_name == NULL) {
15.1481 chat_name = ggp_confer_add_new(gc, NULL);
15.1482 serv_got_joined_chat(gc, info->chats_count, chat_name);
15.1483
15.1484 ggp_confer_participants_add_uin(gc, chat_name,
15.1485 - ev->event.msg.sender);
15.1486 + ev->sender);
15.1487
15.1488 ggp_confer_participants_add(gc, chat_name,
15.1489 - ev->event.msg.recipients,
15.1490 - ev->event.msg.recipients_count);
15.1491 + ev->recipients,
15.1492 + ev->recipients_count);
15.1493 }
15.1494 conv = ggp_confer_find_by_name(gc, chat_name);
15.1495 chat_id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv));
15.1496
15.1497 - buddy_name = ggp_buddy_get_name(gc, ev->event.msg.sender);
15.1498 - serv_got_chat_in(gc, chat_id, buddy_name,
15.1499 - PURPLE_MESSAGE_RECV, msg, mtime);
15.1500 - g_free(buddy_name);
15.1501 + serv_got_chat_in(gc, chat_id,
15.1502 + ggp_buddylist_get_buddy_name(gc, ev->sender),
15.1503 + PURPLE_MESSAGE_RECV, msg, mtime);
15.1504 }
15.1505 g_free(msg);
15.1506 g_free(from);
15.1507 }
15.1508
15.1509 -static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev)
15.1510 -{
15.1511 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.1512 - PurpleStoredImage *image;
15.1513 - gint imgid = GPOINTER_TO_INT(g_hash_table_lookup(info->pending_images, GINT_TO_POINTER(ev->event.image_request.crc32)));
15.1514 -
15.1515 - purple_debug_info("gg", "ggp_send_image_handler: image request received, crc32: %u, imgid: %d\n", ev->event.image_request.crc32, imgid);
15.1516 -
15.1517 - if(imgid)
15.1518 - {
15.1519 - if((image = purple_imgstore_find_by_id(imgid))) {
15.1520 - gint image_size = purple_imgstore_get_size(image);
15.1521 - gconstpointer image_bin = purple_imgstore_get_data(image);
15.1522 - const char *image_filename = purple_imgstore_get_filename(image);
15.1523 -
15.1524 - purple_debug_info("gg", "ggp_send_image_handler: sending image imgid: %i, crc: %u\n", imgid, ev->event.image_request.crc32);
15.1525 - gg_image_reply(info->session, (unsigned long int)ev->event.image_request.sender, image_filename, image_bin, image_size);
15.1526 - purple_imgstore_unref(image);
15.1527 - } else {
15.1528 - purple_debug_error("gg", "ggp_send_image_handler: image imgid: %i, crc: %u in hash but not found in imgstore!\n", imgid, ev->event.image_request.crc32);
15.1529 - }
15.1530 - g_hash_table_remove(info->pending_images, GINT_TO_POINTER(ev->event.image_request.crc32));
15.1531 - }
15.1532 -}
15.1533 -
15.1534 static void ggp_typing_notification_handler(PurpleConnection *gc, uin_t uin, int length) {
15.1535 gchar *from;
15.1536
15.1537 @@ -1728,6 +472,7 @@
15.1538 * @param data Raw XML contents.
15.1539 *
15.1540 * @see http://toxygen.net/libgadu/protocol/#ch1.13
15.1541 + * @todo: this may not be necessary anymore
15.1542 */
15.1543 static void ggp_xml_event_handler(PurpleConnection *gc, char *data)
15.1544 {
15.1545 @@ -1776,7 +521,6 @@
15.1546 purple_debug_info("gg",
15.1547 "ggp_xml_event_handler: avatar updated (uid: %u)\n",
15.1548 event_sender);
15.1549 - ggp_update_buddy_avatar(gc, event_sender);
15.1550 break;
15.1551 default:
15.1552 purple_debug_error("gg",
15.1553 @@ -1795,7 +539,6 @@
15.1554 PurpleConnection *gc = _gc;
15.1555 GGPInfo *info = purple_connection_get_protocol_data(gc);
15.1556 struct gg_event *ev;
15.1557 - int i;
15.1558
15.1559 if (!(ev = gg_watch_fd(info->session))) {
15.1560 purple_debug_error("gg",
15.1561 @@ -1811,7 +554,7 @@
15.1562 /* Nothing happened. */
15.1563 break;
15.1564 case GG_EVENT_MSG:
15.1565 - ggp_recv_message_handler(gc, ev);
15.1566 + ggp_recv_message_handler(gc, &ev->event.msg, FALSE);
15.1567 break;
15.1568 case GG_EVENT_ACK:
15.1569 /* Changing %u to %i fixes compiler warning */
15.1570 @@ -1821,87 +564,14 @@
15.1571 ev->event.ack.seq);
15.1572 break;
15.1573 case GG_EVENT_IMAGE_REPLY:
15.1574 - ggp_recv_image_handler(gc, ev);
15.1575 + ggp_image_recv(gc, &ev->event.image_reply);
15.1576 break;
15.1577 case GG_EVENT_IMAGE_REQUEST:
15.1578 - ggp_send_image_handler(gc, ev);
15.1579 - break;
15.1580 - case GG_EVENT_NOTIFY:
15.1581 - case GG_EVENT_NOTIFY_DESCR:
15.1582 - {
15.1583 - struct gg_notify_reply *n;
15.1584 - char *descr;
15.1585 -
15.1586 - purple_debug_info("gg", "notify_pre: (%d) status: %d\n",
15.1587 - ev->event.notify->uin,
15.1588 - GG_S(ev->event.notify->status));
15.1589 -
15.1590 - n = (ev->type == GG_EVENT_NOTIFY) ? ev->event.notify
15.1591 - : ev->event.notify_descr.notify;
15.1592 -
15.1593 - for (; n->uin; n++) {
15.1594 - descr = (ev->type == GG_EVENT_NOTIFY) ? NULL
15.1595 - : ev->event.notify_descr.descr;
15.1596 -
15.1597 - purple_debug_info("gg",
15.1598 - "notify: (%d) status: %d; descr: %s\n",
15.1599 - n->uin, GG_S(n->status), descr ? descr : "(null)");
15.1600 -
15.1601 - ggp_generic_status_handler(gc,
15.1602 - n->uin, GG_S(n->status), descr);
15.1603 - }
15.1604 - }
15.1605 + ggp_image_send(gc, &ev->event.image_request);
15.1606 break;
15.1607 case GG_EVENT_NOTIFY60:
15.1608 - for (i = 0; ev->event.notify60[i].uin; i++) {
15.1609 - purple_debug_info("gg",
15.1610 - "notify60: (%d) status=%d; version=%d; descr=%s\n",
15.1611 - ev->event.notify60[i].uin,
15.1612 - GG_S(ev->event.notify60[i].status),
15.1613 - ev->event.notify60[i].version,
15.1614 - ev->event.notify60[i].descr ? ev->event.notify60[i].descr : "(null)");
15.1615 -
15.1616 - ggp_generic_status_handler(gc, ev->event.notify60[i].uin,
15.1617 - GG_S(ev->event.notify60[i].status),
15.1618 - ev->event.notify60[i].descr);
15.1619 - }
15.1620 - break;
15.1621 - case GG_EVENT_STATUS:
15.1622 - purple_debug_info("gg", "status: (%d) status=%d; descr=%s\n",
15.1623 - ev->event.status.uin, GG_S(ev->event.status.status),
15.1624 - ev->event.status.descr ? ev->event.status.descr : "(null)");
15.1625 -
15.1626 - ggp_generic_status_handler(gc, ev->event.status.uin,
15.1627 - GG_S(ev->event.status.status), ev->event.status.descr);
15.1628 - break;
15.1629 case GG_EVENT_STATUS60:
15.1630 - purple_debug_info("gg",
15.1631 - "status60: (%d) status=%d; version=%d; descr=%s\n",
15.1632 - ev->event.status60.uin, GG_S(ev->event.status60.status),
15.1633 - ev->event.status60.version,
15.1634 - ev->event.status60.descr ? ev->event.status60.descr : "(null)");
15.1635 -
15.1636 - ggp_generic_status_handler(gc, ev->event.status60.uin,
15.1637 - GG_S(ev->event.status60.status), ev->event.status60.descr);
15.1638 - break;
15.1639 - case GG_EVENT_USERLIST:
15.1640 - if (ev->event.userlist.type == GG_USERLIST_GET_REPLY) {
15.1641 - purple_debug_info("gg", "GG_USERLIST_GET_REPLY\n");
15.1642 - purple_notify_info(gc, NULL,
15.1643 - _("Buddy list downloaded"),
15.1644 - _("Your buddy list was downloaded from the server."));
15.1645 - if (ev->event.userlist.reply != NULL) {
15.1646 - ggp_buddylist_load(gc, ev->event.userlist.reply);
15.1647 - }
15.1648 - } else {
15.1649 - purple_debug_info("gg", "GG_USERLIST_PUT_REPLY\n");
15.1650 - purple_notify_info(gc, NULL,
15.1651 - _("Buddy list uploaded"),
15.1652 - _("Your buddy list was stored on the server."));
15.1653 - }
15.1654 - break;
15.1655 - case GG_EVENT_PUBDIR50_SEARCH_REPLY:
15.1656 - ggp_pubdir_reply_handler(gc, ev->event.pubdir50);
15.1657 + ggp_status_got_others(gc, ev);
15.1658 break;
15.1659 case GG_EVENT_TYPING_NOTIFICATION:
15.1660 ggp_typing_notification_handler(gc, ev->event.typing_notification.uin,
15.1661 @@ -1911,6 +581,21 @@
15.1662 purple_debug_info("gg", "GG_EVENT_XML_EVENT\n");
15.1663 ggp_xml_event_handler(gc, ev->event.xml_event.data);
15.1664 break;
15.1665 + case GG_EVENT_USER_DATA:
15.1666 + ggp_events_user_data(gc, &ev->event.user_data);
15.1667 + break;
15.1668 + case GG_EVENT_USERLIST100_VERSION:
15.1669 + ggp_roster_version(gc, &ev->event.userlist100_version);
15.1670 + break;
15.1671 + case GG_EVENT_USERLIST100_REPLY:
15.1672 + ggp_roster_reply(gc, &ev->event.userlist100_reply);
15.1673 + break;
15.1674 + case GG_EVENT_MULTILOGON_MSG:
15.1675 + ggp_multilogon_msg(gc, &ev->event.multilogon_msg);
15.1676 + break;
15.1677 + case GG_EVENT_MULTILOGON_INFO:
15.1678 + ggp_multilogon_info(gc, &ev->event.multilogon_info);
15.1679 + break;
15.1680 default:
15.1681 purple_debug_error("gg",
15.1682 "unsupported event type=%d\n", ev->type);
15.1683 @@ -1992,15 +677,22 @@
15.1684 break;
15.1685 case GG_EVENT_CONN_SUCCESS:
15.1686 {
15.1687 - purple_debug_info("gg", "GG_EVENT_CONN_SUCCESS\n");
15.1688 + const gchar * server_ip = ggp_ipv4_to_str(
15.1689 + info->session->server_addr);
15.1690 + purple_debug_info("gg", "GG_EVENT_CONN_SUCCESS:"
15.1691 + " successfully connected to %s\n",
15.1692 + server_ip);
15.1693 + ggp_servconn_add_server(server_ip);
15.1694 purple_input_remove(info->inpa);
15.1695 info->inpa = purple_input_add(info->session->fd,
15.1696 PURPLE_INPUT_READ,
15.1697 ggp_callback_recv, gc);
15.1698
15.1699 - ggp_buddylist_send(gc);
15.1700 purple_connection_update_progress(gc, _("Connected"), 1, 2);
15.1701 purple_connection_set_state(gc, PURPLE_CONNECTED);
15.1702 +
15.1703 + ggp_buddylist_send(gc);
15.1704 + ggp_roster_request_update(gc);
15.1705 }
15.1706 break;
15.1707 case GG_EVENT_CONN_FAILED:
15.1708 @@ -2103,39 +795,19 @@
15.1709 return normalized;
15.1710 }
15.1711
15.1712 -static char *ggp_status_text(PurpleBuddy *b)
15.1713 -{
15.1714 - PurpleStatus *status;
15.1715 - const char *msg;
15.1716 - char *text;
15.1717 - char *tmp;
15.1718 -
15.1719 - status = purple_presence_get_active_status(
15.1720 - purple_buddy_get_presence(b));
15.1721 - msg = purple_status_get_attr_string(status, "message");
15.1722 -
15.1723 - if (msg == NULL)
15.1724 - return NULL;
15.1725 -
15.1726 - tmp = purple_markup_strip_html(msg);
15.1727 - text = g_markup_escape_text(tmp, -1);
15.1728 - g_free(tmp);
15.1729 -
15.1730 - return text;
15.1731 -}
15.1732 -
15.1733 static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
15.1734 {
15.1735 PurpleStatus *status;
15.1736 char *tmp;
15.1737 - const char *msg, *name, *alias;
15.1738 + const char *name, *alias;
15.1739 + gchar *msg;
15.1740
15.1741 g_return_if_fail(b != NULL);
15.1742
15.1743 status = purple_presence_get_active_status(purple_buddy_get_presence(b));
15.1744 - msg = purple_status_get_attr_string(status, "message");
15.1745 name = purple_status_get_name(status);
15.1746 alias = purple_buddy_get_alias(b);
15.1747 + ggp_status_from_purplestatus(status, &msg);
15.1748
15.1749 purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), alias);
15.1750
15.1751 @@ -2147,76 +819,13 @@
15.1752 } else {
15.1753 purple_notify_user_info_add_pair_plaintext(user_info, _("Message"), msg);
15.1754 }
15.1755 + g_free(msg);
15.1756 /* We don't want to duplicate 'Status: Offline'. */
15.1757 } else if (PURPLE_BUDDY_IS_ONLINE(b)) {
15.1758 purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), name);
15.1759 }
15.1760 }
15.1761
15.1762 -static GList *ggp_status_types(PurpleAccount *account)
15.1763 -{
15.1764 - PurpleStatusType *type;
15.1765 - GList *types = NULL;
15.1766 -
15.1767 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
15.1768 - NULL, NULL, TRUE, TRUE, FALSE,
15.1769 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1770 - NULL);
15.1771 - types = g_list_append(types, type);
15.1772 -
15.1773 - /*
15.1774 - * New status for GG 8.0: PoGGadaj ze mna (chatty).
15.1775 - * NOTE: at this time, this is used only to set our own status.
15.1776 - */
15.1777 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
15.1778 - "freeforchat", _("Chatty"), TRUE, TRUE, FALSE,
15.1779 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1780 - NULL);
15.1781 - types = g_list_append(types, type);
15.1782 -
15.1783 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
15.1784 - NULL, NULL, TRUE, TRUE, FALSE,
15.1785 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1786 - NULL);
15.1787 - types = g_list_append(types, type);
15.1788 -
15.1789 - /*
15.1790 - * New status for GG 8.0: Nie przeszkadzac (do not disturb).
15.1791 - */
15.1792 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE,
15.1793 - NULL, NULL, TRUE, TRUE, FALSE,
15.1794 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1795 - NULL);
15.1796 - types = g_list_append(types, type);
15.1797 -
15.1798 - /*
15.1799 - * It's used on buddy list if and only if it's showing our own
15.1800 - * (invisible) status.
15.1801 - */
15.1802 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE,
15.1803 - NULL, NULL, TRUE, TRUE, FALSE,
15.1804 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1805 - NULL);
15.1806 - types = g_list_append(types, type);
15.1807 -
15.1808 - /*
15.1809 - * This status is necessary to display guys who are blocking *us*.
15.1810 - */
15.1811 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE,
15.1812 - "blocked", _("Blocked"), TRUE, FALSE, FALSE,
15.1813 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1814 - NULL);
15.1815 - types = g_list_append(types, type);
15.1816 -
15.1817 - type = purple_status_type_new_with_attrs(PURPLE_STATUS_OFFLINE,
15.1818 - NULL, NULL, TRUE, TRUE, FALSE,
15.1819 - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
15.1820 - NULL);
15.1821 - types = g_list_append(types, type);
15.1822 -
15.1823 - return types;
15.1824 -}
15.1825 -
15.1826 static GList *ggp_blist_node_menu(PurpleBlistNode *node)
15.1827 {
15.1828 PurpleMenuAction *act;
15.1829 @@ -2257,18 +866,15 @@
15.1830
15.1831 static void ggp_login(PurpleAccount *account)
15.1832 {
15.1833 - PurpleConnection *gc;
15.1834 - PurplePresence *presence;
15.1835 - PurpleStatus *status;
15.1836 + PurpleConnection *gc = purple_account_get_connection(account);
15.1837 struct gg_login_params *glp;
15.1838 GGPInfo *info;
15.1839 const char *address;
15.1840 const gchar *encryption_type;
15.1841
15.1842 - if (ggp_setup_proxy(account) == -1)
15.1843 + if (!ggp_deprecated_setup_proxy(gc))
15.1844 return;
15.1845
15.1846 - gc = purple_account_get_connection(account);
15.1847 glp = g_new0(struct gg_login_params, 1);
15.1848 info = g_new0(GGPInfo, 1);
15.1849
15.1850 @@ -2276,17 +882,18 @@
15.1851 info->session = NULL;
15.1852 info->chats = NULL;
15.1853 info->chats_count = 0;
15.1854 - info->token = NULL;
15.1855 - info->searches = ggp_search_new();
15.1856 - info->pending_richtext_messages = NULL;
15.1857 - info->pending_images = g_hash_table_new(g_direct_hash, g_direct_equal);
15.1858 - info->status_broadcasting = purple_account_get_bool(account, "status_broadcasting", TRUE);
15.1859
15.1860 purple_connection_set_protocol_data(gc, info);
15.1861
15.1862 - glp->uin = ggp_get_uin(account);
15.1863 - glp->password = charset_convert(purple_account_get_password(account),
15.1864 - "UTF-8", "CP1250");
15.1865 +
15.1866 + ggp_image_setup(gc);
15.1867 + ggp_avatar_setup(gc);
15.1868 + ggp_roster_setup(gc);
15.1869 + ggp_multilogon_setup(gc);
15.1870 + ggp_status_setup(gc);
15.1871 +
15.1872 + glp->uin = ggp_str_to_uin(purple_account_get_username(account));
15.1873 + glp->password = ggp_convert_to_cp1250(purple_account_get_password(account));
15.1874
15.1875 if (glp->uin == 0) {
15.1876 purple_connection_error(gc,
15.1877 @@ -2302,15 +909,12 @@
15.1878 if (purple_account_get_bool(account, "show_links_from_strangers", 1))
15.1879 glp->status_flags |= GG_STATUS_FLAG_SPAM;
15.1880
15.1881 - presence = purple_account_get_presence(account);
15.1882 - status = purple_presence_get_active_status(presence);
15.1883 -
15.1884 glp->encoding = GG_ENCODING_UTF8;
15.1885 - glp->protocol_features = (GG_FEATURE_STATUS80|GG_FEATURE_DND_FFC
15.1886 - |GG_FEATURE_TYPING_NOTIFICATION);
15.1887 + glp->protocol_features = (GG_FEATURE_DND_FFC |
15.1888 + GG_FEATURE_TYPING_NOTIFICATION | GG_FEATURE_MULTILOGON |
15.1889 + GG_FEATURE_USER_DATA);
15.1890
15.1891 glp->async = 1;
15.1892 - glp->status = ggp_to_gg_status(status, &glp->status_descr);
15.1893
15.1894 encryption_type = purple_account_get_string(account, "encryption",
15.1895 "opportunistic_tls");
15.1896 @@ -2333,28 +937,22 @@
15.1897 glp->tls = GG_SSL_DISABLED;
15.1898 purple_debug_info("gg", "TLS mode: %d\n", glp->tls);
15.1899
15.1900 - if (!info->status_broadcasting)
15.1901 - glp->status = glp->status|GG_STATUS_FRIENDS_MASK;
15.1902 + ggp_status_set_initial(gc, glp);
15.1903
15.1904 address = purple_account_get_string(account, "gg_server", "");
15.1905 - if (address && *address) {
15.1906 - /* TODO: Make this non-blocking */
15.1907 - struct in_addr *addr = gg_gethostbyname(address);
15.1908 -
15.1909 - purple_debug_info("gg", "Using gg server given by user (%s)\n", address);
15.1910 -
15.1911 - if (addr == NULL) {
15.1912 - gchar *tmp = g_strdup_printf(_("Unable to resolve hostname '%s': %s"),
15.1913 - address, g_strerror(errno));
15.1914 + if (address && *address)
15.1915 + {
15.1916 + glp->server_addr = inet_addr(address);
15.1917 + glp->server_port = 8074;
15.1918 +
15.1919 + if (glp->server_addr == INADDR_NONE)
15.1920 + {
15.1921 purple_connection_error(gc,
15.1922 - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, /* should this be a settings error? */
15.1923 - tmp);
15.1924 - g_free(tmp);
15.1925 + PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
15.1926 + _("Provided server IP address is not valid"));
15.1927 + g_free(glp);
15.1928 return;
15.1929 }
15.1930 -
15.1931 - glp->server_addr = inet_addr(inet_ntoa(*addr));
15.1932 - glp->server_port = 8074;
15.1933 } else
15.1934 purple_debug_info("gg", "Trying to retrieve address from gg appmsg service\n");
15.1935
15.1936 @@ -2385,24 +983,23 @@
15.1937 info = purple_connection_get_protocol_data(gc);
15.1938
15.1939 if (info) {
15.1940 - PurpleStatus *status = purple_account_get_active_status(account);
15.1941 -
15.1942 - if (info->session != NULL) {
15.1943 - ggp_set_status(account, status);
15.1944 + if (info->session != NULL)
15.1945 + {
15.1946 + ggp_status_set_disconnected(account);
15.1947 gg_logoff(info->session);
15.1948 gg_free_session(info->session);
15.1949 }
15.1950
15.1951 - purple_account_set_bool(account, "status_broadcasting", info->status_broadcasting);
15.1952 -
15.1953 /* Immediately close any notifications on this handle since that process depends
15.1954 * upon the contents of info->searches, which we are about to destroy.
15.1955 */
15.1956 purple_notify_close_with_handle(gc);
15.1957
15.1958 - ggp_search_destroy(info->searches);
15.1959 - g_list_free(info->pending_richtext_messages);
15.1960 - g_hash_table_destroy(info->pending_images);
15.1961 + ggp_image_cleanup(gc);
15.1962 + ggp_avatar_cleanup(gc);
15.1963 + ggp_roster_cleanup(gc);
15.1964 + ggp_multilogon_cleanup(gc);
15.1965 + ggp_status_cleanup(gc);
15.1966
15.1967 if (info->inpa > 0)
15.1968 purple_input_remove(info->inpa);
15.1969 @@ -2425,11 +1022,16 @@
15.1970 gint pos = 0;
15.1971 GData *attribs;
15.1972 const char *start, *end = NULL, *last;
15.1973 + ggp_buddy_data *buddy_data = ggp_buddy_get_data(
15.1974 + purple_find_buddy(purple_connection_get_account(gc), who));
15.1975
15.1976 if (msg == NULL || *msg == '\0') {
15.1977 return 0;
15.1978 }
15.1979
15.1980 + if (buddy_data->blocked)
15.1981 + return -1;
15.1982 +
15.1983 last = msg;
15.1984
15.1985 /* Check if the message is richtext */
15.1986 @@ -2439,53 +1041,58 @@
15.1987 GString *string_buffer = g_string_new(NULL);
15.1988 struct gg_msg_richtext fmt;
15.1989
15.1990 - do {
15.1991 - PurpleStoredImage *image;
15.1992 - const char *id;
15.1993 + do
15.1994 + {
15.1995 + const char *id = g_datalist_get_data(&attribs, "id");
15.1996 + struct gg_msg_richtext_format actformat;
15.1997 + struct gg_msg_richtext_image actimage;
15.1998 + ggp_image_prepare_result prepare_result;
15.1999
15.2000 /* Add text before the image */
15.2001 - if(start - last) {
15.2002 + if(start - last)
15.2003 + {
15.2004 pos = pos + g_utf8_strlen(last, start - last);
15.2005 - g_string_append_len(string_buffer, last, start - last);
15.2006 + g_string_append_len(string_buffer, last,
15.2007 + start - last);
15.2008 + }
15.2009 + last = end + 1;
15.2010 +
15.2011 + if (id == NULL)
15.2012 + {
15.2013 + g_datalist_clear(&attribs);
15.2014 + continue;
15.2015 }
15.2016
15.2017 - if((id = g_datalist_get_data(&attribs, "id")) && (image = purple_imgstore_find_by_id(atoi(id)))) {
15.2018 - struct gg_msg_richtext_format actformat;
15.2019 - struct gg_msg_richtext_image actimage;
15.2020 - gint image_size = purple_imgstore_get_size(image);
15.2021 - gconstpointer image_bin = purple_imgstore_get_data(image);
15.2022 - const char *image_filename = purple_imgstore_get_filename(image);
15.2023 - uint32_t crc32 = gg_crc32(0, image_bin, image_size);
15.2024 -
15.2025 - g_hash_table_insert(info->pending_images, GINT_TO_POINTER(crc32), GINT_TO_POINTER(atoi(id)));
15.2026 - purple_imgstore_ref(image);
15.2027 - purple_debug_info("gg", "ggp_send_im_richtext: got crc: %u for imgid: %i\n", crc32, atoi(id));
15.2028 -
15.2029 + /* add the image itself */
15.2030 + prepare_result = ggp_image_prepare(
15.2031 + gc, atoi(id), who, &actimage);
15.2032 + if (prepare_result == GGP_IMAGE_PREPARE_OK)
15.2033 + {
15.2034 actformat.font = GG_FONT_IMAGE;
15.2035 actformat.position = pos;
15.2036
15.2037 - actimage.unknown1 = 0x0109;
15.2038 - actimage.size = gg_fix32(image_size);
15.2039 - actimage.crc32 = gg_fix32(crc32);
15.2040 -
15.2041 - if (actimage.size > 255000) {
15.2042 - purple_debug_warning("gg", "ggp_send_im_richtext: image over 255kb!\n");
15.2043 - } else {
15.2044 - purple_debug_info("gg", "ggp_send_im_richtext: adding images to richtext, size: %i, crc32: %u, name: %s\n", actimage.size, actimage.crc32, image_filename);
15.2045 -
15.2046 - memcpy(format + format_length, &actformat, sizeof(actformat));
15.2047 - format_length += sizeof(actformat);
15.2048 - memcpy(format + format_length, &actimage, sizeof(actimage));
15.2049 - format_length += sizeof(actimage);
15.2050 - }
15.2051 - } else {
15.2052 - purple_debug_error("gg", "ggp_send_im_richtext: image not found in the image store!");
15.2053 + memcpy(format + format_length, &actformat,
15.2054 + sizeof(actformat));
15.2055 + format_length += sizeof(actformat);
15.2056 + memcpy(format + format_length, &actimage,
15.2057 + sizeof(actimage));
15.2058 + format_length += sizeof(actimage);
15.2059 }
15.2060 -
15.2061 - last = end + 1;
15.2062 + else if (prepare_result == GGP_IMAGE_PREPARE_TOO_BIG)
15.2063 + {
15.2064 + PurpleConversation *conv =
15.2065 + purple_find_conversation_with_account(
15.2066 + PURPLE_CONV_TYPE_IM, who,
15.2067 + purple_connection_get_account(gc));
15.2068 + purple_conversation_write(conv, "",
15.2069 + _("Image is too large, please try "
15.2070 + "smaller one."), PURPLE_MESSAGE_ERROR,
15.2071 + time(NULL));
15.2072 + }
15.2073 +
15.2074 g_datalist_clear(&attribs);
15.2075 -
15.2076 - } while(purple_markup_find_tag("img", last, &start, &end, &attribs));
15.2077 + } while (purple_markup_find_tag("img", last, &start, &end,
15.2078 + &attribs));
15.2079
15.2080 /* Add text after the images */
15.2081 if(last && *last) {
15.2082 @@ -2505,10 +1112,7 @@
15.2083 plain = purple_unescape_html(msg);
15.2084 }
15.2085
15.2086 - /*
15.2087 - tmp = charset_convert(plain, "UTF-8", "CP1250");
15.2088 - */
15.2089 - tmp = g_strdup_printf("%s", plain);
15.2090 + tmp = g_strdup(plain);
15.2091
15.2092 if (tmp && (format_length - sizeof(struct gg_msg_richtext))) {
15.2093 if(gg_send_message_richtext(info->session, GG_CLASS_CHAT, ggp_str_to_uin(who), (unsigned char *)tmp, format, format_length) < 0) {
15.2094 @@ -2554,117 +1158,20 @@
15.2095 return 1; // wait 1 second before another notification
15.2096 }
15.2097
15.2098 -static void ggp_get_info(PurpleConnection *gc, const char *name)
15.2099 -{
15.2100 - GGPInfo *info = purple_connection_get_protocol_data(gc);
15.2101 - GGPSearchForm *form;
15.2102 - guint32 seq;
15.2103 -
15.2104 - form = ggp_search_form_new(GGP_SEARCH_TYPE_INFO);
15.2105 -
15.2106 - form->user_data = info;
15.2107 - form->uin = g_strdup(name);
15.2108 -
15.2109 - seq = ggp_search_start(gc, form);
15.2110 - ggp_search_add(info->searches, seq, form);
15.2111 - purple_debug_info("gg", "ggp_get_info(): Added seq %u", seq);
15.2112 -}
15.2113 -
15.2114 -static int ggp_to_gg_status(PurpleStatus *status, char **msg)
15.2115 -{
15.2116 - const char *status_id = purple_status_get_id(status);
15.2117 - int new_status, new_status_descr;
15.2118 - const char *new_msg;
15.2119 -
15.2120 - g_return_val_if_fail(msg != NULL, 0);
15.2121 -
15.2122 - purple_debug_info("gg", "ggp_to_gg_status: Requested status = %s\n",
15.2123 - status_id);
15.2124 -
15.2125 - if (strcmp(status_id, "available") == 0) {
15.2126 - new_status = GG_STATUS_AVAIL;
15.2127 - new_status_descr = GG_STATUS_AVAIL_DESCR;
15.2128 - } else if (strcmp(status_id, "freeforchat") == 0) {
15.2129 - new_status = GG_STATUS_FFC;
15.2130 - new_status_descr = GG_STATUS_FFC_DESCR;
15.2131 - } else if (strcmp(status_id, "away") == 0) {
15.2132 - new_status = GG_STATUS_BUSY;
15.2133 - new_status_descr = GG_STATUS_BUSY_DESCR;
15.2134 - } else if (strcmp(status_id, "unavailable") == 0) {
15.2135 - new_status = GG_STATUS_DND;
15.2136 - new_status_descr = GG_STATUS_DND_DESCR;
15.2137 - } else if (strcmp(status_id, "invisible") == 0) {
15.2138 - new_status = GG_STATUS_INVISIBLE;
15.2139 - new_status_descr = GG_STATUS_INVISIBLE_DESCR;
15.2140 - } else if (strcmp(status_id, "offline") == 0) {
15.2141 - new_status = GG_STATUS_NOT_AVAIL;
15.2142 - new_status_descr = GG_STATUS_NOT_AVAIL_DESCR;
15.2143 - } else {
15.2144 - new_status = GG_STATUS_AVAIL;
15.2145 - new_status_descr = GG_STATUS_AVAIL_DESCR;
15.2146 - purple_debug_info("gg",
15.2147 - "ggp_set_status: unknown status requested (status_id=%s)\n",
15.2148 - status_id);
15.2149 - }
15.2150 -
15.2151 - new_msg = purple_status_get_attr_string(status, "message");
15.2152 -
15.2153 - if(new_msg) {
15.2154 - /*
15.2155 - char *tmp = purple_markup_strip_html(new_msg);
15.2156 - *msg = charset_convert(tmp, "UTF-8", "CP1250");
15.2157 - g_free(tmp);
15.2158 - */
15.2159 - *msg = purple_markup_strip_html(new_msg);
15.2160 -
15.2161 - return new_status_descr;
15.2162 - } else {
15.2163 - *msg = NULL;
15.2164 - return new_status;
15.2165 - }
15.2166 -}
15.2167 -
15.2168 -static void ggp_set_status(PurpleAccount *account, PurpleStatus *status)
15.2169 -{
15.2170 - PurpleConnection *gc;
15.2171 - GGPInfo *info;
15.2172 - int new_status;
15.2173 - char *new_msg = NULL;
15.2174 -
15.2175 - if (!purple_status_is_active(status))
15.2176 - return;
15.2177 -
15.2178 - gc = purple_account_get_connection(account);
15.2179 - info = purple_connection_get_protocol_data(gc);
15.2180 -
15.2181 - new_status = ggp_to_gg_status(status, &new_msg);
15.2182 -
15.2183 - if (!info->status_broadcasting)
15.2184 - new_status = new_status|GG_STATUS_FRIENDS_MASK;
15.2185 -
15.2186 - if (new_msg == NULL) {
15.2187 - gg_change_status(info->session, new_status);
15.2188 - } else {
15.2189 - gg_change_status_descr(info->session, new_status, new_msg);
15.2190 - g_free(new_msg);
15.2191 - }
15.2192 -
15.2193 - ggp_status_fake_to_self(account);
15.2194 -
15.2195 -}
15.2196 -
15.2197 static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
15.2198 {
15.2199 - PurpleAccount *account;
15.2200 + PurpleAccount *account = purple_connection_get_account(gc);
15.2201 GGPInfo *info = purple_connection_get_protocol_data(gc);
15.2202 const gchar *name = purple_buddy_get_name(buddy);
15.2203
15.2204 gg_add_notify(info->session, ggp_str_to_uin(name));
15.2205
15.2206 - account = purple_connection_get_account(gc);
15.2207 - if (strcmp(purple_account_get_username(account), name) == 0) {
15.2208 - ggp_status_fake_to_self(account);
15.2209 - }
15.2210 + // gg server won't tell us our status here
15.2211 + if (strcmp(purple_account_get_username(account), name) == 0)
15.2212 + ggp_status_fake_to_self(gc);
15.2213 +
15.2214 + ggp_roster_add_buddy(gc, buddy, group, message);
15.2215 + ggp_pubdir_request_buddy_alias(gc, buddy);
15.2216 }
15.2217
15.2218 static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
15.2219 @@ -2673,6 +1180,7 @@
15.2220 GGPInfo *info = purple_connection_get_protocol_data(gc);
15.2221
15.2222 gg_remove_notify(info->session, ggp_str_to_uin(purple_buddy_get_name(buddy)));
15.2223 + ggp_roster_remove_buddy(gc, buddy, group);
15.2224 }
15.2225
15.2226 static void ggp_join_chat(PurpleConnection *gc, GHashTable *data)
15.2227 @@ -2750,11 +1258,6 @@
15.2228 uins[count++] = uin;
15.2229 }
15.2230
15.2231 - /*
15.2232 - plain = purple_unescape_html(message);
15.2233 - msg = charset_convert(plain, "UTF-8", "CP1250");
15.2234 - g_free(plain);
15.2235 - */
15.2236 msg = purple_unescape_html(message);
15.2237 gg_send_message_confer(info->session, GG_CLASS_CHAT, count, uins,
15.2238 (unsigned char *)msg);
15.2239 @@ -2783,11 +1286,24 @@
15.2240 }
15.2241 }
15.2242
15.2243 -static void ggp_register_user(PurpleAccount *account)
15.2244 +static void ggp_action_chpass(PurplePluginAction *action)
15.2245 {
15.2246 - PurpleConnection *gc = purple_account_get_connection(account);
15.2247 + ggp_account_chpass((PurpleConnection *)action->context);
15.2248 +}
15.2249
15.2250 - ggp_token_request(gc, ggp_register_user_dialog);
15.2251 +static void ggp_action_status_broadcasting(PurplePluginAction *action)
15.2252 +{
15.2253 + ggp_status_broadcasting_dialog((PurpleConnection *)action->context);
15.2254 +}
15.2255 +
15.2256 +static void ggp_action_search(PurplePluginAction *action)
15.2257 +{
15.2258 + ggp_pubdir_search((PurpleConnection *)action->context, NULL);
15.2259 +}
15.2260 +
15.2261 +static void ggp_action_set_info(PurplePluginAction *action)
15.2262 +{
15.2263 + ggp_pubdir_set_info((PurpleConnection *)action->context);
15.2264 }
15.2265
15.2266 static GList *ggp_actions(PurplePlugin *plugin, gpointer context)
15.2267 @@ -2796,30 +1312,24 @@
15.2268 PurplePluginAction *act;
15.2269
15.2270 act = purple_plugin_action_new(_("Change password..."),
15.2271 - ggp_change_passwd);
15.2272 + ggp_action_chpass);
15.2273 m = g_list_append(m, act);
15.2274
15.2275 - act = purple_plugin_action_new(_("Find buddies..."),
15.2276 - ggp_find_buddies);
15.2277 - m = g_list_append(m, act);
15.2278 -
15.2279 - act = purple_plugin_action_new(_("Change status broadcasting"),
15.2280 - ggp_action_change_status_broadcasting);
15.2281 + act = purple_plugin_action_new(_("Show status only for buddies"),
15.2282 + ggp_action_status_broadcasting);
15.2283 m = g_list_append(m, act);
15.2284
15.2285 m = g_list_append(m, NULL);
15.2286
15.2287 - act = purple_plugin_action_new(_("Upload buddylist to Server"),
15.2288 - ggp_action_buddylist_put);
15.2289 + act = purple_plugin_action_new(_("Find buddies..."),
15.2290 + ggp_action_search);
15.2291 m = g_list_append(m, act);
15.2292
15.2293 - act = purple_plugin_action_new(_("Download buddylist from Server"),
15.2294 - ggp_action_buddylist_get);
15.2295 + act = purple_plugin_action_new(_("Set User Info"),
15.2296 + ggp_action_set_info);
15.2297 m = g_list_append(m, act);
15.2298
15.2299 - act = purple_plugin_action_new(_("Delete buddylist from Server"),
15.2300 - ggp_action_buddylist_delete);
15.2301 - m = g_list_append(m, act);
15.2302 + m = g_list_append(m, NULL);
15.2303
15.2304 act = purple_plugin_action_new(_("Save buddylist to file..."),
15.2305 ggp_action_buddylist_save);
15.2306 @@ -2832,21 +1342,39 @@
15.2307 return m;
15.2308 }
15.2309
15.2310 +static const char* ggp_list_emblem(PurpleBuddy *buddy)
15.2311 +{
15.2312 + ggp_buddy_data *buddy_data = ggp_buddy_get_data(buddy);
15.2313 +
15.2314 + if (buddy_data->blocked)
15.2315 + return "not-authorized";
15.2316 +
15.2317 + return NULL;
15.2318 +}
15.2319 +
15.2320 static gboolean ggp_offline_message(const PurpleBuddy *buddy)
15.2321 {
15.2322 return TRUE;
15.2323 }
15.2324
15.2325 +static GHashTable * ggp_get_account_text_table(PurpleAccount *account)
15.2326 +{
15.2327 + GHashTable *table;
15.2328 + table = g_hash_table_new(g_str_hash, g_str_equal);
15.2329 + g_hash_table_insert(table, "login_label", (gpointer)_("GG number..."));
15.2330 + return table;
15.2331 +}
15.2332 +
15.2333 static PurplePluginProtocolInfo prpl_info =
15.2334 {
15.2335 sizeof(PurplePluginProtocolInfo), /* struct_size */
15.2336 OPT_PROTO_REGISTER_NOSCREENNAME | OPT_PROTO_IM_IMAGE,
15.2337 NULL, /* user_splits */
15.2338 NULL, /* protocol_options */
15.2339 - {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
15.2340 + {"png", 1, 1, 200, 200, 0, PURPLE_ICON_SCALE_DISPLAY | PURPLE_ICON_SCALE_SEND}, /* icon_spec */
15.2341 ggp_list_icon, /* list_icon */
15.2342 - NULL, /* list_emblem */
15.2343 - ggp_status_text, /* status_text */
15.2344 + ggp_list_emblem, /* list_emblem */
15.2345 + ggp_status_buddy_text, /* status_text */
15.2346 ggp_tooltip_text, /* tooltip_text */
15.2347 ggp_status_types, /* status_types */
15.2348 ggp_blist_node_menu, /* blist_node_menu */
15.2349 @@ -2857,8 +1385,8 @@
15.2350 ggp_send_im, /* send_im */
15.2351 NULL, /* set_info */
15.2352 ggp_send_typing, /* send_typing */
15.2353 - ggp_get_info, /* get_info */
15.2354 - ggp_set_status, /* set_away */
15.2355 + ggp_pubdir_get_info_prpl, /* get_info */
15.2356 + ggp_status_set_purplestatus, /* set_away */
15.2357 NULL, /* set_idle */
15.2358 NULL, /* change_passwd */
15.2359 ggp_add_buddy, /* add_buddy */
15.2360 @@ -2878,15 +1406,15 @@
15.2361 NULL, /* chat_whisper */
15.2362 ggp_chat_send, /* chat_send */
15.2363 ggp_keepalive, /* keepalive */
15.2364 - ggp_register_user, /* register_user */
15.2365 + ggp_account_register, /* register_user */
15.2366 NULL, /* get_cb_info */
15.2367 - NULL, /* alias_buddy */
15.2368 - NULL, /* group_buddy */
15.2369 - NULL, /* rename_group */
15.2370 - NULL, /* buddy_free */
15.2371 + ggp_roster_alias_buddy, /* alias_buddy */
15.2372 + ggp_roster_group_buddy, /* group_buddy */
15.2373 + ggp_roster_rename_group, /* rename_group */
15.2374 + ggp_buddy_free, /* buddy_free */
15.2375 NULL, /* convo_closed */
15.2376 ggp_normalize, /* normalize */
15.2377 - NULL, /* set_buddy_icon */
15.2378 + ggp_avatar_own_set, /* set_buddy_icon */
15.2379 NULL, /* remove_group */
15.2380 NULL, /* get_cb_real_name */
15.2381 NULL, /* set_chat_topic */
15.2382 @@ -2904,14 +1432,17 @@
15.2383 NULL, /* unregister_user */
15.2384 NULL, /* send_attention */
15.2385 NULL, /* get_attention_types */
15.2386 - NULL, /* get_account_text_table */
15.2387 - NULL, /* initiate_media */
15.2388 - NULL, /* can_do_media */
15.2389 + ggp_get_account_text_table, /* get_account_text_table */
15.2390 + NULL, /* initiate_media */
15.2391 + NULL, /* can_do_media */
15.2392 NULL, /* get_moods */
15.2393 NULL, /* set_public_alias */
15.2394 NULL /* get_public_alias */
15.2395 };
15.2396
15.2397 +static gboolean ggp_load(PurplePlugin *plugin);
15.2398 +static gboolean ggp_unload(PurplePlugin *plugin);
15.2399 +
15.2400 static PurplePluginInfo info = {
15.2401 PURPLE_PLUGIN_MAGIC, /* magic */
15.2402 PURPLE_MAJOR_VERSION, /* major_version */
15.2403 @@ -2931,8 +1462,8 @@
15.2404 "boler@sourceforge.net", /* author */
15.2405 PURPLE_WEBSITE, /* homepage */
15.2406
15.2407 - NULL, /* load */
15.2408 - NULL, /* unload */
15.2409 + ggp_load, /* load */
15.2410 + ggp_unload, /* unload */
15.2411 NULL, /* destroy */
15.2412
15.2413 NULL, /* ui_info */
15.2414 @@ -2970,15 +1501,20 @@
15.2415 g_free(msg);
15.2416 }
15.2417
15.2418 +static PurpleAccountOption *ggp_server_option;
15.2419 +
15.2420 static void init_plugin(PurplePlugin *plugin)
15.2421 {
15.2422 PurpleAccountOption *option;
15.2423 GList *encryption_options = NULL;
15.2424
15.2425 + purple_prefs_add_none("/plugins/prpl/gg");
15.2426 +
15.2427 option = purple_account_option_string_new(_("GG server"),
15.2428 "gg_server", "");
15.2429 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
15.2430 option);
15.2431 + ggp_server_option = option;
15.2432
15.2433 #define ADD_VALUE(list, desc, v) { \
15.2434 PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
15.2435 @@ -3002,14 +1538,24 @@
15.2436 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
15.2437 option);
15.2438
15.2439 - my_protocol = plugin;
15.2440 + gg_debug_handler = purple_gg_debug_handler;
15.2441 +}
15.2442
15.2443 - gg_debug_handler = purple_gg_debug_handler;
15.2444 +static gboolean ggp_load(PurplePlugin *plugin)
15.2445 +{
15.2446 + purple_debug_info("gg", "Loading Gadu-Gadu protocol plugin with "
15.2447 + "libgadu %s...\n", gg_libgadu_version());
15.2448 +
15.2449 + ggp_resolver_purple_setup();
15.2450 + ggp_servconn_setup(ggp_server_option);
15.2451
15.2452 -#ifdef _WIN32
15.2453 - gg_global_set_custom_resolver(ggp_resolver_win32thread_start,
15.2454 - ggp_resolver_win32thread_cleanup);
15.2455 -#endif
15.2456 + return TRUE;
15.2457 +}
15.2458 +
15.2459 +static gboolean ggp_unload(PurplePlugin *plugin)
15.2460 +{
15.2461 + ggp_servconn_cleanup();
15.2462 + return TRUE;
15.2463 }
15.2464
15.2465 PURPLE_INIT_PLUGIN(gg, init_plugin, info);
16.1 --- a/libpurple/protocols/gg/gg.h
16.2 +++ b/libpurple/protocols/gg/gg.h
16.3 @@ -24,15 +24,22 @@
16.4 #ifndef _PURPLE_GG_H
16.5 #define _PURPLE_GG_H
16.6
16.7 -#undef printf
16.8 #include <libgadu.h>
16.9 #include "internal.h"
16.10 #include "search.h"
16.11 #include "connection.h"
16.12
16.13 +#include "image.h"
16.14 +#include "avatar.h"
16.15 +#include "account.h"
16.16 +#include "roster.h"
16.17 +#include "multilogon.h"
16.18 +#include "status.h"
16.19
16.20 #define PUBDIR_RESULTS_MAX 20
16.21
16.22 +#define GGP_UIN_LEN_MAX 10
16.23 +
16.24
16.25 typedef struct
16.26 {
16.27 @@ -41,34 +48,27 @@
16.28
16.29 } GGPChat;
16.30
16.31 -typedef void (*GGPTokenCallback)(PurpleConnection *);
16.32 -
16.33 -typedef struct
16.34 -{
16.35 - char *id;
16.36 - char *data;
16.37 - unsigned int size;
16.38 -
16.39 - struct gg_http *req;
16.40 - guint inpa;
16.41 -
16.42 - GGPTokenCallback cb;
16.43 -
16.44 -} GGPToken;
16.45 -
16.46 typedef struct {
16.47
16.48 struct gg_session *session;
16.49 guint inpa;
16.50 - GGPToken *token;
16.51 GList *chats;
16.52 - GGPSearches *searches;
16.53 int chats_count;
16.54 - GList *pending_richtext_messages;
16.55 - GHashTable *pending_images;
16.56 - gboolean status_broadcasting; //When TRUE status is visible to all, when FALSE status is visible only to friends.
16.57 +
16.58 + ggp_image_connection_data image_data;
16.59 + ggp_avatar_session_data avatar_data;
16.60 + ggp_roster_session_data roster_data;
16.61 + ggp_multilogon_session_data *multilogon_data;
16.62 + ggp_status_session_data *status_data;
16.63 } GGPInfo;
16.64
16.65 +typedef struct
16.66 +{
16.67 + gboolean blocked;
16.68 +} ggp_buddy_data;
16.69 +
16.70 +void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event_msg *ev, gboolean multilogon);
16.71 +
16.72 +ggp_buddy_data * ggp_buddy_get_data(PurpleBuddy *buddy);
16.73 +
16.74 #endif /* _PURPLE_GG_H */
16.75 -
16.76 -/* vim: set ts=8 sts=0 sw=8 noet: */
17.1 new file mode 100644
17.2 --- /dev/null
17.3 +++ b/libpurple/protocols/gg/image.c
17.4 @@ -0,0 +1,294 @@
17.5 +/* purple
17.6 + *
17.7 + * Purple is the legal property of its developers, whose names are too numerous
17.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
17.9 + * source distribution.
17.10 + *
17.11 + * Rewritten from scratch during Google Summer of Code 2012
17.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
17.13 + *
17.14 + * Previously implemented by:
17.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
17.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
17.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
17.18 + *
17.19 + * This program is free software; you can redistribute it and/or modify
17.20 + * it under the terms of the GNU General Public License as published by
17.21 + * the Free Software Foundation; either version 2 of the License, or
17.22 + * (at your option) any later version.
17.23 + *
17.24 + * This program is distributed in the hope that it will be useful,
17.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
17.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17.27 + * GNU General Public License for more details.
17.28 + *
17.29 + * You should have received a copy of the GNU General Public License
17.30 + * along with this program; if not, write to the Free Software
17.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
17.32 + */
17.33 +
17.34 +#include "image.h"
17.35 +
17.36 +#include <debug.h>
17.37 +
17.38 +#include "gg.h"
17.39 +#include "utils.h"
17.40 +
17.41 +#define GGP_PENDING_IMAGE_ID_PREFIX "gg-pending-image-"
17.42 +
17.43 +typedef struct
17.44 +{
17.45 + uin_t from;
17.46 + gchar *text;
17.47 + time_t mtime;
17.48 +} ggp_image_pending_message;
17.49 +
17.50 +typedef struct
17.51 +{
17.52 + int id;
17.53 + gchar *conv_name;
17.54 +} ggp_image_pending_image;
17.55 +
17.56 +static void ggp_image_pending_message_free(gpointer data)
17.57 +{
17.58 + ggp_image_pending_message *pending_message =
17.59 + (ggp_image_pending_message*)data;
17.60 + g_free(pending_message->text);
17.61 + g_free(pending_message);
17.62 +}
17.63 +
17.64 +static void ggp_image_pending_image_free(gpointer data)
17.65 +{
17.66 + ggp_image_pending_image *pending_image =
17.67 + (ggp_image_pending_image*)data;
17.68 + g_free(pending_image->conv_name);
17.69 + g_free(pending_image);
17.70 +}
17.71 +
17.72 +static inline ggp_image_connection_data *
17.73 +ggp_image_get_imgdata(PurpleConnection *gc)
17.74 +{
17.75 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
17.76 + return &accdata->image_data;
17.77 +}
17.78 +
17.79 +void ggp_image_setup(PurpleConnection *gc)
17.80 +{
17.81 + ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
17.82 +
17.83 + imgdata->pending_messages = NULL;
17.84 + imgdata->pending_images = g_hash_table_new_full(NULL, NULL, NULL,
17.85 + ggp_image_pending_image_free);
17.86 +}
17.87 +
17.88 +void ggp_image_cleanup(PurpleConnection *gc)
17.89 +{
17.90 + ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
17.91 +
17.92 + g_list_free_full(imgdata->pending_messages,
17.93 + &ggp_image_pending_message_free);
17.94 + g_hash_table_destroy(imgdata->pending_images);
17.95 +}
17.96 +
17.97 +const char * ggp_image_pending_placeholder(uint32_t id)
17.98 +{
17.99 + static char buff[50];
17.100 +
17.101 + g_snprintf(buff, 50, "<img id=\"" GGP_PENDING_IMAGE_ID_PREFIX
17.102 + "%u\">", id);
17.103 +
17.104 + return buff;
17.105 +}
17.106 +
17.107 +void ggp_image_got_im(PurpleConnection *gc, uin_t from, gchar *text,
17.108 + time_t mtime)
17.109 +{
17.110 + ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
17.111 + ggp_image_pending_message *pending_message =
17.112 + g_new(ggp_image_pending_message, 1);
17.113 +
17.114 + purple_debug_info("gg", "ggp_image_got_im: received message with "
17.115 + "images from %u: %s\n", from, text);
17.116 +
17.117 + pending_message->from = from;
17.118 + pending_message->text = text;
17.119 + pending_message->mtime = mtime;
17.120 +
17.121 + imgdata->pending_messages = g_list_append(imgdata->pending_messages,
17.122 + pending_message);
17.123 +}
17.124 +
17.125 +ggp_image_prepare_result ggp_image_prepare(PurpleConnection *gc, const int id,
17.126 + const char *conv_name, struct gg_msg_richtext_image *image_info)
17.127 +{
17.128 + ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
17.129 + PurpleStoredImage *image = purple_imgstore_find_by_id(id);
17.130 + size_t image_size;
17.131 + gconstpointer image_data;
17.132 + const char *image_filename;
17.133 + uint32_t image_crc;
17.134 + ggp_image_pending_image *pending_image;
17.135 +
17.136 + if (!image)
17.137 + {
17.138 + purple_debug_error("gg", "ggp_image_prepare_to_send: image %d "
17.139 + "not found in image store\n", id);
17.140 + return GGP_IMAGE_PREPARE_FAILURE;
17.141 + }
17.142 +
17.143 + image_size = purple_imgstore_get_size(image);
17.144 +
17.145 + if (image_size > GGP_IMAGE_SIZE_MAX)
17.146 + {
17.147 + purple_debug_warning("gg", "ggp_image_prepare_to_send: image "
17.148 + "is too big (max bytes: %d)\n", GGP_IMAGE_SIZE_MAX);
17.149 + return GGP_IMAGE_PREPARE_TOO_BIG;
17.150 + }
17.151 +
17.152 + purple_imgstore_ref(image);
17.153 + image_data = purple_imgstore_get_data(image);
17.154 + image_filename = purple_imgstore_get_filename(image);
17.155 + image_crc = gg_crc32(0, image_data, image_size);
17.156 +
17.157 + purple_debug_info("gg", "ggp_image_prepare_to_send: image prepared "
17.158 + "[id=%d, crc=%u, size=%d, filename=%s]\n",
17.159 + id, image_crc, image_size, image_filename);
17.160 +
17.161 + pending_image = g_new(ggp_image_pending_image, 1);
17.162 + pending_image->id = id;
17.163 + pending_image->conv_name = g_strdup(conv_name);
17.164 + g_hash_table_insert(imgdata->pending_images, GINT_TO_POINTER(image_crc),
17.165 + pending_image);
17.166 +
17.167 + image_info->unknown1 = 0x0109;
17.168 + image_info->size = gg_fix32(image_size);
17.169 + image_info->crc32 = gg_fix32(image_crc);
17.170 +
17.171 + return GGP_IMAGE_PREPARE_OK;
17.172 +}
17.173 +
17.174 +void ggp_image_recv(PurpleConnection *gc,
17.175 + const struct gg_event_image_reply *image_reply)
17.176 +{
17.177 + ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
17.178 + int stored_id;
17.179 + const char *imgtag_search;
17.180 + gchar *imgtag_replace;
17.181 + GList *pending_messages_it;
17.182 +
17.183 + stored_id = purple_imgstore_add_with_id(
17.184 + g_memdup(image_reply->image, image_reply->size),
17.185 + image_reply->size,
17.186 + image_reply->filename);
17.187 +
17.188 + purple_debug_info("gg", "ggp_image_recv: got image "
17.189 + "[id=%d, crc=%u, size=%u, filename=\"%s\"]\n",
17.190 + stored_id,
17.191 + image_reply->crc32,
17.192 + image_reply->size,
17.193 + image_reply->filename);
17.194 +
17.195 + imgtag_search = ggp_image_pending_placeholder(image_reply->crc32);
17.196 + imgtag_replace = g_strdup_printf("<img src=\""
17.197 + PURPLE_STORED_IMAGE_PROTOCOL "%u\">", stored_id);
17.198 +
17.199 + pending_messages_it = g_list_first(imgdata->pending_messages);
17.200 + while (pending_messages_it)
17.201 + {
17.202 + ggp_image_pending_message *pending_message =
17.203 + (ggp_image_pending_message*)pending_messages_it->data;
17.204 + gchar *newText;
17.205 +
17.206 + if (strstr(pending_message->text, imgtag_search) == NULL)
17.207 + {
17.208 + pending_messages_it = g_list_next(pending_messages_it);
17.209 + continue;
17.210 + }
17.211 +
17.212 + purple_debug_misc("gg", "ggp_image_recv: found message "
17.213 + "containing image: %s\n", pending_message->text);
17.214 +
17.215 + newText = purple_strreplace(pending_message->text,
17.216 + imgtag_search, imgtag_replace);
17.217 + g_free(pending_message->text);
17.218 + pending_message->text = newText;
17.219 +
17.220 + if (strstr(pending_message->text,
17.221 + "<img id=\"" GGP_PENDING_IMAGE_ID_PREFIX) == NULL)
17.222 + {
17.223 + purple_debug_info("gg", "ggp_image_recv: "
17.224 + "message is ready to display\n");
17.225 + serv_got_im(gc, ggp_uin_to_str(pending_message->from),
17.226 + pending_message->text,
17.227 + PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_IMAGES,
17.228 + pending_message->mtime);
17.229 +
17.230 + ggp_image_pending_message_free(pending_message);
17.231 + imgdata->pending_messages = g_list_remove(
17.232 + imgdata->pending_messages, pending_message);
17.233 + }
17.234 +
17.235 + pending_messages_it = g_list_next(pending_messages_it);
17.236 + }
17.237 + g_free(imgtag_replace);
17.238 +}
17.239 +
17.240 +void ggp_image_send(PurpleConnection *gc,
17.241 + const struct gg_event_image_request *image_request)
17.242 +{
17.243 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
17.244 + ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
17.245 + ggp_image_pending_image *pending_image;
17.246 + PurpleStoredImage *image;
17.247 + PurpleConversation *conv;
17.248 +
17.249 + purple_debug_info("gg", "ggp_image_send: got image request "
17.250 + "[uin=%u, crc=%u, size=%u]\n",
17.251 + image_request->sender,
17.252 + image_request->crc32,
17.253 + image_request->size);
17.254 +
17.255 + pending_image = g_hash_table_lookup(imgdata->pending_images,
17.256 + GINT_TO_POINTER(image_request->crc32));
17.257 +
17.258 + if (pending_image == NULL)
17.259 + {
17.260 + purple_debug_warning("gg", "ggp_image_send: requested image "
17.261 + "not found\n");
17.262 + return;
17.263 + }
17.264 +
17.265 + purple_debug_misc("gg", "ggp_image_send: requested image found "
17.266 + "[id=%d, conv=%s]\n",
17.267 + pending_image->id,
17.268 + pending_image->conv_name);
17.269 +
17.270 + image = purple_imgstore_find_by_id(pending_image->id);
17.271 +
17.272 + if (!image)
17.273 + {
17.274 + purple_debug_error("gg", "ggp_image_send: requested image "
17.275 + "found, but doesn't exists in image store\n");
17.276 + g_hash_table_remove(imgdata->pending_images,
17.277 + GINT_TO_POINTER(image_request->crc32));
17.278 + return;
17.279 + }
17.280 +
17.281 + //TODO: check allowed recipients
17.282 + gg_image_reply(accdata->session, image_request->sender,
17.283 + purple_imgstore_get_filename(image),
17.284 + purple_imgstore_get_data(image),
17.285 + purple_imgstore_get_size(image));
17.286 + purple_imgstore_unref(image);
17.287 +
17.288 + conv = purple_find_conversation_with_account(
17.289 + PURPLE_CONV_TYPE_IM, pending_image->conv_name,
17.290 + purple_connection_get_account(gc));
17.291 + if (conv != NULL)
17.292 + purple_conversation_write(conv, "", _("Image delivered."),
17.293 + PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_NOTIFY,
17.294 + time(NULL));
17.295 +
17.296 + g_hash_table_remove(imgdata->pending_images,
17.297 + GINT_TO_POINTER(image_request->crc32));
17.298 +}
18.1 new file mode 100644
18.2 --- /dev/null
18.3 +++ b/libpurple/protocols/gg/image.h
18.4 @@ -0,0 +1,66 @@
18.5 +/* purple
18.6 + *
18.7 + * Purple is the legal property of its developers, whose names are too numerous
18.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
18.9 + * source distribution.
18.10 + *
18.11 + * Rewritten from scratch during Google Summer of Code 2012
18.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
18.13 + *
18.14 + * Previously implemented by:
18.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
18.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
18.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
18.18 + *
18.19 + * This program is free software; you can redistribute it and/or modify
18.20 + * it under the terms of the GNU General Public License as published by
18.21 + * the Free Software Foundation; either version 2 of the License, or
18.22 + * (at your option) any later version.
18.23 + *
18.24 + * This program is distributed in the hope that it will be useful,
18.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
18.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18.27 + * GNU General Public License for more details.
18.28 + *
18.29 + * You should have received a copy of the GNU General Public License
18.30 + * along with this program; if not, write to the Free Software
18.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
18.32 + */
18.33 +
18.34 +#ifndef _GGP_IMAGE_H
18.35 +#define _GGP_IMAGE_H
18.36 +
18.37 +#include <internal.h>
18.38 +#include <libgadu.h>
18.39 +
18.40 +#define GGP_IMAGE_SIZE_MAX 255000
18.41 +
18.42 +typedef struct
18.43 +{
18.44 + GList *pending_messages;
18.45 + GHashTable *pending_images;
18.46 +} ggp_image_connection_data;
18.47 +
18.48 +typedef enum
18.49 +{
18.50 + GGP_IMAGE_PREPARE_OK = 0,
18.51 + GGP_IMAGE_PREPARE_FAILURE,
18.52 + GGP_IMAGE_PREPARE_TOO_BIG
18.53 +} ggp_image_prepare_result;
18.54 +
18.55 +void ggp_image_setup(PurpleConnection *gc);
18.56 +void ggp_image_cleanup(PurpleConnection *gc);
18.57 +
18.58 +const char * ggp_image_pending_placeholder(uint32_t id);
18.59 +
18.60 +void ggp_image_got_im(PurpleConnection *gc, uin_t from, gchar *msg,
18.61 + time_t mtime);
18.62 +ggp_image_prepare_result ggp_image_prepare(PurpleConnection *gc, const int id,
18.63 + const char *conv_name, struct gg_msg_richtext_image *image_info);
18.64 +
18.65 +void ggp_image_recv(PurpleConnection *gc,
18.66 + const struct gg_event_image_reply *image_reply);
18.67 +void ggp_image_send(PurpleConnection *gc,
18.68 + const struct gg_event_image_request *image_request);
18.69 +
18.70 +#endif /* _GGP_IMAGE_H */
19.1 rename from libpurple/protocols/gg/lib/libgadu-config.h
19.2 rename to libpurple/protocols/gg/lib/config.h
19.3 --- a/libpurple/protocols/gg/lib/libgadu-config.h
19.4 +++ b/libpurple/protocols/gg/lib/config.h
19.5 @@ -1,21 +1,23 @@
19.6 -/* Local libgadu configuration. */
19.7 +/* Local libgadu configuration file. */
19.8
19.9 -#include "config.h"
19.10 +/* libpurple's config */
19.11 +#include <config.h>
19.12
19.13 -#ifndef __GG_LIBGADU_CONFIG_H
19.14 -#define __GG_LIBGADU_CONFIG_H
19.15 +#define GGP_QUOTE(x) GGP_QUOTE2(x)
19.16 +#define GGP_QUOTE2(x) #x
19.17 +#define GG_LIBGADU_VERSION GGP_QUOTE(GG_INTERNAL_LIBGADU_VERSION)
19.18
19.19 /* Defined if libgadu was compiled for bigendian machine. */
19.20 -#undef __GG_LIBGADU_BIGENDIAN
19.21 +#undef GG_CONFIG_BIGENDIAN
19.22 #ifdef WORDS_BIGENDIAN
19.23 -# define __GG_LIBGADU_BIGENDIAN
19.24 +# define GG_CONFIG_BIGENDIAN
19.25 #endif
19.26
19.27 /* Defined if this machine has gethostbyname_r(). */
19.28 #undef GG_CONFIG_HAVE_GETHOSTBYNAME_R
19.29
19.30 -/* Defined if this machine has _exit(). */
19.31 -#define GG_CONFIG_HAVE__EXIT
19.32 +/* Define to 1 if you have the `_exit' function. */
19.33 +#define HAVE__EXIT 1
19.34
19.35 /* Defined if libgadu was compiled and linked with fork support. */
19.36 #undef GG_CONFIG_HAVE_FORK
19.37 @@ -24,25 +26,25 @@
19.38 #endif
19.39
19.40 /* Defined if libgadu was compiled and linked with pthread support. */
19.41 -/* We don't like pthreads. */
19.42 -#undef __GG_LIBGADU_HAVE_PTHREAD
19.43 +/* We don't use pthreads - they may not be safe. */
19.44 +#undef GG_CONFIG_HAVE_PTHREAD
19.45
19.46 /* Defined if this machine has C99-compiliant vsnprintf(). */
19.47 -#undef __GG_LIBGADU_HAVE_C99_VSNPRINTF
19.48 +#undef HAVE_C99_VSNPRINTF
19.49 #ifndef _WIN32
19.50 -# define __GG_LIBGADU_HAVE_C99_VSNPRINTF
19.51 +# define HAVE_C99_VSNPRINTF
19.52 #endif
19.53
19.54 /* Defined if this machine has va_copy(). */
19.55 -#define __GG_LIBGADU_HAVE_VA_COPY
19.56 +#define GG_CONFIG_HAVE_VA_COPY
19.57
19.58 /* Defined if this machine has __va_copy(). */
19.59 -#define __GG_LIBGADU_HAVE___VA_COPY
19.60 +#define GG_CONFIG_HAVE___VA_COPY
19.61
19.62 /* Defined if this machine supports long long. */
19.63 -#undef __GG_LIBGADU_HAVE_LONG_LONG
19.64 +#undef GG_CONFIG_HAVE_LONG_LONG
19.65 #ifdef HAVE_LONG_LONG
19.66 -# define __GG_LIBGADU_HAVE_LONG_LONG
19.67 +# define GG_CONFIG_HAVE_LONG_LONG
19.68 #endif
19.69
19.70 /* Defined if libgadu was compiled and linked with GnuTLS support. */
19.71 @@ -52,19 +54,26 @@
19.72 #endif
19.73
19.74 /* Defined if libgadu was compiled and linked with OpenSSL support. */
19.75 -/* Always undefined in Purple. */
19.76 -#undef __GG_LIBGADU_HAVE_OPENSSL
19.77 +/* OpenSSL cannot be used with libpurple due to licence type. */
19.78 +#undef GG_CONFIG_HAVE_OPENSSL
19.79
19.80 /* Defined if libgadu was compiled and linked with zlib support. */
19.81 -#undef GG_CONFIG_HAVE_ZLIB
19.82 +#define GG_CONFIG_HAVE_ZLIB
19.83
19.84 /* Defined if uintX_t types are defined in <stdint.h>. */
19.85 #undef GG_CONFIG_HAVE_STDINT_H
19.86 -#if HAVE_STDINT_H
19.87 +#ifdef HAVE_STDINT_H
19.88 # define GG_CONFIG_HAVE_STDINT_H
19.89 #endif
19.90
19.91 +/* Defined if uintX_t types are defined in <inttypes.h>. */
19.92 +#undef GG_CONFIG_HAVE_INTTYPES_H
19.93 +#ifdef HAVE_INTTYPES_H
19.94 +# define GG_CONFIG_HAVE_INTTYPES_H
19.95 +#endif
19.96
19.97 -#define vnsprintf g_vnsprintf
19.98 -
19.99 +/* Defined if uintX_t types are defined in <sys/types.h>. */
19.100 +#undef GG_CONFIG_HAVE_SYS_TYPES_H
19.101 +#ifdef HAVE_SYS_TYPES_H
19.102 +# define GG_CONFIG_HAVE_SYS_TYPES_H
19.103 #endif
20.1 --- a/libpurple/protocols/gg/lib/dcc7.c
20.2 +++ b/libpurple/protocols/gg/lib/dcc7.c
20.3 @@ -49,8 +49,8 @@
20.4 #include "libgadu.h"
20.5 #include "protocol.h"
20.6 #include "resolver.h"
20.7 -#include "libgadu-internal.h"
20.8 -#include "libgadu-debug.h"
20.9 +#include "internal.h"
20.10 +#include "debug.h"
20.11
20.12 #define gg_debug_dcc(dcc, level, fmt...) \
20.13 gg_debug_session(((dcc) != NULL) ? (dcc)->sess : NULL, level, fmt)
21.1 --- a/libpurple/protocols/gg/lib/debug.c
21.2 +++ b/libpurple/protocols/gg/lib/debug.c
21.3 @@ -32,7 +32,7 @@
21.4 #include <string.h>
21.5
21.6 #include "libgadu.h"
21.7 -#include "libgadu-debug.h"
21.8 +#include "debug.h"
21.9
21.10 /**
21.11 * Poziom rejestracji informacji odpluskwiajÄ…cych. Zmienna jest maskÄ… bitowÄ…
22.1 rename from libpurple/protocols/gg/lib/libgadu-debug.h
22.2 rename to libpurple/protocols/gg/lib/debug.h
23.1 --- a/libpurple/protocols/gg/lib/deflate.h
23.2 +++ b/libpurple/protocols/gg/lib/deflate.h
23.3 @@ -1,7 +1,7 @@
23.4 /* $Id$ */
23.5
23.6 /*
23.7 - * (C) Copyright 2009 Jakub Zawadzki <darkjames@darkjames.ath.cx>
23.8 + * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com>
23.9 *
23.10 * This program is free software; you can redistribute it and/or modify
23.11 * it under the terms of the GNU Lesser General Public License Version
24.1 --- a/libpurple/protocols/gg/lib/encoding.c
24.2 +++ b/libpurple/protocols/gg/lib/encoding.c
24.3 @@ -35,22 +35,22 @@
24.4 */
24.5 static const uint16_t table_cp1250[] =
24.6 {
24.7 - 0x20ac, '?', 0x201a, '?', 0x201e, 0x2026, 0x2020, 0x2021,
24.8 - '?', 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
24.9 - '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
24.10 - '?', 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
24.11 - 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
24.12 - 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
24.13 - 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
24.14 - 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
24.15 - 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
24.16 - 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
24.17 - 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
24.18 - 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
24.19 - 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
24.20 - 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
24.21 - 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
24.22 - 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
24.23 + 0x20ac, '?', 0x201a, '?', 0x201e, 0x2026, 0x2020, 0x2021,
24.24 + '?', 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
24.25 + '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
24.26 + '?', 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
24.27 + 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
24.28 + 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
24.29 + 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
24.30 + 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
24.31 + 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
24.32 + 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
24.33 + 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
24.34 + 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
24.35 + 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
24.36 + 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
24.37 + 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
24.38 + 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
24.39 };
24.40
24.41 /**
24.42 @@ -136,11 +136,8 @@
24.43 uint32_t uc = 0, uc_min = 0;
24.44
24.45 for (i = 0, len = 0; (src[i] != 0) && (i < src_length); i++) {
24.46 - if ((src[i] & 0xc0) == 0xc0) {
24.47 + if ((src[i] & 0xc0) != 0x80)
24.48 len++;
24.49 - } else if ((src[i] & 0x80) == 0x00) {
24.50 - len++;
24.51 - }
24.52 }
24.53
24.54 if ((dst_length != -1) && (len > dst_length))
25.1 --- a/libpurple/protocols/gg/lib/events.c
25.2 +++ b/libpurple/protocols/gg/lib/events.c
25.3 @@ -1,4 +1,4 @@
25.4 -/* $Id: events.c 1105 2011-05-25 21:34:50Z wojtekka $ */
25.5 +/* $Id: events.c 1144 2011-07-09 15:43:00Z wojtekka $ */
25.6
25.7 /*
25.8 * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
25.9 @@ -33,9 +33,9 @@
25.10 #include "compat.h"
25.11 #include "libgadu.h"
25.12 #include "protocol.h"
25.13 -#include "libgadu-internal.h"
25.14 +#include "internal.h"
25.15 #include "encoding.h"
25.16 -#include "libgadu-debug.h"
25.17 +#include "debug.h"
25.18 #include "session.h"
25.19
25.20 #include <errno.h>
25.21 @@ -806,14 +806,14 @@
25.22 const gnutls_datum_t *peers;
25.23 gnutls_x509_crt_t cert;
25.24
25.25 - if (gnutls_x509_crt_init(&cert) >= 0) {
25.26 + if (gnutls_x509_crt_init(&cert) == 0) {
25.27 peers = gnutls_certificate_get_peers(GG_SESSION_GNUTLS(sess), &peer_count);
25.28
25.29 if (peers != NULL) {
25.30 char buf[256];
25.31 size_t size;
25.32
25.33 - if (gnutls_x509_crt_import(cert, &peers[0], GNUTLS_X509_FMT_DER) >= 0) {
25.34 + if (gnutls_x509_crt_import(cert, &peers[0], GNUTLS_X509_FMT_DER) == 0) {
25.35 size = sizeof(buf);
25.36 gnutls_x509_crt_get_dn(cert, buf, &size);
25.37 gg_debug_session(sess, GG_DEBUG_MISC, "// cert subject: %s\n", buf);
25.38 @@ -822,6 +822,8 @@
25.39 gg_debug_session(sess, GG_DEBUG_MISC, "// cert issuer: %s\n", buf);
25.40 }
25.41 }
25.42 +
25.43 + gnutls_x509_crt_deinit(cert);
25.44 }
25.45 }
25.46
26.1 --- a/libpurple/protocols/gg/lib/handlers.c
26.2 +++ b/libpurple/protocols/gg/lib/handlers.c
26.3 @@ -39,7 +39,7 @@
26.4 #include "protocol.h"
26.5 #include "encoding.h"
26.6 #include "message.h"
26.7 -#include "libgadu-internal.h"
26.8 +#include "internal.h"
26.9 #include "deflate.h"
26.10
26.11 #include <errno.h>
27.1 rename from libpurple/protocols/gg/lib/libgadu-internal.h
27.2 rename to libpurple/protocols/gg/lib/internal.h
27.3 --- a/libpurple/protocols/gg/lib/libgadu-internal.h
27.4 +++ b/libpurple/protocols/gg/lib/internal.h
27.5 @@ -22,6 +22,7 @@
27.6 #define LIBGADU_INTERNAL_H
27.7
27.8 #include "libgadu.h"
27.9 +#include "config.h"
27.10
27.11 struct gg_dcc7_relay {
27.12 uint32_t addr;
28.1 --- a/libpurple/protocols/gg/lib/libgadu.c
28.2 +++ b/libpurple/protocols/gg/lib/libgadu.c
28.3 @@ -1,4 +1,4 @@
28.4 -/* $Id: libgadu.c 1102 2011-05-05 21:17:57Z wojtekka $ */
28.5 +/* $Id: libgadu.c 1245 2012-01-10 22:48:31Z wojtekka $ */
28.6
28.7 /*
28.8 * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl>
28.9 @@ -37,9 +37,9 @@
28.10 #include "libgadu.h"
28.11 #include "protocol.h"
28.12 #include "resolver.h"
28.13 -#include "libgadu-internal.h"
28.14 +#include "internal.h"
28.15 #include "encoding.h"
28.16 -#include "libgadu-debug.h"
28.17 +#include "debug.h"
28.18 #include "session.h"
28.19 #include "message.h"
28.20 #include "deflate.h"
28.21 @@ -60,8 +60,6 @@
28.22 # include <openssl/rand.h>
28.23 #endif
28.24
28.25 -#define GG_LIBGADU_VERSION "1.11.0"
28.26 -
28.27 /**
28.28 * Port gniazda nasłuchującego dla połączeń bezpośrednich.
28.29 *
28.30 @@ -132,7 +130,7 @@
28.31 #ifdef __GNUC__
28.32 __attribute__ ((unused))
28.33 #endif
28.34 -= "$Id: libgadu.c 1102 2011-05-05 21:17:57Z wojtekka $";
28.35 += "$Id: libgadu.c 1245 2012-01-10 22:48:31Z wojtekka $";
28.36 #endif
28.37
28.38 #endif /* DOXYGEN */
28.39 @@ -149,7 +147,7 @@
28.40 return GG_LIBGADU_VERSION;
28.41 }
28.42
28.43 -#ifdef GG_CONFIG_HAVE_UINT64_T
28.44 +#ifdef HAVE_UINT64_T
28.45 /**
28.46 * \internal Zamienia kolejność bajtów w 64-bitowym słowie.
28.47 *
28.48 @@ -178,7 +176,7 @@
28.49 ((x & (uint64_t) 0xff00000000000000ULL) >> 56));
28.50 #endif
28.51 }
28.52 -#endif /* GG_CONFIG_HAVE_UINT64_T */
28.53 +#endif /* HAVE_UINT64_T */
28.54
28.55 /**
28.56 * \internal Zamienia kolejność bajtów w 32-bitowym słowie.
28.57 @@ -443,11 +441,11 @@
28.58 res = written;
28.59 }
28.60 } else {
28.61 - res = 0;
28.62 -
28.63 if (sess->send_buf == NULL) {
28.64 res = gg_write_common(sess, buf, length);
28.65
28.66 + if (res == -1 && errno == EAGAIN)
28.67 + res = 0;
28.68 if (res == -1)
28.69 return -1;
28.70 }
28.71 @@ -1112,18 +1110,6 @@
28.72 sess->fd = -1;
28.73 }
28.74
28.75 -#ifdef GG_CONFIG_HAVE_GNUTLS
28.76 - if (sess->ssl != NULL) {
28.77 - gg_session_gnutls_t *tmp;
28.78 -
28.79 - tmp = (gg_session_gnutls_t*) sess->ssl;
28.80 - gnutls_deinit(tmp->session);
28.81 - gnutls_certificate_free_credentials(tmp->xcred);
28.82 - gnutls_global_deinit();
28.83 - free(sess->ssl);
28.84 - }
28.85 -#endif
28.86 -
28.87 if (sess->send_buf) {
28.88 free(sess->send_buf);
28.89 sess->send_buf = NULL;
28.90 @@ -1155,6 +1141,18 @@
28.91 free(sess->recv_buf);
28.92 free(sess->header_buf);
28.93
28.94 +#ifdef GG_CONFIG_HAVE_GNUTLS
28.95 + if (sess->ssl != NULL) {
28.96 + gg_session_gnutls_t *tmp;
28.97 +
28.98 + tmp = (gg_session_gnutls_t*) sess->ssl;
28.99 + gnutls_deinit(tmp->session);
28.100 + gnutls_certificate_free_credentials(tmp->xcred);
28.101 + gnutls_global_deinit();
28.102 + free(sess->ssl);
28.103 + }
28.104 +#endif
28.105 +
28.106 #ifdef GG_CONFIG_HAVE_OPENSSL
28.107 if (sess->ssl)
28.108 SSL_free(sess->ssl);
29.1 --- a/libpurple/protocols/gg/lib/libgadu.h
29.2 +++ b/libpurple/protocols/gg/lib/libgadu.h
29.3 @@ -101,7 +101,7 @@
29.4 /* Defined if uintX_t types are defined in <sys/types.h>. */
29.5 #undef GG_CONFIG_HAVE_SYS_TYPES_H
29.6
29.7 -#include "libgadu-config.h"
29.8 +#include "config.h"
29.9
29.10 #ifdef GG_CONFIG_HAVE_OPENSSL
29.11 #include <openssl/ssl.h>
30.1 --- a/libpurple/protocols/gg/lib/obsolete.c
30.2 +++ b/libpurple/protocols/gg/lib/obsolete.c
30.3 @@ -34,7 +34,7 @@
30.4 #include <errno.h>
30.5
30.6 #include "libgadu.h"
30.7 -#include "libgadu-internal.h"
30.8 +#include "internal.h"
30.9
30.10 struct gg_http *gg_userlist_get(uin_t uin, const char *passwd, int async)
30.11 {
31.1 --- a/libpurple/protocols/gg/lib/pubdir50.c
31.2 +++ b/libpurple/protocols/gg/lib/pubdir50.c
31.3 @@ -31,7 +31,7 @@
31.4 #include <time.h>
31.5
31.6 #include "libgadu.h"
31.7 -#include "libgadu-internal.h"
31.8 +#include "internal.h"
31.9 #include "encoding.h"
31.10
31.11 /**
32.1 --- a/libpurple/protocols/gg/lib/resolver.c
32.2 +++ b/libpurple/protocols/gg/lib/resolver.c
32.3 @@ -234,7 +234,7 @@
32.4 /* Kopiuj */
32.5
32.6 for (i = 0; he->h_addr_list[i] != NULL; i++)
32.7 - memcpy(&((*result)[i]), he->h_addr_list[0], sizeof(struct in_addr));
32.8 + memcpy(&((*result)[i]), he->h_addr_list[i], sizeof(struct in_addr));
32.9
32.10 (*result)[i].s_addr = INADDR_NONE;
32.11
32.12 @@ -249,6 +249,9 @@
32.13 /**
32.14 * \internal RozwiÄ…zuje nazwÄ™ i zapisuje wynik do podanego desktyptora.
32.15 *
32.16 + * \note Użycie logowania w tej funkcji może mieć negatywny wpływ na
32.17 + * aplikacje jednowÄ…tkowe korzystajÄ…ce.
32.18 + *
32.19 * \param fd Deskryptor
32.20 * \param hostname Nazwa serwera
32.21 *
32.22 @@ -260,11 +263,10 @@
32.23 int addr_count;
32.24 int res = 0;
32.25
32.26 - gg_debug(GG_DEBUG_MISC, "// gg_resolver_run(%d, %s)\n", fd, hostname);
32.27 -
32.28 if ((addr_ip[0].s_addr = inet_addr(hostname)) == INADDR_NONE) {
32.29 if (gg_gethostbyname_real(hostname, &addr_list, &addr_count, 1) == -1) {
32.30 addr_list = addr_ip;
32.31 + addr_count = 0;
32.32 /* addr_ip[0] już zawiera INADDR_NONE */
32.33 }
32.34 } else {
32.35 @@ -273,8 +275,6 @@
32.36 addr_count = 1;
32.37 }
32.38
32.39 - gg_debug(GG_DEBUG_MISC, "// gg_resolver_run() count = %d\n", addr_count);
32.40 -
32.41 if (write(fd, addr_list, (addr_count + 1) * sizeof(struct in_addr)) != (addr_count + 1) * sizeof(struct in_addr))
32.42 res = -1;
32.43
32.44 @@ -375,7 +375,7 @@
32.45
32.46 status = (gg_resolver_run(pipes[1], hostname) == -1) ? 1 : 0;
32.47
32.48 -#ifdef GG_CONFIG_HAVE__EXIT
32.49 +#ifdef HAVE__EXIT
32.50 _exit(status);
32.51 #else
32.52 exit(status);
33.1 new file mode 100644
33.2 --- /dev/null
33.3 +++ b/libpurple/protocols/gg/libgadu-events.c
33.4 @@ -0,0 +1,83 @@
33.5 +/* purple
33.6 + *
33.7 + * Purple is the legal property of its developers, whose names are too numerous
33.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
33.9 + * source distribution.
33.10 + *
33.11 + * Rewritten from scratch during Google Summer of Code 2012
33.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
33.13 + *
33.14 + * Previously implemented by:
33.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
33.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
33.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
33.18 + *
33.19 + * This program is free software; you can redistribute it and/or modify
33.20 + * it under the terms of the GNU General Public License as published by
33.21 + * the Free Software Foundation; either version 2 of the License, or
33.22 + * (at your option) any later version.
33.23 + *
33.24 + * This program is distributed in the hope that it will be useful,
33.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
33.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33.27 + * GNU General Public License for more details.
33.28 + *
33.29 + * You should have received a copy of the GNU General Public License
33.30 + * along with this program; if not, write to the Free Software
33.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
33.32 + */
33.33 +
33.34 +#include "libgadu-events.h"
33.35 +
33.36 +#include <debug.h>
33.37 +
33.38 +#include "avatar.h"
33.39 +
33.40 +void ggp_events_user_data(PurpleConnection *gc, struct gg_event_user_data *data)
33.41 +{
33.42 + int user_idx;
33.43 + gboolean is_update;
33.44 +
33.45 + purple_debug_info("gg", "GG_EVENT_USER_DATA [type=%d, user_count=%d]\n",
33.46 + data->type, data->user_count);
33.47 +
33.48 + /*
33.49 + type =
33.50 + 1, 3: user information sent after connecting (divided by
33.51 + 20 contacts; 3 - last one; 1 - rest of them)
33.52 + 0: data update
33.53 + */
33.54 + is_update = (data->type == 0);
33.55 +
33.56 + for (user_idx = 0; user_idx < data->user_count; user_idx++)
33.57 + {
33.58 + struct gg_event_user_data_user *data_user =
33.59 + &data->users[user_idx];
33.60 + uin_t uin = data_user->uin;
33.61 + int attr_idx;
33.62 + gboolean got_avatar = FALSE;
33.63 + for (attr_idx = 0; attr_idx < data_user->attr_count; attr_idx++)
33.64 + {
33.65 + struct gg_event_user_data_attr *data_attr =
33.66 + &data_user->attrs[attr_idx];
33.67 + if (strcmp(data_attr->key, "avatar") == 0)
33.68 + {
33.69 + time_t timestamp;
33.70 + if (data_attr->type == 0)
33.71 + {
33.72 + ggp_avatar_buddy_remove(gc, uin);
33.73 + continue;
33.74 + }
33.75 +
33.76 + timestamp = atoi(data_attr->value);
33.77 + if (timestamp <= 0)
33.78 + continue;
33.79 + got_avatar = TRUE;
33.80 + ggp_avatar_buddy_update(gc, uin, timestamp);
33.81 + }
33.82 + }
33.83 +
33.84 + if (!is_update && !got_avatar)
33.85 + ggp_avatar_buddy_remove(gc, uin);
33.86 + }
33.87 +}
34.1 new file mode 100644
34.2 --- /dev/null
34.3 +++ b/libpurple/protocols/gg/libgadu-events.h
34.4 @@ -0,0 +1,39 @@
34.5 +/* purple
34.6 + *
34.7 + * Purple is the legal property of its developers, whose names are too numerous
34.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
34.9 + * source distribution.
34.10 + *
34.11 + * Rewritten from scratch during Google Summer of Code 2012
34.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
34.13 + *
34.14 + * Previously implemented by:
34.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
34.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
34.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
34.18 + *
34.19 + * This program is free software; you can redistribute it and/or modify
34.20 + * it under the terms of the GNU General Public License as published by
34.21 + * the Free Software Foundation; either version 2 of the License, or
34.22 + * (at your option) any later version.
34.23 + *
34.24 + * This program is distributed in the hope that it will be useful,
34.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
34.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34.27 + * GNU General Public License for more details.
34.28 + *
34.29 + * You should have received a copy of the GNU General Public License
34.30 + * along with this program; if not, write to the Free Software
34.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
34.32 + */
34.33 +
34.34 +#ifndef _GGP_LIBGADU_EVENTS_H
34.35 +#define _GGP_LIBGADU_EVENTS_H
34.36 +
34.37 +#include <internal.h>
34.38 +#include <libgadu.h>
34.39 +
34.40 +void ggp_events_user_data(PurpleConnection *gc,
34.41 + struct gg_event_user_data *data);
34.42 +
34.43 +#endif /* _GGP_LIBGADU_EVENTS_H */
35.1 new file mode 100644
35.2 --- /dev/null
35.3 +++ b/libpurple/protocols/gg/libgaduw.c
35.4 @@ -0,0 +1,141 @@
35.5 +/* purple
35.6 + *
35.7 + * Purple is the legal property of its developers, whose names are too numerous
35.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
35.9 + * source distribution.
35.10 + *
35.11 + * Rewritten from scratch during Google Summer of Code 2012
35.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
35.13 + *
35.14 + * Previously implemented by:
35.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
35.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
35.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
35.18 + *
35.19 + * This program is free software; you can redistribute it and/or modify
35.20 + * it under the terms of the GNU General Public License as published by
35.21 + * the Free Software Foundation; either version 2 of the License, or
35.22 + * (at your option) any later version.
35.23 + *
35.24 + * This program is distributed in the hope that it will be useful,
35.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
35.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35.27 + * GNU General Public License for more details.
35.28 + *
35.29 + * You should have received a copy of the GNU General Public License
35.30 + * along with this program; if not, write to the Free Software
35.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
35.32 + */
35.33 +
35.34 +#include "libgaduw.h"
35.35 +
35.36 +#include <debug.h>
35.37 +
35.38 +#include "purplew.h"
35.39 +
35.40 +/*******************************************************************************
35.41 + * HTTP requests.
35.42 + ******************************************************************************/
35.43 +
35.44 +static void ggp_libgaduw_http_processing_cancel(PurpleConnection *gc,
35.45 + void *_req);
35.46 +
35.47 +static void ggp_libgaduw_http_handler(gpointer _req, gint fd,
35.48 + PurpleInputCondition cond);
35.49 +
35.50 +static void ggp_libgaduw_http_finish(ggp_libgaduw_http_req *req,
35.51 + gboolean success);
35.52 +
35.53 +/******************************************************************************/
35.54 +
35.55 +ggp_libgaduw_http_req * ggp_libgaduw_http_watch(PurpleConnection *gc,
35.56 + struct gg_http *h, ggp_libgaduw_http_cb cb,
35.57 + gpointer user_data, gboolean show_processing)
35.58 +{
35.59 + ggp_libgaduw_http_req *req;
35.60 + purple_debug_misc("gg", "ggp_libgaduw_http_watch(h=%x, "
35.61 + "show_processing=%d)\n", (unsigned int)h, show_processing);
35.62 +
35.63 + req = g_new(ggp_libgaduw_http_req, 1);
35.64 + req->user_data = user_data;
35.65 + req->cb = cb;
35.66 + req->cancelled = FALSE;
35.67 + req->h = h;
35.68 + req->processing = NULL;
35.69 + if (show_processing)
35.70 + req->processing = ggp_purplew_request_processing(gc, NULL,
35.71 + req, ggp_libgaduw_http_processing_cancel);
35.72 + req->inpa = ggp_purplew_http_input_add(h, ggp_libgaduw_http_handler,
35.73 + req);
35.74 +
35.75 + return req;
35.76 +}
35.77 +
35.78 +static void ggp_libgaduw_http_processing_cancel(PurpleConnection *gc,
35.79 + void *_req)
35.80 +{
35.81 + ggp_libgaduw_http_req *req = _req;
35.82 + req->processing = NULL;
35.83 + ggp_libgaduw_http_cancel(req);
35.84 +}
35.85 +
35.86 +static void ggp_libgaduw_http_handler(gpointer _req, gint fd,
35.87 + PurpleInputCondition cond)
35.88 +{
35.89 + ggp_libgaduw_http_req *req = _req;
35.90 +
35.91 + if (req->h->callback(req->h) == -1 || req->h->state == GG_STATE_ERROR)
35.92 + {
35.93 + purple_debug_error("gg", "ggp_libgaduw_http_handler: failed to "
35.94 + "make http request: %d\n", req->h->error);
35.95 + ggp_libgaduw_http_finish(req, FALSE);
35.96 + return;
35.97 + }
35.98 +
35.99 + //TODO: verbose mode
35.100 + //purple_debug_misc("gg", "ggp_libgaduw_http_handler: got fd update "
35.101 + // "[check=%d, state=%d]\n", req->h->check, req->h->state);
35.102 +
35.103 + if (req->h->state != GG_STATE_DONE)
35.104 + {
35.105 + purple_input_remove(req->inpa);
35.106 + req->inpa = ggp_purplew_http_input_add(req->h,
35.107 + ggp_libgaduw_http_handler, req);
35.108 + return;
35.109 + }
35.110 +
35.111 + if (!req->h->data || !req->h->body)
35.112 + {
35.113 + purple_debug_error("gg", "ggp_libgaduw_http_handler: got empty "
35.114 + "http response: %d\n", req->h->error);
35.115 + ggp_libgaduw_http_finish(req, FALSE);
35.116 + return;
35.117 + }
35.118 +
35.119 + ggp_libgaduw_http_finish(req, TRUE);
35.120 +}
35.121 +
35.122 +void ggp_libgaduw_http_cancel(ggp_libgaduw_http_req *req)
35.123 +{
35.124 + purple_debug_misc("gg", "ggp_libgaduw_http_cancel\n");
35.125 + req->cancelled = TRUE;
35.126 + gg_http_stop(req->h);
35.127 + ggp_libgaduw_http_finish(req, FALSE);
35.128 +}
35.129 +
35.130 +static void ggp_libgaduw_http_finish(ggp_libgaduw_http_req *req,
35.131 + gboolean success)
35.132 +{
35.133 + purple_debug_misc("gg", "ggp_libgaduw_http_finish(h=%x, processing=%x):"
35.134 + " success=%d\n", (unsigned int)req->h,
35.135 + (unsigned int)req->processing, success);
35.136 + if (req->processing)
35.137 + {
35.138 + ggp_purplew_request_processing_done(req->processing);
35.139 + req->processing = NULL;
35.140 + }
35.141 + purple_input_remove(req->inpa);
35.142 + req->cb(req->h, success, req->cancelled, req->user_data);
35.143 + req->h->destroy(req->h);
35.144 + g_free(req);
35.145 +}
36.1 new file mode 100644
36.2 --- /dev/null
36.3 +++ b/libpurple/protocols/gg/libgaduw.h
36.4 @@ -0,0 +1,58 @@
36.5 +/* purple
36.6 + *
36.7 + * Purple is the legal property of its developers, whose names are too numerous
36.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
36.9 + * source distribution.
36.10 + *
36.11 + * Rewritten from scratch during Google Summer of Code 2012
36.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
36.13 + *
36.14 + * Previously implemented by:
36.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
36.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
36.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
36.18 + *
36.19 + * This program is free software; you can redistribute it and/or modify
36.20 + * it under the terms of the GNU General Public License as published by
36.21 + * the Free Software Foundation; either version 2 of the License, or
36.22 + * (at your option) any later version.
36.23 + *
36.24 + * This program is distributed in the hope that it will be useful,
36.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
36.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36.27 + * GNU General Public License for more details.
36.28 + *
36.29 + * You should have received a copy of the GNU General Public License
36.30 + * along with this program; if not, write to the Free Software
36.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
36.32 + */
36.33 +
36.34 +#ifndef _GGP_LIBGADUW_H
36.35 +#define _GGP_LIBGADUW_H
36.36 +
36.37 +#include <internal.h>
36.38 +#include <libgadu.h>
36.39 +
36.40 +#include "purplew.h"
36.41 +
36.42 +typedef void (*ggp_libgaduw_http_cb)(struct gg_http *h, gboolean success,
36.43 + gboolean cancelled, gpointer user_data);
36.44 +
36.45 +typedef struct
36.46 +{
36.47 + gpointer user_data;
36.48 + ggp_libgaduw_http_cb cb;
36.49 +
36.50 + gboolean cancelled;
36.51 + struct gg_http *h;
36.52 + ggp_purplew_request_processing_handle *processing;
36.53 + guint inpa;
36.54 +} ggp_libgaduw_http_req;
36.55 +
36.56 +ggp_libgaduw_http_req * ggp_libgaduw_http_watch(PurpleConnection *gc,
36.57 + struct gg_http *h, ggp_libgaduw_http_cb cb, gpointer user_data,
36.58 + gboolean show_processing);
36.59 +void ggp_libgaduw_http_cancel(ggp_libgaduw_http_req *req);
36.60 +
36.61 +
36.62 +#endif /* _GGP_LIBGADUW_H */
37.1 new file mode 100644
37.2 --- /dev/null
37.3 +++ b/libpurple/protocols/gg/multilogon.c
37.4 @@ -0,0 +1,94 @@
37.5 +/* purple
37.6 + *
37.7 + * Purple is the legal property of its developers, whose names are too numerous
37.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
37.9 + * source distribution.
37.10 + *
37.11 + * Rewritten from scratch during Google Summer of Code 2012
37.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
37.13 + *
37.14 + * Previously implemented by:
37.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
37.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
37.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
37.18 + *
37.19 + * This program is free software; you can redistribute it and/or modify
37.20 + * it under the terms of the GNU General Public License as published by
37.21 + * the Free Software Foundation; either version 2 of the License, or
37.22 + * (at your option) any later version.
37.23 + *
37.24 + * This program is distributed in the hope that it will be useful,
37.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
37.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37.27 + * GNU General Public License for more details.
37.28 + *
37.29 + * You should have received a copy of the GNU General Public License
37.30 + * along with this program; if not, write to the Free Software
37.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
37.32 + */
37.33 +
37.34 +#include "multilogon.h"
37.35 +
37.36 +#include <debug.h>
37.37 +
37.38 +#include "gg.h"
37.39 +
37.40 +struct _ggp_multilogon_session_data
37.41 +{
37.42 + int session_count;
37.43 +};
37.44 +
37.45 +static inline ggp_multilogon_session_data *
37.46 +ggp_multilogon_get_mldata(PurpleConnection *gc);
37.47 +
37.48 +////////////
37.49 +
37.50 +static inline ggp_multilogon_session_data *
37.51 +ggp_multilogon_get_mldata(PurpleConnection *gc)
37.52 +{
37.53 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
37.54 + return accdata->multilogon_data;
37.55 +}
37.56 +
37.57 +void ggp_multilogon_setup(PurpleConnection *gc)
37.58 +{
37.59 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
37.60 +
37.61 + ggp_multilogon_session_data *mldata = g_new0(ggp_multilogon_session_data, 1);
37.62 + accdata->multilogon_data = mldata;
37.63 +}
37.64 +
37.65 +void ggp_multilogon_cleanup(PurpleConnection *gc)
37.66 +{
37.67 + ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc);
37.68 + g_free(mldata);
37.69 +}
37.70 +
37.71 +void ggp_multilogon_msg(PurpleConnection *gc, struct gg_event_msg *msg)
37.72 +{
37.73 + ggp_recv_message_handler(gc, msg, TRUE);
37.74 +}
37.75 +
37.76 +void ggp_multilogon_info(PurpleConnection *gc,
37.77 + struct gg_event_multilogon_info *info)
37.78 +{
37.79 + ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc);
37.80 + int i;
37.81 +
37.82 + purple_debug_info("gg", "ggp_multilogon_info: session list changed\n");
37.83 + for (i = 0; i < info->count; i++)
37.84 + {
37.85 + purple_debug_misc("gg", "ggp_multilogon_info: "
37.86 + "session [%s] logged in at %lu\n",
37.87 + info->sessions[i].name,
37.88 + info->sessions[i].logon_time);
37.89 + }
37.90 +
37.91 + mldata->session_count = info->count;
37.92 +}
37.93 +
37.94 +int ggp_multilogon_get_session_count(PurpleConnection *gc)
37.95 +{
37.96 + ggp_multilogon_session_data *mldata = ggp_multilogon_get_mldata(gc);
37.97 + return mldata->session_count;
37.98 +}
38.1 new file mode 100644
38.2 --- /dev/null
38.3 +++ b/libpurple/protocols/gg/multilogon.h
38.4 @@ -0,0 +1,47 @@
38.5 +/* purple
38.6 + *
38.7 + * Purple is the legal property of its developers, whose names are too numerous
38.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
38.9 + * source distribution.
38.10 + *
38.11 + * Rewritten from scratch during Google Summer of Code 2012
38.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
38.13 + *
38.14 + * Previously implemented by:
38.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
38.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
38.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
38.18 + *
38.19 + * This program is free software; you can redistribute it and/or modify
38.20 + * it under the terms of the GNU General Public License as published by
38.21 + * the Free Software Foundation; either version 2 of the License, or
38.22 + * (at your option) any later version.
38.23 + *
38.24 + * This program is distributed in the hope that it will be useful,
38.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
38.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38.27 + * GNU General Public License for more details.
38.28 + *
38.29 + * You should have received a copy of the GNU General Public License
38.30 + * along with this program; if not, write to the Free Software
38.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
38.32 + */
38.33 +
38.34 +#ifndef _GGP_MULTILOGON_H
38.35 +#define _GGP_MULTILOGON_H
38.36 +
38.37 +#include <internal.h>
38.38 +#include <libgadu.h>
38.39 +
38.40 +typedef struct _ggp_multilogon_session_data ggp_multilogon_session_data;
38.41 +
38.42 +void ggp_multilogon_setup(PurpleConnection *gc);
38.43 +void ggp_multilogon_cleanup(PurpleConnection *gc);
38.44 +
38.45 +void ggp_multilogon_msg(PurpleConnection *gc, struct gg_event_msg *msg);
38.46 +void ggp_multilogon_info(PurpleConnection *gc,
38.47 + struct gg_event_multilogon_info *msg);
38.48 +
38.49 +int ggp_multilogon_get_session_count(PurpleConnection *gc);
38.50 +
38.51 +#endif /* _GGP_MULTILOGON_H */
39.1 new file mode 100644
39.2 --- /dev/null
39.3 +++ b/libpurple/protocols/gg/oauth/oauth-parameter.c
39.4 @@ -0,0 +1,159 @@
39.5 +/* purple
39.6 + *
39.7 + * Purple is the legal property of its developers, whose names are too numerous
39.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
39.9 + * source distribution.
39.10 + *
39.11 + * Code adapted from libgadu (C) 2008 Wojtek Kaniewski <wojtekka@irc.pl>
39.12 + * (http://toxygen.net/libgadu/) during Google Summer of Code 2012
39.13 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
39.14 + *
39.15 + * This program is free software; you can redistribute it and/or modify
39.16 + * it under the terms of the GNU General Public License as published by
39.17 + * the Free Software Foundation; either version 2 of the License, or
39.18 + * (at your option) any later version.
39.19 + *
39.20 + * This program is distributed in the hope that it will be useful,
39.21 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
39.22 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39.23 + * GNU General Public License for more details.
39.24 + *
39.25 + * You should have received a copy of the GNU General Public License
39.26 + * along with this program; if not, write to the Free Software
39.27 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
39.28 + */
39.29 +
39.30 +#include "oauth-parameter.h"
39.31 +
39.32 +struct gg_oauth_parameter {
39.33 + char *key;
39.34 + char *value;
39.35 + struct gg_oauth_parameter *next;
39.36 +};
39.37 +
39.38 +int gg_oauth_parameter_set(gg_oauth_parameter_t **list, const char *key, const char *value)
39.39 +{
39.40 + gg_oauth_parameter_t *p, *new_p;
39.41 + char *new_key;
39.42 + char *new_value;
39.43 +
39.44 + if (value == NULL)
39.45 + return 0;
39.46 +
39.47 + if (list == NULL)
39.48 + return -1;
39.49 +
39.50 + new_key = strdup(key);
39.51 +
39.52 + if (new_key == NULL)
39.53 + return -1;
39.54 +
39.55 + new_value = strdup(value);
39.56 +
39.57 + if (new_value == NULL) {
39.58 + free(new_key);
39.59 + return -1;
39.60 + }
39.61 +
39.62 + new_p = malloc(sizeof(gg_oauth_parameter_t));
39.63 +
39.64 + if (new_p == NULL) {
39.65 + free(new_key);
39.66 + free(new_value);
39.67 + return -1;
39.68 + }
39.69 +
39.70 + memset(new_p, 0, sizeof(gg_oauth_parameter_t));
39.71 + new_p->key = new_key;
39.72 + new_p->value = new_value;
39.73 +
39.74 + if (*list != NULL) {
39.75 + p = *list;
39.76 +
39.77 + while (p != NULL && p->next != NULL)
39.78 + p = p->next;
39.79 +
39.80 + p->next = new_p;
39.81 + } else {
39.82 + *list = new_p;
39.83 + }
39.84 +
39.85 + return 0;
39.86 +}
39.87 +
39.88 +char *gg_oauth_parameter_join(gg_oauth_parameter_t *list, int header)
39.89 +{
39.90 + gg_oauth_parameter_t *p;
39.91 + int len = 0;
39.92 + char *res, *out;
39.93 +
39.94 + if (header)
39.95 + len += strlen("Authorization: OAuth ");
39.96 +
39.97 + for (p = list; p; p = p->next) {
39.98 + gchar *escaped;
39.99 + len += strlen(p->key);
39.100 +
39.101 + len += (header) ? 3 : 1;
39.102 +
39.103 + escaped = g_uri_escape_string(p->value, NULL, FALSE);
39.104 + len += strlen(escaped);
39.105 + g_free(escaped);
39.106 +
39.107 + if (p->next)
39.108 + len += 1;
39.109 + }
39.110 +
39.111 + res = malloc(len + 1);
39.112 +
39.113 + if (res == NULL)
39.114 + return NULL;
39.115 +
39.116 + out = res;
39.117 +
39.118 + *out = 0;
39.119 +
39.120 + if (header) {
39.121 + strcpy(out, "Authorization: OAuth ");
39.122 + out += strlen(out);
39.123 + }
39.124 +
39.125 + for (p = list; p; p = p->next) {
39.126 + gchar *escaped;
39.127 + strcpy(out, p->key);
39.128 + out += strlen(p->key);
39.129 +
39.130 + strcpy(out++, "=");
39.131 +
39.132 + if (header)
39.133 + strcpy(out++, "\"");
39.134 +
39.135 + escaped = g_uri_escape_string(p->value, NULL, FALSE);
39.136 + strcpy(out, escaped);
39.137 + out += strlen(escaped);
39.138 + g_free(escaped);
39.139 +
39.140 + if (header)
39.141 + strcpy(out++, "\"");
39.142 +
39.143 + if (p->next != NULL)
39.144 + strcpy(out++, (header) ? "," : "&");
39.145 + }
39.146 +
39.147 + return res;
39.148 +}
39.149 +
39.150 +void gg_oauth_parameter_free(gg_oauth_parameter_t *list)
39.151 +{
39.152 + while (list != NULL) {
39.153 + gg_oauth_parameter_t *next;
39.154 +
39.155 + next = list->next;
39.156 +
39.157 + free(list->key);
39.158 + free(list->value);
39.159 + free(list);
39.160 +
39.161 + list = next;
39.162 + }
39.163 +}
40.1 new file mode 100644
40.2 --- /dev/null
40.3 +++ b/libpurple/protocols/gg/oauth/oauth-parameter.h
40.4 @@ -0,0 +1,37 @@
40.5 +/* purple
40.6 + *
40.7 + * Purple is the legal property of its developers, whose names are too numerous
40.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
40.9 + * source distribution.
40.10 + *
40.11 + * Code adapted from libgadu (C) 2008 Wojtek Kaniewski <wojtekka@irc.pl>
40.12 + * (http://toxygen.net/libgadu/) during Google Summer of Code 2012
40.13 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
40.14 + *
40.15 + * This program is free software; you can redistribute it and/or modify
40.16 + * it under the terms of the GNU General Public License as published by
40.17 + * the Free Software Foundation; either version 2 of the License, or
40.18 + * (at your option) any later version.
40.19 + *
40.20 + * This program is distributed in the hope that it will be useful,
40.21 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
40.22 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40.23 + * GNU General Public License for more details.
40.24 + *
40.25 + * You should have received a copy of the GNU General Public License
40.26 + * along with this program; if not, write to the Free Software
40.27 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
40.28 + */
40.29 +
40.30 +#ifndef _GGP_OAUTH_PARAMETER_H
40.31 +#define _GGP_OAUTH_PARAMETER_H
40.32 +
40.33 +#include <internal.h>
40.34 +
40.35 +typedef struct gg_oauth_parameter gg_oauth_parameter_t;
40.36 +
40.37 +int gg_oauth_parameter_set(gg_oauth_parameter_t **list, const char *key, const char *value);
40.38 +char *gg_oauth_parameter_join(gg_oauth_parameter_t *list, int header);
40.39 +void gg_oauth_parameter_free(gg_oauth_parameter_t *list);
40.40 +
40.41 +#endif /* _GGP_OAUTH_PARAMETER_H */
41.1 new file mode 100644
41.2 --- /dev/null
41.3 +++ b/libpurple/protocols/gg/oauth/oauth-purple.c
41.4 @@ -0,0 +1,283 @@
41.5 +/* purple
41.6 + *
41.7 + * Purple is the legal property of its developers, whose names are too numerous
41.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
41.9 + * source distribution.
41.10 + *
41.11 + * Rewritten from scratch during Google Summer of Code 2012
41.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
41.13 + *
41.14 + * Previously implemented by:
41.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
41.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
41.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
41.18 + *
41.19 + * This program is free software; you can redistribute it and/or modify
41.20 + * it under the terms of the GNU General Public License as published by
41.21 + * the Free Software Foundation; either version 2 of the License, or
41.22 + * (at your option) any later version.
41.23 + *
41.24 + * This program is distributed in the hope that it will be useful,
41.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
41.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41.27 + * GNU General Public License for more details.
41.28 + *
41.29 + * You should have received a copy of the GNU General Public License
41.30 + * along with this program; if not, write to the Free Software
41.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
41.32 + */
41.33 +
41.34 +#include "oauth-purple.h"
41.35 +
41.36 +#include "oauth.h"
41.37 +#include "../utils.h"
41.38 +#include "../xml.h"
41.39 +
41.40 +#include <debug.h>
41.41 +
41.42 +#define GGP_OAUTH_RESPONSE_MAX 10240
41.43 +
41.44 +typedef struct
41.45 +{
41.46 + PurpleConnection *gc;
41.47 + ggp_oauth_request_cb callback;
41.48 + gpointer user_data;
41.49 + gchar *token;
41.50 + gchar *token_secret;
41.51 +
41.52 + gchar *sign_method, *sign_url;
41.53 +} ggp_oauth_data;
41.54 +
41.55 +static void ggp_oauth_data_free(ggp_oauth_data *data);
41.56 +
41.57 +static void ggp_oauth_request_token_got(PurpleUtilFetchUrlData *url_data,
41.58 + gpointer user_data, const gchar *url_text, gsize len,
41.59 + const gchar *error_message);
41.60 +
41.61 +static void ggp_oauth_authorization_done(PurpleUtilFetchUrlData *url_data,
41.62 + gpointer user_data, const gchar *url_text, gsize len,
41.63 + const gchar *error_message);
41.64 +
41.65 +static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data,
41.66 + gpointer user_data, const gchar *url_text, gsize len,
41.67 + const gchar *error_message);
41.68 +
41.69 +static void ggp_oauth_data_free(ggp_oauth_data *data)
41.70 +{
41.71 + g_free(data->token);
41.72 + g_free(data->token_secret);
41.73 + g_free(data->sign_method);
41.74 + g_free(data->sign_url);
41.75 + g_free(data);
41.76 +}
41.77 +
41.78 +void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback,
41.79 + gpointer user_data, const gchar *sign_method, const gchar *sign_url)
41.80 +{
41.81 + PurpleAccount *account = purple_connection_get_account(gc);
41.82 + char *auth;
41.83 + const char *method = "POST";
41.84 + const char *url = "http://api.gadu-gadu.pl/request_token";
41.85 + gchar *request;
41.86 + ggp_oauth_data *data;
41.87 +
41.88 + g_return_if_fail((method == NULL) == (url == NULL));
41.89 +
41.90 + purple_debug_misc("gg", "ggp_oauth_request: requesting token...\n");
41.91 +
41.92 + auth = gg_oauth_generate_header(method, url,
41.93 + purple_account_get_username(account),
41.94 + purple_account_get_password(account), NULL, NULL);
41.95 + request = g_strdup_printf(
41.96 + "POST /request_token HTTP/1.1\r\n"
41.97 + "Host: api.gadu-gadu.pl\r\n"
41.98 + "%s\r\n"
41.99 + "Content-Length: 0\r\n"
41.100 + "\r\n",
41.101 + auth);
41.102 + free(auth);
41.103 +
41.104 + data = g_new0(ggp_oauth_data, 1);
41.105 + data->gc = gc;
41.106 + data->callback = callback;
41.107 + data->user_data = user_data;
41.108 + data->sign_method = g_strdup(sign_method);
41.109 + data->sign_url = g_strdup(sign_url);
41.110 +
41.111 + purple_util_fetch_url_request(account, url, FALSE, NULL, TRUE, request,
41.112 + FALSE, GGP_OAUTH_RESPONSE_MAX, ggp_oauth_request_token_got,
41.113 + data);
41.114 +
41.115 + g_free(request);
41.116 +}
41.117 +
41.118 +static void ggp_oauth_request_token_got(PurpleUtilFetchUrlData *url_data,
41.119 + gpointer user_data, const gchar *url_text, gsize len,
41.120 + const gchar *error_message)
41.121 +{
41.122 + ggp_oauth_data *data = user_data;
41.123 + PurpleAccount *account;
41.124 + xmlnode *xml;
41.125 + gchar *request, *request_data;
41.126 + gboolean succ = TRUE;
41.127 +
41.128 + if (!PURPLE_CONNECTION_IS_VALID(data->gc))
41.129 + {
41.130 + ggp_oauth_data_free(data);
41.131 + return;
41.132 + }
41.133 + account = purple_connection_get_account(data->gc);
41.134 +
41.135 + if (len == 0)
41.136 + {
41.137 + purple_debug_error("gg", "ggp_oauth_request_token_got: "
41.138 + "requested token not received\n");
41.139 + ggp_oauth_data_free(data);
41.140 + return;
41.141 + }
41.142 +
41.143 + purple_debug_misc("gg", "ggp_oauth_request_token_got: "
41.144 + "got request token, doing authorization...\n");
41.145 +
41.146 + xml = xmlnode_from_str(url_text, -1);
41.147 + if (xml == NULL)
41.148 + {
41.149 + purple_debug_error("gg", "ggp_oauth_request_token_got: "
41.150 + "invalid xml\n");
41.151 + ggp_oauth_data_free(data);
41.152 + return;
41.153 + }
41.154 +
41.155 + succ &= ggp_xml_get_string(xml, "oauth_token", &data->token);
41.156 + succ &= ggp_xml_get_string(xml, "oauth_token_secret",
41.157 + &data->token_secret);
41.158 + xmlnode_free(xml);
41.159 + if (!succ)
41.160 + {
41.161 + purple_debug_error("gg", "ggp_oauth_request_token_got: "
41.162 + "invalid xml - token is not present\n");
41.163 + ggp_oauth_data_free(data);
41.164 + return;
41.165 + }
41.166 +
41.167 + request_data = g_strdup_printf(
41.168 + "callback_url=http://www.mojageneracja.pl&request_token=%s&"
41.169 + "uin=%s&password=%s", data->token,
41.170 + purple_account_get_username(account),
41.171 + purple_account_get_password(account));
41.172 + request = g_strdup_printf(
41.173 + "POST /authorize HTTP/1.1\r\n"
41.174 + "Host: login.gadu-gadu.pl\r\n"
41.175 + "Content-Length: %d\r\n"
41.176 + "Content-Type: application/x-www-form-urlencoded\r\n"
41.177 + "\r\n%s",
41.178 + strlen(request_data), request_data);
41.179 + g_free(request_data);
41.180 +
41.181 + // we don't need any results, nor 302 redirection
41.182 + purple_util_fetch_url_request(account,
41.183 + "https://login.gadu-gadu.pl/authorize", FALSE, NULL, TRUE,
41.184 + request, FALSE, 0,
41.185 + ggp_oauth_authorization_done, data);
41.186 +
41.187 + g_free(request);
41.188 +}
41.189 +
41.190 +static void ggp_oauth_authorization_done(PurpleUtilFetchUrlData *url_data,
41.191 + gpointer user_data, const gchar *url_text, gsize len,
41.192 + const gchar *error_message)
41.193 +{
41.194 + ggp_oauth_data *data = user_data;
41.195 + PurpleAccount *account;
41.196 + char *auth;
41.197 + const char *url = "http://api.gadu-gadu.pl/access_token";
41.198 + gchar *request;
41.199 +
41.200 + if (!PURPLE_CONNECTION_IS_VALID(data->gc))
41.201 + {
41.202 + ggp_oauth_data_free(data);
41.203 + return;
41.204 + }
41.205 + account = purple_connection_get_account(data->gc);
41.206 +
41.207 + purple_debug_misc("gg", "ggp_oauth_authorization_done: "
41.208 + "authorization done, requesting access token...\n");
41.209 +
41.210 + auth = gg_oauth_generate_header("POST", url,
41.211 + purple_account_get_username(account),
41.212 + purple_account_get_password(account),
41.213 + data->token, data->token_secret);
41.214 +
41.215 + request = g_strdup_printf(
41.216 + "POST /access_token HTTP/1.1\r\n"
41.217 + "Host: api.gadu-gadu.pl\r\n"
41.218 + "%s\r\n"
41.219 + "Content-Length: 0\r\n"
41.220 + "\r\n",
41.221 + auth);
41.222 + free(auth);
41.223 +
41.224 + purple_util_fetch_url_request(account, url, FALSE, NULL, TRUE, request,
41.225 + FALSE, GGP_OAUTH_RESPONSE_MAX, ggp_oauth_access_token_got,
41.226 + data);
41.227 +
41.228 + g_free(request);
41.229 +}
41.230 +
41.231 +static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data,
41.232 + gpointer user_data, const gchar *url_text, gsize len,
41.233 + const gchar *error_message)
41.234 +{
41.235 + ggp_oauth_data *data = user_data;
41.236 + gchar *token, *token_secret;
41.237 + xmlnode *xml;
41.238 + gboolean succ = TRUE;
41.239 +
41.240 + xml = xmlnode_from_str(url_text, -1);
41.241 + if (xml == NULL)
41.242 + {
41.243 + purple_debug_error("gg", "ggp_oauth_access_token_got: "
41.244 + "invalid xml\n");
41.245 + ggp_oauth_data_free(data);
41.246 + return;
41.247 + }
41.248 +
41.249 + succ &= ggp_xml_get_string(xml, "oauth_token", &token);
41.250 + succ &= ggp_xml_get_string(xml, "oauth_token_secret",
41.251 + &token_secret);
41.252 + xmlnode_free(xml);
41.253 + if (!succ || strlen(token) < 10)
41.254 + {
41.255 + purple_debug_error("gg", "ggp_oauth_access_token_got: "
41.256 + "invalid xml - token is not present\n");
41.257 + ggp_oauth_data_free(data);
41.258 + return;
41.259 + }
41.260 +
41.261 + if (data->sign_url)
41.262 + {
41.263 + PurpleAccount *account;
41.264 + gchar *auth;
41.265 +
41.266 + purple_debug_misc("gg", "ggp_oauth_access_token_got: "
41.267 + "got access token, returning signed url\n");
41.268 +
41.269 + account = purple_connection_get_account(data->gc);
41.270 + auth = gg_oauth_generate_header(
41.271 + data->sign_method, data->sign_url,
41.272 + purple_account_get_username(account),
41.273 + purple_account_get_password(account),
41.274 + token, token_secret);
41.275 + data->callback(data->gc, auth, data->user_data);
41.276 + }
41.277 + else
41.278 + {
41.279 + purple_debug_misc("gg", "ggp_oauth_access_token_got: "
41.280 + "got access token, returning it\n");
41.281 + data->callback(data->gc, token, data->user_data);
41.282 + }
41.283 +
41.284 + g_free(token);
41.285 + g_free(token_secret);
41.286 + ggp_oauth_data_free(data);
41.287 +}
42.1 new file mode 100644
42.2 --- /dev/null
42.3 +++ b/libpurple/protocols/gg/oauth/oauth-purple.h
42.4 @@ -0,0 +1,42 @@
42.5 +/* purple
42.6 + *
42.7 + * Purple is the legal property of its developers, whose names are too numerous
42.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
42.9 + * source distribution.
42.10 + *
42.11 + * Rewritten from scratch during Google Summer of Code 2012
42.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
42.13 + *
42.14 + * Previously implemented by:
42.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
42.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
42.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
42.18 + *
42.19 + * This program is free software; you can redistribute it and/or modify
42.20 + * it under the terms of the GNU General Public License as published by
42.21 + * the Free Software Foundation; either version 2 of the License, or
42.22 + * (at your option) any later version.
42.23 + *
42.24 + * This program is distributed in the hope that it will be useful,
42.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
42.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42.27 + * GNU General Public License for more details.
42.28 + *
42.29 + * You should have received a copy of the GNU General Public License
42.30 + * along with this program; if not, write to the Free Software
42.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
42.32 + */
42.33 +
42.34 +#ifndef _GGP_OAUTH_PURPLE_H
42.35 +#define _GGP_OAUTH_PURPLE_H
42.36 +
42.37 +#include <internal.h>
42.38 +#include <libgadu.h>
42.39 +
42.40 +typedef void (*ggp_oauth_request_cb)(PurpleConnection *gc, const gchar *token,
42.41 + gpointer user_data);
42.42 +
42.43 +void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback,
42.44 + gpointer user_data, const gchar *sign_method, const gchar *sign_url);
42.45 +
42.46 +#endif /* _GGP_OAUTH_PURPLE_H */
43.1 new file mode 100644
43.2 --- /dev/null
43.3 +++ b/libpurple/protocols/gg/oauth/oauth.c
43.4 @@ -0,0 +1,145 @@
43.5 +/* purple
43.6 + *
43.7 + * Purple is the legal property of its developers, whose names are too numerous
43.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
43.9 + * source distribution.
43.10 + *
43.11 + * Code adapted from libgadu (C) 2008 Wojtek Kaniewski <wojtekka@irc.pl>
43.12 + * (http://toxygen.net/libgadu/) during Google Summer of Code 2012
43.13 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
43.14 + *
43.15 + * This program is free software; you can redistribute it and/or modify
43.16 + * it under the terms of the GNU General Public License as published by
43.17 + * the Free Software Foundation; either version 2 of the License, or
43.18 + * (at your option) any later version.
43.19 + *
43.20 + * This program is distributed in the hope that it will be useful,
43.21 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
43.22 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43.23 + * GNU General Public License for more details.
43.24 + *
43.25 + * You should have received a copy of the GNU General Public License
43.26 + * along with this program; if not, write to the Free Software
43.27 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
43.28 + */
43.29 +
43.30 +#include "oauth.h"
43.31 +
43.32 +#include "oauth-parameter.h"
43.33 +#include <cipher.h>
43.34 +
43.35 +char *gg_oauth_static_nonce; /* dla unit testów */
43.36 +char *gg_oauth_static_timestamp; /* dla unit testów */
43.37 +
43.38 +static void gg_oauth_generate_nonce(char *buf, int len)
43.39 +{
43.40 + const char charset[] = "0123456789";
43.41 +
43.42 + if (buf == NULL || len < 1)
43.43 + return;
43.44 +
43.45 + while (len > 1) {
43.46 + *buf++ = charset[(unsigned) (((float) sizeof(charset) - 1.0) * rand() / (RAND_MAX + 1.0))];
43.47 + len--;
43.48 + }
43.49 +
43.50 + *buf = 0;
43.51 +}
43.52 +
43.53 +static gchar *gg_hmac_sha1(const char *key, const char *message)
43.54 +{
43.55 + PurpleCipherContext *context;
43.56 + guchar digest[20];
43.57 +
43.58 + context = purple_cipher_context_new_by_name("hmac", NULL);
43.59 + purple_cipher_context_set_option(context, "hash", "sha1");
43.60 + purple_cipher_context_set_key(context, (guchar *)key);
43.61 + purple_cipher_context_append(context, (guchar *)message, strlen(message));
43.62 + purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
43.63 + purple_cipher_context_destroy(context);
43.64 +
43.65 + return purple_base64_encode(digest, sizeof(digest));
43.66 +}
43.67 +
43.68 +static char *gg_oauth_generate_signature(const char *method, const char *url, const char *request, const char *consumer_secret, const char *token_secret)
43.69 +{
43.70 + char *text, *key, *res;
43.71 + gchar *url_e, *request_e, *consumer_secret_e, *token_secret_e;
43.72 +
43.73 + url_e = g_uri_escape_string(url, "?", FALSE);
43.74 + g_strdelimit(url_e, "?", '\0');
43.75 + request_e = g_uri_escape_string(request, NULL, FALSE);
43.76 + text = g_strdup_printf("%s&%s&%s", method, url_e, request_e);
43.77 + g_free(url_e);
43.78 + g_free(request_e);
43.79 +
43.80 + consumer_secret_e = g_uri_escape_string(consumer_secret, NULL, FALSE);
43.81 + token_secret_e = token_secret ? g_uri_escape_string(token_secret, NULL, FALSE) : NULL;
43.82 + key = g_strdup_printf("%s&%s", consumer_secret_e, token_secret ? token_secret_e : "");
43.83 + g_free(consumer_secret_e);
43.84 + g_free(token_secret_e);
43.85 +
43.86 + res = gg_hmac_sha1(key, text);
43.87 +
43.88 + free(key);
43.89 + free(text);
43.90 +
43.91 + return res;
43.92 +}
43.93 +
43.94 +char *gg_oauth_generate_header(const char *method, const char *url, const const char *consumer_key, const char *consumer_secret, const char *token, const char *token_secret)
43.95 +{
43.96 + char *request, *signature, *res;
43.97 + char nonce[80], timestamp[16];
43.98 + gg_oauth_parameter_t *params = NULL;
43.99 +
43.100 + if (gg_oauth_static_nonce == NULL)
43.101 + gg_oauth_generate_nonce(nonce, sizeof(nonce));
43.102 + else {
43.103 + strncpy(nonce, gg_oauth_static_nonce, sizeof(nonce) - 1);
43.104 + nonce[sizeof(nonce) - 1] = 0;
43.105 + }
43.106 +
43.107 + if (gg_oauth_static_timestamp == NULL)
43.108 + snprintf(timestamp, sizeof(timestamp), "%ld", time(NULL));
43.109 + else {
43.110 + strncpy(timestamp, gg_oauth_static_timestamp, sizeof(timestamp) - 1);
43.111 + timestamp[sizeof(timestamp) - 1] = 0;
43.112 + }
43.113 +
43.114 + gg_oauth_parameter_set(¶ms, "oauth_consumer_key", consumer_key);
43.115 + gg_oauth_parameter_set(¶ms, "oauth_nonce", nonce);
43.116 + gg_oauth_parameter_set(¶ms, "oauth_signature_method", "HMAC-SHA1");
43.117 + gg_oauth_parameter_set(¶ms, "oauth_timestamp", timestamp);
43.118 + gg_oauth_parameter_set(¶ms, "oauth_token", token);
43.119 + gg_oauth_parameter_set(¶ms, "oauth_version", "1.0");
43.120 +
43.121 + request = gg_oauth_parameter_join(params, 0);
43.122 +
43.123 + signature = gg_oauth_generate_signature(method, url, request, consumer_secret, token_secret);
43.124 +
43.125 + free(request);
43.126 +
43.127 + gg_oauth_parameter_free(params);
43.128 + params = NULL;
43.129 +
43.130 + if (signature == NULL)
43.131 + return NULL;
43.132 +
43.133 + gg_oauth_parameter_set(¶ms, "oauth_version", "1.0");
43.134 + gg_oauth_parameter_set(¶ms, "oauth_nonce", nonce);
43.135 + gg_oauth_parameter_set(¶ms, "oauth_timestamp", timestamp);
43.136 + gg_oauth_parameter_set(¶ms, "oauth_consumer_key", consumer_key);
43.137 + gg_oauth_parameter_set(¶ms, "oauth_token", token);
43.138 + gg_oauth_parameter_set(¶ms, "oauth_signature_method", "HMAC-SHA1");
43.139 + gg_oauth_parameter_set(¶ms, "oauth_signature", signature);
43.140 +
43.141 + free(signature);
43.142 +
43.143 + res = gg_oauth_parameter_join(params, 1);
43.144 +
43.145 + gg_oauth_parameter_free(params);
43.146 +
43.147 + return res;
43.148 +}
43.149 +
44.1 new file mode 100644
44.2 --- /dev/null
44.3 +++ b/libpurple/protocols/gg/oauth/oauth.h
44.4 @@ -0,0 +1,34 @@
44.5 +/* purple
44.6 + *
44.7 + * Purple is the legal property of its developers, whose names are too numerous
44.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
44.9 + * source distribution.
44.10 + *
44.11 + * Code adapted from libgadu (C) 2008 Wojtek Kaniewski <wojtekka@irc.pl>
44.12 + * (http://toxygen.net/libgadu/) during Google Summer of Code 2012
44.13 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
44.14 + *
44.15 + * This program is free software; you can redistribute it and/or modify
44.16 + * it under the terms of the GNU General Public License as published by
44.17 + * the Free Software Foundation; either version 2 of the License, or
44.18 + * (at your option) any later version.
44.19 + *
44.20 + * This program is distributed in the hope that it will be useful,
44.21 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
44.22 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44.23 + * GNU General Public License for more details.
44.24 + *
44.25 + * You should have received a copy of the GNU General Public License
44.26 + * along with this program; if not, write to the Free Software
44.27 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
44.28 + */
44.29 +
44.30 +#ifndef _GGP_OAUTH_H
44.31 +#define _GGP_OAUTH_H
44.32 +
44.33 +#include <internal.h>
44.34 +#include <libgadu.h>
44.35 +
44.36 +char *gg_oauth_generate_header(const char *method, const char *url, const const char *consumer_key, const char *consumer_secret, const char *token, const char *token_secret);
44.37 +
44.38 +#endif /* _GGP_OAUTH_H */
45.1 new file mode 100644
45.2 --- /dev/null
45.3 +++ b/libpurple/protocols/gg/pubdir-prpl.c
45.4 @@ -0,0 +1,993 @@
45.5 +/* purple
45.6 + *
45.7 + * Purple is the legal property of its developers, whose names are too numerous
45.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
45.9 + * source distribution.
45.10 + *
45.11 + * Rewritten from scratch during Google Summer of Code 2012
45.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
45.13 + *
45.14 + * Previously implemented by:
45.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
45.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
45.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
45.18 + *
45.19 + * This program is free software; you can redistribute it and/or modify
45.20 + * it under the terms of the GNU General Public License as published by
45.21 + * the Free Software Foundation; either version 2 of the License, or
45.22 + * (at your option) any later version.
45.23 + *
45.24 + * This program is distributed in the hope that it will be useful,
45.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
45.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45.27 + * GNU General Public License for more details.
45.28 + *
45.29 + * You should have received a copy of the GNU General Public License
45.30 + * along with this program; if not, write to the Free Software
45.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
45.32 + */
45.33 +
45.34 +#include "pubdir-prpl.h"
45.35 +
45.36 +#include <debug.h>
45.37 +#include <request.h>
45.38 +
45.39 +#include "oauth/oauth-purple.h"
45.40 +#include "xml.h"
45.41 +#include "utils.h"
45.42 +#include "status.h"
45.43 +
45.44 +typedef struct
45.45 +{
45.46 + PurpleConnection *gc;
45.47 + ggp_pubdir_request_cb cb;
45.48 + void *user_data;
45.49 + enum
45.50 + {
45.51 + GGP_PUBDIR_REQUEST_TYPE_INFO,
45.52 + GGP_PUBDIR_REQUEST_TYPE_SEARCH,
45.53 + } type;
45.54 + union
45.55 + {
45.56 + struct
45.57 + {
45.58 + uin_t uin;
45.59 + } user_info;
45.60 + ggp_pubdir_search_form *search_form;
45.61 + } params;
45.62 +} ggp_pubdir_request;
45.63 +
45.64 +void ggp_pubdir_request_free(ggp_pubdir_request *request);
45.65 +void ggp_pubdir_record_free(ggp_pubdir_record *records, int count);
45.66 +
45.67 +static void ggp_pubdir_get_info_got_token(PurpleConnection *gc,
45.68 + const gchar *token, gpointer _request);
45.69 +static void ggp_pubdir_got_data(PurpleUtilFetchUrlData *url_data,
45.70 + gpointer user_data, const gchar *url_text, gsize len,
45.71 + const gchar *error_message);
45.72 +
45.73 +static void ggp_pubdir_get_info_prpl_got(PurpleConnection *gc,
45.74 + int records_count, const ggp_pubdir_record *records, int next_offset,
45.75 + void *_uin);
45.76 +
45.77 +static void ggp_pubdir_request_buddy_alias_got(PurpleConnection *gc,
45.78 + int records_count, const ggp_pubdir_record *records, int next_offset,
45.79 + void *_uin);
45.80 +
45.81 +// Searching for buddies.
45.82 +
45.83 +#define GGP_PUBDIR_SEARCH_TITLE _("Gadu-Gadu Public Directory")
45.84 +#define GGP_PUBDIR_SEARCH_PER_PAGE 20
45.85 +
45.86 +struct _ggp_pubdir_search_form
45.87 +{
45.88 + gchar *nick, *city;
45.89 + ggp_pubdir_gender gender;
45.90 + int offset;
45.91 + int limit;
45.92 +
45.93 + void *display_handle;
45.94 +};
45.95 +
45.96 +void ggp_pubdir_search_form_free(ggp_pubdir_search_form *form);
45.97 +ggp_pubdir_search_form * ggp_pubdir_search_form_clone(
45.98 + const ggp_pubdir_search_form *form);
45.99 +
45.100 +static void ggp_pubdir_search_request(PurpleConnection *gc,
45.101 + PurpleRequestFields *fields);
45.102 +static gchar * ggp_pubdir_search_make_query(const ggp_pubdir_search_form *form);
45.103 +static void ggp_pubdir_search_execute(PurpleConnection *gc,
45.104 + const ggp_pubdir_search_form *form,
45.105 + ggp_pubdir_request_cb cb, void *user_data);
45.106 +static void ggp_pubdir_search_got_token(PurpleConnection *gc,
45.107 + const gchar *token, gpointer _request);
45.108 +static void ggp_pubdir_search_results_display(PurpleConnection *gc,
45.109 + int records_count, const ggp_pubdir_record *records, int next_offset,
45.110 + void *user_data);
45.111 +static void ggp_pubdir_search_results_close(gpointer _form);
45.112 +static void ggp_pubdir_search_results_next(PurpleConnection *gc, GList *row,
45.113 + gpointer _form);
45.114 +static void ggp_pubdir_search_results_add(PurpleConnection *gc, GList *row,
45.115 + gpointer _form);
45.116 +static void ggp_pubdir_search_results_im(PurpleConnection *gc, GList *row,
45.117 + gpointer _form);
45.118 +static void ggp_pubdir_search_results_info(PurpleConnection *gc, GList *row,
45.119 + gpointer _form);
45.120 +static void ggp_pubdir_search_results_new(PurpleConnection *gc, GList *row,
45.121 + gpointer _form);
45.122 +
45.123 +// Own profile.
45.124 +
45.125 +static void ggp_pubdir_set_info_dialog(PurpleConnection *gc, int records_count,
45.126 + const ggp_pubdir_record *records, int next_offset, void *user_data);
45.127 +static void ggp_pubdir_set_info_request(PurpleConnection *gc,
45.128 + PurpleRequestFields *fields);
45.129 +static void ggp_pubdir_set_info_got_token(PurpleConnection *gc,
45.130 + const gchar *token, gpointer _record);
45.131 +static void ggp_pubdir_set_info_got_response(PurpleUtilFetchUrlData *url_data,
45.132 + gpointer user_data, const gchar *url_text, gsize len,
45.133 + const gchar *error_message);
45.134 +
45.135 +/******************************************************************************/
45.136 +
45.137 +static const gchar *ggp_pubdir_provinces[] =
45.138 +{
45.139 + "dolnośląskie",
45.140 + "kujawsko-pomorskie",
45.141 + "lubelskie",
45.142 + "lubuskie",
45.143 + "łódzkie",
45.144 + "małopolskie",
45.145 + "mazowieckie",
45.146 + "opolskie",
45.147 + "podkarpackie",
45.148 + "podlaskie",
45.149 + "pomorskie",
45.150 + "śląskie",
45.151 + "świętokrzyskie",
45.152 + "warmińsko-mazurskie",
45.153 + "wielkopolskie",
45.154 + "zachodniopomorskie",
45.155 +};
45.156 +
45.157 +static int ggp_pubdir_provinces_count = sizeof(ggp_pubdir_provinces)/sizeof(gchar*);
45.158 +
45.159 +/******************************************************************************/
45.160 +
45.161 +void ggp_pubdir_record_free(ggp_pubdir_record *records, int count)
45.162 +{
45.163 + int i;
45.164 + for (i = 0; i < count; i++)
45.165 + {
45.166 + g_free(records[i].label);
45.167 + g_free(records[i].nickname);
45.168 + g_free(records[i].first_name);
45.169 + g_free(records[i].last_name);
45.170 + g_free(records[i].city);
45.171 + }
45.172 + g_free(records);
45.173 +}
45.174 +
45.175 +void ggp_pubdir_request_free(ggp_pubdir_request *request)
45.176 +{
45.177 + if (request->type == GGP_PUBDIR_REQUEST_TYPE_SEARCH)
45.178 + ggp_pubdir_search_form_free(request->params.search_form);
45.179 + g_free(request);
45.180 +}
45.181 +
45.182 +void ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin,
45.183 + ggp_pubdir_request_cb cb, void *user_data)
45.184 +{
45.185 + ggp_pubdir_request *request = g_new0(ggp_pubdir_request, 1);
45.186 + gchar *url;
45.187 +
45.188 + request->type = GGP_PUBDIR_REQUEST_TYPE_INFO;
45.189 + request->gc = gc;
45.190 + request->cb = cb;
45.191 + request->user_data = user_data;
45.192 + request->params.user_info.uin = uin;
45.193 +
45.194 + url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u", uin);
45.195 + ggp_oauth_request(gc, ggp_pubdir_get_info_got_token, request,
45.196 + "GET", url);
45.197 + g_free(url);
45.198 +}
45.199 +
45.200 +static void ggp_pubdir_get_info_got_token(PurpleConnection *gc,
45.201 + const gchar *token, gpointer _request)
45.202 +{
45.203 + gchar *http_request;
45.204 + ggp_pubdir_request *request = _request;
45.205 + gchar *url;
45.206 +
45.207 + if (!token || !PURPLE_CONNECTION_IS_VALID(gc))
45.208 + {
45.209 + request->cb(gc, -1, NULL, 0, request->user_data);
45.210 + ggp_pubdir_request_free(request);
45.211 + return;
45.212 + }
45.213 +
45.214 + url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u",
45.215 + request->params.user_info.uin);
45.216 + http_request = g_strdup_printf(
45.217 + "GET /users/%u HTTP/1.1\r\n"
45.218 + "Host: api.gadu-gadu.pl\r\n"
45.219 + "%s\r\n"
45.220 + "\r\n",
45.221 + request->params.user_info.uin,
45.222 + token);
45.223 +
45.224 + purple_util_fetch_url_request(purple_connection_get_account(gc), url,
45.225 + FALSE, NULL, TRUE, http_request, FALSE, -1,
45.226 + ggp_pubdir_got_data, request);
45.227 +
45.228 + g_free(url);
45.229 + g_free(http_request);
45.230 +}
45.231 +
45.232 +static void ggp_pubdir_got_data(PurpleUtilFetchUrlData *url_data,
45.233 + gpointer _request, const gchar *url_text, gsize len,
45.234 + const gchar *error_message)
45.235 +{
45.236 + ggp_pubdir_request *request = _request;
45.237 + PurpleConnection *gc = request->gc;
45.238 + gboolean succ = TRUE;
45.239 + xmlnode *xml;
45.240 + unsigned int status, next_offset;
45.241 + int record_count, i;
45.242 + ggp_pubdir_record *records;
45.243 +
45.244 + //TODO: verbose
45.245 + //purple_debug_misc("gg", "ggp_pubdir_got_data: [%s]\n", url_text);
45.246 +
45.247 + xml = xmlnode_from_str(url_text, -1);
45.248 + if (xml == NULL)
45.249 + {
45.250 + purple_debug_error("gg", "ggp_pubdir_got_data: "
45.251 + "invalid xml\n");
45.252 + request->cb(gc, -1, NULL, 0, request->user_data);
45.253 + ggp_pubdir_request_free(request);
45.254 + return;
45.255 + }
45.256 +
45.257 + succ &= ggp_xml_get_uint(xml, "status", &status);
45.258 + if (!ggp_xml_get_uint(xml, "nextOffset", &next_offset))
45.259 + next_offset = 0;
45.260 + xml = xmlnode_get_child(xml, "users");
45.261 + if (!succ || status != 0 || !xml)
45.262 + {
45.263 + purple_debug_error("gg", "ggp_pubdir_got_data: "
45.264 + "invalid reply\n");
45.265 + request->cb(gc, -1, NULL, 0, request->user_data);
45.266 + ggp_pubdir_request_free(request);
45.267 + return;
45.268 + }
45.269 +
45.270 + record_count = ggp_xml_child_count(xml, "user");
45.271 + records = g_new0(ggp_pubdir_record, record_count);
45.272 +
45.273 + xml = xmlnode_get_child(xml, "user");
45.274 + i = 0;
45.275 + while (xml)
45.276 + {
45.277 + ggp_pubdir_record *record = &records[i++];
45.278 + gchar *city = NULL, *birth_s = NULL;
45.279 + unsigned int gender = 0;
45.280 + const gchar *uin_s;
45.281 +
45.282 + g_assert(i <= record_count);
45.283 +
45.284 + record->uin = ggp_str_to_uin(xmlnode_get_attrib(xml, "uin"));
45.285 + if (record->uin == 0)
45.286 + ggp_xml_get_uint(xml, "uin", &record->uin);
45.287 + if (record->uin == 0)
45.288 + purple_debug_error("gg", "ggp_pubdir_got_data:"
45.289 + " invalid uin\n");
45.290 + uin_s = ggp_uin_to_str(record->uin);
45.291 +
45.292 + ggp_xml_get_string(xml, "label", &record->label);
45.293 + ggp_xml_get_string(xml, "nick", &record->nickname);
45.294 + ggp_xml_get_string(xml, "name", &record->first_name);
45.295 + ggp_xml_get_string(xml, "surname", &record->last_name);
45.296 + ggp_xml_get_string(xml, "city", &city);
45.297 + ggp_xml_get_string(xml, "birth", &birth_s);
45.298 + ggp_xml_get_uint(xml, "gender", &gender);
45.299 + ggp_xml_get_uint(xml, "age", &record->age);
45.300 + ggp_xml_get_uint(xml, "province", &record->province);
45.301 +
45.302 + record->label = ggp_free_if_equal(record->label, uin_s);
45.303 + record->label = ggp_free_if_equal(record->label, "");
45.304 + record->nickname = ggp_free_if_equal(record->nickname, uin_s);
45.305 + record->nickname = ggp_free_if_equal(record->nickname, "");
45.306 + record->first_name = ggp_free_if_equal(record->first_name, "");
45.307 + record->last_name = ggp_free_if_equal(record->last_name, "");
45.308 +
45.309 + if (record->label) {}
45.310 + else if (record->nickname)
45.311 + record->label = g_strdup(record->nickname);
45.312 + else if (record->first_name && record->last_name)
45.313 + record->label = g_strdup_printf("%s %s",
45.314 + record->first_name, record->last_name);
45.315 + else if (record->first_name)
45.316 + record->label = g_strdup(record->first_name);
45.317 + else if (record->last_name)
45.318 + record->label = g_strdup(record->last_name);
45.319 + if (record->label)
45.320 + g_strstrip(record->label);
45.321 + if (record->nickname)
45.322 + g_strstrip(record->nickname);
45.323 +
45.324 + if (gender == 1)
45.325 + record->gender = GGP_PUBDIR_GENDER_FEMALE;
45.326 + else if (gender == 2)
45.327 + record->gender = GGP_PUBDIR_GENDER_MALE;
45.328 + else
45.329 + record->gender = GGP_PUBDIR_GENDER_UNSPECIFIED;
45.330 +
45.331 + if (city && city[0] != '\0')
45.332 + record->city = g_strdup(city);
45.333 + if (record->city)
45.334 + g_strstrip(record->city);
45.335 + if (!record->city)
45.336 + {
45.337 + g_free(record->city);
45.338 + record->city = NULL;
45.339 + }
45.340 +
45.341 + record->birth = ggp_date_from_iso8601(birth_s);
45.342 + //TODO: calculate age from birth
45.343 +
45.344 + //TODO: verbose
45.345 + purple_debug_misc("gg", "ggp_pubdir_got_data: [uin:%d] "
45.346 + "[label:%s] [nick:%s] [first name:%s] [last name:%s] "
45.347 + "[city:%s] [gender:%d] [age:%d] [birth:%lu]\n",
45.348 + record->uin, record->label, record->nickname,
45.349 + record->first_name, record->last_name, record->city,
45.350 + record->gender, record->age, record->birth);
45.351 +
45.352 + g_free(city);
45.353 +
45.354 + xml = xmlnode_get_next_twin(xml);
45.355 + }
45.356 +
45.357 + request->cb(gc, record_count, records, next_offset, request->user_data);
45.358 +
45.359 + ggp_pubdir_request_free(request);
45.360 + ggp_pubdir_record_free(records, record_count);
45.361 +}
45.362 +
45.363 +void ggp_pubdir_get_info_prpl(PurpleConnection *gc, const char *name)
45.364 +{
45.365 + uin_t uin = ggp_str_to_uin(name);
45.366 +
45.367 + purple_debug_info("gg", "ggp_pubdir_get_info_prpl: %u\n", uin);
45.368 +
45.369 + ggp_pubdir_get_info(gc, uin, ggp_pubdir_get_info_prpl_got, (void*)uin);
45.370 +}
45.371 +
45.372 +static void ggp_pubdir_get_info_prpl_got(PurpleConnection *gc,
45.373 + int records_count, const ggp_pubdir_record *records, int next_offset,
45.374 + void *_uin)
45.375 +{
45.376 + uin_t uin = (uin_t)_uin;
45.377 + PurpleNotifyUserInfo *info = purple_notify_user_info_new();
45.378 + const ggp_pubdir_record *record = &records[0];
45.379 + PurpleBuddy *buddy;
45.380 +
45.381 + if (records_count < 1)
45.382 + {
45.383 + purple_debug_error("gg", "ggp_pubdir_get_info_prpl_got: "
45.384 + "couldn't get info for %u\n", uin);
45.385 + purple_notify_user_info_add_pair_plaintext(info, NULL,
45.386 + _("Cannot get user information"));
45.387 + purple_notify_userinfo(gc, ggp_uin_to_str(uin), info,
45.388 + NULL, NULL);
45.389 + purple_notify_user_info_destroy(info);
45.390 + return;
45.391 + }
45.392 +
45.393 + purple_debug_info("gg", "ggp_pubdir_get_info_prpl_got: %u\n", uin);
45.394 + g_assert(uin == record->uin);
45.395 + g_assert(records_count == 1);
45.396 +
45.397 + buddy = purple_find_buddy(purple_connection_get_account(gc),
45.398 + ggp_uin_to_str(uin));
45.399 + if (buddy)
45.400 + {
45.401 + const char *alias;
45.402 + PurpleStatus *status;
45.403 + gchar *status_message;
45.404 +
45.405 + alias = purple_buddy_get_alias_only(buddy);
45.406 + if (alias)
45.407 + purple_notify_user_info_add_pair_plaintext(info,
45.408 + _("Alias"), alias);
45.409 +
45.410 + status = purple_presence_get_active_status(
45.411 + purple_buddy_get_presence(buddy));
45.412 + ggp_status_from_purplestatus(status, &status_message);
45.413 + purple_notify_user_info_add_pair_plaintext(info, _("Status"),
45.414 + purple_status_get_name(status));
45.415 + if (status_message)
45.416 + purple_notify_user_info_add_pair_plaintext(info,
45.417 + _("Message"), status_message);
45.418 + }
45.419 +
45.420 + if (record->nickname)
45.421 + purple_notify_user_info_add_pair_plaintext(info,
45.422 + _("Nickname"), record->nickname);
45.423 + if (record->first_name)
45.424 + purple_notify_user_info_add_pair_plaintext(info,
45.425 + _("First name"), record->first_name);
45.426 + if (record->last_name)
45.427 + purple_notify_user_info_add_pair_plaintext(info,
45.428 + _("Last name"), record->last_name);
45.429 + if (record->gender != GGP_PUBDIR_GENDER_UNSPECIFIED)
45.430 + purple_notify_user_info_add_pair_plaintext(info, _("Gender"),
45.431 + record->gender == GGP_PUBDIR_GENDER_FEMALE ?
45.432 + _("Female") : _("Male"));
45.433 + if (record->city)
45.434 + purple_notify_user_info_add_pair_plaintext(info, _("City"),
45.435 + record->city);
45.436 + if (record->birth)
45.437 + purple_notify_user_info_add_pair_plaintext(info, _("Birthday"),
45.438 + ggp_date_strftime("%Y-%m-%d", record->birth));
45.439 + else if (record->age)
45.440 + {
45.441 + gchar *age_s = g_strdup_printf("%d", record->age);
45.442 + purple_notify_user_info_add_pair_plaintext(info, _("Age"),
45.443 + age_s);
45.444 + g_free(age_s);
45.445 + }
45.446 +
45.447 + purple_notify_userinfo(gc, ggp_uin_to_str(uin), info, NULL, NULL);
45.448 + purple_notify_user_info_destroy(info);
45.449 +}
45.450 +
45.451 +void ggp_pubdir_request_buddy_alias(PurpleConnection *gc, PurpleBuddy *buddy)
45.452 +{
45.453 + uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy));
45.454 +
45.455 + purple_debug_info("gg", "ggp_pubdir_request_buddy_alias: %u\n", uin);
45.456 +
45.457 + ggp_pubdir_get_info(gc, uin, ggp_pubdir_request_buddy_alias_got, (void*)uin);
45.458 +}
45.459 +
45.460 +static void ggp_pubdir_request_buddy_alias_got(PurpleConnection *gc,
45.461 + int records_count, const ggp_pubdir_record *records, int next_offset,
45.462 + void *_uin)
45.463 +{
45.464 + uin_t uin = (uin_t)_uin;
45.465 + const gchar *alias;
45.466 +
45.467 + if (records_count < 0)
45.468 + {
45.469 + purple_debug_error("gg", "ggp_pubdir_request_buddy_alias_got: "
45.470 + "couldn't get info for %u\n", uin);
45.471 + return;
45.472 + }
45.473 + g_assert(uin == records[0].uin);
45.474 +
45.475 + alias = records[0].label;
45.476 + if (!alias)
45.477 + {
45.478 + purple_debug_info("gg", "ggp_pubdir_request_buddy_alias_got: "
45.479 + "public alias for %u is not available\n", uin);
45.480 + return;
45.481 + }
45.482 +
45.483 + purple_debug_info("gg", "ggp_pubdir_request_buddy_alias_got: "
45.484 + "public alias for %u is \"%s\"\n", uin, alias);
45.485 +
45.486 + serv_got_alias(gc, ggp_uin_to_str(uin), alias);
45.487 +}
45.488 +
45.489 +/*******************************************************************************
45.490 + * Searching for buddies.
45.491 + ******************************************************************************/
45.492 +
45.493 +void ggp_pubdir_search_form_free(ggp_pubdir_search_form *form)
45.494 +{
45.495 + g_free(form->nick);
45.496 + g_free(form->city);
45.497 + g_free(form);
45.498 +}
45.499 +
45.500 +ggp_pubdir_search_form * ggp_pubdir_search_form_clone(
45.501 + const ggp_pubdir_search_form *form)
45.502 +{
45.503 + ggp_pubdir_search_form *dup = g_new(ggp_pubdir_search_form, 1);
45.504 +
45.505 + dup->nick = g_strdup(form->nick);
45.506 + dup->city = g_strdup(form->city);
45.507 + dup->gender = form->gender;
45.508 + dup->offset = form->offset;
45.509 + dup->limit = form->limit;
45.510 +
45.511 + dup->display_handle = form->display_handle;
45.512 +
45.513 + return dup;
45.514 +}
45.515 +
45.516 +void ggp_pubdir_search(PurpleConnection *gc,
45.517 + const ggp_pubdir_search_form *form)
45.518 +{
45.519 + PurpleRequestFields *fields;
45.520 + PurpleRequestFieldGroup *group;
45.521 + PurpleRequestField *field;
45.522 + int default_gender;
45.523 +
45.524 + purple_debug_info("gg", "ggp_pubdir_search\n");
45.525 +
45.526 + fields = purple_request_fields_new();
45.527 + group = purple_request_field_group_new(NULL);
45.528 + purple_request_fields_add_group(fields, group);
45.529 +
45.530 + field = purple_request_field_string_new("name", _("Name"),
45.531 + form ? form->nick : NULL, FALSE);
45.532 + purple_request_field_group_add_field(group, field);
45.533 +
45.534 + field = purple_request_field_string_new("city", _("City"),
45.535 + form ? form->city : NULL, FALSE);
45.536 + purple_request_field_group_add_field(group, field);
45.537 +
45.538 + default_gender = 0;
45.539 + if (form && form->gender == GGP_PUBDIR_GENDER_MALE)
45.540 + default_gender = 1;
45.541 + else if (form && form->gender == GGP_PUBDIR_GENDER_FEMALE)
45.542 + default_gender = 2;
45.543 +
45.544 + field = purple_request_field_choice_new("gender", _("Gender"),
45.545 + default_gender);
45.546 + purple_request_field_choice_add(field, _("Male or female"));
45.547 + purple_request_field_choice_add(field, _("Male"));
45.548 + purple_request_field_choice_add(field, _("Female"));
45.549 + purple_request_field_group_add_field(group, field);
45.550 +
45.551 + purple_request_fields(gc, _("Find buddies"), _("Find buddies"),
45.552 + _("Please, enter your search criteria below"), fields,
45.553 + _("OK"), G_CALLBACK(ggp_pubdir_search_request),
45.554 + _("Cancel"), NULL,
45.555 + purple_connection_get_account(gc), NULL, NULL, gc);
45.556 +}
45.557 +
45.558 +static void ggp_pubdir_search_request(PurpleConnection *gc,
45.559 + PurpleRequestFields *fields)
45.560 +{
45.561 + ggp_pubdir_search_form *form = g_new0(ggp_pubdir_search_form, 1);
45.562 + int gender;
45.563 +
45.564 + purple_debug_info("gg", "ggp_pubdir_search_request\n");
45.565 +
45.566 + form->nick = g_strdup(purple_request_fields_get_string(fields, "name"));
45.567 + form->city = g_strdup(purple_request_fields_get_string(fields, "city"));
45.568 + gender = purple_request_fields_get_choice(fields, "gender");
45.569 + if (gender == 1)
45.570 + form->gender = GGP_PUBDIR_GENDER_MALE;
45.571 + else if (gender == 2)
45.572 + form->gender = GGP_PUBDIR_GENDER_FEMALE;
45.573 +
45.574 + form->offset = 0;
45.575 + form->limit = GGP_PUBDIR_SEARCH_PER_PAGE;
45.576 +
45.577 + ggp_pubdir_search_execute(gc, form, ggp_pubdir_search_results_display,
45.578 + form);
45.579 +}
45.580 +
45.581 +static gchar * ggp_pubdir_search_make_query(const ggp_pubdir_search_form *form)
45.582 +{
45.583 + gchar *nick, *city, *gender;
45.584 + gchar *query;
45.585 +
45.586 + if (form->nick && form->nick[0] != '\0')
45.587 + {
45.588 + gchar *nick_e = g_uri_escape_string(form->nick, NULL, FALSE);
45.589 + nick = g_strdup_printf("&nick=%s", nick_e);
45.590 + g_free(nick_e);
45.591 + }
45.592 + else
45.593 + nick = g_strdup("");
45.594 +
45.595 + if (form->city && form->city[0] != '\0')
45.596 + {
45.597 + gchar *city_e = g_uri_escape_string(form->city, NULL, FALSE);
45.598 + city = g_strdup_printf("&city=%s", city_e);
45.599 + g_free(city_e);
45.600 + }
45.601 + else
45.602 + city = g_strdup("");
45.603 +
45.604 + if (form->gender != GGP_PUBDIR_GENDER_UNSPECIFIED)
45.605 + gender = g_strdup_printf("&gender=%d",
45.606 + form->gender == GGP_PUBDIR_GENDER_MALE ? 2 : 1);
45.607 + else
45.608 + gender = g_strdup("");
45.609 +
45.610 + query = g_strdup_printf("/users.xml?offset=%d&limit=%d%s%s%s",
45.611 + form->offset, form->limit, nick, city, gender);
45.612 +
45.613 + g_free(nick);
45.614 + g_free(city);
45.615 + g_free(gender);
45.616 +
45.617 + return query;
45.618 +}
45.619 +
45.620 +static void ggp_pubdir_search_execute(PurpleConnection *gc,
45.621 + const ggp_pubdir_search_form *form,
45.622 + ggp_pubdir_request_cb cb, void *user_data)
45.623 +{
45.624 + ggp_pubdir_request *request = g_new0(ggp_pubdir_request, 1);
45.625 + gchar *url;
45.626 + ggp_pubdir_search_form *local_form = ggp_pubdir_search_form_clone(form);
45.627 + gchar *query;
45.628 +
45.629 + request->type = GGP_PUBDIR_REQUEST_TYPE_SEARCH;
45.630 + request->gc = gc;
45.631 + request->cb = cb;
45.632 + request->user_data = user_data;
45.633 + request->params.search_form = local_form;
45.634 +
45.635 + query = ggp_pubdir_search_make_query(form);
45.636 + purple_debug_misc("gg", "ggp_pubdir_search_execute: %s\n", query);
45.637 + url = g_strdup_printf("http://api.gadu-gadu.pl%s", query);
45.638 + ggp_oauth_request(gc, ggp_pubdir_search_got_token, request,
45.639 + "GET", url);
45.640 + g_free(query);
45.641 + g_free(url);
45.642 +}
45.643 +
45.644 +static void ggp_pubdir_search_got_token(PurpleConnection *gc,
45.645 + const gchar *token, gpointer _request)
45.646 +{
45.647 + gchar *http_request;
45.648 + ggp_pubdir_request *request = _request;
45.649 + gchar *url;
45.650 + gchar *query;
45.651 +
45.652 + if (!token || !PURPLE_CONNECTION_IS_VALID(gc))
45.653 + {
45.654 + request->cb(gc, -1, NULL, 0, request->user_data);
45.655 + ggp_pubdir_request_free(request);
45.656 + return;
45.657 + }
45.658 +
45.659 + purple_debug_misc("gg", "ggp_pubdir_search_got_token\n");
45.660 +
45.661 + query = ggp_pubdir_search_make_query(request->params.search_form);
45.662 + url = g_strdup_printf("http://api.gadu-gadu.pl%s", query);
45.663 + http_request = g_strdup_printf(
45.664 + "GET %s HTTP/1.1\r\n"
45.665 + "Host: api.gadu-gadu.pl\r\n"
45.666 + "%s\r\n"
45.667 + "\r\n",
45.668 + query, token);
45.669 + g_free(query);
45.670 +
45.671 + purple_util_fetch_url_request(purple_connection_get_account(gc), url,
45.672 + FALSE, NULL, TRUE, http_request, FALSE, -1,
45.673 + ggp_pubdir_got_data, request);
45.674 +
45.675 + g_free(url);
45.676 + g_free(http_request);
45.677 +}
45.678 +
45.679 +
45.680 +static void ggp_pubdir_search_results_display(PurpleConnection *gc,
45.681 + int records_count, const ggp_pubdir_record *records, int next_offset,
45.682 + void *_form)
45.683 +{
45.684 + ggp_pubdir_search_form *form = _form;
45.685 + PurpleNotifySearchResults *results;
45.686 + int i;
45.687 +
45.688 + purple_debug_info("gg", "ggp_pubdir_search_results_display: "
45.689 + "got %d records (next offset: %d)\n",
45.690 + records_count, next_offset);
45.691 +
45.692 + if (records_count < 0 ||
45.693 + (records_count == 0 && form->offset != 0))
45.694 + {
45.695 + purple_notify_error(gc, GGP_PUBDIR_SEARCH_TITLE,
45.696 + _("Error while searching for buddies"), NULL);
45.697 + ggp_pubdir_search_form_free(form);
45.698 + return;
45.699 + }
45.700 +
45.701 + if (records_count == 0)
45.702 + {
45.703 + purple_notify_info(gc, GGP_PUBDIR_SEARCH_TITLE,
45.704 + _("No matching users found"),
45.705 + _("There are no users matching your search criteria."));
45.706 + ggp_pubdir_search_form_free(form);
45.707 + return;
45.708 + }
45.709 +
45.710 + form->offset = next_offset;
45.711 +
45.712 + results = purple_notify_searchresults_new();
45.713 +
45.714 + purple_notify_searchresults_column_add(results,
45.715 + purple_notify_searchresults_column_new(_("GG Number")));
45.716 + purple_notify_searchresults_column_add(results,
45.717 + purple_notify_searchresults_column_new(_("Name")));
45.718 + purple_notify_searchresults_column_add(results,
45.719 + purple_notify_searchresults_column_new(_("City")));
45.720 + purple_notify_searchresults_column_add(results,
45.721 + purple_notify_searchresults_column_new(_("Gender")));
45.722 + purple_notify_searchresults_column_add(results,
45.723 + purple_notify_searchresults_column_new(_("Age")));
45.724 +
45.725 + for (i = 0; i < records_count; i++)
45.726 + {
45.727 + GList *row = NULL;
45.728 + const ggp_pubdir_record *record = &records[i];
45.729 + gchar *gender = NULL, *age = NULL;
45.730 +
45.731 + if (record->gender == GGP_PUBDIR_GENDER_MALE)
45.732 + gender = g_strdup("male");
45.733 + else if (record->gender == GGP_PUBDIR_GENDER_FEMALE)
45.734 + gender = g_strdup("female");
45.735 +
45.736 + if (record->age)
45.737 + age = g_strdup_printf("%d", record->age);
45.738 +
45.739 + row = g_list_append(row, g_strdup(ggp_uin_to_str(record->uin)));
45.740 + row = g_list_append(row, g_strdup(record->label));
45.741 + row = g_list_append(row, g_strdup(record->city));
45.742 + row = g_list_append(row, gender);
45.743 + row = g_list_append(row, age);
45.744 + purple_notify_searchresults_row_add(results, row);
45.745 + }
45.746 +
45.747 + purple_notify_searchresults_button_add(results,
45.748 + PURPLE_NOTIFY_BUTTON_ADD, ggp_pubdir_search_results_add);
45.749 + purple_notify_searchresults_button_add(results,
45.750 + PURPLE_NOTIFY_BUTTON_IM, ggp_pubdir_search_results_im);
45.751 + purple_notify_searchresults_button_add(results,
45.752 + PURPLE_NOTIFY_BUTTON_INFO, ggp_pubdir_search_results_info);
45.753 + purple_notify_searchresults_button_add_labeled(results, _("New search"),
45.754 + ggp_pubdir_search_results_new);
45.755 + if (next_offset != 0)
45.756 + purple_notify_searchresults_button_add(results,
45.757 + PURPLE_NOTIFY_BUTTON_CONTINUE,
45.758 + ggp_pubdir_search_results_next);
45.759 +
45.760 + if (!form->display_handle)
45.761 + form->display_handle = purple_notify_searchresults(gc,
45.762 + GGP_PUBDIR_SEARCH_TITLE, _("Search results"), NULL,
45.763 + results, ggp_pubdir_search_results_close, form);
45.764 + else
45.765 + purple_notify_searchresults_new_rows(gc, results,
45.766 + form->display_handle);
45.767 + g_assert(form->display_handle);
45.768 +}
45.769 +
45.770 +static void ggp_pubdir_search_results_close(gpointer _form)
45.771 +{
45.772 + ggp_pubdir_search_form *form = _form;
45.773 + ggp_pubdir_search_form_free(form);
45.774 +}
45.775 +
45.776 +static void ggp_pubdir_search_results_next(PurpleConnection *gc, GList *row,
45.777 + gpointer _form)
45.778 +{
45.779 + ggp_pubdir_search_form *form = _form;
45.780 + ggp_pubdir_search_execute(gc, form, ggp_pubdir_search_results_display,
45.781 + form);
45.782 +}
45.783 +
45.784 +static void ggp_pubdir_search_results_add(PurpleConnection *gc, GList *row,
45.785 + gpointer _form)
45.786 +{
45.787 + purple_blist_request_add_buddy(purple_connection_get_account(gc),
45.788 + g_list_nth_data(row, 0), NULL, g_list_nth_data(row, 1));
45.789 +}
45.790 +
45.791 +static void ggp_pubdir_search_results_im(PurpleConnection *gc, GList *row,
45.792 + gpointer _form)
45.793 +{
45.794 + purple_conversation_present(purple_conversation_new(PURPLE_CONV_TYPE_IM,
45.795 + purple_connection_get_account(gc), g_list_nth_data(row, 0)));
45.796 +}
45.797 +
45.798 +static void ggp_pubdir_search_results_info(PurpleConnection *gc, GList *row,
45.799 + gpointer _form)
45.800 +{
45.801 + ggp_pubdir_get_info_prpl(gc, g_list_nth_data(row, 0));
45.802 +}
45.803 +
45.804 +static void ggp_pubdir_search_results_new(PurpleConnection *gc, GList *row,
45.805 + gpointer _form)
45.806 +{
45.807 + ggp_pubdir_search_form *form = _form;
45.808 + ggp_pubdir_search(gc, form);
45.809 +}
45.810 +
45.811 +/*******************************************************************************
45.812 + * Own profile.
45.813 + ******************************************************************************/
45.814 +
45.815 +void ggp_pubdir_set_info(PurpleConnection *gc)
45.816 +{
45.817 + ggp_pubdir_get_info(gc, ggp_str_to_uin(purple_account_get_username(
45.818 + purple_connection_get_account(gc))),
45.819 + ggp_pubdir_set_info_dialog, NULL);
45.820 +}
45.821 +
45.822 +static void ggp_pubdir_set_info_dialog(PurpleConnection *gc, int records_count,
45.823 + const ggp_pubdir_record *records, int next_offset, void *user_data)
45.824 +{
45.825 + PurpleRequestFields *fields;
45.826 + PurpleRequestFieldGroup *group;
45.827 + PurpleRequestField *field;
45.828 + int default_gender, i;
45.829 + const ggp_pubdir_record *record;
45.830 +
45.831 + purple_debug_info("gg", "ggp_pubdir_set_info_dialog (record: %d)\n",
45.832 + records_count);
45.833 +
45.834 + record = (records_count == 1 ? &records[0] : NULL);
45.835 +
45.836 + fields = purple_request_fields_new();
45.837 + group = purple_request_field_group_new(NULL);
45.838 + purple_request_fields_add_group(fields, group);
45.839 +
45.840 + field = purple_request_field_string_new("first_name", _("First name"),
45.841 + record ? record->first_name : NULL, FALSE);
45.842 + purple_request_field_group_add_field(group, field);
45.843 +
45.844 + field = purple_request_field_string_new("last_name", _("Last name"),
45.845 + record ? record->last_name : NULL, FALSE);
45.846 + purple_request_field_group_add_field(group, field);
45.847 +
45.848 + default_gender = -1;
45.849 + if (record && record->gender == GGP_PUBDIR_GENDER_MALE)
45.850 + default_gender = 0;
45.851 + else if (record && record->gender == GGP_PUBDIR_GENDER_FEMALE)
45.852 + default_gender = 1;
45.853 +
45.854 + field = purple_request_field_choice_new("gender", _("Gender"),
45.855 + default_gender);
45.856 + purple_request_field_set_required(field, TRUE);
45.857 + purple_request_field_choice_add(field, _("Male"));
45.858 + purple_request_field_choice_add(field, _("Female"));
45.859 + purple_request_field_group_add_field(group, field);
45.860 +
45.861 + field = purple_request_field_string_new("birth_date", _("Birth Day"),
45.862 + (record && record->birth) ?
45.863 + ggp_date_strftime("%Y-%m-%d", record->birth) : NULL, FALSE);
45.864 + purple_request_field_set_required(field, TRUE);
45.865 + purple_request_field_group_add_field(group, field);
45.866 +
45.867 + field = purple_request_field_string_new("city", _("City"),
45.868 + record ? record->city : NULL, FALSE);
45.869 + purple_request_field_group_add_field(group, field);
45.870 +
45.871 + field = purple_request_field_choice_new("province", _("Voivodeship"), 0);
45.872 + purple_request_field_group_add_field(group, field);
45.873 + purple_request_field_choice_add(field, _("Not specified"));
45.874 + for (i = 0; i < ggp_pubdir_provinces_count; i++)
45.875 + {
45.876 + purple_request_field_choice_add(field, ggp_pubdir_provinces[i]);
45.877 + if (record && i + 1 == record->province)
45.878 + {
45.879 + purple_request_field_choice_set_value(field, i + 1);
45.880 + purple_request_field_choice_set_default_value(field,
45.881 + i + 1); // TODO: libpurple bug?
45.882 + }
45.883 + }
45.884 +
45.885 + purple_request_fields(gc, _("Set User Info"), _("Set User Info"),
45.886 + NULL, fields,
45.887 + _("OK"), G_CALLBACK(ggp_pubdir_set_info_request),
45.888 + _("Cancel"), NULL,
45.889 + purple_connection_get_account(gc), NULL, NULL, gc);
45.890 +
45.891 +}
45.892 +
45.893 +static void ggp_pubdir_set_info_request(PurpleConnection *gc,
45.894 + PurpleRequestFields *fields)
45.895 +{
45.896 + gchar *url;
45.897 + uin_t uin = ggp_str_to_uin(purple_account_get_username(
45.898 + purple_connection_get_account(gc)));
45.899 + ggp_pubdir_record *record = g_new0(ggp_pubdir_record, 1);
45.900 + gchar *birth_s;
45.901 +
45.902 + purple_debug_info("gg", "ggp_pubdir_set_info_request\n");
45.903 +
45.904 + record->uin = uin;
45.905 + record->first_name = g_strdup(purple_request_fields_get_string(fields,
45.906 + "first_name"));
45.907 + record->last_name = g_strdup(purple_request_fields_get_string(fields,
45.908 + "last_name"));
45.909 + if (purple_request_fields_get_choice(fields, "gender") == 0)
45.910 + record->gender = GGP_PUBDIR_GENDER_MALE;
45.911 + else
45.912 + record->gender = GGP_PUBDIR_GENDER_FEMALE;
45.913 + record->city = g_strdup(purple_request_fields_get_string(fields,
45.914 + "city"));
45.915 + record->province = purple_request_fields_get_choice(fields, "province");
45.916 +
45.917 + birth_s = g_strdup_printf("%sT10:00:00+00:00",
45.918 + purple_request_fields_get_string(fields, "birth_date"));
45.919 + record->birth = ggp_date_from_iso8601(birth_s);
45.920 + g_free(birth_s);
45.921 + purple_debug_info("gg", "ggp_pubdir_set_info_request: birth [%lu][%s]\n",
45.922 + record->birth, purple_request_fields_get_string(
45.923 + fields, "birth_date"));
45.924 +
45.925 + url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u.xml", uin);
45.926 + ggp_oauth_request(gc, ggp_pubdir_set_info_got_token, record,
45.927 + "PUT", url);
45.928 + g_free(url);
45.929 +}
45.930 +
45.931 +static void ggp_pubdir_set_info_got_token(PurpleConnection *gc,
45.932 + const gchar *token, gpointer _record)
45.933 +{
45.934 + ggp_pubdir_record *record = _record;
45.935 + gchar *request, *request_data, *url;
45.936 + gchar *name, *surname, *city;
45.937 + uin_t uin = record->uin;
45.938 +
45.939 + if (!token || !PURPLE_CONNECTION_IS_VALID(gc))
45.940 + {
45.941 + // TODO: notify about failure
45.942 + ggp_pubdir_record_free(record, 1);
45.943 + return;
45.944 + }
45.945 +
45.946 + name = g_uri_escape_string(record->first_name, NULL, FALSE);
45.947 + surname = g_uri_escape_string(record->last_name, NULL, FALSE);
45.948 + city = g_uri_escape_string(record->city, NULL, FALSE);
45.949 +
45.950 + request_data = g_strdup_printf(
45.951 + "name=%s&"
45.952 + "surname=%s&"
45.953 + "birth=%sT10:00:00%%2B00:00&"
45.954 + "birth_priv=2&"
45.955 + "gender=%d&"
45.956 + "gender_priv=2&"
45.957 + "city=%s&"
45.958 + "province=%d",
45.959 + name, surname,
45.960 + ggp_date_strftime("%Y-%m-%d", record->birth),
45.961 + record->gender,
45.962 + city,
45.963 + record->province);
45.964 +
45.965 + //TODO: verbose
45.966 + //purple_debug_misc("gg", "ggp_pubdir_set_info_got_token: query [%s]\n",
45.967 + // request_data);
45.968 +
45.969 + url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u.xml", uin);
45.970 + request = g_strdup_printf(
45.971 + "PUT /users/%u.xml HTTP/1.1\r\n"
45.972 + "Host: api.gadu-gadu.pl\r\n"
45.973 + "%s\r\n"
45.974 + "Content-Length: %d\r\n"
45.975 + "Content-Type: application/x-www-form-urlencoded\r\n"
45.976 + "\r\n%s",
45.977 + uin, token, strlen(request_data), request_data);
45.978 +
45.979 + purple_util_fetch_url_request(purple_connection_get_account(gc), url,
45.980 + FALSE, NULL, TRUE, request, FALSE, -1,
45.981 + ggp_pubdir_set_info_got_response, NULL);
45.982 +
45.983 + g_free(request);
45.984 + g_free(request_data);
45.985 + g_free(url);
45.986 + ggp_pubdir_record_free(record, 1);
45.987 +}
45.988 +
45.989 +static void ggp_pubdir_set_info_got_response(PurpleUtilFetchUrlData *url_data,
45.990 + gpointer user_data, const gchar *url_text, gsize len,
45.991 + const gchar *error_message)
45.992 +{
45.993 + purple_debug_info("gg", "ggp_pubdir_set_info_got_response: [%s]\n", url_text);
45.994 + //<result><status>0</status></result>
45.995 +
45.996 + //TODO: notify about failure
45.997 +}
46.1 new file mode 100644
46.2 --- /dev/null
46.3 +++ b/libpurple/protocols/gg/pubdir-prpl.h
46.4 @@ -0,0 +1,73 @@
46.5 +/* purple
46.6 + *
46.7 + * Purple is the legal property of its developers, whose names are too numerous
46.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
46.9 + * source distribution.
46.10 + *
46.11 + * Rewritten from scratch during Google Summer of Code 2012
46.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
46.13 + *
46.14 + * Previously implemented by:
46.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
46.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
46.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
46.18 + *
46.19 + * This program is free software; you can redistribute it and/or modify
46.20 + * it under the terms of the GNU General Public License as published by
46.21 + * the Free Software Foundation; either version 2 of the License, or
46.22 + * (at your option) any later version.
46.23 + *
46.24 + * This program is distributed in the hope that it will be useful,
46.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
46.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46.27 + * GNU General Public License for more details.
46.28 + *
46.29 + * You should have received a copy of the GNU General Public License
46.30 + * along with this program; if not, write to the Free Software
46.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
46.32 + */
46.33 +
46.34 +#ifndef _GGP_PUBDIR_PRPL_H
46.35 +#define _GGP_PUBDIR_PRPL_H
46.36 +
46.37 +#include <internal.h>
46.38 +#include <libgadu.h>
46.39 +
46.40 +typedef enum
46.41 +{
46.42 + GGP_PUBDIR_GENDER_UNSPECIFIED,
46.43 + GGP_PUBDIR_GENDER_FEMALE,
46.44 + GGP_PUBDIR_GENDER_MALE,
46.45 +} ggp_pubdir_gender;
46.46 +
46.47 +typedef struct
46.48 +{
46.49 + uin_t uin;
46.50 + gchar *label;
46.51 + gchar *nickname;
46.52 + gchar *first_name;
46.53 + gchar *last_name;
46.54 + ggp_pubdir_gender gender;
46.55 + gchar *city;
46.56 + unsigned int province;
46.57 + time_t birth;
46.58 + unsigned int age;
46.59 +} ggp_pubdir_record;
46.60 +
46.61 +typedef struct _ggp_pubdir_search_form ggp_pubdir_search_form;
46.62 +
46.63 +typedef void (*ggp_pubdir_request_cb)(PurpleConnection *gc, int records_count,
46.64 + const ggp_pubdir_record *records, int next_offset, void *user_data);
46.65 +
46.66 +void ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin,
46.67 + ggp_pubdir_request_cb cb, void *user_data);
46.68 +
46.69 +void ggp_pubdir_get_info_prpl(PurpleConnection *gc, const char *name);
46.70 +void ggp_pubdir_request_buddy_alias(PurpleConnection *gc, PurpleBuddy *buddy);
46.71 +
46.72 +void ggp_pubdir_search(PurpleConnection *gc,
46.73 + const ggp_pubdir_search_form *form);
46.74 +
46.75 +void ggp_pubdir_set_info(PurpleConnection *gc);
46.76 +
46.77 +#endif /* _GGP_PUBDIR_PRPL_H */
47.1 new file mode 100644
47.2 --- /dev/null
47.3 +++ b/libpurple/protocols/gg/purplew.c
47.4 @@ -0,0 +1,149 @@
47.5 +/* purple
47.6 + *
47.7 + * Purple is the legal property of its developers, whose names are too numerous
47.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
47.9 + * source distribution.
47.10 + *
47.11 + * Rewritten from scratch during Google Summer of Code 2012
47.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
47.13 + *
47.14 + * Previously implemented by:
47.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
47.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
47.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
47.18 + *
47.19 + * This program is free software; you can redistribute it and/or modify
47.20 + * it under the terms of the GNU General Public License as published by
47.21 + * the Free Software Foundation; either version 2 of the License, or
47.22 + * (at your option) any later version.
47.23 + *
47.24 + * This program is distributed in the hope that it will be useful,
47.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
47.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47.27 + * GNU General Public License for more details.
47.28 + *
47.29 + * You should have received a copy of the GNU General Public License
47.30 + * along with this program; if not, write to the Free Software
47.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
47.32 + */
47.33 +
47.34 +#include "purplew.h"
47.35 +
47.36 +#include <request.h>
47.37 +#include <debug.h>
47.38 +
47.39 +guint ggp_purplew_http_input_add(struct gg_http *http_req,
47.40 + PurpleInputFunction func, gpointer user_data)
47.41 +{
47.42 + PurpleInputCondition cond = 0;
47.43 + int check = http_req->check;
47.44 +
47.45 + if (check & GG_CHECK_READ)
47.46 + cond |= PURPLE_INPUT_READ;
47.47 + if (check & GG_CHECK_WRITE)
47.48 + cond |= PURPLE_INPUT_WRITE;
47.49 +
47.50 + //TODO: verbose mode
47.51 + //purple_debug_misc("gg", "ggp_purplew_http_input_add: "
47.52 + // "[req=%x, fd=%d, cond=%d]\n",
47.53 + // (unsigned int)http_req, http_req->fd, cond);
47.54 + return purple_input_add(http_req->fd, cond, func, user_data);
47.55 +}
47.56 +
47.57 +static void ggp_purplew_request_processing_cancel(
47.58 + ggp_purplew_request_processing_handle *handle, gint id)
47.59 +{
47.60 + handle->cancel_cb(handle->gc, handle->user_data);
47.61 + g_free(handle);
47.62 +}
47.63 +
47.64 +ggp_purplew_request_processing_handle * ggp_purplew_request_processing(
47.65 + PurpleConnection *gc, const gchar *msg, void *user_data,
47.66 + ggp_purplew_request_processing_cancel_cb cancel_cb)
47.67 +{
47.68 + ggp_purplew_request_processing_handle *handle =
47.69 + g_new(ggp_purplew_request_processing_handle, 1);
47.70 +
47.71 + handle->gc = gc;
47.72 + handle->cancel_cb = cancel_cb;
47.73 + handle->user_data = user_data;
47.74 + handle->request_handle = purple_request_action(gc, _("Please wait..."),
47.75 + (msg ? msg : _("Please wait...")), NULL,
47.76 + PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc),
47.77 + NULL, NULL, handle, 1,
47.78 + _("Cancel"), G_CALLBACK(ggp_purplew_request_processing_cancel));
47.79 +
47.80 + return handle;
47.81 +}
47.82 +
47.83 +void ggp_purplew_request_processing_done(
47.84 + ggp_purplew_request_processing_handle *handle)
47.85 +{
47.86 + purple_request_close(PURPLE_REQUEST_ACTION, handle->request_handle);
47.87 + g_free(handle);
47.88 +}
47.89 +
47.90 +PurpleGroup * ggp_purplew_buddy_get_group_only(PurpleBuddy *buddy)
47.91 +{
47.92 + PurpleGroup *group = purple_buddy_get_group(buddy);
47.93 + if (!group)
47.94 + return NULL;
47.95 + if (0 == strcmp(GGP_PURPLEW_GROUP_DEFAULT, purple_group_get_name(group)))
47.96 + return NULL;
47.97 + return group;
47.98 +}
47.99 +
47.100 +GList * ggp_purplew_group_get_buddies(PurpleGroup *group, PurpleAccount *account)
47.101 +{
47.102 + GList *buddies = NULL;
47.103 + PurpleBlistNode *gnode, *cnode, *bnode;
47.104 +
47.105 + g_return_val_if_fail(group != NULL, NULL);
47.106 +
47.107 + gnode = PURPLE_BLIST_NODE(group);
47.108 + for (cnode = gnode->child; cnode; cnode = cnode->next)
47.109 + {
47.110 + if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
47.111 + continue;
47.112 + for (bnode = cnode->child; bnode; bnode = bnode->next)
47.113 + {
47.114 + PurpleBuddy *buddy;
47.115 + if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
47.116 + continue;
47.117 +
47.118 + buddy = PURPLE_BUDDY(bnode);
47.119 + if (account == NULL || buddy->account == account)
47.120 + buddies = g_list_append(buddies, buddy);
47.121 + }
47.122 + }
47.123 +
47.124 + return buddies;
47.125 +}
47.126 +
47.127 +GList * ggp_purplew_account_get_groups(PurpleAccount *account, gboolean exclusive)
47.128 +{
47.129 + PurpleBlistNode *bnode;
47.130 + GList *groups = NULL;
47.131 + for (bnode = purple_blist_get_root(); bnode; bnode = bnode->next)
47.132 + {
47.133 + PurpleGroup *group;
47.134 + GSList *accounts;
47.135 + gboolean have_specified = FALSE, have_others = FALSE;
47.136 +
47.137 + if (!PURPLE_BLIST_NODE_IS_GROUP(bnode))
47.138 + continue;
47.139 +
47.140 + group = PURPLE_GROUP(bnode);
47.141 + for (accounts = purple_group_get_accounts(group); accounts; accounts = g_slist_delete_link(accounts, accounts))
47.142 + {
47.143 + if (accounts->data == account)
47.144 + have_specified = TRUE;
47.145 + else
47.146 + have_others = TRUE;
47.147 + }
47.148 +
47.149 + if (have_specified && (!exclusive || !have_others))
47.150 + groups = g_list_append(groups, group);
47.151 + }
47.152 + return groups;
47.153 +}
48.1 new file mode 100644
48.2 --- /dev/null
48.3 +++ b/libpurple/protocols/gg/purplew.h
48.4 @@ -0,0 +1,78 @@
48.5 +/* purple
48.6 + *
48.7 + * Purple is the legal property of its developers, whose names are too numerous
48.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
48.9 + * source distribution.
48.10 + *
48.11 + * Rewritten from scratch during Google Summer of Code 2012
48.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
48.13 + *
48.14 + * Previously implemented by:
48.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
48.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
48.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
48.18 + *
48.19 + * This program is free software; you can redistribute it and/or modify
48.20 + * it under the terms of the GNU General Public License as published by
48.21 + * the Free Software Foundation; either version 2 of the License, or
48.22 + * (at your option) any later version.
48.23 + *
48.24 + * This program is distributed in the hope that it will be useful,
48.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
48.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48.27 + * GNU General Public License for more details.
48.28 + *
48.29 + * You should have received a copy of the GNU General Public License
48.30 + * along with this program; if not, write to the Free Software
48.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
48.32 + */
48.33 +
48.34 +#ifndef _GGP_PURPLEW_H
48.35 +#define _GGP_PURPLEW_H
48.36 +
48.37 +#include <internal.h>
48.38 +#include <libgadu.h>
48.39 +
48.40 +#define GGP_PURPLEW_GROUP_DEFAULT _("Buddies")
48.41 +
48.42 +/**
48.43 + * Adds an input handler in purple event loop for http request.
48.44 + *
48.45 + * @see purple_input_add
48.46 + *
48.47 + * @param http_req Http connection to watch.
48.48 + * @param func The callback function for data.
48.49 + * @param user_data User-specified data.
48.50 + *
48.51 + * @return The resulting handle (will be greater than 0).
48.52 + */
48.53 +guint ggp_purplew_http_input_add(struct gg_http *http_req,
48.54 + PurpleInputFunction func, gpointer user_data);
48.55 +
48.56 +typedef void (*ggp_purplew_request_processing_cancel_cb)(PurpleConnection *gc,
48.57 + void *user_data);
48.58 +
48.59 +typedef struct
48.60 +{
48.61 + PurpleConnection *gc;
48.62 + ggp_purplew_request_processing_cancel_cb cancel_cb;
48.63 + void *request_handle;
48.64 + void *user_data;
48.65 +} ggp_purplew_request_processing_handle;
48.66 +
48.67 +ggp_purplew_request_processing_handle * ggp_purplew_request_processing(
48.68 + PurpleConnection *gc, const gchar *msg, void *user_data,
48.69 + ggp_purplew_request_processing_cancel_cb oncancel);
48.70 +
48.71 +void ggp_purplew_request_processing_done(
48.72 + ggp_purplew_request_processing_handle *handle);
48.73 +
48.74 +// ignores default group
48.75 +PurpleGroup * ggp_purplew_buddy_get_group_only(PurpleBuddy *buddy);
48.76 +
48.77 +GList * ggp_purplew_group_get_buddies(PurpleGroup *group, PurpleAccount *account);
48.78 +
48.79 +// you must g_free returned list
48.80 +GList * ggp_purplew_account_get_groups(PurpleAccount *account, gboolean exclusive);
48.81 +
48.82 +#endif /* _GGP_PURPLEW_H */
49.1 new file mode 100644
49.2 --- /dev/null
49.3 +++ b/libpurple/protocols/gg/resolver-purple.c
49.4 @@ -0,0 +1,192 @@
49.5 +/* purple
49.6 + *
49.7 + * Purple is the legal property of its developers, whose names are too numerous
49.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
49.9 + * source distribution.
49.10 + *
49.11 + * Rewritten from scratch during Google Summer of Code 2012
49.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
49.13 + *
49.14 + * Previously implemented by:
49.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
49.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
49.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
49.18 + *
49.19 + * This program is free software; you can redistribute it and/or modify
49.20 + * it under the terms of the GNU General Public License as published by
49.21 + * the Free Software Foundation; either version 2 of the License, or
49.22 + * (at your option) any later version.
49.23 + *
49.24 + * This program is distributed in the hope that it will be useful,
49.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
49.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49.27 + * GNU General Public License for more details.
49.28 + *
49.29 + * You should have received a copy of the GNU General Public License
49.30 + * along with this program; if not, write to the Free Software
49.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
49.32 + */
49.33 +
49.34 +#include <internal.h>
49.35 +#include <debug.h>
49.36 +#include <dnsquery.h>
49.37 +
49.38 +#include <libgadu.h>
49.39 +#include "resolver-purple.h"
49.40 +
49.41 +static int ggp_resolver_purple_start(int *fd, void **private_data,
49.42 + const char *hostname);
49.43 +
49.44 +static void ggp_resolver_purple_cleanup(void **private_data, int force);
49.45 +
49.46 +static void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
49.47 + const char *error_message);
49.48 +
49.49 +typedef struct
49.50 +{
49.51 + PurpleDnsQueryData *purpleQuery;
49.52 +
49.53 + /**
49.54 + * File descriptors:
49.55 + * pipes[0] - for reading
49.56 + * pipes[1] - for writing
49.57 + */
49.58 + int pipes[2];
49.59 +} ggp_resolver_purple_data;
49.60 +
49.61 +
49.62 +extern void ggp_resolver_purple_setup(void)
49.63 +{
49.64 + if (gg_global_set_custom_resolver(ggp_resolver_purple_start,
49.65 + ggp_resolver_purple_cleanup) != 0)
49.66 + {
49.67 + purple_debug_error("gg", "failed to set custom resolver\n");
49.68 + }
49.69 +}
49.70 +
49.71 +void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
49.72 + const char *error_message)
49.73 +{
49.74 + ggp_resolver_purple_data *data = (ggp_resolver_purple_data*)cbdata;
49.75 + const int fd = data->pipes[1];
49.76 + int ipv4_count, all_count, write_size;
49.77 + struct in_addr *addresses;
49.78 +
49.79 + purple_debug_misc("gg", "ggp_resolver_purple_cb(%x, %x, \"%s\")\n",
49.80 + (unsigned int)hosts, (unsigned int)cbdata, error_message);
49.81 +
49.82 + if (error_message)
49.83 + {
49.84 + purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
49.85 + error_message);
49.86 + }
49.87 +
49.88 + all_count = g_slist_length(hosts);
49.89 + g_assert(all_count % 2 == 0);
49.90 + all_count /= 2;
49.91 + addresses = malloc((all_count + 1) * sizeof(struct in_addr));
49.92 +
49.93 + ipv4_count = 0;
49.94 + while (hosts && (hosts = g_slist_delete_link(hosts, hosts)))
49.95 + {
49.96 + const struct sockaddr *addr = hosts->data;
49.97 + char dst[INET6_ADDRSTRLEN];
49.98 +
49.99 + if (addr->sa_family == AF_INET6)
49.100 + {
49.101 + inet_ntop(addr->sa_family,
49.102 + &((struct sockaddr_in6 *) addr)->sin6_addr,
49.103 + dst, sizeof(dst));
49.104 + purple_debug_misc("gg", "ggp_resolver_purple_cb "
49.105 + "ipv6 (ignore): %s\n", dst);
49.106 + }
49.107 + else if (addr->sa_family == AF_INET)
49.108 + {
49.109 + const struct in_addr addr_ipv4 =
49.110 + ((struct sockaddr_in *) addr)->sin_addr;
49.111 + inet_ntop(addr->sa_family, &addr_ipv4,
49.112 + dst, sizeof(dst));
49.113 + purple_debug_misc("gg", "ggp_resolver_purple_cb "
49.114 + "ipv4: %s\n", dst);
49.115 +
49.116 + g_assert(ipv4_count < all_count);
49.117 + addresses[ipv4_count++] = addr_ipv4;
49.118 + }
49.119 + else
49.120 + {
49.121 + purple_debug_warning("gg", "ggp_resolver_purple_cb "
49.122 + "unexpected sa_family: %d\n", addr->sa_family);
49.123 + }
49.124 +
49.125 + g_free(hosts->data);
49.126 + hosts = g_slist_delete_link(hosts, hosts);
49.127 + }
49.128 +
49.129 + addresses[ipv4_count].s_addr = INADDR_NONE;
49.130 +
49.131 + write_size = (ipv4_count + 1) * sizeof(struct in_addr);
49.132 + if (write(fd, addresses, write_size) != write_size)
49.133 + {
49.134 + purple_debug_error("gg",
49.135 + "ggp_resolver_purple_cb write error\n");
49.136 + }
49.137 + free(addresses);
49.138 +}
49.139 +
49.140 +int ggp_resolver_purple_start(int *fd, void **private_data,
49.141 + const char *hostname)
49.142 +{
49.143 + ggp_resolver_purple_data *data;
49.144 + purple_debug_misc("gg", "ggp_resolver_purple_start(%x, %x, \"%s\")\n",
49.145 + (unsigned int)fd, (unsigned int)private_data, hostname);
49.146 +
49.147 + data = malloc(sizeof(ggp_resolver_purple_data));
49.148 + *private_data = (void*)data;
49.149 + data->purpleQuery = NULL;
49.150 + data->pipes[0] = 0;
49.151 + data->pipes[1] = 0;
49.152 +
49.153 + if (purple_input_pipe(data->pipes) != 0)
49.154 + {
49.155 + purple_debug_error("gg", "ggp_resolver_purple_start: "
49.156 + "unable to create pipe\n");
49.157 + ggp_resolver_purple_cleanup(private_data, 0);
49.158 + return -1;
49.159 + }
49.160 +
49.161 + *fd = data->pipes[0];
49.162 +
49.163 + /* account and port is unknown in this context */
49.164 + data->purpleQuery = purple_dnsquery_a(NULL, hostname, 80,
49.165 + ggp_resolver_purple_cb, (gpointer)data);
49.166 +
49.167 + if (!data->purpleQuery)
49.168 + {
49.169 + purple_debug_error("gg", "ggp_resolver_purple_start: "
49.170 + "unable to call purple_dnsquery_a\n");
49.171 + ggp_resolver_purple_cleanup(private_data, 0);
49.172 + return -1;
49.173 + }
49.174 +
49.175 + return 0;
49.176 +}
49.177 +
49.178 +void ggp_resolver_purple_cleanup(void **private_data, int force)
49.179 +{
49.180 + ggp_resolver_purple_data *data =
49.181 + (ggp_resolver_purple_data*)(*private_data);
49.182 +
49.183 + purple_debug_misc("gg", "ggp_resolver_purple_cleanup(%x, %d)\n",
49.184 + (unsigned int)private_data, force);
49.185 +
49.186 + if (!data)
49.187 + return;
49.188 + *private_data = NULL;
49.189 +
49.190 + if (data->pipes[0])
49.191 + close(data->pipes[0]);
49.192 + if (data->pipes[1])
49.193 + close(data->pipes[1]);
49.194 +
49.195 + free(data);
49.196 +}
50.1 new file mode 100644
50.2 --- /dev/null
50.3 +++ b/libpurple/protocols/gg/resolver-purple.h
50.4 @@ -0,0 +1,38 @@
50.5 +/* purple
50.6 + *
50.7 + * Purple is the legal property of its developers, whose names are too numerous
50.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
50.9 + * source distribution.
50.10 + *
50.11 + * Rewritten from scratch during Google Summer of Code 2012
50.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
50.13 + *
50.14 + * Previously implemented by:
50.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
50.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
50.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
50.18 + *
50.19 + * This program is free software; you can redistribute it and/or modify
50.20 + * it under the terms of the GNU General Public License as published by
50.21 + * the Free Software Foundation; either version 2 of the License, or
50.22 + * (at your option) any later version.
50.23 + *
50.24 + * This program is distributed in the hope that it will be useful,
50.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
50.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50.27 + * GNU General Public License for more details.
50.28 + *
50.29 + * You should have received a copy of the GNU General Public License
50.30 + * along with this program; if not, write to the Free Software
50.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
50.32 + */
50.33 +
50.34 +#ifndef _GGP_RESOLVER_PURPLE_H
50.35 +#define _GGP_RESOLVER_PURPLE_H
50.36 +
50.37 +/**
50.38 + * Registers custom resolver for libgadu, that uses libpurple for DNS queries.
50.39 + */
50.40 +void ggp_resolver_purple_setup(void);
50.41 +
50.42 +#endif /* _GGP_RESOLVER_PURPLE_H */
51.1 new file mode 100644
51.2 --- /dev/null
51.3 +++ b/libpurple/protocols/gg/roster.c
51.4 @@ -0,0 +1,1119 @@
51.5 +/* purple
51.6 + *
51.7 + * Purple is the legal property of its developers, whose names are too numerous
51.8 + * to list here. Please refer to the COPYRIGHT file distributed with this
51.9 + * source distribution.
51.10 + *
51.11 + * Rewritten from scratch during Google Summer of Code 2012
51.12 + * by Tomek Wasilczyk (http://www.wasilczyk.pl).
51.13 + *
51.14 + * Previously implemented by:
51.15 + * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
51.16 + * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
51.17 + * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
51.18 + *
51.19 + * This program is free software; you can redistribute it and/or modify
51.20 + * it under the terms of the GNU General Public License as published by
51.21 + * the Free Software Foundation; either version 2 of the License, or
51.22 + * (at your option) any later version.
51.23 + *
51.24 + * This program is distributed in the hope that it will be useful,
51.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
51.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51.27 + * GNU General Public License for more details.
51.28 + *
51.29 + * You should have received a copy of the GNU General Public License
51.30 + * along with this program; if not, write to the Free Software
51.31 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
51.32 + */
51.33 +
51.34 +#include "roster.h"
51.35 +
51.36 +#include "gg.h"
51.37 +#include "xml.h"
51.38 +#include "utils.h"
51.39 +#include "purplew.h"
51.40 +
51.41 +#include <debug.h>
51.42 +
51.43 +#define GGP_ROSTER_SYNC_SETT "gg-synchronized"
51.44 +#define GGP_ROSTER_DEBUG 0
51.45 +#define GGP_ROSTER_GROUPID_DEFAULT "00000000-0000-0000-0000-000000000000"
51.46 +#define GGP_ROSTER_GROUPID_BOTS "0b345af6-0001-0000-0000-000000000004"
51.47 +
51.48 +// TODO: ignored contacts synchronization (?)
51.49 +
51.50 +typedef struct
51.51 +{
51.52 + int version;
51.53 +
51.54 + xmlnode *xml;
51.55 +
51.56 + xmlnode *groups_node, *contacts_node;
51.57 +
51.58 + /**
51.59 + * Key: (uin_t) user identifier
51.60 + * Value: (xmlnode*) xml node for contact
51.61 + */
51.62 + GHashTable *contact_nodes;
51.63 +
51.64 + /**
51.65 + * Key: (gchar*) group id
51.66 + * Value: (xmlnode*) xml node for group
51.67 + */
51.68 + GHashTable *group_nodes;
51.69 +
51.70 + /**
51.71 + * Key: (gchar*) group name
51.72 + * Value: (gchar*) group id
51.73 + */
51.74 + GHashTable *group_ids;
51.75 +
51.76 + /**
51.77 + * Key: (gchar*) group id
51.78 + * Value: (gchar*) group name
51.79 + */
51.80 + GHashTable *group_names;
51.81 +
51.82 + gchar *bots_group_id;
51.83 +
51.84 + gboolean needs_update;
51.85 +} ggp_roster_content;
51.86 +
51.87 +typedef struct
51.88 +{
51.89 + enum
51.90 + {
51.91 + GGP_ROSTER_CHANGE_CONTACT_UPDATE,
51.92 + GGP_ROSTER_CHANGE_CONTACT_REMOVE,
51.93 + GGP_ROSTER_CHANGE_GROUP_RENAME,
51.94 + } type;
51.95 + union
51.96 + {
51.97 + uin_t uin;
51.98 + struct
51.99 + {
51.100 + gchar *old_name;
51.101 + gchar *new_name;
51.102 + } group_rename;
51.103 + } data;
51.104 +} ggp_roster_change;
51.105 +
51.106 +static inline ggp_roster_session_data *
51.107 +ggp_roster_get_rdata(PurpleConnection *gc);
51.108 +static void ggp_roster_content_free(ggp_roster_content *content);
51.109 +static void ggp_roster_change_free(gpointer change);
51.110 +static int ggp_roster_get_version(PurpleConnection *gc);
51.111 +static gboolean ggp_roster_timer_cb(gpointer _gc);
51.112 +#if GGP_ROSTER_DEBUG
51.113 +static void ggp_roster_dump(ggp_roster_content *content);
51.114 +#endif
51.115 +
51.116 +// synchronization control
51.117 +static gboolean ggp_roster_is_synchronized(PurpleBuddy *buddy);
51.118 +static void ggp_roster_set_synchronized(PurpleConnection *gc,
51.119 + PurpleBuddy *buddy, gboolean synchronized);
51.120 +
51.121 +// buddy list import
51.122 +static gboolean ggp_roster_reply_list_read_group(xmlnode *node,
51.123 + ggp_roster_content *content);
51.124 +static gboolean ggp_roster_reply_list_read_buddy(PurpleConnection *gc,
51.125 + xmlnode *node, ggp_roster_content *content, GHashTable *remove_buddies);
51.126 +static void ggp_roster_reply_list(PurpleConnection *gc, uint32_t version,
51.127 + const char *reply);
51.128 +
51.129 +// buddy list export
51.130 +static const gchar * ggp_roster_send_update_group_add(
51.131 + ggp_roster_content *content, PurpleGroup *group);
51.132 +static gboolean ggp_roster_send_update_contact_update(PurpleConnection *gc,
51.133 + ggp_roster_change *change);
51.134 +static gboolean ggp_roster_send_update_contact_remove(PurpleConnection *gc,
51.135 + ggp_roster_change *change);
51.136 +static gboolean ggp_roster_send_update_group_rename(PurpleConnection *gc,
51.137 + ggp_roster_change *change);
51.138 +static void ggp_roster_send_update(PurpleConnection *gc);
51.139 +static void ggp_roster_reply_ack(PurpleConnection *gc, uint32_t version);
51.140 +static void ggp_roster_reply_reject(PurpleConnection *gc, uint32_t version);
51.141 +
51.142 +/******************************************************************************/
51.143 +
51.144 +static inline ggp_roster_session_data *
51.145 +ggp_roster_get_rdata(PurpleConnection *gc)
51.146 +{
51.147 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
51.148 + return &accdata->roster_data;
51.149 +}
51.150 +
51.151 +static void ggp_roster_content_free(ggp_roster_content *content)
51.152 +{
51.153 + if (content == NULL)
51.154 + return;
51.155 + if (content->xml)
51.156 + xmlnode_free(content->xml);
51.157 + if (content->contact_nodes)
51.158 + g_hash_table_destroy(content->contact_nodes);
51.159 + if (content->group_nodes)
51.160 + g_hash_table_destroy(content->group_nodes);
51.161 + if (content->group_ids)
51.162 + g_hash_table_destroy(content->group_ids);
51.163 + if (content->group_names)
51.164 + g_hash_table_destroy(content->group_names);
51.165 + if (content->bots_group_id)
51.166 + g_free(content->bots_group_id);
51.167 + g_free(content);
51.168 +}
51.169 +
51.170 +static void ggp_roster_change_free(gpointer _change)
51.171 +{
51.172 + ggp_roster_change *change = _change;
51.173 +
51.174 + if (change->type == GGP_ROSTER_CHANGE_GROUP_RENAME)
51.175 + {
51.176 + g_free(change->data.group_rename.old_name);
51.177 + g_free(change->data.group_rename.new_name);
51.178 + }
51.179 +
51.180 + g_free(change);
51.181 +}
51.182 +
51.183 +static int ggp_roster_get_version(PurpleConnection *gc)
51.184 +{
51.185 + ggp_roster_content *content = ggp_roster_get_rdata(gc)->content;
51.186 + if (content == NULL)
51.187 + return 0;
51.188 + return content->version;
51.189 +}
51.190 +
51.191 +static gboolean ggp_roster_timer_cb(gpointer _gc)
51.192 +{
51.193 + PurpleConnection *gc = _gc;
51.194 +
51.195 + g_return_val_if_fail(PURPLE_CONNECTION_IS_VALID(gc), FALSE);
51.196 +
51.197 + ggp_roster_send_update(gc);
51.198 +
51.199 + return TRUE;
51.200 +}
51.201 +
51.202 +#if GGP_ROSTER_DEBUG
51.203 +static void ggp_roster_dump(ggp_roster_content *content)
51.204 +{
51.205 + char *str;
51.206 + int len;
51.207 +
51.208 + g_return_if_fail(content != NULL);
51.209 + g_return_if_fail(content->xml != NULL);
51.210 +
51.211 + str = xmlnode_to_formatted_str(content->xml, &len);
51.212 + purple_debug_misc("gg", "ggp_roster_dump: [%s]\n", str);
51.213 + g_free(str);
51.214 +}
51.215 +#endif
51.216 +
51.217 +/*******************************************************************************
51.218 + * Setup.
51.219 + ******************************************************************************/
51.220 +
51.221 +gboolean ggp_roster_enabled(void)
51.222 +{
51.223 + static gboolean checked = FALSE;
51.224 + static gboolean enabled;
51.225 +
51.226 + if (!checked)
51.227 + {
51.228 + enabled = gg_libgadu_check_feature(
51.229 + GG_LIBGADU_FEATURE_USERLIST100);
51.230 + checked = TRUE;
51.231 + }
51.232 + return enabled;
51.233 +}
51.234 +
51.235 +void ggp_roster_setup(PurpleConnection *gc)
51.236 +{
51.237 + ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
51.238 +
51.239 + rdata->content = NULL;
51.240 + rdata->sent_updates = NULL;
51.241 + rdata->pending_updates = NULL;
51.242 + rdata->timer = 0;
51.243 + rdata->is_updating = FALSE;
51.244 +
51.245 + if (ggp_roster_enabled())
51.246 + rdata->timer = purple_timeout_add_seconds(2,
51.247 + ggp_roster_timer_cb, gc);
51.248 +}
51.249 +
51.250 +void ggp_roster_cleanup(PurpleConnection *gc)
51.251 +{
51.252 + ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
51.253 +
51.254 + if (rdata->timer)
51.255 + purple_timeout_remove(rdata->timer);
51.256 + ggp_roster_content_free(rdata->content);
51.257 + g_list_free_full(rdata->sent_updates, ggp_roster_change_free);
51.258 + g_list_free_full(rdata->pending_updates, ggp_roster_change_free);
51.259 +}
51.260 +
51.261 +/*******************************************************************************
51.262 + * Synchronization control.
51.263 + ******************************************************************************/
51.264 +
51.265 +static gboolean ggp_roster_is_synchronized(PurpleBuddy *buddy)
51.266 +{
51.267 + gboolean ret = purple_blist_node_get_bool(PURPLE_BLIST_NODE(buddy),
51.268 + GGP_ROSTER_SYNC_SETT);
51.269 + return ret;
51.270 +}
51.271 +
51.272 +static void ggp_roster_set_synchronized(PurpleConnection *gc,
51.273 + PurpleBuddy *buddy, gboolean synchronized)
51.274 +{
51.275 + ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
51.276 + uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy));
51.277 + ggp_roster_change *change;
51.278 +
51.279 + purple_blist_node_set_bool(PURPLE_BLIST_NODE(buddy),
51.280 + GGP_ROSTER_SYNC_SETT, synchronized);
51.281 + if (!synchronized)
51.282 + {
51.283 + change = g_new0(ggp_roster_change, 1);
51.284 + change->type = GGP_ROSTER_CHANGE_CONTACT_UPDATE;
51.285 + change->data.uin = uin;
51.286 + rdata->pending_updates =
51.287 + g_list_append(rdata->pending_updates, change);
51.288 + }
51.289 +}
51.290 +
51.291 +void ggp_roster_request_update(PurpleConnection *gc)
51.292 +{
51.293 + GGPInfo *accdata = purple_connection_get_protocol_data(gc);
51.294 + int local_version = ggp_roster_get_version(gc);
51.295 +
51.296 + if (!ggp_roster_enabled())
51.297 + {
51.298 + purple_debug_warning("gg", "ggp_roster_request_update: "
51.299 + "feature disabled\n");
51.300 + return;
51.301 + }
51.302 +
51.303 + purple_debug_info("gg", "ggp_roster_request_update: local=%u\n",
51.304 + local_version);
51.305 +
51.306 + gg_userlist100_request(accdata->session, GG_USERLIST100_GET,
51.307 + local_version, GG_USERLIST100_FORMAT_TYPE_GG100, NULL);
51.308 +}
51.309 +
51.310 +/*******************************************************************************
51.311 + * Libgadu callbacks.
51.312 + ******************************************************************************/
51.313 +
51.314 +void ggp_roster_reply(PurpleConnection *gc,
51.315 + struct gg_event_userlist100_reply *reply)
51.316 +{
51.317 + if (GG_USERLIST100_FORMAT_TYPE_GG100 != reply->format_type)
51.318 + {
51.319 + purple_debug_warning("gg", "ggp_roster_reply: "
51.320 + "unsupported format type (%x)\n", reply->format_type);
51.321 + return;
51.322 + }
51.323 +
51.324 + if (reply->type == GG_USERLIST100_REPLY_LIST)
51.325 + ggp_roster_reply_list(gc, reply->version, reply->reply);
51.326 + else if (reply->type == 0x01) // list up to date (TODO: push to libgadu)
51.327 + purple_debug_info("gg", "ggp_roster_reply: list up to date\n");
51.328 + else if (reply->type == GG_USERLIST100_REPLY_ACK)
51.329 + ggp_roster_reply_ack(gc, reply->version);
51.330 + else if (reply->type == GG_USERLIST100_REPLY_REJECT)
51.331 + ggp_roster_reply_reject(gc, reply->version);
51.332 + else
51.333 + purple_debug_error("gg", "ggp_roster_reply: "
51.334 + "unsupported reply (%x)\n", reply->type);
51.335 +}
51.336 +
51.337 +void ggp_roster_version(PurpleConnection *gc,
51.338 + struct gg_event_userlist100_version *version)
51.339 +{
51.340 + int local_version = ggp_roster_get_version(gc);
51.341 + int remote_version = version->version;
51.342 +
51.343 + purple_debug_info("gg", "ggp_roster_version: local=%u, remote=%u\n",
51.344 + local_version, remote_version);
51.345 +
51.346 + if (local_version < remote_version)
51.347 + ggp_roster_request_update(gc);
51.348 +}
51.349 +
51.350 +/*******************************************************************************
51.351 + * Libpurple callbacks.
51.352 + ******************************************************************************/
51.353 +
51.354 +void ggp_roster_alias_buddy(PurpleConnection *gc, const char *who,
51.355 + const char *alias)
51.356 +{
51.357 + PurpleBuddy *buddy;
51.358 +
51.359 + g_return_if_fail(who != NULL);
51.360 +
51.361 + if (!ggp_roster_enabled())
51.362 + return;
51.363 +
51.364 + purple_debug_misc("gg", "ggp_roster_alias_buddy(\"%s\", \"%s\")\n",
51.365 + who, alias);
51.366 +
51.367 + buddy = purple_find_buddy(purple_connection_get_account(gc), who);
51.368 + g_return_if_fail(buddy != NULL);
51.369 +
51.370 + ggp_roster_set_synchronized(gc, buddy, FALSE);
51.371 +}
51.372 +
51.373 +void ggp_roster_group_buddy(PurpleConnection *gc, const char *who,
51.374 + const char *old_group, const char *new_group)
51.375 +{
51.376 + ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
51.377 + ggp_roster_change *change = g_new0(ggp_roster_change, 1);
51.378 +
51.379 + if (!ggp_roster_enabled())
51.380 + return;
51.381 + if (rdata->is_updating)
51.382 + return;
51.383 +
51.384 + purple_debug_misc("gg", "ggp_roster_group_buddy: "
51.385 + "who=\"%s\", group=\"%s\" -> \"%s\")\n",
51.386 + who, old_group, new_group);
51.387 +
51.388 + // purple_find_buddy(..., who) is not accessible at this moment
51.389 + change->type = GGP_ROSTER_CHANGE_CONTACT_UPDATE;
51.390 + change->data.uin = ggp_str_to_uin(who);
51.391 + rdata->pending_updates = g_list_append(rdata->pending_updates, change);
51.392 +}
51.393 +
51.394 +void ggp_roster_rename_group(PurpleConnection *gc, const char *old_name,
51.395 + PurpleGroup *group, GList *moved_buddies)
51.396 +{
51.397 + ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
51.398 + ggp_roster_change *change = g_new0(ggp_roster_change, 1);
51.399 +
51.400 + if (!ggp_roster_enabled())
51.401 + return;
51.402 +
51.403 + change->type = GGP_ROSTER_CHANGE_GROUP_RENAME;
51.404 + change->data.group_rename.old_name = g_strdup(old_name);
51.405 + change->data.group_rename.new_name =
51.406 + g_strdup(purple_group_get_name(group));
51.407 + rdata->pending_updates = g_list_append(rdata->pending_updates, change);
51.408 +}
51.409 +
51.410 +void ggp_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
51.411 + PurpleGroup *group, const char *message)
51.412 +{
51.413 + g_return_if_fail(gc != NULL);
51.414 + g_return_if_fail(buddy != NULL);
51.415 +
51.416 + if (!ggp_roster_enabled())
51.417 + return;
51.418 +
51.419 + ggp_roster_set_synchronized(gc, buddy, FALSE);
51.420 +}
51.421 +
51.422 +void ggp_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
51.423 + PurpleGroup *group)
51.424 +{
51.425 + ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
51.426 + ggp_roster_change *change = g_new0(ggp_roster_change, 1);
51.427 +
51.428 + if (!ggp_roster_enabled())
51.429 + return;
51.430 +
51.431 + change->type = GGP_ROSTER_CHANGE_CONTACT_REMOVE;