pidgin/pidgin

Make sure we remove all the files we install.
release-2.x.y
2021-04-11, Gary Kramlich
5407cbf3c5dd
Make sure we remove all the files we install.

Patch was provided by Johann Lochner.

Testing Done:
Build and ran the installer and uninstaller and verified that `C:\Program Files (x86)\Pidgin` was empty and therefore removed.

Bugs closed: PIDGIN-17515

Reviewed at https://reviews.imfreedom.org/r/612/
/**
* @file sslconn.c SSL API
* @ingroup core
*/
/* 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
*/
#define _PURPLE_SSLCONN_C_
#include "internal.h"
#include "certificate.h"
#include "debug.h"
#include "request.h"
#include "sslconn.h"
static gboolean _ssl_initialized = FALSE;
static PurpleSslOps *_ssl_ops = NULL;
static gboolean
ssl_init(void)
{
PurplePlugin *plugin;
PurpleSslOps *ops;
if (_ssl_initialized)
return FALSE;
plugin = purple_plugins_find_with_id("core-ssl");
if (plugin != NULL && !purple_plugin_is_loaded(plugin))
purple_plugin_load(plugin);
ops = purple_ssl_get_ops();
if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) ||
(ops->connectfunc == NULL) || (ops->close == NULL) ||
(ops->read == NULL) || (ops->write == NULL))
{
return FALSE;
}
return (_ssl_initialized = ops->init());
}
gboolean
purple_ssl_is_supported(void)
{
#ifdef HAVE_SSL
ssl_init();
return (purple_ssl_get_ops() != NULL);
#else
return FALSE;
#endif
}
static void
purple_ssl_connect_cb(gpointer data, gint source, const gchar *error_message)
{
PurpleSslConnection *gsc;
PurpleSslOps *ops;
gsc = data;
gsc->connect_data = NULL;
if (source < 0)
{
if (gsc->error_cb != NULL)
gsc->error_cb(gsc, PURPLE_SSL_CONNECT_FAILED, gsc->connect_cb_data);
purple_ssl_close(gsc);
return;
}
gsc->fd = source;
ops = purple_ssl_get_ops();
ops->connectfunc(gsc);
}
PurpleSslConnection *
purple_ssl_connect(PurpleAccount *account, const char *host, int port,
PurpleSslInputFunction func, PurpleSslErrorFunction error_func,
void *data)
{
return purple_ssl_connect_with_ssl_cn(account, host, port, func, error_func,
NULL, data);
}
PurpleSslConnection *
purple_ssl_connect_with_ssl_cn(PurpleAccount *account, const char *host, int port,
PurpleSslInputFunction func, PurpleSslErrorFunction error_func,
const char *ssl_cn, void *data)
{
PurpleSslConnection *gsc;
g_return_val_if_fail(host != NULL, NULL);
g_return_val_if_fail(port != 0 && port != -1, NULL);
g_return_val_if_fail(func != NULL, NULL);
g_return_val_if_fail(purple_ssl_is_supported(), NULL);
if (!_ssl_initialized)
{
if (!ssl_init())
return NULL;
}
gsc = g_new0(PurpleSslConnection, 1);
gsc->fd = -1;
gsc->host = ssl_cn ? g_strdup(ssl_cn) : g_strdup(host);
gsc->port = port;
gsc->connect_cb_data = data;
gsc->connect_cb = func;
gsc->error_cb = error_func;
/* TODO: Move this elsewhere */
gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
gsc->connect_data = purple_proxy_connect(NULL, account, host, port, purple_ssl_connect_cb, gsc);
if (gsc->connect_data == NULL)
{
g_free(gsc->host);
g_free(gsc);
return NULL;
}
return (PurpleSslConnection *)gsc;
}
static void
recv_cb(gpointer data, gint source, PurpleInputCondition cond)
{
PurpleSslConnection *gsc = data;
gsc->recv_cb(gsc->recv_cb_data, gsc, cond);
}
void
purple_ssl_input_add(PurpleSslConnection *gsc, PurpleSslInputFunction func,
void *data)
{
g_return_if_fail(func != NULL);
g_return_if_fail(purple_ssl_is_supported());
gsc->recv_cb_data = data;
gsc->recv_cb = func;
gsc->inpa = purple_input_add(gsc->fd, PURPLE_INPUT_READ, recv_cb, gsc);
}
const gchar *
purple_ssl_strerror(PurpleSslErrorType error)
{
switch(error) {
case PURPLE_SSL_CONNECT_FAILED:
return _("SSL Connection Failed");
case PURPLE_SSL_HANDSHAKE_FAILED:
return _("SSL Handshake Failed");
case PURPLE_SSL_CERTIFICATE_INVALID:
return _("SSL peer presented an invalid certificate");
default:
purple_debug_warning("sslconn", "Unknown SSL error code %d\n", error);
return _("Unknown SSL error");
}
}
PurpleSslConnection *
purple_ssl_connect_fd(PurpleAccount *account, int fd,
PurpleSslInputFunction func,
PurpleSslErrorFunction error_func,
void *data)
{
return purple_ssl_connect_with_host_fd(account, fd, func, error_func, NULL, data);
}
PurpleSslConnection *
purple_ssl_connect_with_host_fd(PurpleAccount *account, int fd,
PurpleSslInputFunction func,
PurpleSslErrorFunction error_func,
const char *host,
void *data)
{
PurpleSslConnection *gsc;
PurpleSslOps *ops;
g_return_val_if_fail(fd != -1, NULL);
g_return_val_if_fail(func != NULL, NULL);
g_return_val_if_fail(purple_ssl_is_supported(), NULL);
if (!_ssl_initialized)
{
if (!ssl_init())
return NULL;
}
gsc = g_new0(PurpleSslConnection, 1);
gsc->connect_cb_data = data;
gsc->connect_cb = func;
gsc->error_cb = error_func;
gsc->fd = fd;
if (host) {
gsc->host = g_strdup(host);
}
/* TODO: Move this elsewhere */
gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
ops = purple_ssl_get_ops();
ops->connectfunc(gsc);
return (PurpleSslConnection *)gsc;
}
void
purple_ssl_close(PurpleSslConnection *gsc)
{
PurpleSslOps *ops;
g_return_if_fail(gsc != NULL);
purple_request_close_with_handle(gsc);
purple_notify_close_with_handle(gsc);
ops = purple_ssl_get_ops();
(ops->close)(gsc);
if (gsc->connect_data != NULL)
purple_proxy_connect_cancel(gsc->connect_data);
if (gsc->inpa > 0)
purple_input_remove(gsc->inpa);
if (gsc->fd >= 0)
close(gsc->fd);
g_free(gsc->host);
g_free(gsc);
}
size_t
purple_ssl_read(PurpleSslConnection *gsc, void *data, size_t len)
{
PurpleSslOps *ops;
g_return_val_if_fail(gsc != NULL, 0);
g_return_val_if_fail(data != NULL, 0);
g_return_val_if_fail(len > 0, 0);
ops = purple_ssl_get_ops();
return (ops->read)(gsc, data, len);
}
size_t
purple_ssl_write(PurpleSslConnection *gsc, const void *data, size_t len)
{
PurpleSslOps *ops;
g_return_val_if_fail(gsc != NULL, 0);
g_return_val_if_fail(data != NULL, 0);
g_return_val_if_fail(len > 0, 0);
ops = purple_ssl_get_ops();
return (ops->write)(gsc, data, len);
}
GList *
purple_ssl_get_peer_certificates(PurpleSslConnection *gsc)
{
PurpleSslOps *ops;
g_return_val_if_fail(gsc != NULL, NULL);
ops = purple_ssl_get_ops();
return (ops->get_peer_certificates)(gsc);
}
void
purple_ssl_set_ops(PurpleSslOps *ops)
{
_ssl_ops = ops;
}
PurpleSslOps *
purple_ssl_get_ops(void)
{
return _ssl_ops;
}
void
purple_ssl_init(void)
{
/* Although purple_ssl_is_supported will do the initialization on
command, SSL plugins tend to register CertificateSchemes as well
as providing SSL ops. */
if (!ssl_init()) {
purple_debug_error("sslconn", "Unable to initialize SSL.\n");
}
}
void
purple_ssl_uninit(void)
{
PurpleSslOps *ops;
if (!_ssl_initialized)
return;
ops = purple_ssl_get_ops();
ops->uninit();
_ssl_initialized = FALSE;
}