libpurple/smiley-custom.c

Tue, 06 Apr 2021 03:35:20 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Tue, 06 Apr 2021 03:35:20 -0500
changeset 40840
b5f355f90ab0
parent 40669
48dfed6f4f1f
permissions
-rw-r--r--

Port the updates from 2.14.2 and the upcoming 2.14.3 to 3.0.0

* Use the unicode version of the System and UserInfo plugins to fix
non-english languages in the Windows installer.
* Update the installer to use the inetc plugin so that https downloads will
work. This became necessary because Sourceforge now redirects http to
https.
* Standardize everything in pidgin/win32/winpidgin.c to use `wprintf`.

Testing Done:
Compiled and ran on windows 10.

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

/* 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.
 *
 * 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 "smiley-custom.h"

#include "internal.h"
#include "debug.h"
#include "util.h"

#include <glib/gstdio.h>
#include <errno.h>

#define SMILEYS_DEFAULT_FOLDER "custom_smiley"
#define SMILEYS_INDEX_FILE "smileys.xml"

static gchar *smileys_dir;
static gchar *smileys_index;

static PurpleSmileyList *smileys_list;
static gboolean disable_write = FALSE;

/*******************************************************************************
 * XML storage
 ******************************************************************************/

static void
purple_smiley_custom_load(void)
{
	PurpleXmlNode *root_node, *profile_node, *smileyset_node, *smiley_node;
	gchar *basename;
	gchar *dirname;
	int got_smileys = 0;

	if (!g_file_test(smileys_index, G_FILE_TEST_EXISTS))
		return;

	basename = g_path_get_basename(smileys_index);
	dirname = g_path_get_dirname(smileys_index);
	root_node = purple_xmlnode_from_file(dirname, basename,
			"custom smileys index", "smiley-custom");
	g_free(dirname);
	g_free(basename);

	g_return_if_fail(root_node);

	profile_node = purple_xmlnode_get_child(root_node, "profile");
	if (!profile_node) {
		purple_xmlnode_free(root_node);
		g_return_if_fail(profile_node);
	}

	smileyset_node = purple_xmlnode_get_child(profile_node, "smiley_set");
	if (!smileyset_node) {
		purple_xmlnode_free(root_node);
		g_return_if_fail(smileyset_node);
	}

	smiley_node = purple_xmlnode_get_child(smileyset_node, "smiley");
	while (smiley_node) {
		const gchar *shortcut, *file_name;

		shortcut = purple_xmlnode_get_attrib(smiley_node, "shortcut");
		file_name = purple_xmlnode_get_attrib(smiley_node, "filename");

		if (shortcut && file_name) {
			PurpleSmiley *smiley;
			gchar *file_path = g_build_filename(
				smileys_dir, file_name, NULL);

			smiley = purple_smiley_new(shortcut, file_path);
			g_free(file_path);

			if (purple_smiley_list_add(smileys_list, smiley)) {
				got_smileys++;
			} else {
				purple_debug_warning("smiley-custom",
					"Couldn't add '%s' smiley", shortcut);
			}
			g_object_unref(smiley);
		}

		smiley_node = purple_xmlnode_get_next_twin(smiley_node);
	}

	purple_xmlnode_free(root_node);

	purple_debug_info("smiley-custom", "Loaded %d custom smiley(s)",
		got_smileys);
}

static PurpleXmlNode *
smileys_to_xmlnode(void)
{
	PurpleXmlNode *root_node, *profile_node, *smileyset_node;
	GList *smileys, *it;
	gchar *basename;

	root_node = purple_xmlnode_new("smileys");
	purple_xmlnode_set_attrib(root_node, "version", "1.0");

	profile_node = purple_xmlnode_new("profile");
	purple_xmlnode_insert_child(root_node, profile_node);
	purple_xmlnode_set_attrib(profile_node, "name", "Default");

	smileyset_node = purple_xmlnode_new("smiley_set");
	purple_xmlnode_insert_child(profile_node, smileyset_node);

	smileys = purple_smiley_list_get_all(smileys_list);

	for (it = smileys; it; it = g_list_next(it)) {
		PurpleSmiley *smiley = PURPLE_SMILEY(it->data);
		PurpleXmlNode *smiley_node;

		smiley_node = purple_xmlnode_new("smiley");
		purple_xmlnode_insert_child(smileyset_node, smiley_node);
		purple_xmlnode_set_attrib(smiley_node, "shortcut",
			purple_smiley_get_shortcut(smiley));
		basename = g_path_get_basename(purple_image_get_path(
				PURPLE_IMAGE(smiley)));
		purple_xmlnode_set_attrib(smiley_node, "filename", basename);
		g_free(basename);
	}

	return root_node;
}

static void
purple_smiley_custom_save(void)
{
	PurpleXmlNode *root_node;
	gchar *data;
	GError *error = NULL;

	if (disable_write)
		return;

	root_node = smileys_to_xmlnode();
	g_return_if_fail(root_node != NULL);

	data = purple_xmlnode_to_formatted_str(root_node, NULL);
	g_return_if_fail(data != NULL);

	g_file_set_contents(smileys_index, data, -1, &error);

	g_free(data);
	purple_xmlnode_free(root_node);

	if (error) {
		purple_debug_error("smiley-custom",
			"Error writting custom smileys xml file");
	}
}

static gchar *
purple_smiley_custom_img_checksum(PurpleImage *img)
{
	g_return_val_if_fail(PURPLE_IS_IMAGE(img), NULL);

	return g_compute_checksum_for_data(G_CHECKSUM_SHA1,
		purple_image_get_data(img),
		purple_image_get_data_size(img));
}


/*******************************************************************************
 * API implementation
 ******************************************************************************/

PurpleSmiley *
purple_smiley_custom_add(PurpleImage *img, const gchar *shortcut)
{
	PurpleSmiley *existing_smiley, *smiley;
	gchar *checksum, *file_path;
	gchar file_name[256];
	const gchar *file_ext;
	gboolean succ;

	g_return_val_if_fail(PURPLE_IS_IMAGE(img), NULL);

	existing_smiley = purple_smiley_list_get_by_shortcut(
		smileys_list, shortcut);

	g_object_ref(img);

	if (existing_smiley) {
		disable_write = TRUE;
		purple_smiley_custom_remove(existing_smiley);
		disable_write = FALSE;
	}

	checksum = purple_smiley_custom_img_checksum(img);
	file_ext = purple_image_get_extension(img);
	if (file_ext == NULL || g_strcmp0("icon", file_ext) == 0) {
		purple_debug_warning("smiley-custom", "Invalid image type");
		return NULL;
	}

	g_snprintf(file_name, sizeof(file_name), "%s.%s", checksum, file_ext);
	g_free(checksum);

	file_path = g_build_filename(smileys_dir, file_name, NULL);

	if (!purple_image_save(img, file_path)) {
		purple_debug_error("smiley-custom", "Failed writing smiley "
			"file %s", file_path);
		g_free(file_path);
		g_object_unref(img);
		return NULL;
	}
	g_object_unref(img);

	smiley = purple_smiley_new(shortcut, file_path);
	g_free(file_path);
	succ = purple_smiley_list_add(smileys_list, smiley);
	g_object_unref(smiley);

	if (!succ)
		purple_debug_error("smiley-custom", "Failed adding a smiley");

	purple_smiley_custom_save();

	return smiley;
}

void
purple_smiley_custom_remove(PurpleSmiley *smiley)
{
	PurpleSmiley *existing_smiley;
	const gchar *smiley_shortcut, *path;
	GList *other_smileys, *it;
	gboolean is_unique;

	g_return_if_fail(PURPLE_IS_SMILEY(smiley));

	smiley_shortcut = purple_smiley_get_shortcut(smiley);
	existing_smiley = purple_smiley_list_get_by_shortcut(
		smileys_list, smiley_shortcut);
	if (existing_smiley == NULL)
		return;
	if (existing_smiley != smiley) {
		purple_debug_warning("smiley-custom", "Smiley is not in store");
		return;
	}

	g_object_ref(smiley);
	purple_smiley_list_remove(smileys_list, smiley);

	path = purple_image_get_path(PURPLE_IMAGE(smiley));

	other_smileys = purple_smiley_list_get_unique(smileys_list);
	is_unique = TRUE;
	for (it = other_smileys; it; it = g_list_next(it)) {
		PurpleSmiley *other = it->data;
		const gchar *other_path = purple_image_get_path(PURPLE_IMAGE(other));
		if (g_strcmp0(other_path, path) == 0) {
			is_unique = FALSE;
			break;
		}
	}
	g_list_free(other_smileys);

	if (is_unique)
		g_unlink(path);

	g_object_unref(smiley);

	purple_smiley_custom_save();
}

PurpleSmileyList *
purple_smiley_custom_get_list(void)
{
	return smileys_list;
}


/*******************************************************************************
 * Custom smiley subsystem
 ******************************************************************************/

void
_purple_smiley_custom_init(void)
{
	gint ret;

	smileys_dir = g_build_filename(purple_data_dir(),
		SMILEYS_DEFAULT_FOLDER, NULL);
	smileys_index = g_build_filename(purple_config_dir(),
		SMILEYS_INDEX_FILE, NULL);
	smileys_list = purple_smiley_list_new();

	ret = g_mkdir(smileys_dir, S_IRUSR | S_IWUSR | S_IXUSR);
	if (ret != 0 && errno != EEXIST) {
		purple_debug_error("smiley-custom", "Failed creating custom "
			"smileys directory: %s (%d)", g_strerror(errno), errno);
	}

	purple_smiley_custom_load();
}

void
_purple_smiley_custom_uninit(void)
{
	g_free(smileys_dir);
	g_free(smileys_index);
	g_object_unref(smileys_list);
}

mercurial