1 /*
2  * Copyright 2003-2021 The Music Player Daemon Project
3  * http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifndef _UPNPDIR_HXX_INCLUDED_
21 #define _UPNPDIR_HXX_INCLUDED_
22 
23 #include "Compat.hxx"
24 
25 #include <string>
26 #include <forward_list>
27 
28 class UPnPDevice;
29 struct UPnPService;
30 class UPnPDirContent;
31 
32 /**
33  * Content Directory Service class.
34  *
35  * This stores identity data from a directory service
36  * and the device it belongs to, and has methods to query
37  * the directory, using libupnp for handling the UPnP protocols.
38  *
39  * Note: m_rdreqcnt: number of entries requested per directory read.
40  * 0 means all entries. The device can still return less entries than
41  * requested, depending on its own limits. In general it's not optimal
42  * becauses it triggers issues, and is sometimes actually slower, e.g. on
43  * a D-Link NAS 327
44  *
45  * The value chosen may affect by the UpnpSetMaxContentLength
46  * (2000*1024) done during initialization, but this should be ample
47  */
48 class ContentDirectoryService {
49 	std::string m_actionURL;
50 	std::string m_serviceType;
51 	std::string m_deviceId;
52 	std::string m_friendlyName;
53 	std::string m_manufacturer;
54 	std::string m_modelName;
55 
56 	int m_rdreqcnt; // Slice size to use when reading
57 
58 public:
59 	/**
60 	 * Construct by copying data from device and service objects.
61 	 *
62 	 * The discovery service does this: use
63 	 * UPnPDeviceDirectory::GetDirectories()
64 	 */
65 	ContentDirectoryService(const UPnPDevice &device,
66 				const UPnPService &service) noexcept;
67 
68 	/** An empty one */
69 	ContentDirectoryService() = default;
70 
71 	~ContentDirectoryService() noexcept;
72 
73 	/** Read a container's children list into dirbuf.
74 	 *
75 	 * @param objectId the UPnP object Id for the container. Root has Id "0"
76 	 */
77 	UPnPDirContent readDir(UpnpClient_Handle handle,
78 			       const char *objectId) const;
79 
80 	void readDirSlice(UpnpClient_Handle handle,
81 			  const char *objectId, unsigned offset,
82 			  unsigned count, UPnPDirContent& dirbuf,
83 			  unsigned &didread, unsigned &total) const;
84 
85 	/** Search the content directory service.
86 	 *
87 	 * @param objectId the UPnP object Id under which the search
88 	 * should be done. Not all servers actually support this below
89 	 * root. Root has Id "0"
90 	 * @param searchstring an UPnP searchcriteria string. Check the
91 	 * UPnP document: UPnP-av-ContentDirectory-v1-Service-20020625.pdf
92 	 * section 2.5.5. Maybe we'll provide an easier way some day...
93 	 */
94 	UPnPDirContent search(UpnpClient_Handle handle,
95 			      const char *objectId,
96 			      const char *searchstring) const;
97 
98 	/** Read metadata for a given node.
99 	 *
100 	 * @param objectId the UPnP object Id. Root has Id "0"
101 	 */
102 	UPnPDirContent getMetadata(UpnpClient_Handle handle,
103 				   const char *objectId) const;
104 
105 	/** Retrieve search capabilities
106 	 *
107 	 * Throws std::runtime_error on error.
108 	 *
109 	 * @param[out] result an empty vector: no search, or a single '*' element:
110 	 *     any tag can be used in a search, or a list of usable tag names.
111 	 */
112 	std::forward_list<std::string> getSearchCapabilities(UpnpClient_Handle handle) const;
113 
114 	[[gnu::pure]]
GetURI() const115 	std::string GetURI() const noexcept {
116 		return "upnp://" + m_deviceId + "/" + m_serviceType;
117 	}
118 
119 	/** Retrieve the "friendly name" for this server, useful for display. */
getFriendlyName() const120 	const char *getFriendlyName() const noexcept {
121 		return m_friendlyName.c_str();
122 	}
123 };
124 
125 #endif /* _UPNPDIR_HXX_INCLUDED_ */
126