--- a/ChangeLog.API Sun Sep 18 04:06:33 2022 -0500
+++ b/ChangeLog.API Sun Sep 18 22:30:19 2022 -0500
@@ -264,7 +264,8 @@
* purple_str_size_to_units now takes a goffset as the size parameter
* PTFunc renamed to PurpleThemeFunc
* purple_txt_resolve now takes a PurpleAccount as the first parameter
- * UPnPMappingAddRemove renamed to PurpleUPnPMappingAddRemove
+ * purple_upnp_remove_port_mapping no longer returns anything + * purple_upnp_set_port_mapping no longer returns anything * purple_util_fetch_url_request now takes a PurpleAccount as
* purple_util_fetch_url_request now takes a length as the eighth
@@ -707,6 +708,8 @@
* purple_txt_resolve_account
* PurpleType, use GType instead.
* purple_unescape_filename
+ * PurpleUPnPMappingAddRemove + * purple_upnp_cancel_port_mapping * purple_utf8_salvage. Use g_utf8_make_valid instead.
--- a/libpurple/meson.build Sun Sep 18 04:06:33 2022 -0500
+++ b/libpurple/meson.build Sun Sep 18 22:30:19 2022 -0500
@@ -310,8 +310,8 @@
version : PURPLE_LIB_VERSION,
dependencies : # static_link_libs
- [dnsapi, ws2_32, glib, gio, gplugin_dep, gupnp, libsoup,
- libxml, gdk_pixbuf, gstreamer,
+ [dnsapi, ws2_32, glib, gio, gplugin_dep, gupnp, + gupnp_igd, libsoup, libxml, gdk_pixbuf, gstreamer, gstreamer_app, json, sqlite3, math])
install_headers(purple_coreheaders,
--- a/libpurple/upnp.c Sun Sep 18 04:06:33 2022 -0500
+++ b/libpurple/upnp.c Sun Sep 18 22:30:19 2022 -0500
@@ -24,8 +24,7 @@
#include <libgupnp/gupnp-control-point.h>
#include <libgupnp/gupnp-service-info.h>
#include <libgupnp/gupnp-service-proxy.h>
-#include <libsoup/soup.h>
+#include <libgupnp-igd/gupnp-simple-igd.h> @@ -44,45 +43,9 @@
/***************************************************************
****************************************************************/
-/* limit UPnP-triggered http downloads to 128k */
-#define MAX_UPNP_DOWNLOAD (128 * 1024)
-/******************************************************************
-*******************************************************************/
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" \
- "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
- "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" \
- "<u:%s xmlns:u=\"%s\">\r\n" \
-#define PORT_MAPPING_LEASE_TIME "0"
+#define PORT_MAPPING_LEASE_TIME 0 #define PORT_MAPPING_DESCRIPTION "PURPLE_UPNP_PORT_FORWARD"
-#define ADD_PORT_MAPPING_PARAMS \
- "<NewRemoteHost></NewRemoteHost>\r\n" \
- "<NewExternalPort>%i</NewExternalPort>\r\n" \
- "<NewProtocol>%s</NewProtocol>\r\n" \
- "<NewInternalPort>%i</NewInternalPort>\r\n" \
- "<NewInternalClient>%s</NewInternalClient>\r\n" \
- "<NewEnabled>1</NewEnabled>\r\n" \
- "<NewPortMappingDescription>" \
- PORT_MAPPING_DESCRIPTION \
- "</NewPortMappingDescription>\r\n" \
- PORT_MAPPING_LEASE_TIME \
- "</NewLeaseDuration>\r\n"
-#define DELETE_PORT_MAPPING_PARAMS \
- "<NewRemoteHost></NewRemoteHost>\r\n" \
- "<NewExternalPort>%i</NewExternalPort>\r\n" \
- "<NewProtocol>%s</NewProtocol>\r\n"
PURPLE_UPNP_STATUS_UNDISCOVERED = -1,
PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER,
@@ -99,8 +62,7 @@
-struct _PurpleUPnPMappingAddRemove
@@ -108,15 +70,14 @@
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 SoupSession *session = NULL;
+static GUPnPSimpleIgd *simple_igd = NULL; static GSList *discovery_callbacks = NULL;
static void lookup_internal_ip(void);
@@ -287,33 +248,6 @@
control_info.status = PURPLE_UPNP_STATUS_DISCOVERING;
-purple_upnp_generate_action_message_and_send(const gchar *actionName,
- const gchar *actionParams,
- SoupSessionCallback cb,
- /* set the soap message */
- soapMessage = g_strdup_printf(SOAP_ACTION, actionName,
- control_info.service_type, actionParams, actionName);
- msg = soup_message_new("POST", control_info.control_url);
- // purple_http_request_set_max_len(msg, MAX_UPNP_DOWNLOAD);
- action = g_strdup_printf("\"%s#%s\"", control_info.service_type, actionName);
- soup_message_headers_replace(soup_message_get_request_headers(msg),
- soup_message_set_request(msg, "text/xml; charset=utf-8", SOUP_MEMORY_TAKE,
- soapMessage, strlen(soapMessage));
- soup_session_queue_message(session, msg, cb, cb_data);
purple_upnp_get_public_ip()
@@ -431,26 +365,57 @@
-done_port_mapping_cb(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
+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, + G_GNUC_UNUSED const gchar *local_ip, + G_GNUC_UNUSED const gchar *description, - PurpleUPnPMappingAddRemove *ar = user_data;
- gboolean success = TRUE;
+ PurpleUPnPMappingAddRemove *ar = data; - /* determine if port mapping was a success */
- if (!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(msg))) {
- purple_debug_error("upnp",
- "purple_upnp_set_port_mapping(): Failed HTTP_OK: %s",
- soup_message_get_reason_phrase(msg));
- purple_debug_info("upnp",
- "Successfully completed port mapping operation");
+ if(!purple_strequal(ar->protocol, protocol)) { + if(external_port != ar->portmap) {
+ purple_debug_info("upnp", "Successfully completed port mapping operation"); ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
+ g_signal_handlers_disconnect_by_data(igd, ar); +upnp_error_mapping_port_cb(GUPnPSimpleIgd *igd, GError *error, + G_GNUC_UNUSED const gchar *local_ip, + G_GNUC_UNUSED guint16 local_port, + G_GNUC_UNUSED const gchar *description, + PurpleUPnPMappingAddRemove *ar = data; + if(!purple_strequal(ar->protocol, protocol)) { + if(external_port != ar->portmap) { + purple_debug_error("upnp", "purple_upnp_set_port_mapping(): Failed: %s", + ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar); + g_signal_handlers_disconnect_by_data(igd, ar); @@ -458,41 +423,43 @@
PurpleUPnPMappingAddRemove *ar = data;
- if (has_control_mapping) {
- 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->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
- strncpy(action_name, "AddPortMapping",
- action_params = g_strdup_printf(
- ADD_PORT_MAPPING_PARAMS,
- ar->portmap, ar->protocol, ar->portmap,
- strncpy(action_name, "DeletePortMapping", sizeof(action_name));
- action_params = g_strdup_printf(
- DELETE_PORT_MAPPING_PARAMS,
- ar->portmap, ar->protocol);
- ar->msg = purple_upnp_generate_action_message_and_send(
- action_name, action_params, done_port_mapping_cb, ar);
+ if (!has_control_mapping) { + ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
- ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
+ 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->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar); + 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); + 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); @@ -505,38 +472,9 @@
-void purple_upnp_cancel_port_mapping(PurpleUPnPMappingAddRemove *ar)
- /* Remove ar from discovery_callbacks if present; it was inserted after a cb.
- * The same cb may be in the list multiple times, so be careful to remove
- * the one associated with ar. */
- l = discovery_callbacks;
- GSList *next = l->next;
- if (next && (next->data == ar)) {
- discovery_callbacks = g_slist_delete_link(discovery_callbacks, next);
- discovery_callbacks = g_slist_delete_link(discovery_callbacks, l);
- g_source_remove(ar->tima);
- soup_session_cancel_message(session, ar->msg, SOUP_STATUS_CANCELLED);
-PurpleUPnPMappingAddRemove *
-purple_upnp_set_port_mapping(unsigned short portmap, const gchar* protocol,
- PurpleUPnPCallback cb, gpointer cb_data)
+purple_upnp_set_port_mapping(unsigned short portmap, const gchar *protocol, + PurpleUPnPCallback cb, gpointer cb_data) PurpleUPnPMappingAddRemove *ar;
@@ -574,13 +512,11 @@
do_port_mapping_cb(TRUE, ar);
-PurpleUPnPMappingAddRemove *
-purple_upnp_remove_port_mapping(unsigned short portmap, const char* protocol,
- PurpleUPnPCallback cb, gpointer cb_data)
+purple_upnp_remove_port_mapping(unsigned short portmap, const char *protocol, + PurpleUPnPCallback cb, gpointer cb_data) PurpleUPnPMappingAddRemove *ar;
@@ -618,8 +554,6 @@
do_port_mapping_cb(TRUE, ar);
@@ -637,8 +571,6 @@
- session = soup_session_new();
g_signal_connect(g_network_monitor_get_default(),
G_CALLBACK(purple_upnp_network_config_changed_cb),
@@ -648,9 +580,7 @@
- soup_session_abort(session);
- g_clear_object(&session);
+ 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);
--- a/libpurple/upnp.h Sun Sep 18 04:06:33 2022 -0500
+++ b/libpurple/upnp.h Sun Sep 18 22:30:19 2022 -0500
@@ -27,16 +27,12 @@
-typedef struct _PurpleUPnPMappingAddRemove PurpleUPnPMappingAddRemove;
/**************************************************************************/
/**************************************************************************/
-/* typedef struct _PurpleUPnPRequestData PurpleUPnPRequestData; */
typedef void (*PurpleUPnPCallback) (gboolean success, gpointer data);
@@ -80,15 +76,6 @@
const gchar* purple_upnp_get_public_ip(void);
- * purple_upnp_cancel_port_mapping:
- * @mapping_data: The data returned when you initiated the UPnP mapping request.
- * Cancel a pending port mapping request initiated with either
- * purple_upnp_set_port_mapping() or purple_upnp_remove_port_mapping().
-void purple_upnp_cancel_port_mapping(PurpleUPnPMappingAddRemove *mapping_data);
* purple_upnp_set_port_mapping:
* @portmap: The port to map to this client
* @protocol: The protocol to map, either "TCP" or "UDP"
@@ -99,12 +86,8 @@
* 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
- * Returns: (transfer full): Data which can be passed to purple_upnp_cancel_port_mapping() to
-PurpleUPnPMappingAddRemove *purple_upnp_set_port_mapping(unsigned short portmap, const gchar* protocol,
- PurpleUPnPCallback cb, gpointer cb_data);
+void purple_upnp_set_port_mapping(unsigned short portmap, const gchar *protocol, PurpleUPnPCallback cb, gpointer cb_data); * purple_upnp_remove_port_mapping:
@@ -118,12 +101,8 @@
* 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
- * Returns: (transfer full): Data which can be passed to purple_upnp_cancel_port_mapping() to
-PurpleUPnPMappingAddRemove *purple_upnp_remove_port_mapping(unsigned short portmap,
- const gchar* protocol, PurpleUPnPCallback cb, gpointer cb_data);
+void purple_upnp_remove_port_mapping(unsigned short portmap, const gchar *protocol, PurpleUPnPCallback cb, gpointer cb_data); --- a/meson.build Sun Sep 18 04:06:33 2022 -0500
+++ b/meson.build Sun Sep 18 22:30:19 2022 -0500
@@ -294,6 +294,7 @@
#######################################################################
gupnp = dependency('gupnp-1.2', version : '>= 1.2.0')
+gupnp_igd = dependency('gupnp-igd-1.0', version : '>= 1.0.0') #######################################################################
# Check for libsoup (required)