1 /* --------------------------------------------------------------------------
2 
3    libmusicbrainz5 - Client library to access MusicBrainz
4 
5    Copyright (C) 2012 Andrew Hawkins
6 
7    This file is part of libmusicbrainz5.
8 
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 2.1 of the License, or (at your option) any later version.
13 
14    libmusicbrainz5 is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Lesser General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this library.  If not, see <http://www.gnu.org/licenses/>.
21 
22      $Id$
23 
24 ----------------------------------------------------------------------------*/
25 
26 #ifndef _MUSICBRAINZ5_QUERY_H
27 #define _MUSICBRAINZ5_QUERY_H
28 
29 #include "defines.h"
30 
31 #include "Entity.h"
32 
33 #include "musicbrainz5/ReleaseList.h"
34 #include "musicbrainz5/Metadata.h"
35 
36 #include "musicbrainz5/xmlParser.h"
37 
38 #include <string>
39 #include <map>
40 #include <vector>
41 
42 /**
43  * @mainpage libmusicbrainz5
44  *
45  * This is the documentation for libmusicbrainz5, a library for retrieving data from
46  * the <a target="_blank" href="http://musicbrainz.org">MusicBrainz</a> service.
47  *
48  * The main entry point to the library is the MusicBrainz5::CQuery object.
49  *
50  * For details of the C interface, see the documentation for the file mb5_c.h.
51  *
52  * Please report any issues with this library at
53  * <a target="_blank" href="http://tickets.musicbrainz.org/">http://tickets.musicbrainz.org/</a>.
54  *
55  * @par Compiling and Linking
56  *
57  * This package provides a pkg-config script that returns the necessary compiler
58  * and linker flags, as well as the version number.  To build a small sample
59  * program one would use:
60  *
61  * @par
62  *     <tt>g++ -o test_app test_app.cpp `pkg-config libmusicbrainz5 --cflags --libs`</tt>
63  *
64  * If you don't want/can't use pkg-config and you are using the C API, make sure
65  * you link in the C++ standard library:
66  *
67  * @par
68  *     <tt>gcc -o test_app test_app.c -lmusicbrainz5 -lm -lstdc++</tt>
69  *
70  * @par Example:
71  *
72  * A brief example showing how to lookup a list of releases matching a disc id
73  *
74 @code
75 MusicBrainz5::CQuery Query("cdlookupexample-1.0");
76 
77 try
78 {
79 	MusicBrainz5::CMetadata Metadata=Query.Query("discid",DiscID);
80 	if (Metadata.Disc() && Metadata.Disc()->ReleaseList())
81 	{
82 		MusicBrainz5::CReleaseList *ReleaseList=Metadata.Disc()->ReleaseList();
83 
84 		std::cout << "Found " << ReleaseList->NumItems() << " release(s)" << std::endl;
85 
86 		for (int count=0;count<ReleaseList->NumItems();count++)
87 		{
88 			MusicBrainz5::CRelease *Release=ReleaseList->Item(count);
89 
90 			std::cout << "Basic release: " << std::endl << *Release << std::endl;
91 
92 			//The releases returned from LookupDiscID don't contain full information
93 
94 			MusicBrainz5::CQuery::tParamMap Params;
95 			Params["inc"]="artists labels recordings release-groups url-rels discids artist-credits";
96 
97 			Metadata=Query.Query("release",Release.ID(),"",Params);
98 			if (Metadata.Release())
99 			{
100 				MusicBrainz5::CRelease *FullRelease=Metadata.Release();
101 
102 				std::cout << *FullRelease << std::endl;
103 			}
104 		}
105 	}
106 }
107 
108 catch (MusicBrainz5::CConnectionError& Error)
109 {
110 	std::cout << "Connection Exception: '" << Error.what() << "'" << std::endl;
111 	std::cout << "LastResult: " << Query.LastResult() << std::endl;
112 	std::cout << "LastHTTPCode: " << Query.LastHTTPCode() << std::endl;
113 	std::cout << "LastErrorMessage: " << Query.LastErrorMessage() << std::endl;
114 }
115 
116 catch (MusicBrainz5::CTimeoutError& Error)
117 {
118 	std::cout << "Timeout Exception: '" << Error.what() << "'" << std::endl;
119 	std::cout << "LastResult: " << Query.LastResult() << std::endl;
120 	std::cout << "LastHTTPCode: " << Query.LastHTTPCode() << std::endl;
121 	std::cout << "LastErrorMessage: " << Query.LastErrorMessage() << std::endl;
122 }
123 
124 catch (MusicBrainz5::CAuthenticationError& Error)
125 {
126 	std::cout << "Authentication Exception: '" << Error.what() << "'" << std::endl;
127 	std::cout << "LastResult: " << Query.LastResult() << std::endl;
128 	std::cout << "LastHTTPCode: " << Query.LastHTTPCode() << std::endl;
129 	std::cout << "LastErrorMessage: " << Query.LastErrorMessage() << std::endl;
130 }
131 
132 catch (MusicBrainz5::CFetchError& Error)
133 {
134 	std::cout << "Fetch Exception: '" << Error.what() << "'" << std::endl;
135 	std::cout << "LastResult: " << Query.LastResult() << std::endl;
136 	std::cout << "LastHTTPCode: " << Query.LastHTTPCode() << std::endl;
137 	std::cout << "LastErrorMessage: " << Query.LastErrorMessage() << std::endl;
138 }
139 
140 catch (MusicBrainz5::CRequestError& Error)
141 {
142 	std::cout << "Request Exception: '" << Error.what() << "'" << std::endl;
143 	std::cout << "LastResult: " << Query.LastResult() << std::endl;
144 	std::cout << "LastHTTPCode: " << Query.LastHTTPCode() << std::endl;
145 	std::cout << "LastErrorMessage: " << Query.LastErrorMessage() << std::endl;
146 }
147 
148 catch (MusicBrainz5::CResourceNotFoundError& Error)
149 {
150 	std::cout << "ResourceNotFound Exception: '" << Error.what() << "'" << std::endl;
151 	std::cout << "LastResult: " << Query.LastResult() << std::endl;
152 	std::cout << "LastHTTPCode: " << Query.LastHTTPCode() << std::endl;
153 	std::cout << "LastErrorMessage: " << Query.LastErrorMessage() << std::endl;
154 }
155 @endcode
156  */
157 
158 namespace MusicBrainz5
159 {
160 	class CQueryPrivate;
161 
162 	/**
163 	 * @brief Main object for generating queries to MusicBrainz
164 	 *
165 	 * This object is the main entry point for the library, generating a query to the
166 	 * MusicBrainz service, and parsing the results. The resultant objects can be used
167 	 * to retrieve information appropriate to the query.
168 	 *
169 	 * For information on generating queries and the expected responses, see the
170 	 * documentation for the
171 	 * <a target="_blank" href="http://musicbrainz.org/doc/XML_Web_Service/Version_2">web service</a>.
172 	 *
173 	 * For information on search syntax, see the documentation for
174 	 * <a target="_blank" href="http://wiki.musicbrainz.org/Text_Search_Syntax">search syntax</a>.
175 	 *
176 	 * @b Note It is the responsibility of the caller to validate any pointers returned
177 	 * from the library. It is valid for a pointer to be NULL if the information was not
178 	 * present in the response from the MusicBrainz service.
179 	 *
180 	 * @b Note The ownership of any pointers returned from the C++ interfaces remains
181 	 * with the library. The caller should not delete any pointer returned from the
182 	 * library. Users of the C library should take note of the documentation for each
183 	 * individual function in mb5_c.h
184 	 */
185 	class CQuery
186 	{
187 	public:
188 		typedef std::map<std::string,std::string> tParamMap;
189 
190 		/**
191 		 * @brief Enumerated type for query status
192 		 *
193 		 * Enumerated type for query status
194 		 */
195 		enum tQueryResult
196 		{
197 			eQuery_Success=0,
198 			eQuery_ConnectionError,
199 			eQuery_Timeout,
200 			eQuery_AuthenticationError,
201 			eQuery_FetchError,
202 			eQuery_RequestError,
203 			eQuery_ResourceNotFound
204 		};
205 
206 		/**
207 		 * @brief Constructor for MusicBrainz::CQuery object
208 		 *
209 		 * This is the constructor for the MusicBrainz::CQuery object.
210 		 *
211 		 * @param UserAgent User agent to use in any queries and submissions. The format
212 		 * 		is @c "application-version", where application is your application's name
213 		 *		and version is a version number which may not contain a '-' character.
214 		 * @param Server Server to be used (defaults to musicbrainz.org if not specified)
215 		 * @param Port Port to use (defaults to 80 if not specified)
216 		 *
217 		 */
218 
219 		CQuery(const std::string& UserAgent, const std::string& Server="musicbrainz.org", int Port=80);
220 
221 		~CQuery();
222 
223 		/**
224 		 * @brief Set the user name
225 		 *
226 		 * Set the user name to use when authenticating to the MusicBrainz service
227 		 *
228 		 * @param UserName Username to use
229 		 */
230 
231 		void SetUserName(const std::string& UserName);
232 
233 		/**
234 		 * @brief Set the password
235 		 *
236 		 * Set the password to use when authenticating to the MusicBrainz service
237 		 *
238 		 * @param Password Password to use
239 		 */
240 
241 		void SetPassword(const std::string& Password);
242 
243 		/**
244 		 * @brief Set proxy server
245 		 *
246 		 * Set the proxy server to use for queries. @b Note The http_proxy environment variable
247 		 * will be used to set a 'default' proxy server. Calls to this method will override any
248 		 * proxy settings set by the http_proxy environment variable.
249 		 *
250 		 * @param ProxyHost Proxy server to use
251 		 */
252 
253 		void SetProxyHost(const std::string& ProxyHost);
254 
255 		/**
256 		 * @brief Set proxy server port
257 		 *
258 		 * Set the proxy server port to use for queries. @b Note The http_proxy environment variable
259 		 * will be used to set a 'default' proxy server. Calls to this method will override any
260 		 * proxy settings set by the http_proxy environment variable.
261 		 *
262 		 * @param ProxyPort Proxy port to use
263 		 */
264 
265 		void SetProxyPort(int ProxyPort);
266 
267 		/**
268 		 * @brief Set proxy server user name
269 		 *
270 		 * Set the user name to use when authenticating to the proxy server. @b Note The http_proxy
271 		 * environment variable will be used to set a 'default' proxy server. Calls to this method
272 		 * will override any proxy settings set by the http_proxy environment variable.
273 		 *
274 		 * @param ProxyUserName Proxy user name to use
275 		 */
276 
277 		void SetProxyUserName(const std::string& ProxyUserName);
278 
279 		/**
280 		 * @brief Set proxy server password
281 		 *
282 		 * Set the password to use when authenticating to the proxy server. @b Note The http_proxy
283 		 * environment variable will be used to set a 'default' proxy server. Calls to this method
284 		 * will override any proxy settings set by the http_proxy environment variable.
285 		 *
286 		 * @param ProxyPassword Proxy password to use
287 		 */
288 
289 		void SetProxyPassword(const std::string& ProxyPassword);
290 
291 		/**
292 		 * @brief Return a list of releases that match a disc ID
293 		 *
294 		 * Request a list of releases matching the specified disc ID.
295 		 *
296 		 * @param DiscID Disc id to match
297 		 *
298 		 * @return MusicBrainz5::CReleaseList
299 		 */
300 
301 		CReleaseList LookupDiscID(const std::string& DiscID);
302 
303 		/**
304 		 * @brief Return full information about a release
305 		 *
306 		 * Query for detailed information about a specific release
307 		 *
308 		 * @param ReleaseID MusicBrainz release ID to lookup
309 		 *
310 		 * @return MusicBrainz::CRelease object
311 		 *
312 		 * @throw CConnectionError An error occurred connecting to the web server
313 		 * @throw CTimeoutError A timeout occurred when connecting to the web server
314 		 * @throw CAuthenticationError An authentication error occurred
315 		 * @throw CFetchError An error occurred fetching data
316 		 * @throw CRequestError The request was invalid
317 		 * @throw CResourceNotFoundError The requested resource was not found
318 		 */
319 
320 		CRelease LookupRelease(const std::string& ReleaseID);
321 
322 		/**
323 		 * @brief Perform a generic query
324 		 *
325 		 * Performs a generic query.
326 		 *
327 		 * Assuming the following parameters are set:
328 		 *
329 		 * "param1" = "p1v1 p1v2 p1v3"<br>
330 		 * "param2" = "p2v1"<br>
331 		 * "param3" = ""<br>
332 		 *
333 		 * The following query will be generated:
334 		 *
335 		 * /ws/2/Entity/ID/Resource?param1=p1v1+p1v2+p1v3&param2=p2v1&param3
336 		 *
337 		 * If any of ID or Resource are empty, those components will be omitted from the query.
338 		 *
339 		 * For full details about generating queries, see the
340 		 * <a target="_blank" href="http://musicbrainz.org/doc/XML_Web_Service/Version_2">web service</a>
341 		 * documentation.
342 		 *
343 		 * @param Entity Entity to lookup (e.g. artist, release, discid)
344 		 * @param ID The MusicBrainz ID of the entity
345 		 * @param Resource The resource (currently only used for collections)
346 		 * @param Params Map of parameters to add to the query (e.g. inc)
347 		 *
348 		 * @return MusicBrainz5::CMetadata object
349 		 *
350 		 * @throw CConnectionError An error occurred connecting to the web server
351 		 * @throw CTimeoutError A timeout occurred when connecting to the web server
352 		 * @throw CAuthenticationError An authentication error occurred
353 		 * @throw CFetchError An error occurred fetching data
354 		 * @throw CRequestError The request was invalid
355 		 * @throw CResourceNotFoundError The requested resource was not found
356 		 */
357 
358 		CMetadata Query(const std::string& Entity,const std::string& ID="",const std::string& Resource="",const tParamMap& Params=tParamMap());
359 
360 		/**
361 		 * @brief Add entries to the specified collection
362 		 *
363 		 * Add a list of releases to the specified collection.
364 		 *
365 		 * @param CollectionID The MusicBrainz ID of the collection to add entries to
366 		 * @param Entries List of MusicBrainz Release IDs to add to the collection
367 		 *
368 		 * @return true if successful, false otherwise
369 		 *
370 		 * @throw CConnectionError An error occurred connecting to the web server
371 		 * @throw CTimeoutError A timeout occurred when connecting to the web server
372 		 * @throw CAuthenticationError An authentication error occurred
373 		 * @throw CFetchError An error occurred fetching data
374 		 * @throw CRequestError The request was invalid
375 		 * @throw CResourceNotFoundError The requested resource was not found
376 		 */
377 
378 		bool AddCollectionEntries(const std::string& CollectionID, const std::vector<std::string>& Entries);
379 
380 		/**
381 		 * @brief Delete entries from the specified collection
382 		 *
383 		 * Delete a list of releases from the specified collection.
384 		 *
385 		 * @param CollectionID The MusicBrainz ID of the collection to delete entries from
386 		 * @param Entries List of MusicBrainz Release IDs to delete from the collection
387 		 *
388 		 * @return true if successful, false otherwise
389 		 *
390 		 * @throw CConnectionError An error occurred connecting to the web server
391 		 * @throw CTimeoutError A timeout occurred when connecting to the web server
392 		 * @throw CAuthenticationError An authentication error occurred
393 		 * @throw CFetchError An error occurred fetching data
394 		 * @throw CRequestError The request was invalid
395 		 * @throw CResourceNotFoundError The requested resource was not found
396 		 */
397 
398 		bool DeleteCollectionEntries(const std::string& CollectionID, const std::vector<std::string>& Entries);
399 
400 		/**
401 		 * @brief Return result of the last query
402 		 *
403 		 * Return the result of the last query
404 		 *
405 		 * @return Result of last query
406 		 */
407 
408 		CQuery::tQueryResult LastResult() const;
409 
410 		/**
411 		 * @brief Return HTTP code of the last query
412 		 *
413 		 * Return the HTTP code of the last query
414 		 *
415 		 * @return HTTP code of last query
416 		 */
417 		int LastHTTPCode() const;
418 
419 		/**
420 		 * @brief Return error message from the last query
421 		 *
422 		 * Return the error message from the last query
423 		 *
424 		 * @return Error message from last query
425 		 */
426 		std::string LastErrorMessage() const;
427 
428 		/**
429 		 * @brief Return the library version
430 		 *
431 		 * Return the library version
432 		 *
433 		 * @return Library version
434 		 */
435 		std::string Version() const;
436 
437 	private:
438 		CQueryPrivate * const m_d;
439 
440 		CMetadata PerformQuery(const std::string& Query);
441 		void WaitRequest() const;
442 		std::string UserAgent() const;
443 		bool EditCollection(const std::string& CollectionID, const std::vector<std::string>& Entries, const std::string& Action);
444 		std::string URIEscape(const std::string& URI);
445 		std::string URLEncode(const std::map<std::string,std::string>& Params);
446 	};
447 }
448 
449 #endif
450