# HG changeset patch
# Node ID 5de661a9d8c4
# Parent  c0c9eeca7d4b
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -101,7 +101,6 @@
 	'signals.c',
 	'status.c',
 	'stun.c',
-	'upnp.c',
 	'util.c',
 	'version.c',
 	'xfer.c',
@@ -210,7 +209,6 @@
 	'status.h',
 	'stun.h',
 	'tests.h',
-	'upnp.h',
 	'util.h',
 	'xfer.h',
 	'xmlnode.h',
@@ -323,9 +321,9 @@
                     install : true,
                     version : PURPLE_LIB_VERSION,
                     dependencies : # static_link_libs
-                        [dnsapi, ws2_32, glib, gio, gplugin_dep, gupnp,
-                         gupnp_igd, libsoup, libxml, gdk_pixbuf, gstreamer,
-                         gstreamer_app, json, sqlite3, math])
+                        [dnsapi, ws2_32, glib, gio, gplugin_dep, libsoup,
+                         libxml, gdk_pixbuf, gstreamer, gstreamer_app, json,
+                         sqlite3, math])
 
 install_headers(purple_coreheaders,
                 subdir : purple_include_base)
diff --git a/libpurple/network.c b/libpurple/network.c
--- a/libpurple/network.c
+++ b/libpurple/network.c
@@ -46,7 +46,6 @@
 #include "network.h"
 #include "prefs.h"
 #include "stun.h"
-#include "upnp.h"
 
 static gboolean force_online = FALSE;
 
@@ -134,12 +133,6 @@
 		return;
 	}
 
-	/* Attempt to get the IP from a NAT device using UPnP */
-	ip = purple_upnp_get_public_ip();
-	if (ip != NULL) {
-		return;
-	}
-
 	/* Attempt to get the IP from a NAT device using NAT-PMP */
 	ip = purple_pmp_get_public_ip();
 	if (ip != NULL) {
@@ -167,12 +160,6 @@
 			return g_strdup(stun->publicip);
 		}
 
-		/* Attempt to get the IP from a NAT device using UPnP */
-		ip = purple_upnp_get_public_ip();
-		if (ip != NULL) {
-			return g_strdup(ip);
-		}
-
 		/* Attempt to get the IP from a NAT device using NAT-PMP */
 		ip = purple_pmp_get_public_ip();
 		if (ip != NULL) {
@@ -325,11 +312,7 @@
 	purple_prefs_add_int   ("/purple/network/ports_range_start", 1024);
 	purple_prefs_add_int   ("/purple/network/ports_range_end", 2048);
 
-	if(purple_prefs_get_bool("/purple/network/map_ports") || purple_prefs_get_bool("/purple/network/auto_ip"))
-		purple_upnp_discover(NULL, NULL);
-
 	purple_pmp_init();
-	purple_upnp_init();
 
 	purple_network_set_stun_server(
 		purple_prefs_get_string("/purple/network/stun_server"));
@@ -342,9 +325,4 @@
 {
 	g_free(stun_ip);
 	g_free(turn_ip);
-
-	/* TODO: clean up remaining port mappings, note calling
-	 purple_upnp_remove_port_mapping from here doesn't quite work... */
-
-	purple_upnp_uninit();
 }
diff --git a/libpurple/upnp.h b/libpurple/upnp.h
deleted file mode 100644
--- a/libpurple/upnp.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * 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, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_UPNP_H
-#define PURPLE_UPNP_H
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* UPnP API                                                               */
-/**************************************************************************/
-
-typedef void (*PurpleUPnPCallback) (gboolean success, gpointer data);
-
-
-/**
- * purple_upnp_init:
- *
- * Initialize UPnP
- */
-void purple_upnp_init(void);
-
-/**
- * purple_upnp_uninit:
- *
- * Shuts down UPnP
- */
-void purple_upnp_uninit(void);
-
-/**
- * purple_upnp_discover:
- * @cb: (scope async): An optional callback function to be notified when the
- *      UPnP discovery is complete.
- * @cb_data: (closure): Extra data to be passed to the callback.
- *
- * Sends a discovery request to search for a UPnP enabled IGD that
- * contains the WANIPConnection service that will allow us to receive the
- * public IP address of the IGD, and control it for forwarding ports.
- * The result will be cached for further use.
- */
-void purple_upnp_discover(PurpleUPnPCallback cb, gpointer cb_data);
-
-/**
- * purple_upnp_get_public_ip:
- *
- * Gets the IP address from a UPnP enabled IGD that sits on the local
- * network, so when getting the network IP, instead of returning the
- * local network IP, the public IP is retrieved.  This is a cached value from
- * the time of the UPnP discovery.
- *
- * Returns: The IP address of the network, or NULL if something went wrong
- */
-const gchar* purple_upnp_get_public_ip(void);
-
-/**
- * purple_upnp_set_port_mapping:
- * @portmap: The port to map to this client
- * @protocol: The protocol to map, either "TCP" or "UDP"
- * @cb: (scope async): An optional callback function to be notified when the
- *      mapping addition is complete.
- * @cb_data: (closure): Extra data to be passed to the callback.
- *
- * Maps Ports in a UPnP enabled IGD that sits on the local network to
- * this purple client. Essentially, this function takes care of the port
- * forwarding so things like file transfers can work behind NAT firewalls
- */
-void purple_upnp_set_port_mapping(unsigned short portmap, const gchar *protocol, PurpleUPnPCallback cb, gpointer cb_data);
-
-/**
- * purple_upnp_remove_port_mapping:
- * @portmap: The port to delete the mapping for
- * @protocol: The protocol to map to. Either "TCP" or "UDP"
- * @cb: (scope async): An optional callback function to be notified when the
- *      mapping removal is complete.
- * @cb_data: (closure): Extra data to be passed to the callback.
- *
- * Deletes a port mapping in a UPnP enabled IGD that sits on the local network
- * to this purple client. Essentially, this function takes care of deleting the
- * port forwarding after they have completed a connection so another client on
- * the local network can take advantage of the port forwarding
- */
-void purple_upnp_remove_port_mapping(unsigned short portmap, const gchar *protocol, PurpleUPnPCallback cb, gpointer cb_data);
-
-G_END_DECLS
-
-#endif /* PURPLE_UPNP_H */
diff --git a/libpurple/upnp.c b/libpurple/upnp.c
deleted file mode 100644
--- a/libpurple/upnp.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/* 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 <gio/gio.h>
-
-#include <libgupnp/gupnp-context-manager.h>
-#include <libgupnp/gupnp-control-point.h>
-#include <libgupnp/gupnp-service-info.h>
-#include <libgupnp/gupnp-service-proxy.h>
-#include <libgupnp-igd/gupnp-simple-igd.h>
-
-#include "upnp.h"
-
-#include "glibcompat.h"
-#include "soupcompat.h"
-
-#include "debug.h"
-#include "eventloop.h"
-#include "network.h"
-#include "proxy.h"
-#include "purplegio.h"
-#include "signals.h"
-#include "util.h"
-#include "xmlnode.h"
-
-/***************************************************************
-** General Defines                                             *
-****************************************************************/
-#define PORT_MAPPING_LEASE_TIME 0
-#define PORT_MAPPING_DESCRIPTION "PURPLE_UPNP_PORT_FORWARD"
-
-typedef enum {
-	PURPLE_UPNP_STATUS_UNDISCOVERED = -1,
-	PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER,
-	PURPLE_UPNP_STATUS_DISCOVERING,
-	PURPLE_UPNP_STATUS_DISCOVERED
-} PurpleUPnPStatus;
-
-typedef struct {
-	PurpleUPnPStatus status;
-	gchar *control_url;
-	gchar *service_type;
-	char publicip[16];
-	char internalip[16];
-	gint64 lookup_time;
-} PurpleUPnPControlInfo;
-
-typedef struct {
-	unsigned short portmap;
-	gchar protocol[4];
-	gboolean add;
-	PurpleUPnPCallback cb;
-	gpointer cb_data;
-	gboolean success;
-	guint tima; /* g_timeout_add handle */
-} PurpleUPnPMappingAddRemove;
-
-static PurpleUPnPControlInfo control_info = {
-	PURPLE_UPNP_STATUS_UNDISCOVERED,
-	NULL, "\0", "\0", "\0", 0};
-
-static GUPnPContextManager *manager = NULL;
-static GUPnPSimpleIgd *simple_igd = NULL;
-static GSList *discovery_callbacks = NULL;
-
-static void lookup_internal_ip(void);
-
-static gboolean
-fire_ar_cb_async_and_free(gpointer data)
-{
-	PurpleUPnPMappingAddRemove *ar = data;
-	if (ar) {
-		if (ar->cb)
-			ar->cb(ar->success, ar->cb_data);
-		g_free(ar);
-	}
-
-	return FALSE;
-}
-
-static void
-fire_discovery_callbacks(gboolean success)
-{
-	while(discovery_callbacks) {
-		gpointer data;
-		PurpleUPnPCallback cb = discovery_callbacks->data;
-		discovery_callbacks = g_slist_delete_link(discovery_callbacks, discovery_callbacks);
-		data = discovery_callbacks->data;
-		discovery_callbacks = g_slist_delete_link(discovery_callbacks, discovery_callbacks);
-		cb(success, data);
-	}
-}
-
-static void
-upnp_service_proxy_call_action_cb(GObject *source, GAsyncResult *result,
-                                  G_GNUC_UNUSED gpointer data)
-{
-	GError *error = NULL;
-	char *ip = NULL;
-	GUPnPServiceProxyAction *action = NULL;
-
-	action = gupnp_service_proxy_call_action_finish(GUPNP_SERVICE_PROXY(source),
-	                                                result, &error);
-	if (error != NULL) {
-		control_info.publicip[0] = '\0';
-
-		purple_debug_error("upnp",
-		                   "Failed to call GetExternalIPAddress action: %s",
-		                   error->message);
-		g_error_free(error);
-		return;
-	}
-
-	gupnp_service_proxy_action_get_result(action, &error,
-	                                      "NewExternalIPAddress",
-	                                      G_TYPE_STRING, &ip, NULL);
-	if (error == NULL) {
-		g_strlcpy(control_info.publicip, ip, sizeof(control_info.publicip));
-
-		purple_debug_info("upnp", "NAT Returned IP: %s", control_info.publicip);
-		g_free(ip);
-	} else {
-		control_info.publicip[0] = '\0';
-
-		purple_debug_error("upnp",
-		                   "Failed to get result from GetExternalIPAddress: %s",
-		                   error->message);
-		g_error_free(error);
-	}
-
-	gupnp_service_proxy_action_unref(action);
-}
-
-static void
-upnp_service_proxy_available_cb(G_GNUC_UNUSED GUPnPControlPoint *cp,
-                                GUPnPServiceProxy *proxy,
-                                G_GNUC_UNUSED gpointer data)
-{
-	gchar *control_url = NULL;
-	const gchar *service_type = NULL;
-
-	control_url = gupnp_service_info_get_control_url(GUPNP_SERVICE_INFO(proxy));
-	service_type = gupnp_service_info_get_service_type(GUPNP_SERVICE_INFO(proxy));
-	purple_debug_info("upnp",
-	                  "Service proxy available for %s on control URL %s",
-	                  service_type,
-	                  control_url);
-
-	control_info.lookup_time = g_get_monotonic_time();
-	control_info.control_url = control_url;
-	control_info.service_type = g_strdup(service_type);
-
-	if(control_url) {
-		GUPnPServiceProxyAction *action = NULL;
-
-		control_info.status = PURPLE_UPNP_STATUS_DISCOVERED;
-		fire_discovery_callbacks(TRUE);
-
-		lookup_internal_ip();
-		action = gupnp_service_proxy_action_new("GetExternalIPAddress", NULL);
-		gupnp_service_proxy_call_action_async(proxy, action, NULL,
-		                                      upnp_service_proxy_call_action_cb,
-		                                      NULL);
-	} else {
-		control_info.status = PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER;
-		fire_discovery_callbacks(FALSE);
-	}
-}
-
-static void
-upnp_context_unavailable_cb(G_GNUC_UNUSED GUPnPContextManager *manager,
-                            GUPnPContext *context, G_GNUC_UNUSED gpointer data)
-{
-	purple_debug_info("upnp",
-	                  "UPnP context no longer available for interface %s",
-	                  gssdp_client_get_interface(GSSDP_CLIENT(context)));
-
-	/* Delete these to prevent them owning refs back on the context. */
-	g_object_set_data(G_OBJECT(context), "WANIPConnection", NULL);
-	g_object_set_data(G_OBJECT(context), "WANPPPConnection", NULL);
-}
-
-static void
-upnp_context_available_cb(G_GNUC_UNUSED GUPnPContextManager *manager,
-                          GUPnPContext *context, G_GNUC_UNUSED gpointer data)
-{
-	GUPnPControlPoint *cp;
-
-	purple_debug_info("upnp", "UPnP context now available for interface %s",
-	                  gssdp_client_get_interface(GSSDP_CLIENT(context)));
-
-	cp = gupnp_control_point_new(context,
-	                             "urn:schemas-upnp-org:service:WANIPConnection:1");
-	g_signal_connect(cp, "service-proxy-available",
-	                 G_CALLBACK(upnp_service_proxy_available_cb), NULL);
-	gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
-	g_object_set_data_full(G_OBJECT(context), "WANIPConnection", cp,
-	                       g_object_unref);
-
-	cp = gupnp_control_point_new(context,
-	                             "urn:schemas-upnp-org:service:WANPPPConnection:1");
-	g_signal_connect(cp, "service-proxy-available",
-	                 G_CALLBACK(upnp_service_proxy_available_cb), NULL);
-	gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
-	g_object_set_data_full(G_OBJECT(context), "WANPPPConnection", cp,
-	                       g_object_unref);
-}
-
-void
-purple_upnp_discover(PurpleUPnPCallback cb, gpointer cb_data)
-{
-	if (cb) {
-		discovery_callbacks = g_slist_append(discovery_callbacks, cb);
-		discovery_callbacks = g_slist_append(discovery_callbacks, cb_data);
-	}
-
-	if (control_info.status == PURPLE_UPNP_STATUS_DISCOVERING) {
-		return;
-	}
-
-	purple_debug_info("upnp",
-	                  "Starting discovery on all available interfaces");
-
-	g_clear_object(&manager);
-	manager = gupnp_context_manager_create(0);
-	g_signal_connect(manager, "context-available",
-	                 G_CALLBACK(upnp_context_available_cb), NULL);
-	g_signal_connect(manager, "context-unavailable",
-	                 G_CALLBACK(upnp_context_unavailable_cb), NULL);
-
-	control_info.status = PURPLE_UPNP_STATUS_DISCOVERING;
-}
-
-const gchar *
-purple_upnp_get_public_ip()
-{
-	if (control_info.status == PURPLE_UPNP_STATUS_DISCOVERED
-			&& *control_info.publicip)
-		return control_info.publicip;
-
-	/* Trigger another UPnP discovery if 5 minutes have elapsed since the
-	 * last one, and it wasn't successful */
-	if (control_info.status < PURPLE_UPNP_STATUS_DISCOVERING &&
-	    (g_get_monotonic_time() - control_info.lookup_time) >
-	            300 * G_USEC_PER_SEC) {
-		purple_upnp_discover(NULL, NULL);
-	}
-
-	return NULL;
-}
-
-/* TODO: This could be exported */
-static const gchar *
-purple_upnp_get_internal_ip(void)
-{
-	if (control_info.status == PURPLE_UPNP_STATUS_DISCOVERED
-			&& *control_info.internalip)
-		return control_info.internalip;
-
-	/* Trigger another UPnP discovery if 5 minutes have elapsed since the
-	 * last one, and it wasn't successful */
-	if (control_info.status < PURPLE_UPNP_STATUS_DISCOVERING &&
-	    (g_get_monotonic_time() - control_info.lookup_time) >
-	            300 * G_USEC_PER_SEC) {
-		purple_upnp_discover(NULL, NULL);
-	}
-
-	return NULL;
-}
-
-static void
-looked_up_internal_ip_cb(GObject *source, GAsyncResult *result,
-                         G_GNUC_UNUSED gpointer user_data)
-{
-	GSocketConnection *conn;
-	GSocketAddress *addr;
-	GInetSocketAddress *inetsockaddr;
-	GError *error = NULL;
-
-	conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
-	                                              result, &error);
-	if (conn == NULL) {
-		purple_debug_error("upnp", "Unable to look up local IP: %s",
-		                   error->message);
-		g_clear_error(&error);
-		return;
-	}
-
-	g_strlcpy(control_info.internalip, "0.0.0.0",
-	          sizeof(control_info.internalip));
-
-	addr = g_socket_connection_get_local_address(conn, &error);
-	if ((inetsockaddr = G_INET_SOCKET_ADDRESS(addr)) != NULL) {
-		GInetAddress *inetaddr =
-		        g_inet_socket_address_get_address(inetsockaddr);
-		if (g_inet_address_get_family(inetaddr) == G_SOCKET_FAMILY_IPV4 &&
-		    !g_inet_address_get_is_loopback(inetaddr))
-		{
-			gchar *ip = g_inet_address_to_string(inetaddr);
-			g_strlcpy(control_info.internalip, ip,
-			          sizeof(control_info.internalip));
-			g_free(ip);
-		}
-	} else {
-		purple_debug_error(
-		        "upnp", "Unable to get local address of connection: %s",
-		        error ? error->message : "unknown socket address type");
-		g_clear_error(&error);
-	}
-	g_object_unref(addr);
-
-	purple_debug_info("upnp", "Local IP: %s", control_info.internalip);
-	g_object_unref(conn);
-}
-
-static void
-lookup_internal_ip(void)
-{
-	gchar *host;
-	gint port;
-	GSocketClient *client;
-	GError *error = NULL;
-
-	if (!g_uri_split_network(control_info.control_url, G_URI_FLAGS_NONE, NULL,
-	                         &host, &port, &error))
-	{
-		purple_debug_error("upnp",
-			"lookup_internal_ip(): Failed In Parse URL: %s",
-			error->message);
-		return;
-	}
-
-	client = purple_gio_socket_client_new(NULL, &error);
-	if (client == NULL) {
-		purple_debug_error("upnp", "Get Local IP Connect to %s:%d Failed: %s",
-		                   host, port, error->message);
-		g_clear_error(&error);
-		g_free(host);
-		return;
-	}
-
-	purple_debug_info("upnp", "Attempting connection to %s:%u\n", host, port);
-	g_socket_client_connect_to_host_async(client, host, port, NULL,
-	                                      looked_up_internal_ip_cb, NULL);
-
-	g_object_unref(client);
-	g_free(host);
-}
-
-static void
-upnp_mapped_external_port_cb(GUPnPSimpleIgd *igd, const gchar *protocol,
-                             G_GNUC_UNUSED const gchar *external_ip,
-                             G_GNUC_UNUSED const gchar *replaces_external_ip,
-                             guint16 external_port,
-                             G_GNUC_UNUSED const gchar *local_ip,
-                             guint16 local_port,
-                             G_GNUC_UNUSED const gchar *description,
-                             gpointer data)
-{
-	PurpleUPnPMappingAddRemove *ar = data;
-
-	if(!purple_strequal(ar->protocol, protocol)) {
-		return;
-	}
-	if(external_port != ar->portmap) {
-		return;
-	}
-
-	purple_debug_info("upnp", "Successfully completed port mapping operation");
-
-	ar->success = TRUE;
-	ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
-
-	g_signal_handlers_disconnect_by_data(igd, ar);
-}
-
-static void
-upnp_error_mapping_port_cb(GUPnPSimpleIgd *igd, GError *error,
-                           const gchar *protocol,
-                           guint16 external_port,
-                           G_GNUC_UNUSED const gchar *local_ip,
-                           G_GNUC_UNUSED guint16 local_port,
-                           G_GNUC_UNUSED const gchar *description,
-                           gpointer data)
-{
-	PurpleUPnPMappingAddRemove *ar = data;
-
-	if(!purple_strequal(ar->protocol, protocol)) {
-		return;
-	}
-	if(external_port != ar->portmap) {
-		return;
-	}
-
-	purple_debug_error("upnp", "purple_upnp_set_port_mapping(): Failed: %s",
-	                   error->message);
-
-	ar->success = FALSE;
-	ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
-
-	g_signal_handlers_disconnect_by_data(igd, ar);
-}
-
-static void
-do_port_mapping_cb(gboolean has_control_mapping, gpointer data)
-{
-	PurpleUPnPMappingAddRemove *ar = data;
-
-	if (!has_control_mapping) {
-		ar->success = FALSE;
-		ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
-		return;
-	}
-
-	if(ar->add) {
-		const gchar *internal_ip;
-		/* get the internal IP */
-		if(!(internal_ip = purple_upnp_get_internal_ip())) {
-			purple_debug_error("upnp",
-				"purple_upnp_set_port_mapping(): couldn't get local ip\n");
-			ar->success = FALSE;
-			ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
-			return;
-		}
-
-		if(simple_igd == NULL) {
-			simple_igd = gupnp_simple_igd_new();
-		}
-
-		gupnp_simple_igd_add_port(simple_igd, ar->protocol, ar->portmap,
-		                          internal_ip, ar->portmap,
-		                          PORT_MAPPING_LEASE_TIME,
-		                          PORT_MAPPING_DESCRIPTION);
-	} else {
-		if(simple_igd == NULL) {
-			simple_igd = gupnp_simple_igd_new();
-		}
-
-		gupnp_simple_igd_remove_port(simple_igd, ar->protocol, ar->portmap);
-	}
-
-	g_signal_connect(simple_igd, "mapped-external-port",
-	                 G_CALLBACK(upnp_mapped_external_port_cb), ar);
-	g_signal_connect(simple_igd, "error-mapping-port",
-	                 G_CALLBACK(upnp_error_mapping_port_cb), ar);
-}
-
-static gboolean
-fire_port_mapping_failure_cb(gpointer data)
-{
-	PurpleUPnPMappingAddRemove *ar = data;
-
-	ar->tima = 0;
-	do_port_mapping_cb(FALSE, data);
-	return FALSE;
-}
-
-void
-purple_upnp_set_port_mapping(unsigned short portmap, const gchar *protocol,
-                             PurpleUPnPCallback cb, gpointer cb_data)
-{
-	PurpleUPnPMappingAddRemove *ar;
-
-	ar = g_new0(PurpleUPnPMappingAddRemove, 1);
-	ar->cb = cb;
-	ar->cb_data = cb_data;
-	ar->add = TRUE;
-	ar->portmap = portmap;
-	g_strlcpy(ar->protocol, protocol, sizeof(ar->protocol));
-
-	switch(control_info.status) {
-		case PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER:
-			if (g_get_monotonic_time() - control_info.lookup_time >
-				300 * G_USEC_PER_SEC) {
-				/* If we haven't had a successful UPnP discovery, check if 5 minutes
-				 * has elapsed since the last try, try again */
-				purple_upnp_discover(do_port_mapping_cb, ar);
-			} else if (cb) {
-				/* Asynchronously trigger a failed response */
-				ar->tima = g_timeout_add(10, fire_port_mapping_failure_cb, ar);
-			} else {
-				/* No need to do anything if nobody expects a response*/
-				g_free(ar);
-				ar = NULL;
-			}
-			break;
-
-		case PURPLE_UPNP_STATUS_UNDISCOVERED:
-		case PURPLE_UPNP_STATUS_DISCOVERING:
-			purple_upnp_discover(do_port_mapping_cb, ar);
-			break;
-
-		case PURPLE_UPNP_STATUS_DISCOVERED:
-		default:
-			do_port_mapping_cb(TRUE, ar);
-			break;
-	}
-}
-
-void
-purple_upnp_remove_port_mapping(unsigned short portmap, const char *protocol,
-                                PurpleUPnPCallback cb, gpointer cb_data)
-{
-	PurpleUPnPMappingAddRemove *ar;
-
-	ar = g_new0(PurpleUPnPMappingAddRemove, 1);
-	ar->cb = cb;
-	ar->cb_data = cb_data;
-	ar->add = FALSE;
-	ar->portmap = portmap;
-	g_strlcpy(ar->protocol, protocol, sizeof(ar->protocol));
-
-	switch(control_info.status) {
-		case PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER:
-			if (g_get_monotonic_time() - control_info.lookup_time >
-				300 * G_USEC_PER_SEC) {
-				/* If we haven't had a successful UPnP discovery, check if 5 minutes
-				 * has elapsed since the last try, try again */
-				purple_upnp_discover(do_port_mapping_cb, ar);
-			} else if (cb) {
-				/* Asynchronously trigger a failed response */
-				ar->tima = g_timeout_add(10, fire_port_mapping_failure_cb, ar);
-			} else {
-				/* No need to do anything if nobody expects a response*/
-				g_free(ar);
-				ar = NULL;
-			}
-			break;
-
-		case PURPLE_UPNP_STATUS_DISCOVERING:
-		case PURPLE_UPNP_STATUS_UNDISCOVERED:
-			purple_upnp_discover(do_port_mapping_cb, ar);
-			break;
-
-		case PURPLE_UPNP_STATUS_DISCOVERED:
-		default:
-			do_port_mapping_cb(TRUE, ar);
-			break;
-	}
-}
-
-static void
-purple_upnp_network_config_changed_cb(GNetworkMonitor *monitor, gboolean available, gpointer data)
-{
-	/* Reset the control_info to default values */
-	control_info.status = PURPLE_UPNP_STATUS_UNDISCOVERED;
-	g_clear_pointer(&control_info.control_url, g_free);
-	g_clear_pointer(&control_info.service_type, g_free);
-	control_info.publicip[0] = '\0';
-	control_info.internalip[0] = '\0';
-	control_info.lookup_time = 0;
-}
-
-void
-purple_upnp_init()
-{
-	g_signal_connect(g_network_monitor_get_default(),
-	                 "network-changed",
-	                 G_CALLBACK(purple_upnp_network_config_changed_cb),
-	                 NULL);
-}
-
-void
-purple_upnp_uninit(void)
-{
-	g_clear_object(&simple_igd);
-	g_clear_pointer(&control_info.control_url, g_free);
-	g_clear_pointer(&control_info.service_type, g_free);
-	g_clear_object(&manager);
-}
diff --git a/meson.build b/meson.build
--- a/meson.build
+++ b/meson.build
@@ -282,16 +282,7 @@
 
 json = dependency('json-glib-1.0', version : '>= 0.14.0')
 
-#######################################################################
-# Check for gUPnP (required)
-#######################################################################
-
-gupnp = dependency('gupnp-1.2', version : '>= 1.2.0')
-gupnp_igd = dependency('gupnp-igd-1.0',
-	version : '>= 1.2.0',
-	allow_fallback : get_option('build-dependencies'))
-
-#######################################################################
+######################################################################
 # Check for libsoup (required)
 #######################################################################
 
diff --git a/pidgin/prefs/pidginnetworkprefs.c b/pidgin/prefs/pidginnetworkprefs.c
--- a/pidgin/prefs/pidginnetworkprefs.c
+++ b/pidgin/prefs/pidginnetworkprefs.c
@@ -116,14 +116,10 @@
 		if ((stun != NULL) && (stun->status == PURPLE_STUN_STATUS_DISCOVERED)) {
 			ip = stun->publicip;
 		} else {
-			/* Attempt to get the IP from a NAT device using UPnP */
-			ip = purple_upnp_get_public_ip();
+			/* Attempt to get the IP from a NAT device using NAT-PMP */
+			ip = purple_pmp_get_public_ip();
 			if (ip == NULL) {
-				/* Attempt to get the IP from a NAT device using NAT-PMP */
-				ip = purple_pmp_get_public_ip();
-				if (ip == NULL) {
-					ip = "0.0.0.0";
-				}
+				ip = "0.0.0.0";
 			}
 		}
 	} else {
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -306,7 +306,6 @@
 libpurple/tests/test_util.c
 libpurple/tests/test_whiteboard_manager.c
 libpurple/tests/test_xmlnode.c
-libpurple/upnp.c
 libpurple/util.c
 libpurple/version.c
 libpurple/win32/libc_interface.c
diff --git a/subprojects/gupnp-igd-1.0.wrap b/subprojects/gupnp-igd-1.0.wrap
deleted file mode 100644
--- a/subprojects/gupnp-igd-1.0.wrap
+++ /dev/null
@@ -1,10 +0,0 @@
-[wrap-file]
-directory = gupnp-igd-1.2.0
-source_url = https://download.gnome.org/sources/gupnp-igd/1.2/gupnp-igd-1.2.0.tar.xz
-source_filename = gupnp-igd-1.2.0.tar.xz
-source_hash = 4b5120098aa13edd27818ba9ee4d7fe961bf540bf50d056ff703c61545e02be1
-
-[provide]
-dependency_names = gupnp-igd-1.0
-gupnp-igd-1.0 = gupnp_igd
-
