1 /* libmpdclient
2    (c) 2003-2019 The Music Player Daemon Project
3    This project's homepage is: http://www.musicpd.org
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8 
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 
16    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
20    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <mpd/queue.h>
30 #include <mpd/send.h>
31 #include <mpd/recv.h>
32 #include <mpd/pair.h>
33 #include <mpd/response.h>
34 #include <mpd/song.h>
35 #include "internal.h"
36 #include "isend.h"
37 #include "run.h"
38 
39 #include <limits.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 
43 bool
mpd_send_list_queue_meta(struct mpd_connection * connection)44 mpd_send_list_queue_meta(struct mpd_connection *connection)
45 {
46 	return mpd_send_command(connection, "playlistinfo", NULL);
47 }
48 
49 bool
mpd_send_list_queue_range_meta(struct mpd_connection * connection,unsigned start,unsigned end)50 mpd_send_list_queue_range_meta(struct mpd_connection *connection,
51 			       unsigned start, unsigned end)
52 {
53 	return mpd_send_range_command(connection, "playlistinfo", start, end);
54 }
55 
56 bool
mpd_send_get_queue_song_pos(struct mpd_connection * connection,unsigned pos)57 mpd_send_get_queue_song_pos(struct mpd_connection *connection, unsigned pos)
58 {
59 	return mpd_send_int_command(connection, "playlistinfo", pos);
60 }
61 
62 struct mpd_song *
mpd_run_get_queue_song_pos(struct mpd_connection * connection,unsigned pos)63 mpd_run_get_queue_song_pos(struct mpd_connection *connection, unsigned pos)
64 {
65 	struct mpd_song *song;
66 
67 	if (!mpd_run_check(connection) ||
68 	    !mpd_send_get_queue_song_pos(connection, pos))
69 		return NULL;
70 
71 	song = mpd_recv_song(connection);
72 	if (!mpd_response_finish(connection) && song != NULL) {
73 		mpd_song_free(song);
74 		return NULL;
75 	}
76 
77 	return song;
78 
79 }
80 
81 bool
mpd_send_get_queue_song_id(struct mpd_connection * connection,unsigned id)82 mpd_send_get_queue_song_id(struct mpd_connection *connection, unsigned id)
83 {
84 	return mpd_send_int_command(connection, "playlistid", id);
85 }
86 
87 struct mpd_song *
mpd_run_get_queue_song_id(struct mpd_connection * connection,unsigned id)88 mpd_run_get_queue_song_id(struct mpd_connection *connection, unsigned id)
89 {
90 	struct mpd_song *song;
91 
92 	if (!mpd_run_check(connection) ||
93 	    !mpd_send_get_queue_song_id(connection, id))
94 		return NULL;
95 
96 	song = mpd_recv_song(connection);
97 	if (!mpd_response_finish(connection) && song != NULL) {
98 		mpd_song_free(song);
99 		return NULL;
100 	}
101 
102 	return song;
103 
104 }
105 
106 bool
mpd_send_queue_changes_meta(struct mpd_connection * connection,unsigned version)107 mpd_send_queue_changes_meta(struct mpd_connection *connection,
108 			    unsigned version)
109 {
110 	return mpd_send_ll_command(connection, "plchanges", version);
111 }
112 
113 bool
mpd_send_queue_changes_meta_range(struct mpd_connection * connection,unsigned version,unsigned start,unsigned end)114 mpd_send_queue_changes_meta_range(struct mpd_connection *connection,
115 				  unsigned version,
116 				  unsigned start, unsigned end)
117 {
118 	return mpd_send_u_range_command(connection, "plchanges",
119 					version, start, end);
120 }
121 
122 bool
mpd_send_queue_changes_brief(struct mpd_connection * connection,unsigned version)123 mpd_send_queue_changes_brief(struct mpd_connection *connection,
124 			     unsigned version)
125 {
126 	return mpd_send_ll_command(connection, "plchangesposid", version);
127 }
128 
129 bool
mpd_send_queue_changes_brief_range(struct mpd_connection * connection,unsigned version,unsigned start,unsigned end)130 mpd_send_queue_changes_brief_range(struct mpd_connection *connection,
131 				   unsigned version,
132 				   unsigned start, unsigned end)
133 {
134 	return mpd_send_u_range_command(connection, "plchangesposid",
135 					version, start, end);
136 }
137 
138 bool
mpd_recv_queue_change_brief(struct mpd_connection * connection,unsigned * position_r,unsigned * id_r)139 mpd_recv_queue_change_brief(struct mpd_connection *connection,
140 			    unsigned *position_r, unsigned *id_r)
141 {
142 	struct mpd_pair *pair;
143 
144 	pair = mpd_recv_pair_named(connection, "cpos");
145 	if (pair == NULL)
146 		return false;
147 
148 	*position_r = atoi(pair->value);
149 	mpd_return_pair(connection, pair);
150 
151 	pair = mpd_recv_pair_named(connection, "Id");
152 	if (pair == NULL) {
153 		mpd_return_pair(connection, pair);
154 
155 		if (!mpd_error_is_defined(&connection->error)) {
156 			mpd_error_code(&connection->error,
157 				       MPD_ERROR_MALFORMED);
158 			mpd_error_message(&connection->error,
159 					  "No id received");
160 		}
161 
162 		return false;
163 	}
164 
165 	*id_r = atoi(pair->value);
166 	mpd_return_pair(connection, pair);
167 
168 	return !mpd_error_is_defined(&connection->error);
169 }
170 
171 bool
mpd_send_add(struct mpd_connection * connection,const char * uri)172 mpd_send_add(struct mpd_connection *connection, const char *uri)
173 {
174 	return mpd_send_command(connection, "add", uri, NULL);
175 }
176 
177 bool
mpd_run_add(struct mpd_connection * connection,const char * uri)178 mpd_run_add(struct mpd_connection *connection, const char *uri)
179 {
180 	return mpd_run_check(connection) &&
181 		mpd_send_add(connection, uri) &&
182 		mpd_response_finish(connection);
183 }
184 
185 bool
mpd_send_add_whence(struct mpd_connection * connection,const char * uri,unsigned to,enum mpd_position_whence whence)186 mpd_send_add_whence(struct mpd_connection *connection, const char *uri,
187 		   unsigned to, enum mpd_position_whence whence)
188 {
189 	const char *whence_s = mpd_position_whence_char(whence);
190 
191 	char to_str[64] = "";
192 	snprintf(to_str, 64, "%s%u", whence_s, to);
193 
194 	return mpd_send_s_s_command(connection, "add", uri, to_str);
195 }
196 
197 bool
mpd_run_add_whence(struct mpd_connection * connection,const char * uri,unsigned to,enum mpd_position_whence whence)198 mpd_run_add_whence(struct mpd_connection *connection, const char *uri,
199 		  unsigned to, enum mpd_position_whence whence)
200 {
201 	return mpd_run_check(connection) &&
202 		mpd_send_add_whence(connection, uri, to, whence) &&
203 		mpd_response_finish(connection);
204 }
205 
206 bool
mpd_send_add_id(struct mpd_connection * connection,const char * uri)207 mpd_send_add_id(struct mpd_connection *connection, const char *uri)
208 {
209 	return mpd_send_command(connection, "addid", uri, NULL);
210 }
211 
212 bool
mpd_send_add_id_to(struct mpd_connection * connection,const char * uri,unsigned to)213 mpd_send_add_id_to(struct mpd_connection *connection, const char *uri,
214 		   unsigned to)
215 {
216 	return mpd_send_s_u_command(connection, "addid", uri, to);
217 }
218 
219 bool
mpd_send_add_id_whence(struct mpd_connection * connection,const char * uri,unsigned to,enum mpd_position_whence whence)220 mpd_send_add_id_whence(struct mpd_connection *connection, const char *uri,
221 		   unsigned to, enum mpd_position_whence whence)
222 {
223 	const char *whence_s = mpd_position_whence_char(whence);
224 
225 	char to_str[64] = "";
226 	snprintf(to_str, 64, "%s%u", whence_s, to);
227 
228 	return mpd_send_s_s_command(connection, "addid", uri, to_str);
229 }
230 
231 int
mpd_recv_song_id(struct mpd_connection * connection)232 mpd_recv_song_id(struct mpd_connection *connection)
233 {
234 	struct mpd_pair *pair;
235 	int id = -1;
236 
237 	pair = mpd_recv_pair_named(connection, "Id");
238 	if (pair != NULL) {
239 		id = atoi(pair->value);
240 		mpd_return_pair(connection, pair);
241 	}
242 
243 	return id;
244 }
245 
246 int
mpd_run_add_id(struct mpd_connection * connection,const char * uri)247 mpd_run_add_id(struct mpd_connection *connection, const char *uri)
248 {
249 	int id;
250 
251 	if (!mpd_run_check(connection) ||
252 	    !mpd_send_add_id(connection, uri))
253 		return -1;
254 
255 	id = mpd_recv_song_id(connection);
256 
257 	if (!mpd_response_finish(connection))
258 		id = -1;
259 
260 	return id;
261 }
262 
263 int
mpd_run_add_id_to(struct mpd_connection * connection,const char * uri,unsigned to)264 mpd_run_add_id_to(struct mpd_connection *connection, const char *uri,
265 		  unsigned to)
266 {
267 	int id;
268 
269 	if (!mpd_run_check(connection) ||
270 	    !mpd_send_add_id_to(connection, uri, to))
271 		return -1;
272 
273 	id = mpd_recv_song_id(connection);
274 
275 	if (!mpd_response_finish(connection))
276 		id = -1;
277 
278 	return id;
279 }
280 
281 int
mpd_run_add_id_whence(struct mpd_connection * connection,const char * uri,unsigned to,enum mpd_position_whence whence)282 mpd_run_add_id_whence(struct mpd_connection *connection, const char *uri,
283 		  unsigned to, enum mpd_position_whence whence)
284 {
285 	int id;
286 
287 	if (!mpd_run_check(connection) ||
288 	    !mpd_send_add_id_whence(connection, uri, to, whence))
289 		return -1;
290 
291 	id = mpd_recv_song_id(connection);
292 
293 	if (!mpd_response_finish(connection))
294 		id = -1;
295 
296 	return id;
297 }
298 
299 bool
mpd_send_delete(struct mpd_connection * connection,unsigned pos)300 mpd_send_delete(struct mpd_connection *connection, unsigned pos)
301 {
302 	return mpd_send_int_command(connection, "delete", pos);
303 }
304 
305 bool
mpd_run_delete(struct mpd_connection * connection,unsigned pos)306 mpd_run_delete(struct mpd_connection *connection, unsigned pos)
307 {
308 	return mpd_run_check(connection) &&
309 		mpd_send_delete(connection, pos) &&
310 		mpd_response_finish(connection);
311 }
312 
313 bool
mpd_send_delete_range(struct mpd_connection * connection,unsigned start,unsigned end)314 mpd_send_delete_range(struct mpd_connection *connection,
315 		      unsigned start, unsigned end)
316 {
317 	return mpd_send_range_command(connection, "delete", start, end);
318 }
319 
320 bool
mpd_run_delete_range(struct mpd_connection * connection,unsigned start,unsigned end)321 mpd_run_delete_range(struct mpd_connection *connection,
322 		     unsigned start, unsigned end)
323 {
324 	return mpd_run_check(connection) &&
325 		mpd_send_delete_range(connection, start, end) &&
326 		mpd_response_finish(connection);
327 }
328 
329 bool
mpd_send_delete_id(struct mpd_connection * connection,unsigned id)330 mpd_send_delete_id(struct mpd_connection *connection, unsigned id)
331 {
332 	return mpd_send_int_command(connection, "deleteid", id);
333 }
334 
335 bool
mpd_run_delete_id(struct mpd_connection * connection,unsigned id)336 mpd_run_delete_id(struct mpd_connection *connection, unsigned id)
337 {
338 	return mpd_run_check(connection) &&
339 		mpd_send_delete_id(connection, id) &&
340 		mpd_response_finish(connection);
341 }
342 
343 bool
mpd_send_shuffle(struct mpd_connection * connection)344 mpd_send_shuffle(struct mpd_connection *connection)
345 {
346 	return mpd_send_command(connection, "shuffle", NULL);
347 }
348 
349 bool
mpd_run_shuffle(struct mpd_connection * connection)350 mpd_run_shuffle(struct mpd_connection *connection)
351 {
352 	return mpd_run_check(connection) &&
353 		mpd_send_shuffle(connection) &&
354 		mpd_response_finish(connection);
355 }
356 
357 bool
mpd_send_shuffle_range(struct mpd_connection * connection,unsigned start,unsigned end)358 mpd_send_shuffle_range(struct mpd_connection *connection, unsigned start, unsigned end)
359 {
360 	return mpd_send_range_command(connection, "shuffle", start, end);
361 }
362 
363 bool
mpd_run_shuffle_range(struct mpd_connection * connection,unsigned start,unsigned end)364 mpd_run_shuffle_range(struct mpd_connection *connection,
365 		      unsigned start, unsigned end)
366 {
367 	return mpd_run_check(connection) &&
368 		mpd_send_shuffle_range(connection, start, end) &&
369 		mpd_response_finish(connection);
370 }
371 
372 bool
mpd_send_clear(struct mpd_connection * connection)373 mpd_send_clear(struct mpd_connection *connection)
374 {
375 	return mpd_send_command(connection, "clear", NULL);
376 }
377 
378 bool
mpd_run_clear(struct mpd_connection * connection)379 mpd_run_clear(struct mpd_connection *connection)
380 {
381 	return mpd_run_check(connection) &&
382 		mpd_send_clear(connection) &&
383 		mpd_response_finish(connection);
384 }
385 
386 bool
mpd_send_move(struct mpd_connection * connection,unsigned from,unsigned to)387 mpd_send_move(struct mpd_connection *connection, unsigned from, unsigned to)
388 {
389 	return mpd_send_int2_command(connection, "move", from, to);
390 }
391 
392 bool
mpd_run_move(struct mpd_connection * connection,unsigned from,unsigned to)393 mpd_run_move(struct mpd_connection *connection, unsigned from, unsigned to)
394 {
395 	return mpd_run_check(connection) &&
396 		mpd_send_move(connection, from, to) &&
397 		mpd_response_finish(connection);
398 }
399 
400 bool
mpd_send_move_id(struct mpd_connection * connection,unsigned from,unsigned to)401 mpd_send_move_id(struct mpd_connection *connection, unsigned from, unsigned to)
402 {
403 	return mpd_send_int2_command(connection, "moveid", from, to);
404 }
405 
406 bool
mpd_run_move_id(struct mpd_connection * connection,unsigned from,unsigned to)407 mpd_run_move_id(struct mpd_connection *connection, unsigned from, unsigned to)
408 {
409 	return mpd_run_check(connection) &&
410 		mpd_send_move_id(connection, from, to) &&
411 		mpd_response_finish(connection);
412 }
413 
414 bool
mpd_send_move_range(struct mpd_connection * connection,unsigned start,unsigned end,unsigned to)415 mpd_send_move_range(struct mpd_connection *connection,
416 		    unsigned start, unsigned end, unsigned to)
417 {
418 	return mpd_send_range_u_command(connection, "move", start, end, to);
419 }
420 
421 bool
mpd_run_move_range(struct mpd_connection * connection,unsigned start,unsigned end,unsigned to)422 mpd_run_move_range(struct mpd_connection *connection,
423 		   unsigned start, unsigned end, unsigned to)
424 {
425 	return mpd_run_check(connection) &&
426 		mpd_send_move_range(connection, start, end, to) &&
427 		mpd_response_finish(connection);
428 }
429 
430 bool
mpd_send_swap(struct mpd_connection * connection,unsigned pos1,unsigned pos2)431 mpd_send_swap(struct mpd_connection *connection, unsigned pos1, unsigned pos2)
432 {
433 	return mpd_send_int2_command(connection, "swap", pos1, pos2);
434 }
435 
436 bool
mpd_run_swap(struct mpd_connection * connection,unsigned pos1,unsigned pos2)437 mpd_run_swap(struct mpd_connection *connection, unsigned pos1, unsigned pos2)
438 {
439 	return mpd_run_check(connection) &&
440 		mpd_send_swap(connection, pos1, pos2) &&
441 		mpd_response_finish(connection);
442 }
443 
444 bool
mpd_send_swap_id(struct mpd_connection * connection,unsigned id1,unsigned id2)445 mpd_send_swap_id(struct mpd_connection *connection, unsigned id1, unsigned id2)
446 {
447 	return mpd_send_int2_command(connection, "swapid", id1, id2);
448 }
449 
450 bool
mpd_run_swap_id(struct mpd_connection * connection,unsigned id1,unsigned id2)451 mpd_run_swap_id(struct mpd_connection *connection, unsigned id1, unsigned id2)
452 {
453 	return mpd_run_check(connection) &&
454 		mpd_send_swap_id(connection, id1, id2) &&
455 		mpd_response_finish(connection);
456 }
457 
458 bool
mpd_send_add_tag_id(struct mpd_connection * connection,unsigned id,enum mpd_tag_type tag,const char * value)459 mpd_send_add_tag_id(struct mpd_connection *connection, unsigned id,
460 		    enum mpd_tag_type tag, const char *value)
461 {
462 	return mpd_send_u_s_s_command(connection, "addtagid",
463 				      id, mpd_tag_name(tag), value);
464 }
465 
466 bool
mpd_run_add_tag_id(struct mpd_connection * connection,unsigned id,enum mpd_tag_type tag,const char * value)467 mpd_run_add_tag_id(struct mpd_connection *connection, unsigned id,
468 		   enum mpd_tag_type tag, const char *value)
469 {
470 	return mpd_run_check(connection) &&
471 		mpd_send_add_tag_id(connection, id, tag, value) &&
472 		mpd_response_finish(connection);
473 }
474 
475 bool
mpd_send_clear_tag_id(struct mpd_connection * connection,unsigned id,enum mpd_tag_type tag)476 mpd_send_clear_tag_id(struct mpd_connection *connection, unsigned id,
477 		      enum mpd_tag_type tag)
478 {
479 	return mpd_send_u_s_command(connection, "cleartagid",
480 				    id, mpd_tag_name(tag));
481 }
482 
483 bool
mpd_run_clear_tag_id(struct mpd_connection * connection,unsigned id,enum mpd_tag_type tag)484 mpd_run_clear_tag_id(struct mpd_connection *connection, unsigned id,
485 		     enum mpd_tag_type tag)
486 {
487 	return mpd_run_check(connection) &&
488 		mpd_send_clear_tag_id(connection, id, tag) &&
489 		mpd_response_finish(connection);
490 }
491 
492 bool
mpd_send_clear_all_tags_id(struct mpd_connection * connection,unsigned id)493 mpd_send_clear_all_tags_id(struct mpd_connection *connection, unsigned id)
494 {
495 	return mpd_send_int_command(connection, "cleartagid", id);
496 }
497 
498 bool
mpd_run_clear_all_tags_id(struct mpd_connection * connection,unsigned id)499 mpd_run_clear_all_tags_id(struct mpd_connection *connection, unsigned id)
500 {
501 	return mpd_run_check(connection) &&
502 		mpd_send_clear_all_tags_id(connection, id) &&
503 		mpd_response_finish(connection);
504 }
505 
506 bool
mpd_send_prio(struct mpd_connection * connection,unsigned priority,unsigned position)507 mpd_send_prio(struct mpd_connection *connection, unsigned priority,
508 	      unsigned position)
509 {
510 	return mpd_send_int2_command(connection, "prio", priority, position);
511 }
512 
513 bool
mpd_run_prio(struct mpd_connection * connection,unsigned priority,unsigned position)514 mpd_run_prio(struct mpd_connection *connection, unsigned priority,
515 	     unsigned position)
516 {
517 	return mpd_run_check(connection) &&
518 		mpd_send_prio(connection, priority, position) &&
519 		mpd_response_finish(connection);
520 }
521 
522 bool
mpd_send_prio_range(struct mpd_connection * connection,unsigned priority,unsigned start,unsigned end)523 mpd_send_prio_range(struct mpd_connection *connection, unsigned priority,
524 		    unsigned start, unsigned end)
525 {
526 	return mpd_send_i_range_command(connection, "prio", priority,
527 					start, end);
528 }
529 
530 bool
mpd_run_prio_range(struct mpd_connection * connection,unsigned priority,unsigned start,unsigned end)531 mpd_run_prio_range(struct mpd_connection *connection, unsigned priority,
532 		   unsigned start, unsigned end)
533 {
534 	return mpd_run_check(connection) &&
535 		mpd_send_prio_range(connection, priority, start, end) &&
536 		mpd_response_finish(connection);
537 }
538 
539 bool
mpd_send_prio_id(struct mpd_connection * connection,unsigned priority,unsigned id)540 mpd_send_prio_id(struct mpd_connection *connection, unsigned priority,
541 		 unsigned id)
542 {
543 	return mpd_send_int2_command(connection, "prioid", priority, id);
544 }
545 
546 bool
mpd_run_prio_id(struct mpd_connection * connection,unsigned priority,unsigned id)547 mpd_run_prio_id(struct mpd_connection *connection, unsigned priority,
548 		unsigned id)
549 {
550 	return mpd_run_check(connection) &&
551 		mpd_send_prio_id(connection, priority, id) &&
552 		mpd_response_finish(connection);
553 }
554 
555 bool
mpd_send_range_id(struct mpd_connection * connection,unsigned id,float start,float end)556 mpd_send_range_id(struct mpd_connection *connection, unsigned id,
557 		  float start, float end)
558 {
559 	return mpd_send_u_frange_command(connection, "rangeid", id, start, end);
560 }
561 
562 bool
mpd_run_range_id(struct mpd_connection * connection,unsigned id,float start,float end)563 mpd_run_range_id(struct mpd_connection *connection, unsigned id,
564 		 float start, float end)
565 {
566 	return mpd_run_check(connection) &&
567 		mpd_send_range_id(connection, id, start, end) &&
568 		mpd_response_finish(connection);
569 }
570