treewide: Run refresh on all packages
[feed/packages.git] / sound / mpd / patches / 020-npupnp.patch
1 From 61df54155a3cb1846e6bf15e4f007ec8d623de63 Mon Sep 17 00:00:00 2001
2 From: Jean-Francois Dockes <jf@dockes.org>
3 Date: Sun, 23 Aug 2020 14:22:21 +0200
4 Subject: [PATCH] Modification to use npupnp instead of pupnp when the upnp
5 meson option is set
6
7 ---
8 meson_options.txt | 5 +-
9 .../plugins/upnp/ContentDirectoryService.cxx | 101 ++++++++++++++++++
10 src/lib/upnp/Action.hxx | 2 +
11 src/lib/upnp/ClientInit.cxx | 12 +--
12 src/lib/upnp/Compat.hxx | 4 +-
13 src/lib/upnp/ContentDirectoryService.cxx | 25 +++++
14 src/lib/upnp/Init.cxx | 4 +
15 src/lib/upnp/UniqueIxml.hxx | 2 +
16 src/lib/upnp/ixmlwrap.cxx | 4 +
17 src/lib/upnp/ixmlwrap.hxx | 2 +
18 src/lib/upnp/meson.build | 20 +++-
19 11 files changed, 170 insertions(+), 11 deletions(-)
20
21 --- a/meson_options.txt
22 +++ b/meson_options.txt
23 @@ -54,7 +54,10 @@ option('dsd', type: 'boolean', value: tr
24 #
25
26 option('database', type: 'boolean', value: true, description: 'enable support for the music database')
27 -option('upnp', type: 'feature', description: 'UPnP client support')
28 +option('upnp', type: 'combo',
29 + choices: ['auto', 'pupnp', 'npupnp', 'disabled'],
30 + value: 'auto',
31 + description: 'UPnP client support')
32 option('libmpdclient', type: 'feature', description: 'libmpdclient support (for the proxy database plugin)')
33
34 #
35 --- a/src/db/plugins/upnp/ContentDirectoryService.cxx
36 +++ b/src/db/plugins/upnp/ContentDirectoryService.cxx
37 @@ -18,7 +18,10 @@
38 */
39
40 #include "lib/upnp/ContentDirectoryService.hxx"
41 +#include "config.h"
42 +#ifdef USING_PUPNP
43 #include "lib/upnp/ixmlwrap.hxx"
44 +#endif
45 #include "lib/upnp/UniqueIxml.hxx"
46 #include "lib/upnp/Action.hxx"
47 #include "Directory.hxx"
48 @@ -28,8 +31,11 @@
49 #include "util/ScopeExit.hxx"
50 #include "util/StringFormat.hxx"
51
52 +#include <algorithm>
53 +
54 #include <stdio.h>
55
56 +#ifdef USING_PUPNP
57 static void
58 ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
59 {
60 @@ -39,6 +45,7 @@ ReadResultTag(UPnPDirContent &dirbuf, IX
61
62 dirbuf.Parse(p);
63 }
64 +#endif
65
66 inline void
67 ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
68 @@ -47,6 +54,7 @@ ContentDirectoryService::readDirSlice(Up
69 unsigned &didreadp,
70 unsigned &totalp) const
71 {
72 +#ifdef USING_PUPNP
73 // Some devices require an empty SortCriteria, else bad params
74 IXML_Document *request =
75 MakeActionHelper("Browse", m_serviceType.c_str(),
76 @@ -82,6 +90,37 @@ ContentDirectoryService::readDirSlice(Up
77 totalp = ParseUnsigned(value);
78
79 ReadResultTag(dirbuf, response);
80 +#else
81 + std::vector<std::pair<std::string, std::string> > actionParams{
82 + { "ObjectID", objectId },
83 + { "BrowseFlag", "BrowseDirectChildren" },
84 + { "Filter", "*" },
85 + { "SortCriteria", "" },
86 + { "StartingIndex", StringFormat<32>("%u", offset).c_str() },
87 + { "RequestedCount", StringFormat<32>("%u", count).c_str() }
88 + };
89 + std::vector<std::pair<std::string, std::string> > responseData;
90 + int errcode;
91 + std::string errdesc;
92 + int code =
93 + UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
94 + actionParams, responseData, &errcode, errdesc);
95 + if (code != UPNP_E_SUCCESS)
96 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
97 + UpnpGetErrorMessage(code));
98 + const char *p = "";
99 + didreadp = 0;
100 + for (const auto &entry : responseData) {
101 + if (entry.first == "Result") {
102 + p = entry.second.c_str();
103 + } else if (entry.first == "TotalMatches") {
104 + totalp = ParseUnsigned(entry.second.c_str());
105 + } else if (entry.first == "NumberReturned") {
106 + didreadp = ParseUnsigned(entry.second.c_str());
107 + }
108 + }
109 + dirbuf.Parse(p);
110 +#endif
111 }
112
113 UPnPDirContent
114 @@ -110,6 +149,7 @@ ContentDirectoryService::search(UpnpClie
115 unsigned offset = 0, total = -1, count;
116
117 do {
118 +#ifdef USING_PUPNP
119 UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
120 "ContainerID", objectId,
121 "SearchCriteria", ss,
122 @@ -147,6 +187,39 @@ ContentDirectoryService::search(UpnpClie
123 total = ParseUnsigned(value);
124
125 ReadResultTag(dirbuf, response.get());
126 +#else
127 + std::vector<std::pair<std::string, std::string> > actionParams{
128 + { "ContainerID", objectId },
129 + { "SearchCriteria", ss },
130 + { "Filter", "*" },
131 + { "SortCriteria", "" },
132 + { "StartingIndex",
133 + StringFormat<32>("%u", offset).c_str() },
134 + { "RequestedCount", "0" }
135 + };
136 + std::vector<std::pair<std::string, std::string> > responseData;
137 + int errcode;
138 + std::string errdesc;
139 + int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
140 + "Search", actionParams, responseData,
141 + &errcode, errdesc);
142 + if (code != UPNP_E_SUCCESS)
143 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
144 + UpnpGetErrorMessage(code));
145 + const char *p = "";
146 + count = 0;
147 + for (const auto &entry : responseData) {
148 + if (entry.first == "Result") {
149 + p = entry.second.c_str();
150 + } else if (entry.first == "TotalMatches") {
151 + total = ParseUnsigned(entry.second.c_str());
152 + } else if (entry.first == "NumberReturned") {
153 + count = ParseUnsigned(entry.second.c_str());
154 + offset += count;
155 + }
156 + }
157 + dirbuf.Parse(p);
158 +#endif
159 } while (count > 0 && offset < total);
160
161 return dirbuf;
162 @@ -156,6 +229,7 @@ UPnPDirContent
163 ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
164 const char *objectId) const
165 {
166 +#ifdef USING_PUPNP
167 // Create request
168 UniqueIxmlDocument request(MakeActionHelper("Browse", m_serviceType.c_str(),
169 "ObjectID", objectId,
170 @@ -179,4 +253,31 @@ ContentDirectoryService::getMetadata(Upn
171 UPnPDirContent dirbuf;
172 ReadResultTag(dirbuf, response.get());
173 return dirbuf;
174 +#else
175 + std::vector<std::pair<std::string, std::string> > actionParams{
176 + { "ObjectID", objectId }, { "BrowseFlag", "BrowseMetadata" },
177 + { "Filter", "*" }, { "SortCriteria", "" },
178 + { "StartingIndex", "0" }, { "RequestedCount", "1" }
179 + };
180 + std::vector<std::pair<std::string, std::string> > responseData;
181 + int errcode;
182 + std::string errdesc;
183 + int code =
184 + UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
185 + actionParams, responseData, &errcode, errdesc);
186 + if (code != UPNP_E_SUCCESS)
187 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
188 + UpnpGetErrorMessage(code));
189 + const char *p = "";
190 + for (const auto &entry : responseData) {
191 + if (entry.first == "Result") {
192 + p = entry.second.c_str();
193 + break;
194 + }
195 + }
196 +
197 + UPnPDirContent dirbuf;
198 + dirbuf.Parse(p);
199 + return dirbuf;
200 +#endif
201 }
202 --- a/src/lib/upnp/Action.hxx
203 +++ b/src/lib/upnp/Action.hxx
204 @@ -38,6 +38,7 @@ CountNameValuePairs(gcc_unused const cha
205 return 1 + CountNameValuePairs(args...);
206 }
207
208 +#ifdef USING_PUPNP
209 /**
210 * A wrapper for UpnpMakeAction() that counts the number of name/value
211 * pairs and adds the nullptr sentinel.
212 @@ -52,5 +53,6 @@ MakeActionHelper(const char *action_name
213 args...,
214 nullptr, nullptr);
215 }
216 +#endif
217
218 #endif
219 --- a/src/lib/upnp/ClientInit.cxx
220 +++ b/src/lib/upnp/ClientInit.cxx
221 @@ -31,14 +31,12 @@ static Mutex upnp_client_init_mutex;
222 static unsigned upnp_client_ref;
223 static UpnpClient_Handle upnp_client_handle;
224
225 -static int
226 -UpnpClientCallback(Upnp_EventType et,
227 -#if UPNP_VERSION >= 10800
228 - const
229 +static int UpnpClientCallback(Upnp_EventType et,
230 +#if 1
231 + const
232 #endif
233 - void *evp,
234 - void *cookie) noexcept
235 -{
236 + void *evp,
237 + void *cookie) noexcept {
238 if (cookie == nullptr)
239 /* this is the cookie passed to UpnpRegisterClient();
240 but can this ever happen? Will libupnp ever invoke
241 --- a/src/lib/upnp/Compat.hxx
242 +++ b/src/lib/upnp/Compat.hxx
243 @@ -22,14 +22,14 @@
244
245 #include <upnp.h>
246
247 -#if UPNP_VERSION < 10800
248 +#if 0
249 /* emulate the libupnp 1.8 API with older versions */
250
251 using UpnpDiscovery = Upnp_Discovery;
252
253 #endif
254
255 -#if UPNP_VERSION < 10624
256 +#if 0
257 #include "util/Compiler.h"
258
259 gcc_pure
260 --- a/src/lib/upnp/ContentDirectoryService.cxx
261 +++ b/src/lib/upnp/ContentDirectoryService.cxx
262 @@ -17,15 +17,21 @@
263 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
264 */
265
266 +#include "config.h"
267 +
268 #include "ContentDirectoryService.hxx"
269 #include "UniqueIxml.hxx"
270 #include "Device.hxx"
271 +#ifdef USING_PUPNP
272 #include "ixmlwrap.hxx"
273 +#endif
274 #include "Action.hxx"
275 #include "util/UriUtil.hxx"
276 #include "util/RuntimeError.hxx"
277 #include "util/SplitString.hxx"
278
279 +#include <algorithm>
280 +
281 ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device,
282 const UPnPService &service) noexcept
283 :m_actionURL(uri_apply_base(service.controlURL, device.URLBase)),
284 @@ -51,6 +57,7 @@ ContentDirectoryService::~ContentDirecto
285 std::forward_list<std::string>
286 ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
287 {
288 +#ifdef USING_PUPNP
289 UniqueIxmlDocument request(UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
290 0,
291 nullptr, nullptr));
292 @@ -69,6 +76,24 @@ ContentDirectoryService::getSearchCapabi
293
294 const char *s = ixmlwrap::getFirstElementValue(response.get(),
295 "SearchCaps");
296 +#else
297 + std::vector<std::pair<std::string, std::string> > responseData;
298 + int errcode;
299 + std::string errdesc;
300 + auto code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
301 + "GetSearchCapabilities", {}, responseData,
302 + &errcode, errdesc);
303 + if (code != UPNP_E_SUCCESS)
304 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
305 + UpnpGetErrorMessage(code));
306 + const char *s{ nullptr };
307 + for (auto &entry : responseData) {
308 + if (entry.first == "SearchCaps") {
309 + s = entry.second.c_str();
310 + break;
311 + }
312 + }
313 +#endif
314 if (s == nullptr || *s == 0)
315 /* we could just "return {}" here, but GCC 5 doesn't
316 understand that */
317 --- a/src/lib/upnp/Init.cxx
318 +++ b/src/lib/upnp/Init.cxx
319 @@ -23,7 +23,9 @@
320
321 #include <upnp.h>
322 #include <upnptools.h>
323 +#ifdef USING_PUPNP
324 #include <ixml.h>
325 +#endif
326
327 #include <assert.h>
328
329 @@ -44,8 +46,10 @@ DoInit()
330
331 UpnpSetMaxContentLength(2000*1024);
332
333 +#ifdef USING_PUPNP
334 // Servers sometimes make error (e.g.: minidlna returns bad utf-8)
335 ixmlRelaxParser(1);
336 +#endif
337 }
338
339 void
340 --- a/src/lib/upnp/UniqueIxml.hxx
341 +++ b/src/lib/upnp/UniqueIxml.hxx
342 @@ -20,6 +20,7 @@
343 #ifndef MPD_UPNP_UNIQUE_XML_HXX
344 #define MPD_UPNP_UNIQUE_XML_HXX
345
346 +#ifdef USING_PUPNP
347 #include <ixml.h>
348
349 #include <memory>
350 @@ -37,4 +38,5 @@ struct UpnpIxmlDeleter {
351 typedef std::unique_ptr<IXML_Document, UpnpIxmlDeleter> UniqueIxmlDocument;
352 typedef std::unique_ptr<IXML_NodeList, UpnpIxmlDeleter> UniqueIxmlNodeList;
353
354 +#endif /* USING_PUPNP */
355 #endif
356 --- a/src/lib/upnp/ixmlwrap.cxx
357 +++ b/src/lib/upnp/ixmlwrap.cxx
358 @@ -15,6 +15,9 @@
359 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
360 */
361
362 +#include "config.h"
363 +
364 +#ifdef USING_PUPNP
365 #include "ixmlwrap.hxx"
366 #include "UniqueIxml.hxx"
367
368 @@ -39,3 +42,4 @@ getFirstElementValue(IXML_Document *doc,
369 }
370
371 }
372 +#endif
373 --- a/src/lib/upnp/ixmlwrap.hxx
374 +++ b/src/lib/upnp/ixmlwrap.hxx
375 @@ -17,6 +17,7 @@
376 #ifndef _IXMLWRAP_H_INCLUDED_
377 #define _IXMLWRAP_H_INCLUDED_
378
379 +#ifdef USING_PUPNP
380 #include <ixml.h>
381
382 #include <string>
383 @@ -32,4 +33,5 @@ namespace ixmlwrap {
384
385 }
386
387 +#endif /* USING_PUPNP */
388 #endif /* _IXMLWRAP_H_INCLUDED_ */
389 --- a/src/lib/upnp/meson.build
390 +++ b/src/lib/upnp/meson.build
391 @@ -1,4 +1,22 @@
392 -upnp_dep = dependency('libupnp', required: get_option('upnp'))
393 +upnp_option = get_option('upnp')
394 +
395 +if upnp_option == 'auto'
396 + upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)
397 + conf.set('USING_PUPNP', upnp_dep.found())
398 + if not upnp_dep.found()
399 + upnp_dep = dependency('libnpupnp', version: '>= 1.8', required: false)
400 + endif
401 +elif upnp_option == 'pupnp'
402 + upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)
403 + conf.set('USING_PUPNP', true)
404 +elif upnp_option == 'npupnp'
405 + upnp_dep = dependency('libnpupnp', required: true)
406 + conf.set('USING_PUPNP', false)
407 +elif upnp_option == 'disabled'
408 + upnp_dep = dependency('', required: false)
409 + subdir_done()
410 +endif
411 +
412 conf.set('ENABLE_UPNP', upnp_dep.found())
413 if not upnp_dep.found()
414 subdir_done()