diff src/protocols/gg/gg.c @ 11360:cf15c1cdcfbd

[gaim-migrate @ 13582] New Gadu-Gadu implementation. committer: Tailor Script <tailor@pidgin.im>
author Bartoz Oler <bartosz@pidgin.im>
date Sun, 28 Aug 2005 22:46:01 +0000
parents 90be432e8385
children 54934c165625
line wrap: on
line diff
--- a/src/protocols/gg/gg.c	Sun Aug 28 22:21:24 2005 +0000
+++ b/src/protocols/gg/gg.c	Sun Aug 28 22:46:01 2005 +0000
@@ -1,89 +1,79 @@
+
 /*
- * gaim - Gadu-Gadu Protocol Plugin
- *
- * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * NOTES
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ * I don't like automatic updates of the buddylist stored on the server, so not
+ * going to implement this. Maybe some kind of option to enable/disable this
+ * feature.
  */
+
 #include "internal.h"
 
-/* Library from EKG (Eksperymentalny Klient Gadu-Gadu) */
-#include "libgg.h"
-
-#include "account.h"
-#include "accountopt.h"
+#include "plugin.h"
+#include "version.h"
+#include "notify.h"
+#include "status.h"
 #include "blist.h"
-#include "connection.h"
+#include "accountopt.h"
 #include "debug.h"
-#include "notify.h"
-#include "proxy.h"
-#include "prpl.h"
-#include "server.h"
 #include "util.h"
-#include "version.h"
+#include "request.h"
 
-#define GG_CONNECT_STEPS 5
+#include "lib/libgadu.h"
 
-#define AGG_BUF_LEN 1024
+static GaimPlugin *my_protocol = NULL;
 
-#define AGG_GENDER_NONE -1
+typedef struct
+{
+	char *token_id;
 
-#define AGG_PUBDIR_USERLIST_EXPORT_FORM "/appsvc/fmcontactsput.asp"
-#define AGG_PUBDIR_USERLIST_IMPORT_FORM "/appsvc/fmcontactsget.asp"
-#define AGG_PUBDIR_SEARCH_FORM "/appsvc/fmpubquery2.asp"
-#define AGG_REGISTER_DATA_FORM "/appsvc/fmregister.asp"
-#define AGG_PUBDIR_MAX_ENTRIES 200
+} GGPToken;
+
+typedef struct {
 
-#define AGG_STATUS_AVAIL              _("Available")
-#define AGG_STATUS_AVAIL_FRIENDS      _("Available for friends only")
-#define AGG_STATUS_BUSY               _("Away")
-#define AGG_STATUS_BUSY_FRIENDS       _("Away for friends only")
-#define AGG_STATUS_INVISIBLE          _("Invisible")
-#define AGG_STATUS_INVISIBLE_FRIENDS  _("Invisible for friends only")
-#define AGG_STATUS_NOT_AVAIL          _("Unavailable")
+	char *uin;
+	char *lastname;
+	char *firstname;
+	char *nickname;
+	char *city;
+	char *birthyear;
+	char *gender;
+	char *active;
+	char *offset;
 
-#define AGG_HTTP_NONE			0
-#define AGG_HTTP_SEARCH			1
-#define AGG_HTTP_USERLIST_IMPORT	2
-#define AGG_HTTP_USERLIST_EXPORT	3
-#define AGG_HTTP_USERLIST_DELETE	4
-#define AGG_HTTP_PASSWORD_CHANGE	5
+	char *last_uin;
+
+} GGPSearchForm;
+
+typedef struct {
 
-#define UC_NORMAL 2
+	struct gg_session *session;
+	GGPSearchForm *search_form;
+	GGPToken *register_token;
+	GGPToken *chpasswd_token;
+	void *searchresults_window;
 
-struct agg_data {
-	struct gg_session *sess;
-	int own_status;
-};
+} GGPInfo;
 
-struct agg_http {
-	GaimConnection *gc;
-	gchar *request;
-	gchar *form;
-	gchar *host;
-	int inpa;
-	int type;
-};
-
-
+/**
+ * Convert enconding of a given string.
+ *
+ * @param locstr Input string.
+ * @param encsrc Current encoding of the string.
+ * @param encdst Target encoding of the string.
+ *
+ * @return Converted string (it must be g_free()ed when not used. Or NULL if
+ * locstr is NULL.
+ */
+/* static gchar *charset_convert(const gchar *locstr, const char *encsrc, const char *encdst) {{{ */
 static gchar *charset_convert(const gchar *locstr, const char *encsrc, const char *encdst)
 {
 	gchar *msg;
 	GError *err = NULL;
 
+	if (locstr == NULL)
+		return NULL;
+
 	msg = g_convert_with_fallback(locstr, strlen(locstr), encdst, encsrc, "?", NULL, NULL, &err);
 	if (err != NULL) {
 		gaim_debug_error("gg", "Error converting from %s to %s: %s\n",
@@ -97,673 +87,96 @@
 
 	return msg;
 }
-
-static gboolean invalid_uin(const char *uin)
-{
-	unsigned long int res = strtol(uin, (char **)NULL, 10);
-	if (res == ULONG_MAX || res == 0)
-		return TRUE;
-	return FALSE;
-}
-
-static gint args_compare(gconstpointer a, gconstpointer b)
-{
-	return g_ascii_strcasecmp((const gchar *)a,(const gchar *)b);
-}
-
-static gboolean allowed_uin(GaimConnection *gc, char *uin)
-{
-	GaimAccount *account = gaim_connection_get_account(gc);
-
-	switch (account->perm_deny) {
-	case 1:
-		/* permit all, deny none */
-		return TRUE;
-		break;
-	case 2:
-		/* deny all, permit none. */
-		return FALSE;
-		break;
-	case 3:
-		/* permit some. */
-		if (g_slist_find_custom(gc->account->permit, uin, args_compare))
-			return TRUE;
-		return FALSE;
-		break;
-	case 4:
-		/* deny some. */
-		if (g_slist_find_custom(gc->account->deny, uin, args_compare))
-			return FALSE;
-		return TRUE;
-		break;
-	default:
-		return TRUE;
-		break;
-	}
-}
-
-static char *handle_errcode(GaimConnection *gc, int errcode)
-{
-	static char msg[AGG_BUF_LEN];
-
-	switch (errcode) {
-	case GG_FAILURE_RESOLVING:
-		g_snprintf(msg, sizeof(msg), _("Unable to resolve hostname."));
-		break;
-	case GG_FAILURE_CONNECTING:
-		g_snprintf(msg, sizeof(msg), _("Unable to connect to server."));
-		break;
-	case GG_FAILURE_INVALID:
-		g_snprintf(msg, sizeof(msg), _("Invalid response from server."));
-		break;
-	case GG_FAILURE_READING:
-		g_snprintf(msg, sizeof(msg), _("Error while reading from socket."));
-		break;
-	case GG_FAILURE_WRITING:
-		g_snprintf(msg, sizeof(msg), _("Error while writing to socket."));
-		break;
-	case GG_FAILURE_PASSWORD:
-		g_snprintf(msg, sizeof(msg), _("Authentication failed."));
-		break;
-	default:
-		g_snprintf(msg, sizeof(msg), _("Unknown Error Code."));
-		break;
-	}
-
-	gaim_connection_error(gc, msg);
-
-	return msg;
-}
+/* }}} */
 
-static void agg_set_status(GaimAccount *account, GaimStatus *status)
+/*
+ * Convert string to number. Check wheter a given
+ * string is a correct UIN.
+ *
+ * Return UIN or 0 if an error occurred.
+ */
+/* static uin_t ggp_str_to_uin(const char *text) {{{ */
+static uin_t ggp_str_to_uin(const char *text)
 {
-	GaimConnection *gc;
-	struct agg_data *gd;
-	gboolean connected;
-	GaimStatusType *type;
-	int primitive;
-	int status_num;
-	const char *status_id;
-	char *msg = NULL;
-
-	connected = gaim_account_is_connected(account);
-	type = gaim_status_get_type(status);
-	primitive = gaim_status_type_get_primitive(type);
-
-	if (!gaim_status_is_active(status))
-		return;
-
-	if (!connected) {
-		if (primitive != GAIM_STATUS_OFFLINE)
-			gaim_account_connect(account);
-		return;
-	}
-
-	if (primitive == GAIM_STATUS_OFFLINE) {
-		gaim_account_disconnect(account);
-		return;
-	}
-
-	gc = gaim_account_get_connection(account);
-	gd = (struct agg_data *)gc->proto_data;
-	status_num = gd->own_status;
-	status_id = gaim_status_get_id(status);
-
-	if (!strcmp(status_id, "available"))
-		status_num = GG_STATUS_AVAIL;
-	else if (!strcmp(status_id, "available-friends"))
-		status_num = GG_STATUS_AVAIL | GG_STATUS_FRIENDS_MASK;
-	else if (!strcmp(status_id, "away"))
-		status_num = GG_STATUS_BUSY;
-	else if (!strcmp(status_id, "away-friends"))
-		status_num = GG_STATUS_BUSY | GG_STATUS_FRIENDS_MASK;
-	else if (!strcmp(status_id, "invisible"))
-		status_num = GG_STATUS_INVISIBLE;
-	else if (!strcmp(status_id, "invisible-friends"))
-		status_num = GG_STATUS_INVISIBLE | GG_STATUS_FRIENDS_MASK;
-	else if (!strcmp(status_id, "unavailable"))
-		status_num = GG_STATUS_NOT_AVAIL;
-	else
-		/* Don't need to do anything */
-		return;
-
-	/* XXX: this was added between the status_rewrite and now and needs to be fixed */
-	if (msg != NULL) {
-	    switch (status_num) {
-		case GG_STATUS_AVAIL:
-		    status_num = GG_STATUS_AVAIL_DESCR;
-		    break;
-		case GG_STATUS_BUSY:
-		    status_num = GG_STATUS_BUSY_DESCR;
-		    break;
-		case GG_STATUS_INVISIBLE:
-		    status_num = GG_STATUS_INVISIBLE_DESCR;
-		    break;
-		case GG_STATUS_NOT_AVAIL:
-		    status_num = GG_STATUS_NOT_AVAIL_DESCR;
-		    break;
-	    }
-	}
-
-	gd->own_status = status_num;
-
-	if (msg)
-	    gg_change_status_descr(gd->sess, status_num, msg);
-	else
-	    gg_change_status(gd->sess, status_num);
-}
-
+	char *tmp;
+	long num;
 
-#if 0
-static void agg_get_away(GaimConnection *gc, const char *who)
-{
-    GaimBuddy *buddy;
-    char *dialog_msg, **splitmsg;
-
-    if (invalid_uin(who))
-		return;
-    
-    buddy = gaim_find_buddy(gaim_connection_get_account(gc), who);
-    if (buddy->proto_data) {
-		/* Split at (carriage return/newline)'s, then rejoin later with BRs between. */
-		splitmsg = g_strsplit(buddy->proto_data, "\r\n", 0);
-    
-		dialog_msg = g_strdup_printf(_("<B>UIN:</B> %s<BR><B>Status:</B> %s<HR>%s"), who, (char *)buddy->proto_data, g_strjoinv("<BR>", splitmsg));
-		gaim_notify_userinfo(gc, who, NULL, _("Buddy Information"), buddy->proto_data, dialog_msg, NULL, NULL);
-    }
-}
-#endif
-
-static gchar *get_away_text(GaimBuddy *buddy)
-{
-	GaimPresence *presence = gaim_buddy_get_presence(buddy);
-
-	if (gaim_presence_is_status_active(presence, "available"))
-		return AGG_STATUS_AVAIL;
-	else if (gaim_presence_is_status_active(presence, "available-friends"))
-		return AGG_STATUS_AVAIL_FRIENDS;
-	else if (gaim_presence_is_status_active(presence, "away"))
-		return AGG_STATUS_BUSY;
-	else if (gaim_presence_is_status_active(presence, "away-friends"))
-		return AGG_STATUS_BUSY_FRIENDS;
-	else if (gaim_presence_is_status_active(presence, "invisible"))
-  		return AGG_STATUS_INVISIBLE;
-	else if (gaim_presence_is_status_active(presence, "invisible-friends"))
-  		return AGG_STATUS_INVISIBLE_FRIENDS;
-	else if (gaim_presence_is_status_active(presence, "unavailable"))
-		return AGG_STATUS_NOT_AVAIL;
+	if (!text)
+		return 0;
 
-	return AGG_STATUS_AVAIL;
-}
-
-
-static GList *agg_status_types(GaimAccount *account)
-{
-	GaimStatusType *type;
-	GList *types = NULL;
-
-	type = gaim_status_type_new(GAIM_STATUS_OFFLINE, "offline",
-								_("Offline"), FALSE);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new(GAIM_STATUS_ONLINE, "online",
-								_("Online"), FALSE);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_AVAILABLE, "available", AGG_STATUS_AVAIL,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_AWAY, "away", AGG_STATUS_BUSY,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_HIDDEN, "invisible", AGG_STATUS_INVISIBLE,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_AVAILABLE, "available-friends", AGG_STATUS_AVAIL_FRIENDS,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
+	errno = 0;
+	num = strtol(text, &tmp, 0);
 
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_AWAY, "away-friends", AGG_STATUS_BUSY_FRIENDS,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_HIDDEN, "invisible-friends", AGG_STATUS_INVISIBLE_FRIENDS,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = gaim_status_type_new_with_attrs(
-		GAIM_STATUS_UNAVAILABLE, "unavailable", AGG_STATUS_NOT_AVAIL,
-		TRUE, TRUE, FALSE,
-		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	return types;
-}
-
-/* Enhance these functions, more options and such stuff */
-static GList *agg_buddy_menu(GaimBuddy *buddy)
-{
-	GList *m = NULL;
-	GaimBlistNodeAction *act;
-
-	static char buf[AGG_BUF_LEN];
-	g_snprintf(buf, sizeof(buf), _("Status: %s"), get_away_text(buddy));
-
-	/* um... this seems silly. since in this pass, I'm only converting
-	   over the menu building, I'm not going to mess with it though */
-	/* XXX: shouldn't this be in the tooltip instead? */
-	act = gaim_blist_node_action_new(buf, NULL, NULL, NULL);
-	m = g_list_append(m, act);
-
-	return m;
-}
-
+	if (*text == '\0' || *tmp != '\0')
+		return 0;
 
-static GList *
-agg_blist_node_menu(GaimBlistNode *node)
-{
-	if(GAIM_BLIST_NODE_IS_BUDDY(node)) {
-		return agg_buddy_menu((GaimBuddy *) node);
-	} else {
-		return NULL;
-	}
-}
-
-
-static void agg_load_buddy_list(GaimConnection *gc, char *buddylist)
-{
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	gchar *ptr = buddylist;
-	gchar **users_tbl;
-	int i;
-	uin_t *userlist = NULL;
-	int userlist_size = 0;
+	if ((errno == ERANGE || (num == LONG_MAX || num == LONG_MIN)) || num > UINT_MAX || num < 0)
+		return 0;
 
-	users_tbl = g_strsplit(ptr, "\r\n", AGG_PUBDIR_MAX_ENTRIES);
-
-	/* Parse array of Buddies List */
-	for (i = 0; users_tbl[i] != NULL; i++) {
-		gchar **data_tbl;
-		gchar *name, *show;
-
-		if (strlen(users_tbl[i])==0) {
-			gaim_debug(GAIM_DEBUG_MISC, "gg",
-					   "import_buddies_server_results: users_tbl[i] is empty\n");
-			continue;
-		}
-
-		data_tbl = g_strsplit(users_tbl[i], ";", 8);
-
-		show = charset_convert(data_tbl[3], "CP1250", "UTF-8");
-		name = data_tbl[6];
-
-		if (invalid_uin(name)) {
-			continue;
-		}
+	return (uin_t) num;
+}
+/* }}} */
 
-		gaim_debug(GAIM_DEBUG_MISC, "gg",
-				   "import_buddies_server_results: uin: %s\n", name);
-		if (!gaim_find_buddy(gc->account, name)) {
-			GaimBuddy *b;
-			GaimGroup *g;
-			/* Default group if none specified on server */
-			gchar *group = g_strdup("Gadu-Gadu");
-			if (strlen(data_tbl[5])) {
-				gchar **group_tbl = g_strsplit(data_tbl[5], ",", 2);
-				if (strlen(group_tbl[0])) {
-					g_free(group);
-					group = g_strdup(group_tbl[0]);
-				}
-				g_strfreev(group_tbl);
-			}
-			/* Add Buddy to our userlist */
-			if (!(g = gaim_find_group(group))) {
-				g = gaim_group_new(group);
-				gaim_blist_add_group(g, NULL);
-			}
-			b = gaim_buddy_new(gc->account, name, strlen(show) ? show : NULL);
-			gaim_blist_add_buddy(b,NULL,g,NULL);
-
-			userlist_size++;
-			userlist = g_renew(uin_t, userlist, userlist_size);
-			userlist[userlist_size - 1] =
-			    (uin_t) strtol((char *)name, (char **)NULL, 10);
-
-			g_free(group);
-		}
-		g_free(show);
-		g_strfreev(data_tbl);
-	}
-	g_strfreev(users_tbl);
-
-	if (userlist) {
-	    gg_notify(gd->sess, userlist, userlist_size);
-	    g_free(userlist);
-	}
+/**
+ * Get UIN of a given account.
+ *
+ * @param account Current account.
+ *
+ * @return UIN of an account.
+ */
+/* static ggp_get_uin(GaimAccount *account) {{{ */
+static uin_t ggp_get_uin(GaimAccount *account)
+{
+	return ggp_str_to_uin(gaim_account_get_username(account));
 }
-
-static void agg_save_buddy_list(GaimConnection *gc, char *existlist)
-{
-    struct agg_data *gd = (struct agg_data *)gc->proto_data;
-    GaimBlistNode *gnode, *cnode, *bnode;
-    char *buddylist = g_strdup(existlist ? existlist : "");
-    char *ptr;
-
-    for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
-		GaimGroup *g = (GaimGroup *)gnode;
-		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
-			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
-			if(!GAIM_BLIST_NODE_IS_CONTACT(cnode))
-				continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
-				GaimBuddy *b = (GaimBuddy *)bnode;
-
-				if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
-					continue;
-
-				if(b->account == gc->account) {
-					gchar *newdata;
-					/* GG Number */
-					gchar *name = b->name;
-					/* GG Pseudo */
-					gchar *show = b->alias ? b->alias : b->name;
-					/* Group Name */
-					gchar *gname = g->name;
-
-					newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s;%s%s\r\n",
-							show, show, show, show, "", gname, name, "", "");
-
-					ptr = buddylist;
-					buddylist = g_strconcat(ptr, newdata, NULL);
-
-					g_free(newdata);
-					g_free(ptr);
-				}
-			}
-		}
-	}
+/* }}} */
 
-	/* save the list to the gadu gadu server */
-	gg_userlist_request(gd->sess, GG_USERLIST_PUT, buddylist);
-}
-
-static void main_callback(gpointer data, gint source, GaimInputCondition cond)
+/**
+ * Create a new GGPSearchForm structure, and set the fields
+ * to the sane defaults.
+ *
+ * @return Newly allocated GGPSearchForm.
+ */
+/* GGPSearchForm *ggp_searchform_new() {{{ */
+GGPSearchForm *ggp_searchform_new()
 {
-	GaimConnection *gc = data;
-	GaimAccount *account = gaim_connection_get_account(gc);
-	struct agg_data *gd = gc->proto_data;
-	struct gg_event *e;
-
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "main_callback enter: begin\n");
-
-	if (gd->sess->fd != source)
-		gd->sess->fd = source;
-
-	if (source == 0) {
-		gaim_connection_error(gc, _("Could not connect"));
-		return;
-	}
-
-	if (!(e = gg_watch_fd(gd->sess))) {
-		gaim_debug(GAIM_DEBUG_ERROR, "gg",
-				   "main_callback: gg_watch_fd failed - CRITICAL!\n");
-		gaim_connection_error(gc, _("Unable to read socket"));
-		return;
-	}
-
-	switch (e->type) {
-	case GG_EVENT_NONE:
-		/* do nothing */
-		break;
-	case GG_EVENT_CONN_SUCCESS:
-		gaim_debug(GAIM_DEBUG_WARNING, "gg",
-				   "main_callback: CONNECTED AGAIN!?\n");
-		break;
-	case GG_EVENT_CONN_FAILED:
-		if (gc->inpa)
-			gaim_input_remove(gc->inpa);
-		handle_errcode(gc, e->event.failure);
-		break;
-	case GG_EVENT_MSG:
-		{
-			gchar *imsg;
-			gchar *jmsg;
-			gchar user[20];
-
-			g_snprintf(user, sizeof(user), "%lu", e->event.msg.sender);
-			if (!allowed_uin(gc, user))
-				break;
-			imsg = charset_convert(e->event.msg.message, "CP1250", "UTF-8");
-			gaim_str_strip_cr(imsg);
-			jmsg = g_markup_escape_text(imsg, -1);
-			serv_got_im(gc, user, jmsg, 0, e->event.msg.time);
-			g_free(imsg);
-			g_free(jmsg);
-		}
-		break;
-	case GG_EVENT_NOTIFY:
-		{
-			gchar user[20];
-			struct gg_notify_reply *n = e->event.notify;
-			const char *status_id;
-
-			while (n->uin) {
-				switch (n->status) {
-					case GG_STATUS_NOT_AVAIL:
-						status_id = "unavailable";
-						break;
-
-					case GG_STATUS_AVAIL:
-						status_id = "available";
-						break;
-
-					case GG_STATUS_BUSY:
-						status_id = "away";
-						break;
-
-					case GG_STATUS_INVISIBLE:
-						status_id = "invisible";
-						break;
-
-					default:
-						status_id = "available";
-						break;
-
-				}
+	GGPSearchForm *form;
 
-				g_snprintf(user, sizeof(user), "%lu", n->uin);
-				gaim_prpl_got_user_status(account, user, status_id, NULL);
-				n++;
-			}
-		}
-		break;
-	case GG_EVENT_NOTIFY60:
-		{
-			gchar user[20];
-			const char *status_id;
-			guint i = 0;
-
-			for (i = 0; e->event.notify60[i].uin; i++) {
-				GaimBuddy *buddy;
-				
-				g_snprintf(user, sizeof(user), "%lu", (long unsigned int)e->event.notify60[i].uin);
-
-				buddy = gaim_find_buddy(gaim_connection_get_account(gc), user);
-				if (buddy && buddy->proto_data != NULL) {
-					g_free(buddy->proto_data);
-					buddy->proto_data = NULL;
-				}
-			
-				switch (e->event.notify60[i].status) {
-					case GG_STATUS_NOT_AVAIL:
-					case GG_STATUS_NOT_AVAIL_DESCR:
-						status_id = "unavailable";
-						break;
-
-					case GG_STATUS_AVAIL:
-					case GG_STATUS_AVAIL_DESCR:
-						status_id = "available";
-						break;
-
-					case GG_STATUS_BUSY:
-					case GG_STATUS_BUSY_DESCR:
-						status_id = "away";
-						break;
+	form = g_new0(GGPSearchForm, 1);
+	form->uin = NULL;
+	form->lastname = NULL;
+	form->firstname = NULL;
+	form->nickname = NULL;
+	form->city = NULL;
+	form->birthyear = NULL;
+	form->gender = NULL;
+	form->active = NULL;
+	form->offset = NULL;
 
-					case GG_STATUS_INVISIBLE:
-					case GG_STATUS_INVISIBLE_DESCR:
-						status_id = "invisible";
-						break;
-
-					default:
-						status_id = "available";
-						break;
-				}
-				
-				if (buddy && e->event.notify60[i].descr != NULL) {
-					buddy->proto_data = g_strdup(e->event.notify60[i].descr);
-				}
-
-				gaim_prpl_got_user_status(account, user, status_id, NULL);
-				i++;
-			}
-		}
-		break;
-	case GG_EVENT_STATUS:
-		{
-			gchar user[20];
-			const char *status_id;
-
-			switch (e->event.status.status) {
- 				case GG_STATUS_NOT_AVAIL:
-					status_id = "unavailable";
-					break;
-
-				case GG_STATUS_AVAIL:
-					status_id = "available";
-					break;
-
-				case GG_STATUS_BUSY:
-					status_id = "away";
-					break;
-
-				case GG_STATUS_INVISIBLE:
-					status_id = "invisible";
-					break;
-
-				default:
-					status_id = "available";
-					break;
-			}
+	form->last_uin = NULL;
 
-			g_snprintf(user, sizeof(user), "%lu", e->event.status.uin);
-			gaim_prpl_got_user_status(account, user, status_id, NULL);
-		}
-		break;
-	case GG_EVENT_STATUS60:
-		{
-			gchar user[20];
-			const char *status_id;
-
-			GaimBuddy *buddy;
-				
-			g_snprintf(user, sizeof(user), "%lu", e->event.status60.uin);
-
-			buddy = gaim_find_buddy(gaim_connection_get_account(gc), user);
-			if (buddy && buddy->proto_data != NULL) {
-				g_free(buddy->proto_data);
-				buddy->proto_data = NULL;
-			}
+	return form;
+}
+/* }}} */
 
-			switch (e->event.status60.status) {
-				case GG_STATUS_NOT_AVAIL_DESCR:
-				case GG_STATUS_NOT_AVAIL:
-					status_id = "unavailable";
-					break;
-
-				case GG_STATUS_AVAIL:
-				case GG_STATUS_AVAIL_DESCR:
-					status_id = "available";
-					break;
-
-				case GG_STATUS_BUSY:
-				case GG_STATUS_BUSY_DESCR:
-					status_id = "away";
-					break;
-
-				case GG_STATUS_INVISIBLE:
-				case GG_STATUS_INVISIBLE_DESCR:
-					status_id = "invisible";
-					break;
+/* ---------------------------------------------------------------------- */
+/* ----- BUDDYLIST STUFF ------------------------------------------------ */
+/* ---------------------------------------------------------------------- */
 
-				default:
-					status_id = "available";
-					break;
-			}
- 
-			if (buddy && e->event.status60.descr != NULL) {
-				buddy->proto_data = g_strdup(e->event.status60.descr);
-			}
-
-			gaim_prpl_got_user_status(account, user, status_id, NULL);
-		}
-		break;
-	case GG_EVENT_ACK:
-		gaim_debug(GAIM_DEBUG_MISC, "gg",
-				   "main_callback: message %d to %lu sent with status %d\n",
-			     e->event.ack.seq, e->event.ack.recipient, e->event.ack.status);
-		break;
-	case GG_EVENT_USERLIST:
-	{
-	    gaim_debug(GAIM_DEBUG_MISC, "gg", "main_callback: received userlist reply\n");
-	    switch (e->event.userlist.type) {
-		case GG_USERLIST_GET_REPLY:
-		{
+/*
+ * Adapted from the previous GG implementation in Gaim
+ * by Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ */
+/* static void ggp_buddylist_send(GaimConnection *gc) {{{ */
+static void ggp_buddylist_send(GaimConnection *gc)
+{
+	GGPInfo *info = gc->proto_data;
 
-			if (e->event.userlist.reply) {
-			    agg_load_buddy_list(gc, e->event.userlist.reply);
-			}
-			break;
-		}
-
-		case GG_USERLIST_PUT_REPLY:
-		{
-		    /* ignored */
-		}
-	    }
-	}
-
-	default:
-		gaim_debug(GAIM_DEBUG_ERROR, "gg",
-				   "main_callback: unsupported event %d\n", e->type);
-		break;
-	}
-	gg_free_event(e);
-}
-
-static void agg_send_buddylist(GaimConnection *gc)
-{
 	GaimBuddyList *blist;
 	GaimBlistNode *gnode, *cnode, *bnode;
 	GaimBuddy *buddy;
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
 	uin_t *userlist = NULL;
+	gchar *types = NULL;
 	int userlist_size = 0;
 
 	if ((blist = gaim_get_blist()) != NULL)
@@ -781,1061 +194,1612 @@
 					if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
 						continue;
 					buddy = (GaimBuddy *)bnode;
-					if (invalid_uin(buddy->name))
+
+					if (buddy->account != gc->account)
 						continue;
+
 					userlist_size++;
-					userlist = g_renew(uin_t, userlist, userlist_size);
-					userlist[userlist_size - 1] =
-					    (uin_t) strtol(buddy->name, (char **)NULL, 10);
+					userlist = (uin_t *) g_renew(uin_t, userlist, userlist_size);
+					types = (gchar *) g_renew(gchar, types, userlist_size);
+					userlist[userlist_size - 1] = ggp_str_to_uin(buddy->name);
+					types[userlist_size - 1] = GG_USER_NORMAL;
+					gaim_debug_info("gg", "ggp_buddylist_send: adding %d\n", userlist[userlist_size - 1]);
 				}
 			}
 		}
 	}
 
 	if (userlist) {
-		gg_notify(gd->sess, userlist, userlist_size);
+		int ret = gg_notify_ex(info->session, userlist, types, userlist_size);
 		g_free(userlist);
-	}
-
-	agg_save_buddy_list(gc, NULL);
-}
-
-void login_callback(gpointer data, gint source, GaimInputCondition cond)
-{
-	GaimConnection *gc = data;
-	struct agg_data *gd = gc->proto_data;
-	struct gg_event *e;
-
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "login_callback...\n");
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "Found GG connection\n");
-
-	if (source == 0) {
-		gaim_connection_error(gc, _("Unable to connect."));
-		return;
-	}
-
-	gd->sess->fd = source;
-
-	gaim_debug(GAIM_DEBUG_MISC, "gg", "Source is valid.\n");
-	if (gc->inpa == 0) {
-		gaim_debug(GAIM_DEBUG_MISC, "gg",
-				   "login_callback.. checking gc->inpa .. is 0.. setting fd watch\n");
-		gc->inpa = gaim_input_add(gd->sess->fd, GAIM_INPUT_READ, login_callback, gc);
-		gaim_debug(GAIM_DEBUG_INFO, "gg", "Adding watch on fd\n"); 
-	}
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "Checking State.\n");
-	switch (gd->sess->state) {
-	case GG_STATE_READING_DATA:
-		gaim_connection_update_progress(gc, _("Reading data"), 1, GG_CONNECT_STEPS);
-		break;
-	case GG_STATE_CONNECTING_GG:
-		gaim_connection_update_progress(gc, _("Balancer handshake"), 2, GG_CONNECT_STEPS);
-		break;
-	case GG_STATE_READING_KEY:
-		gaim_connection_update_progress(gc, _("Reading server key"), 3, GG_CONNECT_STEPS);
-		break;
-	case GG_STATE_READING_REPLY:
-		gaim_connection_update_progress(gc, _("Exchanging key hash"), 4, GG_CONNECT_STEPS);
-		break;
-	default:
-		gaim_debug(GAIM_DEBUG_INFO, "gg", "No State found\n");
-		break;
-	}
-	gaim_debug(GAIM_DEBUG_MISC, "gg", "gg_watch_fd\n");
-	if (!(e = gg_watch_fd(gd->sess))) {
-		gaim_debug(GAIM_DEBUG_ERROR, "gg",
-				   "login_callback: gg_watch_fd failed - CRITICAL!\n");
-		gaim_connection_error(gc, _("Critical error in GG library\n"));
-		return;
-	}
-
-	/* If we are GG_STATE_CONNECTING_GG then we still need to connect, as
-	   we could not use gaim_proxy_connect in libgg.c */
-	switch( gd->sess->state ) {
-	case GG_STATE_CONNECTING_GG:
-		{
-			struct in_addr ip;
-			char buf[256];
-
-			/* Remove watch on initial socket - now that we have ip and port of login server */
-			gaim_input_remove(gc->inpa);
-
-			ip.s_addr = gd->sess->server_ip;
+		g_free(types);
 
-			if (gaim_proxy_connect(gc->account, inet_ntoa(ip), gd->sess->port, login_callback, gc) < 0) {
-				g_snprintf(buf, sizeof(buf), _("Connect to %s failed"), inet_ntoa(ip));
-				gaim_connection_error(gc, buf);
-				return;
-			}
-			break;
-		}
-	case GG_STATE_READING_KEY:
-		/* Set new watch on login server ip */
-		if(gc->inpa)
-			gc->inpa = gaim_input_add(gd->sess->fd, GAIM_INPUT_READ, login_callback, gc);
-		gaim_debug(GAIM_DEBUG_INFO, "gg",
-				   "Setting watch on connection with login server.\n"); 
-		break;
-	}/* end switch() */
-
-	gaim_debug(GAIM_DEBUG_MISC, "gg", "checking gg_event\n");
-	switch (e->type) {
-	case GG_EVENT_NONE:
-		/* nothing */
-		break;
-	case GG_EVENT_CONN_SUCCESS:
-		/* Setup new input handler */
-		if (gc->inpa)
-			gaim_input_remove(gc->inpa);
-		gc->inpa = gaim_input_add(gd->sess->fd, GAIM_INPUT_READ, main_callback, gc);
-
-		/* Our signon is complete */
-		gaim_connection_set_state(gc, GAIM_CONNECTED);
-
-		/* Send the server our buddy list */
-		agg_send_buddylist(gc);
-
-		break;
-	case GG_EVENT_CONN_FAILED:
-		gaim_input_remove(gc->inpa);
-		gc->inpa = 0;
-		handle_errcode(gc, e->event.failure);
-		break;
-	default:
-		gaim_debug(GAIM_DEBUG_MISC, "gg", "no gg_event\n");
-		break;
-	}
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "Returning from login_callback\n");
-	gg_free_event(e);
-}
-
-static void agg_keepalive(GaimConnection *gc)
-{
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	if (gg_ping(gd->sess) < 0) {
-		gaim_connection_error(gc, _("Unable to ping server"));
-		return;
-	}
-}
-
-static void agg_login(GaimAccount *account, GaimStatus *status)
-{
-	GaimConnection *gc = gaim_account_get_connection(account);
-	struct agg_data *gd = gc->proto_data = g_new0(struct agg_data, 1);
-	char buf[80];
-
-#if 0
-	gc->checkbox = _("Send as message");
-#endif
-
-	gd->sess = g_new0(struct gg_session, 1);
-
-	gaim_connection_update_progress(gc, _("Looking up GG server"), 0, GG_CONNECT_STEPS);
-
-	if (invalid_uin(account->username)) {
-		gaim_connection_error(gc, _("Invalid Gadu-Gadu UIN specified"));
-		return;
-	}
-
-	gc->inpa = 0;
-
-	/*
-	   if (gg_login(gd->sess, strtol(user->username, (char **)NULL, 10), user->password, 1) < 0) {
-	   gaim_debug(GAIM_DEBUG_MISC, "gg", "uin=%u, pass=%s", strtol(user->username, (char **)NULL, 10), user->password); 
-	   gaim_connection_error(gc, _("Unable to connect."));
-	   signoff(gc);
-	   return;
-	   }
-
-	   gg_login() sucks for me, so I'm using gaim_proxy_connect()
-	 */
-
-	gd->sess->uin = (uin_t) strtol(account->username, (char **)NULL, 10);
-	gd->sess->password = g_strdup(gaim_connection_get_password(gc));
-	gd->sess->state = GG_STATE_CONNECTING;
-	gd->sess->check = GG_CHECK_WRITE;
-	gd->sess->async = 1;
-	if (gaim_proxy_connect(account, GG_APPMSG_HOST, GG_APPMSG_PORT, login_callback, gc) < 0) {
-		g_snprintf(buf, sizeof(buf), _("Connect to %s failed"), GG_APPMSG_HOST);
-		gaim_connection_error(gc, buf);
-		return;
+		gaim_debug_info("gg", "send: ret=%d; size=%d\n", ret, userlist_size);
 	}
 }
-
-static void agg_close(GaimConnection *gc)
-{
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	if (gc->inpa)
-		gaim_input_remove(gc->inpa);
-	gg_logoff(gd->sess);
-	gd->own_status = GG_STATUS_NOT_AVAIL;
-	gg_free_session(gd->sess);
-	g_free(gc->proto_data);
-}
-
-static int agg_send_im(GaimConnection *gc, const char *who, const char *msg, GaimConvImFlags flags)
-{
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-
-	if (invalid_uin(who)) {
-		gaim_notify_error(gc, NULL,
-						  _("You are trying to send a message to an "
-							"invalid Gadu-Gadu UIN."), NULL);
-		return -1;
-	}
-
-	if (strlen(msg) > 0) {
-		gchar *imsg = charset_convert(msg, "UTF-8", "CP1250");
-		if (imsg != NULL && strlen(imsg) > 0) {
-			if (gg_send_message(gd->sess, GG_CLASS_CHAT,
-				    strtol(who, (char **)NULL, 10), imsg) < 0)
-				return -1;
-		}
-		if (imsg != NULL)
-			g_free(imsg);
-	}
-	return 1;
-}
-
-static void agg_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
-{
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	if (invalid_uin(buddy->name))
-		return;
-	gg_add_notify(gd->sess, strtol(buddy->name, (char **)NULL, 10));
-	agg_save_buddy_list(gc, NULL);
-}
-
-static void agg_rem_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
-{
-	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	if (invalid_uin(buddy->name))
-		return;
-	gg_remove_notify(gd->sess, strtol(buddy->name, (char **)NULL, 10));
-	agg_save_buddy_list(gc, NULL);
-}
-
-static void agg_buddy_free (GaimBuddy *buddy)
-{
-    if (buddy->proto_data) {
-	g_free(buddy->proto_data);
-	buddy->proto_data = NULL;
-    }
-}
-
-static void search_results(GaimConnection *gc, gchar *webdata)
-{
-	gchar **webdata_tbl;
-	gchar *buf;
-	char *ptr;
-	int i, j;
-
-	if ((ptr = strstr(webdata, "query_results:")) == NULL || (ptr = strchr(ptr, '\n')) == NULL) {
-		gaim_debug(GAIM_DEBUG_MISC, "gg", "search_callback: pubdir result [%s]\n", webdata);
-		gaim_notify_error(gc, NULL, _("Couldn't get search results"), NULL);
-		return;
-	}
-	ptr++;
-
-	buf = g_strconcat("<B>", _("Gadu-Gadu Search Engine"), "</B><BR>\n", NULL);
-
-	webdata_tbl = g_strsplit(ptr, "\n", AGG_PUBDIR_MAX_ENTRIES);
-
-	j = 0;
-
-	/* Parse array */
-	/* XXX - Make this use a GString */
-	for (i = 0; webdata_tbl[i] != NULL; i++) {
-		gchar *p, *oldibuf;
-		static gchar *ibuf;
-
-		g_strdelimit(webdata_tbl[i], "\t\n", ' ');
+/* }}} */
 
-		/* GG_PUBDIR_HOST service returns 7 lines of data per directory entry */
-		if (i % 8 == 0)
-			j = 0;
-
-		p = charset_convert(g_strstrip(webdata_tbl[i]), "CP1250", "UTF-8");
-
-		oldibuf = ibuf;
-
-		switch (j) {
-		case 0:
-			ibuf = g_strconcat("---------------------------------<BR>\n", NULL);
-			oldibuf = ibuf;
-			ibuf = g_strconcat(oldibuf, "<B>", _("Active"), ":</B> ",
-					   (atoi(p) == 2) ? _("Yes") : _("No"), "<BR>\n", NULL);
-			g_free(oldibuf);
-			break;
-		case 1:
-			ibuf = g_strconcat(oldibuf, "<B>", _("UIN"), ":</B> ", p, "<BR>\n", NULL);
-			g_free(oldibuf);
-			break;
-		case 2:
-			ibuf = g_strconcat(oldibuf, "<B>", _("First Name"), ":</B> ", p, "<BR>\n", NULL);
-			g_free(oldibuf);
-			break;
-		case 3:
-			ibuf =
-			    g_strconcat(oldibuf, "<B>", _("Last Name"), ":</B> ", p, "<BR>\n", NULL);
-			g_free(oldibuf);
-			break;
-		case 4:
-			ibuf = g_strconcat(oldibuf, "<B>", _("Nick"), ":</B> ", p, "<BR>\n", NULL);
-			g_free(oldibuf);
-			break;
-		case 5:
-			/* Hack, invalid_uin does what we really want here but may change in future */
-			if (invalid_uin(p))
-				ibuf =
-				    g_strconcat(oldibuf, "<B>", _("Birth Year"), ":</B> <BR>\n", NULL);
-			else
-				ibuf =
-				    g_strconcat(oldibuf, "<B>", _("Birth Year"), ":</B> ", p, "<BR>\n",
-						NULL);
-			g_free(oldibuf);
-			break;
-		case 6:
-			if (atoi(p) == GG_GENDER_FEMALE)
-				ibuf = g_strconcat(oldibuf, "<B>", _("Sex"), ":</B> woman<BR>\n", NULL);
-			else if (atoi(p) == GG_GENDER_MALE)
-				ibuf = g_strconcat(oldibuf, "<B>", _("Sex"), ":</B> man<BR>\n", NULL);
-			else
-				ibuf = g_strconcat(oldibuf, "<B>", _("Sex"), ":</B> <BR>\n", NULL);
-			g_free(oldibuf);
-			break;
-		case 7:
-			ibuf = g_strconcat(oldibuf, "<B>", _("City"), ":</B> ", p, "<BR>\n", NULL);
-			g_free(oldibuf);
-
-			/* We have all lines, so add them to buffer */
-			{
-				gchar *oldbuf = buf;
-				buf = g_strconcat(oldbuf, ibuf, NULL);
-				g_free(oldbuf);
-			}
-
-			g_free(ibuf);
-			break;
-		}
-
-		g_free(p);
-
-		j++;
-	}
-
-	g_strfreev(webdata_tbl);
-
-	gaim_notify_formatted(gc, NULL, _("Buddy Information"), NULL,
-						  buf, NULL, NULL);
-
-	g_free(buf);
-}
-
-static void
-change_pass(GaimPluginAction *action)
+/**
+ * Load buddylist from server into the rooster.
+ *
+ * @param gc GaimConnection
+ * @param buddylist Pointer to the buddylist that will be loaded.
+ */
+/* static void ggp_buddylist_load(GaimConnection *gc, char *buddylist) {{{ */
+static void ggp_buddylist_load(GaimConnection *gc, char *buddylist)
 {
-	GaimConnection *gc = (GaimConnection *) action->context;
-	GaimAccount *account = gaim_connection_get_account(gc);
-	gaim_account_request_change_password(account);
-}
-
-#if 0
-static void import_buddies_server_results(GaimConnection *gc, gchar *webdata)
-{
-	gchar *ptr;
+	GaimBuddy *buddy;
+	GaimGroup *group;
 	gchar **users_tbl;
 	int i;
-	if (strstr(webdata, "no_data:")) {
-		gaim_notify_error(gc, NULL,
-						  _("There is no Buddy List stored on the "
-							"Gadu-Gadu server."), NULL);
-		return;
-	}
 
-	if ((ptr = strstr(webdata, "get_results:")) == NULL || (ptr = strchr(ptr, ':')) == NULL) {
-		gaim_debug(GAIM_DEBUG_MISC, "gg", "import_buddies_server_results: import buddies result [%s]\n", webdata);
-		gaim_notify_error(gc, NULL,
-						  _("Couldn't Import Buddy List from Server"), NULL);
-		return;
-	}
-	ptr++;
+	users_tbl = g_strsplit(buddylist, "\r\n", 200);
 
-	users_tbl = g_strsplit(ptr, "\n", AGG_PUBDIR_MAX_ENTRIES);
-
-	/* Parse array of Buddies List */
 	for (i = 0; users_tbl[i] != NULL; i++) {
 		gchar **data_tbl;
 		gchar *name, *show;
 
-		if (strlen(users_tbl[i])==0) {
-			gaim_debug(GAIM_DEBUG_MISC, "gg",
-					   "import_buddies_server_results: users_tbl[i] is empty\n");
+		if (strlen(users_tbl[i]) == 0)
 			continue;
-		}
 
-		g_strdelimit(users_tbl[i], "\r\t\n\015", ' ');
 		data_tbl = g_strsplit(users_tbl[i], ";", 8);
 
 		show = charset_convert(data_tbl[3], "CP1250", "UTF-8");
 		name = data_tbl[6];
 
-		if (invalid_uin(name)) {
+		gaim_debug_info("gg", "got buddy: name=%s show=%s\n", name, show);
+
+		if (gaim_find_buddy(gaim_connection_get_account(gc), name)) {
+			g_free(show);
+			g_strfreev(data_tbl);
 			continue;
 		}
 
-		gaim_debug(GAIM_DEBUG_MISC, "gg",
-				   "import_buddies_server_results: uin: %s\n", name);
-		if (!gaim_find_buddy(gc->account, name)) {
-			GaimBuddy *b;
-			GaimGroup *g;
-			/* Default group if none specified on server */
-			gchar *group = g_strdup("Gadu-Gadu");
-			if (strlen(data_tbl[5])) {
-				gchar **group_tbl = g_strsplit(data_tbl[5], ",", 2);
-				if (strlen(group_tbl[0])) {
-					g_free(group);
-					group = g_strdup(group_tbl[0]);
-				}
-				g_strfreev(group_tbl);
+		gchar *g = g_strdup("Gadu-Gadu");
+
+		if (strlen(data_tbl[5])) {
+			/* Hard limit to at most 50 groups */
+			gchar **group_tbl = g_strsplit(data_tbl[5], ",", 50);
+			if (strlen(group_tbl[0]) > 0) {
+				g_free(g);
+				g = g_strdup(group_tbl[0]);
 			}
-			/* Add Buddy to our userlist */
-			if (!(g = gaim_find_group(group))) {
-				g = gaim_group_new(group);
-				gaim_blist_add_group(g, NULL);
-			}
-			b = gaim_buddy_new(gc->account, name, strlen(show) ? show : NULL);
-			gaim_blist_add_buddy(b, NULL, g, NULL);
-			g_free(group);
+			g_strfreev(group_tbl);
 		}
+
+		buddy = gaim_buddy_new(gaim_connection_get_account(gc), name, strlen(show) ? show : NULL);
+		if (!(group = gaim_find_group(g))) {
+			group = gaim_group_new(g);
+			gaim_blist_add_group(group, NULL);
+		}
+
+		gaim_blist_add_buddy(buddy, NULL, group, NULL);
+		g_free(g);
+
 		g_free(show);
 		g_strfreev(data_tbl);
 	}
 	g_strfreev(users_tbl);
-}
+
+	ggp_buddylist_send(gc);
 
-static void export_buddies_server_results(GaimConnection *gc, gchar *webdata)
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_generic_status_handler(GaimConnection *gc, uin_t uin, int status, const char *descr) {{{ */
+static void ggp_generic_status_handler(GaimConnection *gc, uin_t uin, int status, const char *descr)
 {
-	if (strstr(webdata, "put_success:")) {
-		gaim_notify_info(gc, NULL,
-						 _("Buddy List successfully transferred to "
-						   "Gadu-Gadu server"), NULL);
-		return;
+	gchar *from;
+	const char *st;
+	gchar *msg;
+
+	from = g_strdup_printf("%ld", (unsigned long int)uin);
+	switch (status) {
+		case GG_STATUS_NOT_AVAIL:
+		case GG_STATUS_NOT_AVAIL_DESCR:
+			st = "offline";
+			break;
+		case GG_STATUS_AVAIL:
+		case GG_STATUS_AVAIL_DESCR:
+			st = "online";
+			break;
+		case GG_STATUS_BUSY:
+		case GG_STATUS_BUSY_DESCR:
+			st = "away";
+			break;
+		case GG_STATUS_BLOCKED:
+			/* user is blocking us.... */
+			st = "blocked";
+			break;
+		default:
+			st = "online";
+			gaim_debug_info("gg", "GG_EVENT_NOTIFY: Unknown status: %d\n", status);
+			break;
 	}
 
-	gaim_debug(GAIM_DEBUG_MISC, "gg",
-			   "export_buddies_server_results: webdata [%s]\n", webdata);
-	gaim_notify_error(gc, NULL,
-					  _("Couldn't transfer Buddy List to Gadu-Gadu server"),
-					  NULL);
+	gaim_debug_info("gg", "st = %s\n", st);
+	msg = charset_convert(descr, "CP1250", "UTF-8");
+	gaim_prpl_got_user_status(gaim_connection_get_account(gc), from, st, "message", msg, NULL);
+	g_free(from);
+	g_free(msg);
 }
+/* }}} */
 
-static void delete_buddies_server_results(GaimConnection *gc, gchar *webdata)
+/*
+ */
+/* static void ggp_pubdir_start_search(GaimConnection *gc, GGPSearchForm *form) {{{ */
+static void ggp_pubdir_start_search(GaimConnection *gc, GGPSearchForm *form)
 {
-	if (strstr(webdata, "put_success:")) {
-		gaim_notify_info(gc, NULL,
-						 _("Buddy List successfully deleted from "
-						   "Gadu-Gadu server"), NULL);
+	GGPInfo *info = gc->proto_data;
+	gg_pubdir50_t req;
+
+	gaim_debug_info("gg", "It's time to perform a search...\n");
+
+	if ((req = gg_pubdir50_new(GG_PUBDIR50_SEARCH)) == NULL) {
+		gaim_debug_error("gg", "ggp_bmenu_show_details: Unable to create req variable.\n");
 		return;
 	}
 
-	gaim_debug(GAIM_DEBUG_MISC, "gg",
-			   "delete_buddies_server_results: webdata [%s]\n", webdata);
-	gaim_notify_error(gc, NULL,
-					  _("Couldn't delete Buddy List from Gadu-Gadu server"),
-					  NULL);
-}
-#endif
+	if (form->uin != NULL) {
+		gaim_debug_info("gg", "    uin: %s\n", form->uin);
+		gg_pubdir50_add(req, GG_PUBDIR50_UIN, form->uin);
+	} else {
+		if (form->lastname != NULL) {
+			gaim_debug_info("gg", "    lastname: %s\n", form->lastname);
+			gg_pubdir50_add(req, GG_PUBDIR50_LASTNAME, form->lastname);
+		}
+
+		if (form->firstname != NULL) {
+			gaim_debug_info("gg", "    firstname: %s\n", form->firstname);
+			gg_pubdir50_add(req, GG_PUBDIR50_FIRSTNAME, form->firstname);
+		}
+
+		if (form->nickname != NULL) {
+			gaim_debug_info("gg", "    nickname: %s\n", form->nickname);
+			gg_pubdir50_add(req, GG_PUBDIR50_NICKNAME, form->nickname);
+		}
 
-static void password_change_server_results(GaimConnection *gc, gchar *webdata)
-{
-	if (strstr(webdata, "reg_success:")) {
-		gaim_notify_info(gc, NULL,
-						 _("Password changed successfully"), NULL);
+		if (form->city != NULL) {
+			gaim_debug_info("gg", "    city: %s\n", form->city);
+			gg_pubdir50_add(req, GG_PUBDIR50_CITY, form->city);
+		}
+
+		if (form->birthyear != NULL) {
+			gaim_debug_info("gg", "    birthyear: %s\n", form->birthyear);
+			gg_pubdir50_add(req, GG_PUBDIR50_BIRTHYEAR, form->birthyear);
+		}
+
+		if (form->gender != NULL) {
+			gaim_debug_info("gg", "    gender: %s\n", form->gender);
+			gg_pubdir50_add(req, GG_PUBDIR50_GENDER, form->gender);
+		}
+
+		if (form->active != NULL) {
+			gaim_debug_info("gg", "    active: %s\n", form->active);
+			gg_pubdir50_add(req, GG_PUBDIR50_ACTIVE, form->active);
+		}
+	}
+
+	gaim_debug_info("gg", "offset: %s\n", form->offset);
+	gg_pubdir50_add(req, GG_PUBDIR50_START, g_strdup(form->offset));
+
+	if (gg_pubdir50(info->session, req) == 0) {
+		gaim_debug_warning("gg", "ggp_bmenu_show_details: Search failed.\n");
 		return;
 	}
 
-	gaim_debug(GAIM_DEBUG_MISC, "gg",
-			   "password_change_server_results: webdata [%s]\n", webdata);
-	gaim_notify_error(gc, NULL,
-					  _("Password couldn't be changed"), NULL);
+	gg_pubdir50_free(req);
+}
+/* }}} */
+
+/*
+ * Return converted to the UTF-8 value of the specified field.
+ *
+ * @param res    Public directory look-up result
+ * @param num    Id of the record
+ * @param fileld Name of the field
+ * 
+ * @return UTF-8 encoded value of the field
+ */
+/* static char *ggp_get_pubdir_info(gg_pubdir50_t res, int num, const char *field) {{{ */
+static char *ggp_get_pubdir_info(gg_pubdir50_t res, int num, const char *field)
+{
+	char *tmp;
+
+	tmp = charset_convert(gg_pubdir50_get(res, num, field), "CP1250", "UTF-8");
+
+	return (tmp == NULL) ? g_strdup("") : tmp;
+}
+/* }}} */
+
+static void ggp_callback_show_next(GaimConnection *gc, GList *row)
+{
+	GGPInfo *info = gc->proto_data;
+
+	g_free(info->search_form->offset);
+	info->search_form->offset = g_strdup(info->search_form->last_uin);
+	gaim_debug_info("gg", "london calling... offset = %s\n", info->search_form->offset);
+	ggp_pubdir_start_search(gc, info->search_form);
 }
 
-static void http_results(gpointer data, gint source, GaimInputCondition cond)
+static void ggp_callback_add_buddy(GaimConnection *gc, GList *row)
 {
-	struct agg_http *hdata = data;
-	GaimConnection *gc = hdata->gc;
-	char *webdata;
-	int len;
-	char read_data;
+	gaim_blist_request_add_buddy(gaim_connection_get_account(gc),
+			g_list_nth_data(row, 0), NULL, NULL);
+}
 
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "http_results: begin\n");
+/*
+ */
+/* static void ggp_callback_recv(gpointer _gc, gint fd, GaimInputCondition cond) {{{ */
+static void ggp_callback_recv(gpointer _gc, gint fd, GaimInputCondition cond)
+{
+	GaimConnection *gc = _gc;
+	GGPInfo *info = gc->proto_data;
+	struct gg_event *ev;
+	int i;
 
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		gaim_debug(GAIM_DEBUG_ERROR, "gg",
-				   "search_callback: g_slist_find error\n");
-		gaim_input_remove(hdata->inpa);
-		g_free(hdata);
-		close(source);
+	if (!(ev = gg_watch_fd(info->session))) {
+		gaim_debug_error("gg", "ggp_callback_recv: gg_watch_fd failed -- CRITICAL!\n");
+		gaim_connection_error(gc, _("Unable to read socket"));
 		return;
 	}
 
-	webdata = NULL;
-	len = 0;
+	switch (ev->type) {
+		case GG_EVENT_NONE:
+			/* Nothing happened. */
+			break;
+		case GG_EVENT_MSG:
+			{
+				gchar *from;
+				gchar *msg;
+				gchar *tmp;
+
+				from = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender);
 
-	while (read(source, &read_data, 1) > 0 || errno == EWOULDBLOCK) {
-		if (errno == EWOULDBLOCK) {
-			errno = 0;
-			continue;
-		}
+				msg = charset_convert((const char *)ev->event.msg.message,
+									  "CP1250", "UTF-8");
+				gaim_str_strip_cr(msg);
+				tmp = g_markup_escape_text(msg, -1);
+				gaim_debug_info("gg", "msg form (%s): %s (class = %d)\n", from, tmp, ev->event.msg.msgclass);
+				serv_got_im(gc, from, tmp, 0, ev->event.msg.time);
+				g_free(msg);
+				g_free(tmp);
+				g_free(from);
+			}
+			break;
+		case GG_EVENT_ACK:
+			gaim_debug_info("gg", "message sent to: %ld, delivery status=%d, seq=%d\n",
+					ev->event.ack.recipient, ev->event.ack.status, ev->event.ack.seq);
+			break;
+		case GG_EVENT_NOTIFY:
+		case GG_EVENT_NOTIFY_DESCR:
+			{
+				struct gg_notify_reply *n;
+				char *descr;
 
-		if (!read_data)
-			continue;
+				gaim_debug_info("gg", "notify_pre: (%d) status: %d\n",
+						ev->event.notify->uin,
+						ev->event.notify->status);
+
+				n = (ev->type == GG_EVENT_NOTIFY) ? ev->event.notify
+								  : ev->event.notify_descr.notify;
 
-		len++;
-		webdata = g_realloc(webdata, len);
-		webdata[len - 1] = read_data;
-	}
+				for (; n->uin; n++) {
+					descr = (ev->type == GG_EVENT_NOTIFY) ? NULL
+					      				      : ev->event.notify_descr.descr;
+					gaim_debug_info("gg", "notify: (%d) status: %d; descr: %s\n",
+							n->uin, n->status, descr);
+
+					ggp_generic_status_handler(gc,
+							n->uin, n->status, descr);
+				}
+			}
+			break;
+		case GG_EVENT_NOTIFY60:
+			gaim_debug_info("gg", "notify60_pre: (%d) status=%d; version=%d; descr=%s\n",
+					ev->event.notify60->uin, ev->event.notify60->status,
+					ev->event.notify60->version, ev->event.notify60->descr);
+
+			for (i = 0; ev->event.notify60[i].uin; i++) {
+				gaim_debug_info("gg", "notify60: (%d) status=%d; version=%d; descr=%s\n",
+						ev->event.notify60[i].uin, ev->event.notify60[i].status,
+						ev->event.notify60[i].version, ev->event.notify60[i].descr);
 
-	webdata = g_realloc(webdata, len + 1);
-	webdata[len] = 0;
+				ggp_generic_status_handler(gc,
+						ev->event.notify60[i].uin,
+						ev->event.notify60[i].status,
+						ev->event.notify60[i].descr);
+			}
+			break;
+		case GG_EVENT_STATUS:
+			gaim_debug_info("gg", "status: (%d) status=%d; descr=%s\n",
+					ev->event.status.uin, ev->event.status.status,
+					ev->event.status.descr);
 
-	gaim_input_remove(hdata->inpa);
-	close(source);
-
-	gaim_debug(GAIM_DEBUG_MISC, "gg",
-			   "http_results: type %d, webdata [%s]\n", hdata->type, webdata);
+			ggp_generic_status_handler(gc,
+						   ev->event.status.uin,
+						   ev->event.status.status,
+						   ev->event.status.descr);
+			break;
+		case GG_EVENT_STATUS60:
+			gaim_debug_info("gg", "status60: (%d) status=%d; version=%d; descr=%s\n",
+					ev->event.status60.uin,
+					ev->event.status60.status,
+					ev->event.status60.version,
+					ev->event.status60.descr);
 
-	switch (hdata->type) {
-	case AGG_HTTP_SEARCH:
-		search_results(gc, webdata);
-		break;
-#if 0
-	case AGG_HTTP_USERLIST_IMPORT:
-		import_buddies_server_results(gc, webdata);
-		break;
-	case AGG_HTTP_USERLIST_EXPORT:
-		export_buddies_server_results(gc, webdata);
-		break;
-	case AGG_HTTP_USERLIST_DELETE:
-	        delete_buddies_server_results(gc, webdata);
-		break;
-#endif
-	case AGG_HTTP_PASSWORD_CHANGE:
-		password_change_server_results(gc, webdata);
-		break;
-	case AGG_HTTP_NONE:
-	default:
-		gaim_debug(GAIM_DEBUG_ERROR, "gg",
-				   "http_results: unsupported type %d\n", hdata->type);
-		break;
-	}
+			ggp_generic_status_handler(gc,
+						   ev->event.status60.uin,
+						   ev->event.status60.status,
+						   ev->event.status60.descr);
+			break;
+		case GG_EVENT_USERLIST:
+	    		if (ev->event.userlist.type == GG_USERLIST_GET_REPLY) {
+				gaim_debug_info("gg", "GG_USERLIST_GET_REPLY\n");
+				if (ev->event.userlist.reply != NULL) {
+				    ggp_buddylist_load(gc, ev->event.userlist.reply);
+				}
+			break;
+			} else {
+				gaim_debug_info("gg", "GG_USERLIST_PUT_REPLY. Userlist stored on the server.\n");
+			}
+			break;
+		case GG_EVENT_PUBDIR50_SEARCH_REPLY:
+			{
+				GaimNotifySearchResults *results;
+				GaimNotifySearchColumn *column;
+				gg_pubdir50_t req = ev->event.pubdir50;
+				int res_count = 0;
+				int start;
+				int i;
+
+				res_count = gg_pubdir50_count(req);
+				if (res_count < 1) {
+					gaim_debug_info("gg", "GG_EVENT_PUBDIR50_SEARCH_REPLY: Nothing found\n");
+					return;
+				}
+				res_count = (res_count > 20) ? 20 : res_count;
+
+				results = gaim_notify_searchresults_new();
+
+				column = gaim_notify_searchresults_column_new("UIN");
+				gaim_notify_searchresults_column_add(results, column);
+
+				column = gaim_notify_searchresults_column_new("First name");
+				gaim_notify_searchresults_column_add(results, column);
+
+				column = gaim_notify_searchresults_column_new("Nick name");
+				gaim_notify_searchresults_column_add(results, column);
 
-	g_free(webdata);
-	g_free(hdata);
-}
+				column = gaim_notify_searchresults_column_new("City");
+				gaim_notify_searchresults_column_add(results, column);
 
-static void http_req_callback(gpointer data, gint source, GaimInputCondition cond)
-{
-	struct agg_http *hdata = data;
-	GaimConnection *gc = hdata->gc;
-	gchar *request = hdata->request;
-	gchar *buf;
+				column = gaim_notify_searchresults_column_new("Birth year");
+				gaim_notify_searchresults_column_add(results, column);
 
-	gaim_debug(GAIM_DEBUG_INFO, "gg", "http_req_callback: begin\n");
+				gaim_debug_info("gg", "Going with %d entries\n", res_count);
+
+				start = (int)ggp_str_to_uin(gg_pubdir50_get(req, 0, GG_PUBDIR50_START));
+				gaim_debug_info("gg", "start = %d\n", start);
 
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		gaim_debug(GAIM_DEBUG_ERROR, "gg",
-				   "http_req_callback: g_slist_find error\n");
-		g_free(request);
-		g_free(hdata);
-		close(source);
-		return;
-	}
+				for (i = 0; i < res_count; i++) {
+					GList *row = NULL;
+					char *birth = ggp_get_pubdir_info(req, i, GG_PUBDIR50_BIRTHYEAR);
+					
+					/* TODO: Status will be displayed as an icon. */
+					/* row = g_list_append(row, ggp_get_pubdir_info(req, i, GG_PUBDIR50_STATUS)); */
+					row = g_list_append(row, ggp_get_pubdir_info(req, i, GG_PUBDIR50_UIN));
+					row = g_list_append(row, ggp_get_pubdir_info(req, i, GG_PUBDIR50_FIRSTNAME));
+					row = g_list_append(row, ggp_get_pubdir_info(req, i, GG_PUBDIR50_NICKNAME));
+					row = g_list_append(row, ggp_get_pubdir_info(req, i, GG_PUBDIR50_CITY));
+					row = g_list_append(row, (birth && strncmp(birth, "0", 1)) ? birth : g_strdup("-"));
+					gaim_notify_searchresults_row_add(results, row);
+					if (i == res_count - 1) {
+						g_free(info->search_form->last_uin);
+						info->search_form->last_uin = ggp_get_pubdir_info(req, i, GG_PUBDIR50_UIN);
+					}
+				}
 
-	if (source == 0) {
-		g_free(request);
-		g_free(hdata);
-		return;
+				gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_CONTINUE, ggp_callback_show_next);
+				gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD_BUDDY, ggp_callback_add_buddy);
+				if (info->searchresults_window == NULL) {
+					void *h = gaim_notify_searchresults(gc, _("Gadu-Gadu Public Directory"),
+											  _("Search results"), NULL, results, NULL, NULL);
+					info->searchresults_window = h;
+				} else {
+					gaim_notify_searchresults_new_rows(gc, results, info->searchresults_window, NULL);
+				}
+			}
+			break;
+		default:
+			gaim_debug_error("gg", "unsupported event type=%d\n", ev->type);
+			break;
 	}
 
-	gaim_debug(GAIM_DEBUG_MISC, "gg",
-			   "http_req_callback: http request [%s]\n", request);
-
-	buf = g_strdup_printf("POST %s HTTP/1.0\r\n"
-			      "Host: %s\r\n"
-			      "Content-Type: application/x-www-form-urlencoded\r\n"
-			      "User-Agent: " GG_HTTP_USERAGENT "\r\n"
-			      "Content-Length: %d\r\n"
-			      "Pragma: no-cache\r\n" "\r\n" "%s\r\n",
-			      hdata->form, hdata->host, (int)strlen(request), request);
-
-	g_free(request);
+	gg_free_event(ev);
+}
+/* }}} */
 
-	if (write(source, buf, strlen(buf)) < strlen(buf)) {
-		g_free(buf);
-		g_free(hdata);
-		close(source);
-		gaim_notify_error(gc, NULL,
-						  _("Error communicating with Gadu-Gadu server"),
-						  _("Gaim was unable to complete your request due "
-							"to a problem communicating with the Gadu-Gadu "
-							"HTTP server.  Please try again later."));
-		return;
-	}
-
-	g_free(buf);
+/**
+ * Set offline status for all buddies.
+ *
+ * @param gc Connection handler
+ */
+/* static void ggp_buddylist_offline(GaimConnection *gc) {{{ */
+static void ggp_buddylist_offline(GaimConnection *gc)
+{
+	GaimBuddyList *blist;
+	GaimBlistNode *gnode, *cnode, *bnode;
+	GaimBuddy *buddy;
 
-	hdata->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_results, hdata);
-}
-
-#if 0
-static void import_buddies_server(GaimConnection *gc)
-{
-	struct agg_http *hi = g_new0(struct agg_http, 1);
-	gchar *u = gg_urlencode(gaim_account_get_username(gc->account));
-	gchar *p = gg_urlencode(gaim_connection_get_password(gc));
+	if ((blist = gaim_get_blist()) != NULL)
+	{
+		for (gnode = blist->root; gnode != NULL; gnode = gnode->next)
+		{
+			if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
+				continue;
+			for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
+			{
+				if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
+					continue;
+				for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
+				{
+					if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+						continue;
 
-	hi->gc = gc;
-	hi->type = AGG_HTTP_USERLIST_IMPORT;
-	hi->form = AGG_PUBDIR_USERLIST_IMPORT_FORM;
-	hi->host = GG_PUBDIR_HOST;
-	hi->request = g_strdup_printf("FmNum=%s&Pass=%s", u, p);
+					buddy = (GaimBuddy *)bnode;
 
-	g_free(u);
-	g_free(p);
+					if (buddy->account != gc->account)
+						continue;
 
-	if (gaim_proxy_connect(gc->account, GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, hi) < 0) {
-		gaim_notify_error(gc, NULL,
-						  _("Unable to import Gadu-Gadu buddy list"),
-						  _("Gaim was unable to connect to the Gadu-Gadu "
-							"buddy list server.  Please try again later."));
-		g_free(hi->request);
-		g_free(hi);
-		return;
+					gaim_prpl_got_user_status(
+						gaim_connection_get_account(gc),
+						buddy->name, "offline", NULL);
+					gaim_debug_info("gg", "ggp_buddylist_offline: gone: %s\n", buddy->name);
+				}
+			}
+		}
 	}
 }
-
-static void export_buddies_server(GaimConnection *gc)
-{
-	struct agg_http *he = g_new0(struct agg_http, 1);
-	gchar *ptr;
-	gchar *u = gg_urlencode(gaim_account_get_username(gc->account));
-	gchar *p = gg_urlencode(gaim_connection_get_password(gc));
+/* }}} */
 
+/**
+ * Get all the buddies in the current account.
+ *
+ * @param account Current account.
+ * 
+ * @return List of buddies.
+ */
+/* static char *ggp_buddylist_dump(GaimAccount *account) {{{ */
+static char *ggp_buddylist_dump(GaimAccount *account)
+{
+	GaimBuddyList *blist;
 	GaimBlistNode *gnode, *cnode, *bnode;
-
-	he->gc = gc;
-	he->type = AGG_HTTP_USERLIST_EXPORT;
-	he->form = AGG_PUBDIR_USERLIST_EXPORT_FORM;
-	he->host = GG_PUBDIR_HOST;
-	he->request = g_strdup_printf("FmNum=%s&Pass=%s&Contacts=", u, p);
+	GaimGroup *group;
+	GaimBuddy *buddy;
 
-	g_free(u);
-	g_free(p);
+	char *buddylist = g_strdup("");
+	char *ptr;
 
-	for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
-		GaimGroup *g = (GaimGroup *)gnode;
-		int num_added=0;
-		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
+	if ((blist = gaim_get_blist()) == NULL)
+		return NULL;
+
+	for (gnode = blist->root; gnode != NULL; gnode = gnode->next) {
+		if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
-			if(!GAIM_BLIST_NODE_IS_CONTACT(cnode))
+
+		group = (GaimGroup *)gnode;
+
+		for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) {
+			if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
-				GaimBuddy *b = (GaimBuddy *)bnode;
 
-				if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
+				if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 
-				if(b->account == gc->account) {
-					gchar *newdata;
-					/* GG Number */
-					gchar *name = gg_urlencode(b->name);
-					/* GG Pseudo */
-					gchar *show = gg_urlencode(b->alias ? b->alias : b->name);
-					/* Group Name */
-					gchar *gname = gg_urlencode(g->name);
-
-					ptr = he->request;
-					newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s",
-							show, show, show, show, "", gname, name);
+				buddy = (GaimBuddy *)bnode;
+				if (buddy->account != account)
+					continue;
 
-					if(num_added > 0)
-						he->request = g_strconcat(ptr, "%0d%0a", newdata, NULL);
-					else
-						he->request = g_strconcat(ptr, newdata, NULL);
-
-					num_added++;
+				gchar *newdata;
+				/* GG Number */
+				gchar *name = buddy->name;
+				/* GG Pseudo */
+				gchar *show = buddy->alias ? buddy->alias : buddy->name;
+				/* Group Name */
+				gchar *gname = group->name;
 
-					g_free(newdata);
-					g_free(ptr);
+				newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s;%s%s\r\n",
+						show, show, show, show, "", gname, name, "", "");
 
-					g_free(gname);
-					g_free(show);
-					g_free(name);
-				}
+				ptr = buddylist;
+				buddylist = g_strconcat(ptr, newdata, NULL);
+
+				g_free(newdata);
+				g_free(ptr);
 			}
 		}
 	}
 
-	if (gaim_proxy_connect(gc->account, GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, he) < 0) {
-		gaim_notify_error(gc, NULL,
-						  _("Couldn't export buddy list"),
-						  _("Gaim was unable to connect to the buddy "
-							"list server.  Please try again later."));
-		g_free(he->request);
-		g_free(he);
+	return buddylist;
+}
+/* }}} */
+
+/**
+ * Request buddylist from the server.
+ * Buddylist is received in the ggp_callback_recv().
+ *
+ * @param Current action handler.
+ */
+/* static void ggp_action_buddylist_get(GaimPluginAction *action) {{{ */
+static void ggp_action_buddylist_get(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+	GGPInfo *info = gc->proto_data;
+
+	gaim_debug_info("gg", "Downloading...\n");
+
+	gg_userlist_request(info->session, GG_USERLIST_GET, NULL);
+}
+/* }}} */
+
+/**
+ * Upload the buddylist to the server.
+ *
+ * @param action Current action handler.
+ */
+/* static void ggp_action_buddylist_put(GaimPluginAction *action) {{{ */
+static void ggp_action_buddylist_put(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+	GGPInfo *info = gc->proto_data;
+
+	char *buddylist = ggp_buddylist_dump(gaim_connection_get_account(gc));
+
+	gaim_debug_info("gg", "Uploading...\n");
+	
+	if (buddylist == NULL)
+		return;
+
+	gg_userlist_request(info->session, GG_USERLIST_PUT, buddylist);
+	g_free(buddylist);
+}
+/* }}} */
+
+/**
+ * Delete buddylist from the server.
+ *
+ * @param action Current action handler.
+ */
+/* static void ggp_action_buddylist_delete(GaimPluginAction *action) {{{ */
+static void ggp_action_buddylist_delete(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+	GGPInfo *info = gc->proto_data;
+
+	gaim_debug_info("gg", "Deleting...\n");
+
+	gg_userlist_request(info->session, GG_USERLIST_PUT, NULL);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_callback_buddylist_save_ok(GaimConnection *gc, gchar *file) {{{ */
+static void ggp_callback_buddylist_save_ok(GaimConnection *gc, gchar *file)
+{
+	GaimAccount *account = gaim_connection_get_account(gc);
+
+	FILE *fh;
+	char *buddylist = ggp_buddylist_dump(account);
+	gchar *msg;
+
+	gaim_debug_info("gg", "Saving...\n");
+	gaim_debug_info("gg", "file = %s\n", file);
+
+	if (buddylist == NULL) {
+		gaim_notify_info(account, _("Save Buddylist..."),
+				 _("Your buddylist is empty, nothing was written to the file."),
+				 NULL);
 		return;
 	}
-}
 
-static void delete_buddies_server(GaimConnection *gc)
-{
-	struct agg_http *he = g_new0(struct agg_http, 1);
-	gchar *u = gg_urlencode(gaim_account_get_username(gc->account));
-	gchar *p = gg_urlencode(gaim_connection_get_password(gc));
+	if ((fh = g_fopen(file, "wb")) == NULL) {
+		msg = g_strconcat(_("Couldn't open file"), ": ", file, "\n", NULL);
+		gaim_debug_error("gg", "Could not open file: %s\n", file);
+		gaim_notify_error(account, _("Couldn't open file"), msg, NULL);
+		g_free(msg);
+		g_free(file);
+		return;
+	}
+
+	fwrite(buddylist, sizeof(char), g_utf8_strlen(buddylist, -1), fh);
+	fclose(fh);
+	g_free(buddylist);
+
+	gaim_notify_info(account, _("Save Buddylist..."),
+			 _("Buddylist saved successfully!"), NULL);
+}
+/* }}} */
 
-	he->gc = gc;
-	he->type = AGG_HTTP_USERLIST_DELETE;
-	he->form = AGG_PUBDIR_USERLIST_EXPORT_FORM;
-	he->host = GG_PUBDIR_HOST;
-	he->request = g_strdup_printf("FmNum=%s&Pass=%s&Delete=1", u, p);
+/*
+ */
+/* static void ggp_callback_buddylist_load_ok(GaimConnection *gc, gchar *file) {{{ */
+static void ggp_callback_buddylist_load_ok(GaimConnection *gc, gchar *file)
+{
+	GaimAccount *account = gaim_connection_get_account(gc);
+	char *buddylist, *tmp, *ptr;
+	FILE *fh;
+	gchar *msg;
 
-	if (gaim_proxy_connect(gc->account, GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, he) < 0) {
-		gaim_notify_error(gc, NULL,
-						  _("Unable to delete Gadu-Gadu buddy list"),
-						  _("Gaim was unable to connect to the buddy "
-							"list server.  Please try again later."));
-		g_free(he->request);
-		g_free(he);
+	buddylist = g_strdup("");
+	tmp = g_new0(gchar, 50);
+
+	gaim_debug_info("gg", "file_name = %s\n", file);
+
+	if ((fh = g_fopen(file, "rb")) == NULL) {
+		msg = g_strconcat(_("Couldn't open file"), ": ", file, "\n", NULL);
+		gaim_debug_error("gg", "Could not open file: %s\n", file);
+		gaim_notify_error(account, _("Could't open file"), msg, NULL);
+		g_free(msg);
+		g_free(file);
 		return;
 	}
+
+	while (fread(tmp, sizeof(gchar), 49, fh) == 49) {
+		tmp[49] = '\0';
+		/* gaim_debug_info("gg", "read: %s\n", tmp); */
+		ptr = g_strconcat(buddylist, tmp, NULL);
+		memset(tmp, '\0', 50); 
+		g_free(buddylist);
+		buddylist = ptr;
+	}
+	fclose(fh);
+	g_free(tmp);
+
+	ggp_buddylist_load(gc, buddylist);
+	g_free(buddylist);
+
+	gaim_notify_info(account,
+			 _("Load Buddylist..."),
+			 _("Buddylist loaded successfully!"), NULL);
 }
-#endif
+/* }}} */
+
+/*
+ */
+/* static void ggp_action_buddylist_save(GaimPluginAction *action) {{{ */
+static void ggp_action_buddylist_save(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+
+	gaim_request_file(action, _("Save buddylist..."), NULL, TRUE,
+				G_CALLBACK(ggp_callback_buddylist_save_ok), NULL, gc);
+}
+/* }}} */
 
-#if 0
-static void agg_dir_search(GaimConnection *gc, const char *first, const char *middle,
-			   const char *last, const char *maiden, const char *city, const char *state,
-			   const char *country, const char *email)
+/*
+ */
+/* static void ggp_action_buddylist_load(GaimPluginAction *action) {{{ */
+static void ggp_action_buddylist_load(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+
+	gaim_request_file(action, "Load buddylist from file...", NULL, FALSE,
+				G_CALLBACK(ggp_callback_buddylist_load_ok), NULL, gc);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_callback_change_passwd_ok(GaimConnection *gc, GaimRequestFields *fields) {{{ */
+static void ggp_callback_change_passwd_ok(GaimConnection *gc, GaimRequestFields *fields)
 {
-	struct agg_http *srch = g_new0(struct agg_http, 1);
-	srch->gc = gc;
-	srch->type = AGG_HTTP_SEARCH;
-	srch->form = AGG_PUBDIR_SEARCH_FORM;
-	srch->host = GG_PUBDIR_HOST;
+	GaimAccount *account;
+	GGPInfo *info = gc->proto_data;
+	struct gg_http *h;
+	gchar *cur, *p1, *p2, *t;
+
+	cur = charset_convert(gaim_request_fields_get_string(fields, "password_cur"),
+			     "UTF-8", "CP1250");
+	p1  = charset_convert(gaim_request_fields_get_string(fields, "password1"),
+			     "UTF-8", "CP1250");
+	p2  = charset_convert(gaim_request_fields_get_string(fields, "password2"),
+			     "UTF-8", "CP1250");
+	t   = charset_convert(gaim_request_fields_get_string(fields, "token"),
+			     "UTF-8", "CP1250");
+
+	account = gaim_connection_get_account(gc);
+
+	if (cur == NULL || p1 == NULL || p2 == NULL || t == NULL ||
+	    *cur == '\0' || *p1 == '\0' || *p2 == '\0' || *t == '\0') {
+		gaim_notify_error(account, NULL, _("Fill in the fields."), NULL);
+		goto exit_err;
+	}
+
+	if (g_utf8_collate(p1, p2) != 0) {
+		gaim_notify_error(account, NULL, _("New passwords do not match."), NULL);
+		goto exit_err;
+	}
 
-	if (email && strlen(email)) {
-		gchar *eemail = gg_urlencode(email);
-		srch->request = g_strdup_printf("Mode=1&Email=%s", eemail);
-		g_free(eemail);
-	} else {
-		gchar *new_first = charset_convert(first, "UTF-8", "CP1250");
-		gchar *new_last = charset_convert(last, "UTF-8", "CP1250");
-		gchar *new_city = charset_convert(city, "UTF-8", "CP1250");
+	if (g_utf8_collate(cur, gaim_account_get_password(account)) != 0) {
+		gaim_notify_error(account, NULL,
+			_("Your current password is different from the one that you specified."),
+			NULL);
+		goto exit_err;
+	}
+
+	gaim_debug_info("gg", "change_passwd: old=%s; p1=%s; token=%s\n",
+			cur, p1, info->chpasswd_token->token_id);
+
+	/* XXX: this e-mail should be a pref... */
+	h = gg_change_passwd4(ggp_get_uin(account),
+			      "user@example.net", gaim_account_get_password(account),
+			      p1, info->chpasswd_token->token_id, t, 0);
 
-		gchar *enew_first = gg_urlencode(new_first);
-		gchar *enew_last = gg_urlencode(new_last);
-		gchar *enew_city = gg_urlencode(new_city);
+	if (h == NULL) {
+		gaim_notify_error(account, NULL,
+			_("Unable to change password. Error occured.\n"),
+			NULL);
+		goto exit_err;
+	}
+
+	gaim_account_set_password(account, p1);
+
+	gg_change_passwd_free(h);
+
+	gaim_notify_info(account, _("Change password for the Gadu-Gadu account"),
+			 _("Password was changed successfully!"), NULL);
+
+exit_err:
+	g_free(cur);
+	g_free(p1);
+	g_free(p2);
+	g_free(t);
+	g_free(info->chpasswd_token->token_id);
+	g_free(info->chpasswd_token);
+}
+/* }}} */
 
-		g_free(new_first);
-		g_free(new_last);
-		g_free(new_city);
+/*
+ */
+/* static void ggp_callback_register_account_ok(GaimConnection *gc, GaimRequestFields *fields) {{{ */
+static void ggp_callback_register_account_ok(GaimConnection *gc, GaimRequestFields *fields)
+{
+	GaimAccount *account;
+	GGPInfo *info = gc->proto_data;
+	struct gg_http *h = NULL;
+	struct gg_pubdir *s;
+	uin_t uin;
+	gchar *email, *p1, *p2, *t;
 
-		/* For active only add &ActiveOnly= */
-		srch->request = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d"
-						"&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d",
-						enew_first, enew_last, AGG_GENDER_NONE,
-						"", enew_city, 0, 0);
+	email = charset_convert(gaim_request_fields_get_string(fields, "email"),
+			     "UTF-8", "CP1250");
+	p1  = charset_convert(gaim_request_fields_get_string(fields, "password1"),
+			     "UTF-8", "CP1250");
+	p2  = charset_convert(gaim_request_fields_get_string(fields, "password2"),
+			     "UTF-8", "CP1250");
+	t   = charset_convert(gaim_request_fields_get_string(fields, "token"),
+			     "UTF-8", "CP1250");
+
+	account = gaim_connection_get_account(gc);
 
-		g_free(enew_first);
-		g_free(enew_last);
-		g_free(enew_city);
+	if (email == NULL || p1 == NULL || p2 == NULL || t == NULL ||
+	    *email == '\0' || *p1 == '\0' || *p2 == '\0' || *t == '\0') {
+		gaim_notify_error(account, NULL, _("Fill in the fields."), NULL);
+		goto exit_err;
+	}
+
+	if (g_utf8_collate(p1, p2) != 0) {
+		gaim_notify_error(account, NULL, _("Passwords do not match."), NULL);
+		goto exit_err;
+	}
+
+	h = gg_register3(email, p1, info->register_token->token_id, t, 0);
+	if (h == NULL || !(s = h->data) || !s->success) {
+		gaim_notify_error(account, NULL,
+			_("Unable to register new account. Error occured.\n"),
+			NULL);
+		goto exit_err;
 	}
 
-	if (gaim_proxy_connect(gc->account, GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, srch) < 0) {
-		gaim_notify_error(gc, NULL,
-						  _("Unable to access directory"),
-						  _("Gaim was unable to search the Directory "
-							"because it was unable to connect to the "
-							"directory server.  Please try again later."));
-		g_free(srch->request);
-		g_free(srch);
+	uin = s->uin;
+	gaim_debug_info("gg", "registered uin: %d\n", uin);
+
+	gaim_notify_info(NULL, _("New Gadu-Gadu Account Registered"),
+			 _("Registration completed successfully!"), NULL);
+
+exit_err:
+	gg_register_free(h);
+	g_free(email);
+	g_free(p1);
+	g_free(p2);
+	g_free(t);
+	g_free(info->register_token->token_id);
+	g_free(info->register_token);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_callback_find_buddies(GaimConnection *gc, GaimRequestFields *fields) {{{ */
+static void ggp_callback_find_buddies(GaimConnection *gc, GaimRequestFields *fields)
+{
+	GGPInfo *info = gc->proto_data;
+	GGPSearchForm *form;
+
+	form = ggp_searchform_new();
+	/*
+	 * TODO: Fail if we have already a form attached. Only one search
+	 * at a time will be allowed for now.
+	 */
+	info->search_form = form;
+
+	form->lastname  = charset_convert(gaim_request_fields_get_string(fields, "lastname"),
+									 "UTF-8", "CP1250");
+	form->firstname = charset_convert(gaim_request_fields_get_string(fields, "firstname"),
+									 "UTF-8", "CP1250");
+	form->nickname  = charset_convert(gaim_request_fields_get_string(fields, "nickname"),
+									 "UTF-8", "CP1250");
+	form->city      = charset_convert(gaim_request_fields_get_string(fields, "city"),
+									 "UTF-8", "CP1250");
+	form->birthyear = charset_convert(gaim_request_fields_get_string(fields, "year"),
+								     "UTF-8", "CP1250");
+
+	switch (gaim_request_fields_get_choice(fields, "gender")) {
+		case 1:
+			form->gender = g_strdup(GG_PUBDIR50_GENDER_MALE);
+			break;
+		case 2:
+			form->gender = g_strdup(GG_PUBDIR50_GENDER_FEMALE);
+			break;
+		default:
+			form->gender = NULL;
+			break;
+	}
+
+	form->active = gaim_request_fields_get_bool(fields, "active")
+				   ? g_strdup(GG_PUBDIR50_ACTIVE_TRUE) : NULL;
+
+	form->offset = g_strdup("0");
+
+	ggp_pubdir_start_search(gc, form);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_find_buddies(GaimPluginAction *action) {{{ */
+static void ggp_find_buddies(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+
+	GaimRequestFields *fields;
+	GaimRequestFieldGroup *group;
+	GaimRequestField *field;
+
+	fields = gaim_request_fields_new();
+	group = gaim_request_field_group_new(NULL);
+	gaim_request_fields_add_group(fields, group);
+
+	field = gaim_request_field_string_new("lastname", _("Last name"), NULL, FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("firstname", _("First name"), NULL, FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("nickname", _("Nickname"), NULL, FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("city", _("City"), NULL, FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("year", _("Year of birth"), NULL, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_choice_new("gender", "Gender", 0);
+	gaim_request_field_choice_add(field, "Male or female");
+	gaim_request_field_choice_add(field, "Male");
+	gaim_request_field_choice_add(field, "Female");
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_bool_new("active", _("Only online"), FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	gaim_request_fields(gc,
+		_("Find buddies"),
+		_("Find buddies"),
+		_("Please, enter your search criteria below"),
+		fields,
+		_("OK"), G_CALLBACK(ggp_callback_find_buddies),
+		_("Cancel"), NULL,
+		gc);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_change_passwd(GaimPluginAction *action) {{{ */
+static void ggp_change_passwd(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *)action->context;
+	GGPInfo *info = gc->proto_data;
+	GGPToken *token;
+
+	GaimRequestFields *fields;
+	GaimRequestFieldGroup *group;
+	GaimRequestField *field;
+
+	struct gg_http *req;
+	struct gg_token *t;
+	gchar *msg;
+
+	gaim_debug_info("gg", "token: requested.\n");
+
+	/* TODO: This should be async. */
+	if ((req = gg_token(0)) == NULL) {
+		gaim_notify_error(gaim_connection_get_account(gc),
+						  _("Token Error"),
+						  _("Unable to fetch the token.\n"), NULL);
 		return;
 	}
+
+	t = req->data;
+
+	token = g_new0(GGPToken, 1);
+	token->token_id = g_strdup(t->tokenid);
+	info->chpasswd_token = token;
+
+
+	fields = gaim_request_fields_new();
+	group = gaim_request_field_group_new(NULL);
+	gaim_request_fields_add_group(fields, group);
+
+	field = gaim_request_field_string_new("password_cur", _("Current password"), "", FALSE);
+	gaim_request_field_string_set_masked(field, TRUE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("password1", _("Password"), "", FALSE);
+	gaim_request_field_string_set_masked(field, TRUE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("password2", _("Password (retype)"), "", FALSE);
+	gaim_request_field_string_set_masked(field, TRUE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("token", _("Enter current token"), "", FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	/* original size: 60x24 */
+	field = gaim_request_field_image_new("token_img", _("Current token"), req->body, req->body_size);
+	gaim_request_field_group_add_field(group, field);
+
+	gg_token_free(req);
+
+	msg = g_strdup_printf("%s %d",
+			_("Please, enter your current password and your new password for UIN: "),
+			ggp_get_uin(gaim_connection_get_account(gc)));
+
+	gaim_request_fields(gc,
+		_("Change Gadu-Gadu Password"),
+		_("Change Gadu-Gadu Password"),
+		msg,
+		fields, _("OK"), G_CALLBACK(ggp_callback_change_passwd_ok),
+		_("Cancel"), NULL, gc);
+
+	g_free(msg);
+}
+/* }}} */
+
+/* ---------------------------------------------------------------------- */
+/* ----- GaimPluginProtocolInfo ----------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+/*
+ */
+/* static const char *ggp_list_icon(GaimAccount *account, GaimBuddy *buddy) {{{ */
+static const char *ggp_list_icon(GaimAccount *account, GaimBuddy *buddy)
+{
+	return "gadu-gadu";
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne) {{{ */
+static void ggp_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne)
+{
+	GaimPresence *presence = gaim_buddy_get_presence(b);
+
+	/* 
+	 * Note to myself:
+	 * 	The only valid status types are those defined
+	 * 	in prpl_info->status_types.
+	 *
+	 * Usable icons: away, blocked, dnd, extendedaway,
+	 * freeforchat, ignored, invisible, na, offline.
+	 */
+
+	if (!GAIM_BUDDY_IS_ONLINE(b)) {
+		*se = "offline";
+	} else if (gaim_presence_is_status_active(presence, "away")) {
+		*se = "away";
+	} else if (gaim_presence_is_status_active(presence, "online")) {
+		*se = "online";
+	} else if (gaim_presence_is_status_active(presence, "offline")) {
+		*se = "offline";
+	} else if (gaim_presence_is_status_active(presence, "blocked")) {
+		*se = "blocked";
+	} else {
+		*se = "offline";
+		gaim_debug_info("gg", "ggp_list_emblems: unknown status\n");
+	}
 }
-#endif
+/* }}} */
 
-static void agg_change_passwd(GaimConnection *gc, const char *old, const char *new)
+/*
+ */
+/* static char *ggp_status_text(GaimBuddy *b) {{{ */
+static char *ggp_status_text(GaimBuddy *b)
 {
-	struct agg_http *hpass = g_new0(struct agg_http, 1);
-	gchar *u = gg_urlencode(gaim_account_get_username(gc->account));
-	gchar *p = gg_urlencode(gaim_connection_get_password(gc));
-	gchar *enew = gg_urlencode(new);
-	gchar *eold = gg_urlencode(old);
+	GaimStatus *status;
+	const char *msg;
+	char *text;
+	char *tmp;
 
-	hpass->gc = gc;
-	hpass->type = AGG_HTTP_PASSWORD_CHANGE;
-	hpass->form = AGG_REGISTER_DATA_FORM;
-	hpass->host = GG_REGISTER_HOST;
+	status = gaim_presence_get_active_status(gaim_buddy_get_presence(b));
 
-	/* We are using old password as place for email - it's ugly */
-	hpass->request = g_strdup_printf("fmnumber=%s&fmpwd=%s&pwd=%s&email=%s&code=%u",
-					 u, p, enew, eold, gg_http_hash(old, new));
+	msg = gaim_status_get_attr_string(status, "message");
 
-	g_free(u);
-	g_free(p);
-	g_free(enew);
-	g_free(eold);
+	if (msg != NULL) {
+		tmp = gaim_markup_strip_html(msg);
+		text = g_markup_escape_text(tmp, -1);
+		g_free(tmp);
 
-	if (gaim_proxy_connect(gc->account, GG_REGISTER_HOST, GG_REGISTER_PORT, http_req_callback, hpass) < 0) {
-		gaim_notify_error(gc, NULL,
-							  _("Unable to change Gadu-Gadu password"),
-							  _("Gaim was unable to change your password "
-								"due to an error connecting to the "
-								"Gadu-Gadu server.  Please try again "
-								"later."));
-		g_free(hpass->request);
-		g_free(hpass);
-		return;
+		return text;
+	} else {
+		tmp = g_strdup(gaim_status_get_name(status));
+		text = g_markup_escape_text(tmp, -1);
+		g_free(tmp);
+
+		return text;
 	}
 }
+/* }}} */
 
-static GList *agg_actions(GaimPlugin *plugin, gpointer context)
+/*
+ */
+/* static char *ggp_tooltip_text(GaimBuddy *b) {{{ */
+static char *ggp_tooltip_text(GaimBuddy *b)
+{
+	GaimStatus *status;
+	char *text;
+	gchar *ret;
+	const char *msg, *name;
+
+	status = gaim_presence_get_active_status(gaim_buddy_get_presence(b));
+	msg = gaim_status_get_attr_string(status, "message");
+	name = gaim_status_get_name(status);
+
+	if (msg != NULL) {
+		char *tmp = gaim_markup_strip_html(msg);
+		text = g_markup_escape_text(tmp, -1);
+		g_free(tmp);
+
+		ret = g_strdup_printf("\n<b>%s:</b> %s: %s",
+							  _("Status"), name, text);
+
+		g_free(text);
+	} else {
+		ret = g_strdup_printf("\n<b>%s:</b> %s",
+							  _("Status"), name);
+	}
+
+	return ret;
+}
+/* }}} */
+
+/*
+ */
+/* static GList *ggp_status_types(GaimAccount *account) {{{ */
+static GList *ggp_status_types(GaimAccount *account)
+{
+	GaimStatusType *type;
+	GList *types = NULL;
+
+	type = gaim_status_type_new_with_attrs(GAIM_STATUS_OFFLINE, "offline", _("Offline"),
+	                                       TRUE, TRUE, FALSE, "message", _("Message"),
+					       gaim_value_new(GAIM_TYPE_STRING), NULL);
+	types = g_list_append(types, type);
+
+	type = gaim_status_type_new_with_attrs(GAIM_STATUS_ONLINE, "online", _("Online"),
+	                                       TRUE, TRUE, FALSE, "message", _("Message"),
+					       gaim_value_new(GAIM_TYPE_STRING), NULL);
+	types = g_list_append(types, type);
+
+	/*
+	 * Without this selecting Available or Invisible as own status doesn't
+	 * work. It's not used and not needed to show status of buddies.
+	 */
+	type = gaim_status_type_new_with_attrs(GAIM_STATUS_AVAILABLE, "available", _("Available"),
+					       TRUE, TRUE, FALSE, "message", _("Message"),
+					       gaim_value_new(GAIM_TYPE_STRING), NULL);
+	types = g_list_append(types, type);
+
+	type = gaim_status_type_new_with_attrs(GAIM_STATUS_HIDDEN, "invisible", _("Invisible"),
+					       TRUE, TRUE, FALSE, "message", _("Message"),
+					       gaim_value_new(GAIM_TYPE_STRING), NULL);
+	types = g_list_append(types, type);
+
+	/* type = gaim_status_type_new_with_attrs(GAIM_STATUS_UNAVAILABLE, "not-available", "Not Available", */
+	/*                                        TRUE, TRUE, FALSE, "message", _("Message"),                */
+	/*                                        gaim_value_new(GAIM_TYPE_STRING), NULL);                   */
+	/* types = g_list_append(types, type);                                                               */
+
+	type = gaim_status_type_new_with_attrs(GAIM_STATUS_AWAY, "away", _("Busy"),
+					       TRUE, TRUE, FALSE, "message", _("Message"),
+					       gaim_value_new(GAIM_TYPE_STRING), NULL);
+	types = g_list_append(types, type);
+
+	type = gaim_status_type_new_with_attrs(GAIM_STATUS_HIDDEN, "blocked", _("Blocked"),
+					       TRUE, TRUE, FALSE, "message", _("Message"),
+					       gaim_value_new(GAIM_TYPE_STRING), NULL);
+	types = g_list_append(types, type);
+
+	return types;
+}
+/* }}} */
+
+/*
+ */
+/* static GList *ggp_blist_node_menu(GaimBlistNode *node) {{{ */
+static GList *ggp_blist_node_menu(GaimBlistNode *node)
 {
 	GList *m = NULL;
-	GaimPluginAction *act = NULL;
-
-#if 0
-	act = gaim_plugin_action_new(_("Directory Search"), show_find_info);
-	m = g_list_append(m, act);
-	m = g_list_append(m, NULL);
-#endif
-
-	act = gaim_plugin_action_new(_("Change Password"), change_pass);
-	m = g_list_append(m, act);
 
-#if 0
-	act = gaim_plugin_action_new(_("Import Buddy List from Server"),
-			import_buddies_server);
-	m = g_list_append(m, act);
+	if (!GAIM_BLIST_NODE_IS_BUDDY(node))
+		return NULL;
 
-	act = gaim_plugin_action_new(_("Export Buddy List to Server"),
-			export_buddies_server);
-	m = g_list_append(m, act);
-
-	act = gaim_plugin_action_new(_("Delete Buddy List from Server"),
-			delete_buddies_server);
-	m = g_list_append(m, act);
-#endif
+	/* act = gaim_blist_node_action_new("Change Password", ggp_bmenu_change_passwd, NULL, NULL); */
+	/* m = g_list_append(m, act);                                                                */
 
 	return m;
 }
+/* }}} */
 
-static void agg_get_info(GaimConnection *gc, const char *who)
+/*
+ */
+/* static void ggp_login(GaimAccount *account, GaimStatus *status) {{{ */
+static void ggp_login(GaimAccount *account, GaimStatus *status)
 {
-	struct agg_http *srch = g_new0(struct agg_http, 1);
-	srch->gc = gc;
-	srch->type = AGG_HTTP_SEARCH;
-	srch->form = AGG_PUBDIR_SEARCH_FORM;
-	srch->host = GG_PUBDIR_HOST;
+	GaimConnection *gc = gaim_account_get_connection(account);
+	struct gg_login_params *glp = g_new0(struct gg_login_params, 1);
+	GGPInfo *info = g_new0(GGPInfo, 1);
+
+	info->session = NULL;
+	info->searchresults_window = NULL;
+
+	gc->proto_data = info;
+
+	glp->uin = ggp_get_uin(account);
+	glp->password = (char *)gaim_account_get_password(account);
+
+	glp->async = 0;
+	glp->status = GG_STATUS_AVAIL;
+	glp->tls = 0;
+
+	info->session = gg_login(glp);
+	if (info->session == NULL) {
+		gaim_connection_error(gc, _("Connection failed."));
+		g_free(glp);
+		return;
+	}
+	gaim_debug_info("gg", "ggp_login: so far so good.\n");
+
+	gc->inpa = gaim_input_add(info->session->fd, GAIM_INPUT_READ, ggp_callback_recv, gc);
 
-	/* If it's invalid uin then maybe it's nickname? */
-	if (invalid_uin(who)) {
-		gchar *new_who = charset_convert(who, "UTF-8", "CP1250");
-		gchar *enew_who = gg_urlencode(new_who);
+	gg_change_status(info->session, GG_STATUS_AVAIL);
+	gaim_connection_set_state(gc, GAIM_CONNECTED);
+	ggp_buddylist_send(gc);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_close(GaimConnection *gc) {{{ */
+static void ggp_close(GaimConnection *gc)
+{
+	GGPInfo *info;
 
-		g_free(new_who);
+	if (gc == NULL) {
+		gaim_debug_info("gg", "gc == NULL\n");
+		return;
+	}
+
+	info = gc->proto_data;
+
+	/* XXX: Any way to pass description here? */
+	if (info->session != NULL)
+		gg_change_status(info->session, GG_STATUS_NOT_AVAIL);
+
+	if (gc->inpa > 0)
+		gaim_input_remove(gc->inpa);
+
+	gg_logoff(info->session);
+	gg_free_session(info->session);
+	ggp_buddylist_offline(gc);
 
-		srch->request = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d"
-						"&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d",
-						"", "", AGG_GENDER_NONE, enew_who, "", 0, 0);
+	gaim_debug_info("gg", "Connection closed.\n");
+}
+/* }}} */
+
+/*
+ */
+/* static int ggp_send_im(GaimConnection *gc, const char *who, const char *msg, GaimConvImFlags flags) {{{ */
+static int ggp_send_im(GaimConnection *gc, const char *who, const char *msg, GaimConvImFlags flags)
+{
+	GGPInfo *info = gc->proto_data;
+	const char *tmp;
+
+	if (strlen(msg) == 0)
+		return 1;
+
+	tmp = charset_convert(msg, "UTF-8", "CP1250");
 
-		g_free(enew_who);
-	} else
-		srch->request = g_strdup_printf("Mode=3&UserId=%s", who);
+	if (tmp != NULL && strlen(tmp) > 0) {
+		if (gg_send_message(info->session, GG_CLASS_CHAT, ggp_str_to_uin(who), tmp) < 0) {
+			return -1;
+		}
+	}
+
+	return 1;
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_get_info(GaimConnection *gc, const char *name) { {{{ */
+static void ggp_get_info(GaimConnection *gc, const char *name)
+{
+	GGPInfo *info = gc->proto_data;
+	GGPSearchForm *form;
 
-	if (gaim_proxy_connect(gc->account, GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, srch) < 0) {
-		gaim_notify_error(gc, NULL,
-						  _("Unable to access user profile."),
-						  _("Gaim was unable to access this user's "
-							"profile due to an error connecting to the "
-							"directory server.  Please try again later."));
-		g_free(srch->request);
-		g_free(srch);
+	form = ggp_searchform_new();
+	info->search_form = form;
+
+	form->uin = g_strdup(name);
+	form->offset = g_strdup("0");
+	form->last_uin = g_strdup("0");
+
+	ggp_pubdir_start_search(gc, form);
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_set_status(GaimAccount *account, GaimStatus *status) {{{ */
+static void ggp_set_status(GaimAccount *account, GaimStatus *status)
+{
+	GaimStatusPrimitive prim;
+	GaimConnection *gc;
+	GGPInfo *info;
+	const char *status_id;
+	int new_status, new_status_descr;
+
+	prim = gaim_status_type_get_primitive(gaim_status_get_type(status));
+
+	if (!gaim_status_is_active(status))
+		return;
+
+	if (prim == GAIM_STATUS_OFFLINE) {
+		gaim_account_disconnect(account);
+		return;
+	}
+
+	if (!gaim_account_is_connected(account)) {
+		gaim_account_connect(account);
 		return;
 	}
-}
+
+	gc = gaim_account_get_connection(account);
+	info = gc->proto_data;
+
+	status_id = gaim_status_get_id(status);
+
+	gaim_debug_info("gg", "ggp_set_status: Requested status = %s\n", status_id);
 
-static const char *agg_list_icon(GaimAccount *a, GaimBuddy *b)
-{
-	return "gadu-gadu";
-}
+	if (strcmp(status_id, "available") == 0) {
+		new_status = GG_STATUS_AVAIL;
+		new_status_descr = GG_STATUS_AVAIL_DESCR;
+	} else if (strcmp(status_id, "away") == 0) {
+		new_status = GG_STATUS_BUSY;
+		new_status_descr = GG_STATUS_BUSY_DESCR;
+	} else if (strcmp(status_id, "invisible") == 0) {
+		new_status = GG_STATUS_INVISIBLE;
+		new_status_descr = GG_STATUS_INVISIBLE_DESCR;
+	} else {
+		new_status = GG_STATUS_AVAIL;
+		new_status_descr = GG_STATUS_AVAIL_DESCR;
+		gaim_debug_info("gg", "ggp_set_status: uknown status requested (status_id=%s)\n", status_id);
+	}
 
-static void agg_list_emblems(GaimBuddy *b, const char **se, const char **sw,
-							 const char **nw, const char **ne)
-{
-	GaimPresence *presence = gaim_buddy_get_presence(b);
+	const char *msg = gaim_status_get_attr_string(status, "message");
+
+	if (msg == NULL) {
+		gaim_debug_info("gg", "ggp_set_status: msg == NULL\n");
+		gg_change_status(info->session, new_status);
+	} else {
+		char *tmp = charset_convert(msg, "UTF-8", "CP1250");
+		gaim_debug_info("gg", "ggp_set_status: msg != NULL. msg = %s\n", tmp);
+		gaim_debug_info("gg", "ggp_set_status: gg_change_status_descr() = %d\n",
+				gg_change_status_descr(info->session, new_status_descr, tmp));
+		g_free(tmp);
+	}
 
-	if (!GAIM_BUDDY_IS_ONLINE(b))
-		*se = "offline";
-	else if (gaim_presence_is_status_active(presence, "away") ||
-			 gaim_presence_is_status_active(presence, "away-friends"))
-	{
-		*se = "away";
-	}
-	else if (gaim_presence_is_status_active(presence, "invisible") ||
-			 gaim_presence_is_status_active(presence, "invisible-friends"))
-	{
-		*se = "invisible";
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) {{{ */
+static void ggp_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
+{
+	GGPInfo *info = gc->proto_data;
+
+	gg_add_notify(info->session, ggp_str_to_uin(buddy->name));
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) {{{ */
+static void ggp_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
+{
+	GGPInfo *info = gc->proto_data;
+
+	gg_remove_notify(info->session, ggp_str_to_uin(buddy->name));
+}
+/* }}} */
+
+/*
+ */
+/* static void ggp_keepalive(GaimConnection *gc) {{{ */
+static void ggp_keepalive(GaimConnection *gc)
+{
+	GGPInfo *info = gc->proto_data;
+
+	/* gaim_debug_info("gg", "Keeping connection alive....\n"); */
+
+	if (gg_ping(info->session) < 0) {
+		gaim_debug_info("gg", "Not connected to the server "
+				"or gg_session is not correct\n");
+		gaim_connection_error(gc, _("Not connected to the server."));
 	}
 }
+/* }}} */
+
+/*
+ */
+/* static void ggp_register_user(GaimAccount *account) {{{ */
+static void ggp_register_user(GaimAccount *account)
+{
+	GaimConnection *gc;
+	GaimRequestFields *fields;
+	GaimRequestFieldGroup *group;
+	GaimRequestField *field;
+	GGPInfo *info;
+	GGPToken *token;
+
+	struct gg_http *req;
+	struct gg_token *t;
+
+	gaim_debug_info("gg", "token: requested.\n");
+
+	if ((req = gg_token(0)) == NULL) {
+		gaim_notify_error(account, _("Token Error"),
+				_("Unable to fetch the token.\n"), NULL);
+		return;
+	}
+	t = req->data;
+
+	gc = gaim_account_get_connection(account);
+
+	info = g_new0(GGPInfo, 1);
+	gc->proto_data = info;
+
+	token = g_new0(GGPToken, 1);
+	token->token_id = g_strdup(t->tokenid);
+	info->register_token = token;
+
+	fields = gaim_request_fields_new();
+	group = gaim_request_field_group_new(NULL);
+	gaim_request_fields_add_group(fields, group);
+
+	field = gaim_request_field_string_new("email", _("e-Mail"), "", FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("password1", _("Password"), "", FALSE);
+	gaim_request_field_string_set_masked(field, TRUE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("password2", _("Password (retype)"), "", FALSE);
+	gaim_request_field_string_set_masked(field, TRUE);
+	gaim_request_field_group_add_field(group, field);
+
+	field = gaim_request_field_string_new("token", _("Enter current token"), "", FALSE);
+	gaim_request_field_string_set_masked(field, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	/* original size: 60x24 */
+	field = gaim_request_field_image_new("token_img", _("Current token"), req->body, req->body_size);
+	gaim_request_field_group_add_field(group, field);
+
+	gg_token_free(req);
 
 
-static void agg_set_permit_deny_dummy(GaimConnection *gc)
-{
-	/* It's implemented on client side because GG server doesn't support this */
+	gaim_request_fields(account,
+		_("Register New Gadu-Gadu Account"),
+		_("Register New Gadu-Gadu Account"),
+		_("Please, fill in the following fields"),
+		fields, _("OK"), G_CALLBACK(ggp_callback_register_account_ok),
+		_("Cancel"), NULL, gc);
 }
+/* }}} */
 
-static void agg_permit_deny_dummy(GaimConnection *gc, const char *who)
-{
-	/* It's implemented on client side because GG server doesn't support this */
-}
-
-static void agg_group_buddy (GaimConnection *gc, const char *who,
-			const char *old_group, const char *new_group)
+/*
+ */
+/* static GList *ggp_actions(GaimPlugin *plugin, gpointer context) {{{ */
+static GList *ggp_actions(GaimPlugin *plugin, gpointer context)
 {
-    GaimBuddy *buddy = gaim_find_buddy(gaim_connection_get_account(gc), who);
-    gchar *newdata;
-    /* GG Number */
-    gchar *name = buddy->name;
-    /* GG Pseudo */
-    gchar *show = buddy->alias ? buddy->alias : buddy->name;
-    /* Group Name */
-    const gchar *gname = new_group;
+	GList *m = NULL;
+	GaimPluginAction *act;
+
+	act = gaim_plugin_action_new(_("Find buddies"), ggp_find_buddies);
+	m = g_list_append(m, act);
+
+	m = g_list_append(m, NULL);
+
+	act = gaim_plugin_action_new(_("Change password"), ggp_change_passwd);
+	m = g_list_append(m, act);
+
+	m = g_list_append(m, NULL);
+
+	act = gaim_plugin_action_new(_("Upload buddylist to Server"), ggp_action_buddylist_put);
+	m = g_list_append(m, act);
 
-    newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s;%s%s\r\n",
-		    show, show, show, show, "", gname, name, "", "");
-    agg_save_buddy_list(gc, newdata);
-    g_free(newdata);
-}
+	act = gaim_plugin_action_new(_("Download buddylist from Server"), ggp_action_buddylist_get);
+	m = g_list_append(m, act);
+
+	act = gaim_plugin_action_new(_("Delete buddylist from Server"), ggp_action_buddylist_delete);
+	m = g_list_append(m, act);
+
+	act = gaim_plugin_action_new(_("Save buddylist to file"), ggp_action_buddylist_save);
+	m = g_list_append(m, act);
 
-static void agg_rename_group (GaimConnection *gc, const char *old_name,
-		     GaimGroup *group, GList *moved_buddies)
-{
-    agg_save_buddy_list(gc, NULL);
+	act = gaim_plugin_action_new(_("Load buddylist from file"), ggp_action_buddylist_load);
+	m = g_list_append(m, act);
+
+	return m;
 }
+/* }}} */
 
-static GaimPlugin *my_protocol = NULL;
-
+/* prpl_info setup {{{ */
 static GaimPluginProtocolInfo prpl_info =
 {
-	0,
-	NULL,						/* user_splits */
-	NULL,						/* protocol_options */
+	OPT_PROTO_REGISTER_NOSCREENNAME,
+	NULL,					/* user_splits */
+	NULL,					/* protocol_options */
 	NO_BUDDY_ICONS,			/* icon_spec */
-	agg_list_icon,			/* list_icon */
-	agg_list_emblems,		/* list_emblems */
-	NULL,						/* status_text */
-	NULL,						/* tooltip_text */
-	agg_status_types,		/* status_types */
-	agg_blist_node_menu,		/* blist_node_menu */
-	NULL,						/* chat_info */
-	NULL,						/* chat_info_defaults */
-	agg_login,			/* login */
-	agg_close,			/* close */
-	agg_send_im,			/* send_im */
-	NULL,						/* set_info */
-	NULL,						/* send_typing */
-	agg_get_info,			/* get_info */
-	agg_set_status,			/* set_away */
-	NULL,						/* set_idle */
-	agg_change_passwd,			/* change_passwd */
-	agg_add_buddy,				/* add_buddy */
-	NULL,						/* add_buddies */
-	agg_rem_buddy,				/* remove_buddy */
-	NULL,						/* remove_buddies */
-	agg_permit_deny_dummy,		/* add_permit */
-	agg_permit_deny_dummy,		/* add_deny */
-	agg_permit_deny_dummy,		/* rem_permit */
-	agg_permit_deny_dummy,		/* rem_deny */
-	agg_set_permit_deny_dummy,	/* set_permit_deny */
-	NULL,						/* join_chat */
-	NULL,						/* reject_chat */
-	NULL,						/* get_chat_name */
-	NULL,						/* chat_invite */
-	NULL,						/* chat_leave */
-	NULL,						/* chat_whisper */
-	NULL,						/* chat_send */
-	agg_keepalive,			/* keepalive */
-	NULL,						/* register_user */
-	NULL,						/* get_cb_info */
-	NULL,						/* get_cb_away */
-	NULL,						/* alias_buddy */
-	agg_group_buddy,		/* group_buddy */
-	agg_rename_group,		/* rename_group */
-	agg_buddy_free,			/* buddy_free */
-	NULL,						/* convo_closed */
-	NULL,						/* normalize */
-	NULL,						/* set_buddy_icon */
-	NULL,						/* remove_group */
-	NULL,						/* get_cb_real_name */
-	NULL,						/* set_chat_topic */
-	NULL,						/* find_blist_chat */
-	NULL,						/* roomlist_get_list */
-	NULL,						/* roomlist_cancel */
-	NULL,						/* roomlist_expand_category */
-	NULL,						/* can_receive_file */
-	NULL						/* send_file */
+	ggp_list_icon,			/* list_icon */
+	ggp_list_emblems,		/* list_emblems */
+	ggp_status_text,		/* status_text */
+	ggp_tooltip_text,		/* tooltip_text */
+	ggp_status_types,		/* status_types */
+	ggp_blist_node_menu,	/* blist_node_menu */
+	NULL,					/* chat_info */
+	NULL,					/* chat_info_defaults */
+	ggp_login,				/* login */
+	ggp_close,				/* close */
+	ggp_send_im,			/* send_im */
+	NULL,					/* set_info */
+	NULL,					/* send_typing */
+	ggp_get_info,			/* get_info */
+	ggp_set_status,			/* set_away */
+	NULL,					/* set_idle */
+	NULL,					/* change_passwd */
+	ggp_add_buddy,			/* add_buddy */
+	NULL,					/* add_buddies */
+	ggp_remove_buddy,		/* remove_buddy */
+	NULL,					/* remove_buddies */
+	NULL,					/* add_permit */
+	NULL,					/* add_deny */
+	NULL,					/* rem_permit */
+	NULL,					/* rem_deny */
+	NULL,					/* set_permit_deny */
+	NULL,					/* join_chat */
+	NULL,					/* reject_chat */
+	NULL,					/* get_chat_name */
+	NULL,					/* chat_invite */
+	NULL,					/* chat_leave */
+	NULL,					/* chat_whisper */
+	NULL,					/* chat_send */
+	ggp_keepalive,			/* keepalive */
+	ggp_register_user,		/* register_user */
+	NULL,					/* get_cb_info */
+	NULL,					/* get_cb_away */
+	NULL,					/* alias_buddy */
+	NULL,					/* group_buddy */
+	NULL,					/* rename_group */
+	NULL,					/* buddy_free */
+	NULL,					/* convo_closed */
+	NULL,					/* normalize */
+	NULL,					/* set_buddy_icon */
+	NULL,					/* remove_group */
+	NULL,					/* get_cb_real_name */
+	NULL,					/* set_chat_topic */
+	NULL,					/* find_blist_chat */
+	NULL,					/* roomlist_get_list */
+	NULL,					/* roomlist_cancel */
+	NULL,					/* roomlist_expand_category */
+	NULL,					/* can_receive_file */
+	NULL					/* send_file */
 };
+/* }}} */
 
-static GaimPluginInfo info =
-{
-	GAIM_PLUGIN_MAGIC,
-	GAIM_MAJOR_VERSION,
-	GAIM_MINOR_VERSION,
-	GAIM_PLUGIN_PROTOCOL,                             /**< type           */
-	NULL,                                             /**< ui_requirement */
-	0,                                                /**< flags          */
-	NULL,                                             /**< dependencies   */
-	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
+/* GaimPluginInfo setup {{{ */
+static GaimPluginInfo info = {
+	GAIM_PLUGIN_MAGIC,		/* magic */
+	GAIM_MAJOR_VERSION,		/* major_version */
+	GAIM_MINOR_VERSION,		/* minor_version */
+	GAIM_PLUGIN_PROTOCOL,		/* plugin type */
+	NULL,				/* ui_requirement */
+	0,				/* flags */
+	NULL,				/* dependencies */
+	GAIM_PRIORITY_DEFAULT,		/* priority */
+
+	"prpl-gg",			/* id */
+	"Gadu-Gadu",			/* name */
+	VERSION,			/* version */
 
-	"prpl-gg",		                          /**< id             */
-	"Gadu-Gadu",                                      /**< name           */
-	VERSION,                                          /**< version        */
-	                                                  /**  summary        */
-	N_("Gadu-Gadu Protocol Plugin"),
-	                                                  /**  description    */
-	N_("Gadu-Gadu Protocol Plugin"),
-	"Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>",       /**< author         */
-	GAIM_WEBSITE,                                     /**< homepage       */
+	N_("Gadu-Gadu Protocol Plugin"),	/* summary */
+	N_("Polish popular IM"),		/* description */
+	"boler@sourceforge.net",	/* author */
+	GAIM_WEBSITE,			/* homepage */
+
+	NULL,				/* load */
+	NULL,				/* unload */
+	NULL,				/* destroy */
 
-	NULL,                                             /**< load           */
-	NULL,                                             /**< unload         */
-	NULL,                                             /**< destroy        */
+	NULL,				/* ui_info */
+	&prpl_info,			/* extra_info */
+	NULL,				/* prefs_info */
+	ggp_actions			/* actions */
+};
+/* }}} */
 
-	NULL,                                             /**< ui_info        */
-	&prpl_info,                                       /**< extra_info     */
-	NULL,
-	agg_actions
-};
-
-static void
-init_plugin(GaimPlugin *plugin)
+/*
+ */
+/* static void init_plugin(GaimPlugin *plugin) {{{ */
+static void init_plugin(GaimPlugin *plugin)
 {
 	GaimAccountOption *option;
 
-	option = gaim_account_option_string_new(_("Nick"), "nick",
-			"Gadu-Gadu User");
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
-			option);
+	option = gaim_account_option_string_new(_("Nickname"), "nick", _("Gadu-Gadu User"));
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
 	my_protocol = plugin;
 }
+/* }}} */
 
-GAIM_INIT_PLUGIN(gg, init_plugin, info)
+GAIM_INIT_PLUGIN(gadu-gadu, init_plugin, info);
+
+/* vim: set ts=4 sts=0 sw=4 noet: */