+++ /dev/null
-From 61df54155a3cb1846e6bf15e4f007ec8d623de63 Mon Sep 17 00:00:00 2001
-From: Jean-Francois Dockes <jf@dockes.org>
-Date: Sun, 23 Aug 2020 14:22:21 +0200
-Subject: [PATCH] Modification to use npupnp instead of pupnp when the upnp
- meson option is set
-
----
- meson_options.txt | 5 +-
- .../plugins/upnp/ContentDirectoryService.cxx | 101 ++++++++++++++++++
- src/lib/upnp/Action.hxx | 2 +
- src/lib/upnp/ClientInit.cxx | 12 +--
- src/lib/upnp/Compat.hxx | 4 +-
- src/lib/upnp/ContentDirectoryService.cxx | 25 +++++
- src/lib/upnp/Init.cxx | 4 +
- src/lib/upnp/UniqueIxml.hxx | 2 +
- src/lib/upnp/ixmlwrap.cxx | 4 +
- src/lib/upnp/ixmlwrap.hxx | 2 +
- src/lib/upnp/meson.build | 20 +++-
- 11 files changed, 170 insertions(+), 11 deletions(-)
-
---- a/meson_options.txt
-+++ b/meson_options.txt
-@@ -54,7 +54,10 @@ option('dsd', type: 'boolean', value: tr
- #
-
- option('database', type: 'boolean', value: true, description: 'enable support for the music database')
--option('upnp', type: 'feature', description: 'UPnP client support')
-+option('upnp', type: 'combo',
-+ choices: ['auto', 'pupnp', 'npupnp', 'disabled'],
-+ value: 'auto',
-+ description: 'UPnP client support')
- option('libmpdclient', type: 'feature', description: 'libmpdclient support (for the proxy database plugin)')
-
- #
---- a/src/db/plugins/upnp/ContentDirectoryService.cxx
-+++ b/src/db/plugins/upnp/ContentDirectoryService.cxx
-@@ -18,7 +18,10 @@
- */
-
- #include "lib/upnp/ContentDirectoryService.hxx"
-+#include "config.h"
-+#ifdef USING_PUPNP
- #include "lib/upnp/ixmlwrap.hxx"
-+#endif
- #include "lib/upnp/UniqueIxml.hxx"
- #include "lib/upnp/Action.hxx"
- #include "Directory.hxx"
-@@ -28,8 +31,11 @@
- #include "util/ScopeExit.hxx"
- #include "util/StringFormat.hxx"
-
-+#include <algorithm>
-+
- #include <stdio.h>
-
-+#ifdef USING_PUPNP
- static void
- ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
- {
-@@ -39,6 +45,7 @@ ReadResultTag(UPnPDirContent &dirbuf, IX
-
- dirbuf.Parse(p);
- }
-+#endif
-
- inline void
- ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
-@@ -47,6 +54,7 @@ ContentDirectoryService::readDirSlice(Up
- unsigned &didreadp,
- unsigned &totalp) const
- {
-+#ifdef USING_PUPNP
- // Some devices require an empty SortCriteria, else bad params
- IXML_Document *request =
- MakeActionHelper("Browse", m_serviceType.c_str(),
-@@ -82,6 +90,37 @@ ContentDirectoryService::readDirSlice(Up
- totalp = ParseUnsigned(value);
-
- ReadResultTag(dirbuf, response);
-+#else
-+ std::vector<std::pair<std::string, std::string> > actionParams{
-+ { "ObjectID", objectId },
-+ { "BrowseFlag", "BrowseDirectChildren" },
-+ { "Filter", "*" },
-+ { "SortCriteria", "" },
-+ { "StartingIndex", StringFormat<32>("%u", offset).c_str() },
-+ { "RequestedCount", StringFormat<32>("%u", count).c_str() }
-+ };
-+ std::vector<std::pair<std::string, std::string> > responseData;
-+ int errcode;
-+ std::string errdesc;
-+ int code =
-+ UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
-+ actionParams, responseData, &errcode, errdesc);
-+ if (code != UPNP_E_SUCCESS)
-+ throw FormatRuntimeError("UpnpSendAction() failed: %s",
-+ UpnpGetErrorMessage(code));
-+ const char *p = "";
-+ didreadp = 0;
-+ for (const auto &entry : responseData) {
-+ if (entry.first == "Result") {
-+ p = entry.second.c_str();
-+ } else if (entry.first == "TotalMatches") {
-+ totalp = ParseUnsigned(entry.second.c_str());
-+ } else if (entry.first == "NumberReturned") {
-+ didreadp = ParseUnsigned(entry.second.c_str());
-+ }
-+ }
-+ dirbuf.Parse(p);
-+#endif
- }
-
- UPnPDirContent
-@@ -110,6 +149,7 @@ ContentDirectoryService::search(UpnpClie
- unsigned offset = 0, total = -1, count;
-
- do {
-+#ifdef USING_PUPNP
- UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
- "ContainerID", objectId,
- "SearchCriteria", ss,
-@@ -147,6 +187,39 @@ ContentDirectoryService::search(UpnpClie
- total = ParseUnsigned(value);
-
- ReadResultTag(dirbuf, response.get());
-+#else
-+ std::vector<std::pair<std::string, std::string> > actionParams{
-+ { "ContainerID", objectId },
-+ { "SearchCriteria", ss },
-+ { "Filter", "*" },
-+ { "SortCriteria", "" },
-+ { "StartingIndex",
-+ StringFormat<32>("%u", offset).c_str() },
-+ { "RequestedCount", "0" }
-+ };
-+ std::vector<std::pair<std::string, std::string> > responseData;
-+ int errcode;
-+ std::string errdesc;
-+ int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
-+ "Search", actionParams, responseData,
-+ &errcode, errdesc);
-+ if (code != UPNP_E_SUCCESS)
-+ throw FormatRuntimeError("UpnpSendAction() failed: %s",
-+ UpnpGetErrorMessage(code));
-+ const char *p = "";
-+ count = 0;
-+ for (const auto &entry : responseData) {
-+ if (entry.first == "Result") {
-+ p = entry.second.c_str();
-+ } else if (entry.first == "TotalMatches") {
-+ total = ParseUnsigned(entry.second.c_str());
-+ } else if (entry.first == "NumberReturned") {
-+ count = ParseUnsigned(entry.second.c_str());
-+ offset += count;
-+ }
-+ }
-+ dirbuf.Parse(p);
-+#endif
- } while (count > 0 && offset < total);
-
- return dirbuf;
-@@ -156,6 +229,7 @@ UPnPDirContent
- ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
- const char *objectId) const
- {
-+#ifdef USING_PUPNP
- // Create request
- UniqueIxmlDocument request(MakeActionHelper("Browse", m_serviceType.c_str(),
- "ObjectID", objectId,
-@@ -179,4 +253,31 @@ ContentDirectoryService::getMetadata(Upn
- UPnPDirContent dirbuf;
- ReadResultTag(dirbuf, response.get());
- return dirbuf;
-+#else
-+ std::vector<std::pair<std::string, std::string> > actionParams{
-+ { "ObjectID", objectId }, { "BrowseFlag", "BrowseMetadata" },
-+ { "Filter", "*" }, { "SortCriteria", "" },
-+ { "StartingIndex", "0" }, { "RequestedCount", "1" }
-+ };
-+ std::vector<std::pair<std::string, std::string> > responseData;
-+ int errcode;
-+ std::string errdesc;
-+ int code =
-+ UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
-+ actionParams, responseData, &errcode, errdesc);
-+ if (code != UPNP_E_SUCCESS)
-+ throw FormatRuntimeError("UpnpSendAction() failed: %s",
-+ UpnpGetErrorMessage(code));
-+ const char *p = "";
-+ for (const auto &entry : responseData) {
-+ if (entry.first == "Result") {
-+ p = entry.second.c_str();
-+ break;
-+ }
-+ }
-+
-+ UPnPDirContent dirbuf;
-+ dirbuf.Parse(p);
-+ return dirbuf;
-+#endif
- }
---- a/src/lib/upnp/Action.hxx
-+++ b/src/lib/upnp/Action.hxx
-@@ -38,6 +38,7 @@ CountNameValuePairs(gcc_unused const cha
- return 1 + CountNameValuePairs(args...);
- }
-
-+#ifdef USING_PUPNP
- /**
- * A wrapper for UpnpMakeAction() that counts the number of name/value
- * pairs and adds the nullptr sentinel.
-@@ -52,5 +53,6 @@ MakeActionHelper(const char *action_name
- args...,
- nullptr, nullptr);
- }
-+#endif
-
- #endif
---- a/src/lib/upnp/ClientInit.cxx
-+++ b/src/lib/upnp/ClientInit.cxx
-@@ -31,14 +31,12 @@ static Mutex upnp_client_init_mutex;
- static unsigned upnp_client_ref;
- static UpnpClient_Handle upnp_client_handle;
-
--static int
--UpnpClientCallback(Upnp_EventType et,
--#if UPNP_VERSION >= 10800
-- const
-+static int UpnpClientCallback(Upnp_EventType et,
-+#if 1
-+ const
- #endif
-- void *evp,
-- void *cookie) noexcept
--{
-+ void *evp,
-+ void *cookie) noexcept {
- if (cookie == nullptr)
- /* this is the cookie passed to UpnpRegisterClient();
- but can this ever happen? Will libupnp ever invoke
---- a/src/lib/upnp/Compat.hxx
-+++ b/src/lib/upnp/Compat.hxx
-@@ -22,14 +22,14 @@
-
- #include <upnp.h>
-
--#if UPNP_VERSION < 10800
-+#if 0
- /* emulate the libupnp 1.8 API with older versions */
-
- using UpnpDiscovery = Upnp_Discovery;
-
- #endif
-
--#if UPNP_VERSION < 10624
-+#if 0
- #include "util/Compiler.h"
-
- gcc_pure
---- a/src/lib/upnp/ContentDirectoryService.cxx
-+++ b/src/lib/upnp/ContentDirectoryService.cxx
-@@ -17,15 +17,21 @@
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-+#include "config.h"
-+
- #include "ContentDirectoryService.hxx"
- #include "UniqueIxml.hxx"
- #include "Device.hxx"
-+#ifdef USING_PUPNP
- #include "ixmlwrap.hxx"
-+#endif
- #include "Action.hxx"
- #include "util/UriUtil.hxx"
- #include "util/RuntimeError.hxx"
- #include "util/SplitString.hxx"
-
-+#include <algorithm>
-+
- ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device,
- const UPnPService &service) noexcept
- :m_actionURL(uri_apply_base(service.controlURL, device.URLBase)),
-@@ -51,6 +57,7 @@ ContentDirectoryService::~ContentDirecto
- std::forward_list<std::string>
- ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
- {
-+#ifdef USING_PUPNP
- UniqueIxmlDocument request(UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
- 0,
- nullptr, nullptr));
-@@ -69,6 +76,24 @@ ContentDirectoryService::getSearchCapabi
-
- const char *s = ixmlwrap::getFirstElementValue(response.get(),
- "SearchCaps");
-+#else
-+ std::vector<std::pair<std::string, std::string> > responseData;
-+ int errcode;
-+ std::string errdesc;
-+ auto code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
-+ "GetSearchCapabilities", {}, responseData,
-+ &errcode, errdesc);
-+ if (code != UPNP_E_SUCCESS)
-+ throw FormatRuntimeError("UpnpSendAction() failed: %s",
-+ UpnpGetErrorMessage(code));
-+ const char *s{ nullptr };
-+ for (auto &entry : responseData) {
-+ if (entry.first == "SearchCaps") {
-+ s = entry.second.c_str();
-+ break;
-+ }
-+ }
-+#endif
- if (s == nullptr || *s == 0)
- /* we could just "return {}" here, but GCC 5 doesn't
- understand that */
---- a/src/lib/upnp/Init.cxx
-+++ b/src/lib/upnp/Init.cxx
-@@ -23,7 +23,9 @@
-
- #include <upnp.h>
- #include <upnptools.h>
-+#ifdef USING_PUPNP
- #include <ixml.h>
-+#endif
-
- #include <assert.h>
-
-@@ -44,8 +46,10 @@ DoInit()
-
- UpnpSetMaxContentLength(2000*1024);
-
-+#ifdef USING_PUPNP
- // Servers sometimes make error (e.g.: minidlna returns bad utf-8)
- ixmlRelaxParser(1);
-+#endif
- }
-
- void
---- a/src/lib/upnp/UniqueIxml.hxx
-+++ b/src/lib/upnp/UniqueIxml.hxx
-@@ -20,6 +20,7 @@
- #ifndef MPD_UPNP_UNIQUE_XML_HXX
- #define MPD_UPNP_UNIQUE_XML_HXX
-
-+#ifdef USING_PUPNP
- #include <ixml.h>
-
- #include <memory>
-@@ -37,4 +38,5 @@ struct UpnpIxmlDeleter {
- typedef std::unique_ptr<IXML_Document, UpnpIxmlDeleter> UniqueIxmlDocument;
- typedef std::unique_ptr<IXML_NodeList, UpnpIxmlDeleter> UniqueIxmlNodeList;
-
-+#endif /* USING_PUPNP */
- #endif
---- a/src/lib/upnp/ixmlwrap.cxx
-+++ b/src/lib/upnp/ixmlwrap.cxx
-@@ -15,6 +15,9 @@
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-+#include "config.h"
-+
-+#ifdef USING_PUPNP
- #include "ixmlwrap.hxx"
- #include "UniqueIxml.hxx"
-
-@@ -39,3 +42,4 @@ getFirstElementValue(IXML_Document *doc,
- }
-
- }
-+#endif
---- a/src/lib/upnp/ixmlwrap.hxx
-+++ b/src/lib/upnp/ixmlwrap.hxx
-@@ -17,6 +17,7 @@
- #ifndef _IXMLWRAP_H_INCLUDED_
- #define _IXMLWRAP_H_INCLUDED_
-
-+#ifdef USING_PUPNP
- #include <ixml.h>
-
- #include <string>
-@@ -32,4 +33,5 @@ namespace ixmlwrap {
-
- }
-
-+#endif /* USING_PUPNP */
- #endif /* _IXMLWRAP_H_INCLUDED_ */
---- a/src/lib/upnp/meson.build
-+++ b/src/lib/upnp/meson.build
-@@ -1,4 +1,22 @@
--upnp_dep = dependency('libupnp', required: get_option('upnp'))
-+upnp_option = get_option('upnp')
-+
-+if upnp_option == 'auto'
-+ upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)
-+ conf.set('USING_PUPNP', upnp_dep.found())
-+ if not upnp_dep.found()
-+ upnp_dep = dependency('libnpupnp', version: '>= 1.8', required: false)
-+ endif
-+elif upnp_option == 'pupnp'
-+ upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)
-+ conf.set('USING_PUPNP', true)
-+elif upnp_option == 'npupnp'
-+ upnp_dep = dependency('libnpupnp', required: true)
-+ conf.set('USING_PUPNP', false)
-+elif upnp_option == 'disabled'
-+ upnp_dep = dependency('', required: false)
-+ subdir_done()
-+endif
-+
- conf.set('ENABLE_UPNP', upnp_dep.found())
- if not upnp_dep.found()
- subdir_done()