libpurple/protocols/gg/status.c

Mon, 20 Mar 2023 21:12:08 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Mon, 20 Mar 2023 21:12:08 -0500
changeset 42162
853501870190
parent 42128
118067ca0367
permissions
-rw-r--r--

Remove purple_protocol_client_status_text as it is no longer used

Testing Done:
Compiled

Reviewed at https://reviews.imfreedom.org/r/2367/

/* purple
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * Rewritten from scratch during Google Summer of Code 2012
 * by Tomek Wasilczyk (http://www.wasilczyk.pl).
 *
 * Previously implemented by:
 *  - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
 *  - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
 *  - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */

#include <glib/gi18n-lib.h>

#include <libgadu.h>

#include "status.h"

#include "gg.h"
#include "utils.h"

struct _ggp_status_session_data
{
	gboolean status_broadcasting;
	gchar *current_description;
};

static inline ggp_status_session_data *
ggp_status_get_ssdata(PurpleConnection *gc);

static gchar * ggp_status_validate_description(const gchar* msg);

static inline ggp_status_session_data *
ggp_status_get_ssdata(PurpleConnection *gc)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	return accdata->status_data;
}

void ggp_status_setup(PurpleConnection *gc)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	PurpleAccount *account = purple_connection_get_account(gc);

	ggp_status_session_data *ssdata = g_new0(ggp_status_session_data, 1);
	accdata->status_data = ssdata;

	ssdata->status_broadcasting =
		purple_account_get_bool(account, "status_broadcasting", TRUE);
}

void ggp_status_cleanup(PurpleConnection *gc)
{
	ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc);
	g_free(ssdata->current_description);
	g_free(ssdata);
}

static gchar * ggp_status_validate_description(const gchar* msg)
{
	if (msg == NULL || msg[0] == '\0')
		return NULL;

	return ggp_utf8_strndup(msg, GG_STATUS_DESCR_MAXSIZE);
}

GList *
ggp_status_types(G_GNUC_UNUSED PurpleProtocol *protocol,
                 G_GNUC_UNUSED PurpleAccount *account)
{
	GList *types = NULL;

	types = g_list_append(types, purple_status_type_new_with_attrs(
		PURPLE_STATUS_AVAILABLE, NULL, NULL,
		TRUE, TRUE, FALSE, "message", _("Message"),
		purple_value_new(G_TYPE_STRING), NULL));

	types = g_list_append(types, purple_status_type_new_with_attrs(
		PURPLE_STATUS_AVAILABLE, "freeforchat", _("Chatty"),
		TRUE, TRUE, FALSE, "message", _("Message"),
		purple_value_new(G_TYPE_STRING), NULL));

	types = g_list_append(types, purple_status_type_new_with_attrs(
		PURPLE_STATUS_AWAY, NULL, NULL,
		TRUE, TRUE, FALSE, "message", _("Message"),
		purple_value_new(G_TYPE_STRING), NULL));

	types = g_list_append(types, purple_status_type_new_with_attrs(
		PURPLE_STATUS_UNAVAILABLE, NULL, NULL,
		TRUE, TRUE, FALSE, "message", _("Message"),
		purple_value_new(G_TYPE_STRING), NULL));

	types = g_list_append(types, purple_status_type_new_with_attrs(
		PURPLE_STATUS_INVISIBLE, NULL, NULL,
		TRUE, TRUE, FALSE, "message", _("Message"),
		purple_value_new(G_TYPE_STRING), NULL));

	types = g_list_append(types, purple_status_type_new_with_attrs(
		PURPLE_STATUS_OFFLINE, NULL, NULL,
		TRUE, TRUE, FALSE, "message", _("Message"),
		purple_value_new(G_TYPE_STRING), NULL));

	return types;
}

int ggp_status_from_purplestatus(PurpleStatus *status, gchar **message)
{
	const char *status_id = purple_status_get_id(status);
	const char *status_message =
		purple_status_get_attr_string(status, "message");

	g_return_val_if_fail(message != NULL, 0);

	*message = NULL;
	if (status_message) {
		gchar *stripped = purple_markup_strip_html(status_message);
		g_strstrip(stripped);
		*message = ggp_status_validate_description(stripped);
		g_free(stripped);
	}

	if (0 == strcmp(status_id, "available"))
		return status_message ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL;
	if (0 == strcmp(status_id, "freeforchat"))
		return status_message ? GG_STATUS_FFC_DESCR : GG_STATUS_FFC;
	if (0 == strcmp(status_id, "away"))
		return status_message ? GG_STATUS_BUSY_DESCR : GG_STATUS_BUSY;
	if (0 == strcmp(status_id, "unavailable"))
		return status_message ? GG_STATUS_DND_DESCR : GG_STATUS_DND;
	if (0 == strcmp(status_id, "invisible"))
		return status_message ?
			GG_STATUS_INVISIBLE_DESCR : GG_STATUS_INVISIBLE;
	if (0 == strcmp(status_id, "offline"))
		return status_message ?
			GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL;

	purple_debug_error("gg", "ggp_status_from_purplestatus: "
		"unknown status requested (%s)\n", status_id);
	return status_message ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL;
}

const gchar * ggp_status_to_purplestatus(int status)
{
	switch (status)
	{
		case GG_STATUS_NOT_AVAIL:
		case GG_STATUS_NOT_AVAIL_DESCR:
		case GG_STATUS_BLOCKED:
		case GG_STATUS_UNKNOWN:
			return purple_primitive_get_id_from_type(
				PURPLE_STATUS_OFFLINE);
		case GG_STATUS_FFC:
		case GG_STATUS_FFC_DESCR:
			return "freeforchat";
		case GG_STATUS_AVAIL:
		case GG_STATUS_AVAIL_DESCR:
			return purple_primitive_get_id_from_type(
				PURPLE_STATUS_AVAILABLE);
		case GG_STATUS_BUSY:
		case GG_STATUS_BUSY_DESCR:
			return purple_primitive_get_id_from_type(
				PURPLE_STATUS_AWAY);
		case GG_STATUS_INVISIBLE:
		case GG_STATUS_INVISIBLE_DESCR:
			return purple_primitive_get_id_from_type(
				PURPLE_STATUS_INVISIBLE);
		case GG_STATUS_DND:
		case GG_STATUS_DND_DESCR:
			return purple_primitive_get_id_from_type(
				PURPLE_STATUS_UNAVAILABLE);
		default:
			purple_debug_warning("gg", "ggp_status_to_purplestatus: unknown status %#02x\n", status);
			return purple_primitive_get_id_from_type(
				PURPLE_STATUS_AVAILABLE);
	}
}

const gchar * ggp_status_get_name(const gchar *purple_status)
{
	if (g_strcmp0(purple_status, "freeforchat") == 0)
		return _("Chatty");
	return purple_primitive_get_name_from_type(
		purple_primitive_get_type_from_id(purple_status));
}

/*******************************************************************************
 * Own status.
 ******************************************************************************/

void ggp_status_set_initial(PurpleConnection *gc, struct gg_login_params *glp)
{
	ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc);
	PurpleAccount *account = purple_connection_get_account(gc);

	glp->status = ggp_status_from_purplestatus(
		purple_account_get_active_status(account), &glp->status_descr);
	if (!ggp_status_get_status_broadcasting(gc))
		glp->status |= GG_STATUS_FRIENDS_MASK;
	ssdata->current_description = g_strdup(glp->status_descr);
}

gboolean ggp_status_set(PurpleAccount *account, int status, const gchar* msg)
{
	PurpleConnection *gc = purple_account_get_connection(account);
	ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc);
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	gchar *new_description = ggp_status_validate_description(msg);

	if (!ssdata->status_broadcasting)
		status |= GG_STATUS_FRIENDS_MASK;

	if ((status == GG_STATUS_NOT_AVAIL ||
		status == GG_STATUS_NOT_AVAIL_DESCR) &&
		0 == g_strcmp0(ssdata->current_description, new_description))
	{
		purple_debug_info("gg", "ggp_status_set: new status doesn't "
			"differ when closing connection - ignore\n");
		g_free(new_description);
		return FALSE;
	}
	g_free(ssdata->current_description);
	ssdata->current_description = new_description;

	if (msg == NULL)
		gg_change_status(accdata->session, status);
	else
		gg_change_status_descr(accdata->session, status, new_description);

	return TRUE;
}

void
ggp_status_set_purplestatus(G_GNUC_UNUSED PurpleProtocolServer *protocol_server,
                            PurpleAccount *account, PurpleStatus *status)
{
	int status_gg;
	gchar *msg = NULL;

	if (!purple_status_is_active(status))
		return;

	status_gg = ggp_status_from_purplestatus(status, &msg);
	ggp_status_set(account, status_gg, msg);
	g_free(msg);
}

void ggp_status_set_disconnected(PurpleAccount *account)
{
	gchar *msg = NULL;

	ggp_status_from_purplestatus(purple_account_get_active_status(account),
		&msg);
	if (!ggp_status_set(account,
		msg ? GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL, msg))
	{
		g_free(msg);
		return;
	}

	/*
	struct gg_event *ev;
	guint64 wait_start = ggp_microtime(), now;
	int sleep_time = 5000;
	while ((ev = gg_watch_fd(info->session)) != NULL)
	{
		if (ev->type == GG_EVENT_DISCONNECT_ACK)
			break;
		now = ggp_microtime();
		if (now - wait_start + sleep_time >= 100000)
			break;
		usleep(sleep_time);
		sleep_time *= 2;
	}
	*/
	g_usleep(100000);

	g_free(msg);
}

void ggp_status_fake_to_self(PurpleConnection *gc)
{
	PurpleAccount *account = purple_connection_get_account(gc);
	PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
	PurpleStatus *status = purple_presence_get_active_status(
		purple_account_get_presence(account));
	const char *status_msg = purple_status_get_attr_string(status,
		"message");
	gchar *status_msg_gg = NULL;

	if (status_msg != NULL && status_msg[0] != '\0') {
		status_msg_gg = g_new0(gchar, GG_STATUS_DESCR_MAXSIZE + 1);
		g_utf8_strncpy(status_msg_gg, status_msg,
			GG_STATUS_DESCR_MAXSIZE);
	}

	purple_protocol_got_user_status(account,
		purple_contact_info_get_username(info),
		purple_status_get_id(status),
		status_msg_gg ? "message" : NULL, status_msg_gg, NULL);

	g_free(status_msg_gg);
}

gboolean ggp_status_get_status_broadcasting(PurpleConnection *gc)
{
	return ggp_status_get_ssdata(gc)->status_broadcasting;
}

void ggp_status_set_status_broadcasting(PurpleConnection *gc,
	gboolean broadcasting)
{
	PurpleAccount *account = purple_connection_get_account(gc);

	ggp_status_get_ssdata(gc)->status_broadcasting = broadcasting;
	purple_account_set_bool(account, "status_broadcasting", broadcasting);
	ggp_status_set_purplestatus(NULL, account,
		purple_account_get_active_status(account));
}

static void
ggp_status_broadcasting_dialog_ok(PurpleConnection *gc,
                                  PurpleRequestPage *page)
{
	gboolean buddies_only = purple_request_page_get_bool(page, "buddies_only");
	ggp_status_set_status_broadcasting(gc, !buddies_only);
}

void ggp_status_broadcasting_dialog(PurpleConnection *gc)
{
	PurpleRequestPage *page;
	PurpleRequestGroup *group;
	PurpleRequestField *field;

	page = purple_request_page_new();
	group = purple_request_group_new(NULL);
	purple_request_page_add_group(page, group);

	field = purple_request_field_bool_new("buddies_only",
		_("Show status only for buddies"),
		!ggp_status_get_status_broadcasting(gc));
	purple_request_group_add_field(group, field);

	purple_request_fields(gc,
		_("Change status broadcasting"),
		_("Please, select who can see your status"),
		NULL,
		page,
		_("OK"), G_CALLBACK(ggp_status_broadcasting_dialog_ok),
		_("Cancel"), NULL,
		purple_request_cpar_from_connection(gc), gc);
}

/*******************************************************************************
 * Buddy status.
 ******************************************************************************/

void ggp_status_got_others_buddy(PurpleConnection *gc, uin_t uin, int status,
	const char *descr);

/******************************************************************************/

void ggp_status_got_others(PurpleConnection *gc, struct gg_event *ev)
{
	if (ev->type == GG_EVENT_NOTIFY60) {
		struct gg_event_notify60 *notify = ev->event.notify60;
		int i;
		for (i = 0; notify[i].uin; i++)
			ggp_status_got_others_buddy(gc, notify[i].uin,
				GG_S(notify[i].status), notify[i].descr);
	} else if (ev->type == GG_EVENT_STATUS60) {
		struct gg_event_status60 *notify = &ev->event.status60;
		ggp_status_got_others_buddy(gc, notify->uin,
			GG_S(notify->status), notify->descr);
	} else {
		purple_debug_error("gg", "ggp_status_got_others: unexpected event %d",
		                   ev->type);
	}
}

void ggp_status_got_others_buddy(PurpleConnection *gc, uin_t uin, int status,
	const char *descr)
{
	PurpleAccount *account = purple_connection_get_account(gc);
	PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
	PurpleBuddy *buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin));
	const gchar *purple_status = ggp_status_to_purplestatus(status);
	gchar *status_message = NULL;
	gboolean is_own;

	is_own = (!g_strcmp0(ggp_uin_to_str(uin),
	                     purple_contact_info_get_username(info)));

	if (!buddy) {
		if (!is_own) {
			purple_debug_warning("gg",
				"ggp_status_got_others_buddy: "
				"buddy %u not found\n", uin);
		}
		return;
	}
	ggp_buddy_get_data(buddy)->blocked = (status == GG_STATUS_BLOCKED);
	ggp_buddy_get_data(buddy)->not_a_friend = (status == GG_STATUS_UNKNOWN);

	if (descr != NULL) {
		status_message = g_strdup(descr);
		g_strstrip(status_message);
		if (status_message[0] == '\0') {
			g_free(status_message);
			status_message = NULL;
		}
	}

	if (uin == ggp_str_to_uin(purple_contact_info_get_username(info))) {
		purple_debug_info("gg", "ggp_status_got_others_buddy: "
			"own status changed to %s [%s]\n",
			purple_status, status_message ? status_message : "");
	} else if (purple_debug_is_verbose()) {
		purple_debug_misc("gg", "ggp_status_got_others_buddy: "
			"status of %u changed to %s [%s]\n", uin,
			purple_status, status_message ? status_message : "");
	}

	if (status_message) {
		purple_protocol_got_user_status(account, ggp_uin_to_str(uin),
			purple_status, "message", status_message, NULL);
	} else {
		purple_protocol_got_user_status(account, ggp_uin_to_str(uin),
			purple_status, NULL);
	}

	g_free(status_message);
}

mercurial