1 #include "libmpdclient.h"
2
3 #include "gbemol-mpd.h"
4 #include "gbemol-marshal.h"
5
6 /* Properties */
7 enum {
8 GBEMOL_MPD_HOST = 1,
9 GBEMOL_MPD_PASS,
10 GBEMOL_MPD_PORT,
11 GBEMOL_MPD_TIMEOUT
12 };
13
14 /* Signals */
15 typedef enum {
16 STATE_CHANGED_SIGNAL,
17 SONG_CHANGED_SIGNAL,
18 PLAYLIST_CHANGED_SIGNAL,
19 REFRESH_SIGNAL,
20 ERROR_SIGNAL,
21 LAST_SIGNAL
22 } GbemolMpdSignalType;
23
24 struct _GbemolMpdPrivate {
25 mpd_Connection *conn;
26
27 gchar *host; /* MPD Host */
28 gchar *pass; /* MPD Pass */
29 guint port; /* MPD TCP Port */
30
31 float timeout; /* Timeout, in seconds */
32
33 gboolean connected; /* Connected to the daemon? */
34
35 int error; /* Error code, 0 for no error */
36
37 GList* not_commands; /* List of not allowed commands */
38 };
39
40 static guint gbemol_mpd_signals [LAST_SIGNAL] = { 0 };
41
42 static void gbemol_mpd_class_init (GObjectClass *g_class);
43 static void gbemol_mpd_init (GbemolMpd *obj);
44 static void gbemol_mpd_finalize (GObject *object);
45 static gboolean gbemol_mpd_refresh (GbemolMpd *obj);
46 static void gbemol_mpd_get_not_commands_list (GbemolMpd *obj);
47 gboolean gbemol_mpd_check_permission (GbemolMpd *obj, gchar *command);
48
49 /* Utils */
50 static gboolean gbemol_mpd_finish_and_check (GbemolMpd *obj);
51 static gboolean gbemol_mpd_finish_and_handle (GbemolMpd *obj);
52
53
54 /* Finishes a command and checks if an error has ocurred, true if yes */
55
56 GType
gbemol_mpd_get_type(void)57 gbemol_mpd_get_type (void)
58 {
59 static GType type = 0;
60 if (type == 0) {
61 static const GTypeInfo info = {
62 sizeof (GbemolMpdClass),
63 NULL, /* base_init */
64 NULL, /* base_finalize */
65 (GClassInitFunc)gbemol_mpd_class_init, /* class_init */
66 NULL, /* class_finalize */
67 NULL, /* class_data */
68 sizeof (GbemolMpd),
69 0, /* n_preallocs */
70 (GInstanceInitFunc)gbemol_mpd_init /* instance_init */
71 };
72
73 type = g_type_register_static (G_TYPE_OBJECT,
74 "GbemolMpd",
75 &info, 0);
76 }
77 return type;
78 }
79
80
81 static void
gbemol_mpd_init(GbemolMpd * obj)82 gbemol_mpd_init (GbemolMpd *obj)
83 {
84 obj->priv = g_new0 (GbemolMpdPrivate, 1);
85
86 /* Default values */
87 obj->status = NULL;
88
89 obj->priv->host = g_strdup ("localhost");
90 obj->priv->pass = NULL;
91 obj->priv->port = 6600;
92 obj->priv->timeout = 1.0;
93
94 obj->priv->connected = FALSE;
95
96 obj->priv->conn = NULL;
97
98 obj->priv->not_commands = NULL;
99 }
100
101 static void
gbemol_mpd_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)102 gbemol_mpd_set_property (GObject *object,
103 guint property_id,
104 const GValue *value,
105 GParamSpec *pspec)
106 {
107 GbemolMpd *obj = GBEMOL_MPD (object);
108
109 switch (property_id)
110 {
111 case GBEMOL_MPD_HOST:
112 g_free (obj->priv->host);
113 obj->priv->host = g_value_dup_string (value);
114 break;
115 case GBEMOL_MPD_PASS:
116 g_free (obj->priv->pass);
117 obj->priv->pass = g_value_dup_string (value);
118 break;
119 case GBEMOL_MPD_PORT:
120 obj->priv->port = g_value_get_int (value);
121 break;
122 case GBEMOL_MPD_TIMEOUT:
123 obj->priv->timeout = g_value_get_float (value);
124 break;
125 default:
126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
127 break;
128 }
129 }
130
131 static void
gbemol_mpd_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)132 gbemol_mpd_get_property (GObject *object,
133 guint property_id,
134 GValue *value,
135 GParamSpec *pspec)
136 {
137 GbemolMpd *obj = GBEMOL_MPD (object);
138
139 switch (property_id)
140 {
141 case GBEMOL_MPD_HOST:
142 g_value_set_string (value, obj->priv->host);
143 break;
144 case GBEMOL_MPD_PASS:
145 g_value_set_string (value, obj->priv->pass);
146 break;
147 case GBEMOL_MPD_PORT:
148 g_value_set_int (value, obj->priv->port);
149 break;
150 case GBEMOL_MPD_TIMEOUT:
151 g_value_set_float (value, obj->priv->timeout);
152 break;
153 default:
154 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
155 break;
156 }
157 }
158
159 static void
gbemol_mpd_class_init(GObjectClass * g_class)160 gbemol_mpd_class_init (GObjectClass *g_class)
161 {
162 GParamSpec *pspec;
163
164 g_class->set_property = gbemol_mpd_set_property;
165 g_class->get_property = gbemol_mpd_get_property;
166 g_class->finalize = gbemol_mpd_finalize;
167
168 pspec = g_param_spec_string ("host",
169 "MPD Host",
170 "Set MPD server host name",
171 "localhost" /* default value */,
172 G_PARAM_READWRITE);
173
174 g_object_class_install_property (g_class,
175 GBEMOL_MPD_HOST,
176 pspec);
177
178 pspec = g_param_spec_string ("pass",
179 "MPD Password",
180 "Set MPD server password",
181 NULL /* default value */,
182 G_PARAM_READWRITE);
183
184 g_object_class_install_property (g_class,
185 GBEMOL_MPD_PASS,
186 pspec);
187
188 pspec = g_param_spec_int ("port",
189 "MPD Port",
190 "Set MPD TCP/IP port to use",
191 0,
192 65535,
193 6600,
194 G_PARAM_READWRITE);
195
196 g_object_class_install_property (g_class,
197 GBEMOL_MPD_PORT,
198 pspec);
199
200 pspec = g_param_spec_float ("timeout",
201 "MPD Timeout",
202 "Set MPD connection timeout",
203 0,
204 65535,
205 1.0,
206 G_PARAM_READWRITE);
207
208 g_object_class_install_property (g_class,
209 GBEMOL_MPD_TIMEOUT,
210 pspec);
211
212 /* Signals */
213 gbemol_mpd_signals [STATE_CHANGED_SIGNAL] =
214 g_signal_new ("state_changed",
215 G_TYPE_FROM_CLASS (g_class),
216 G_SIGNAL_RUN_LAST,
217 0,
218 NULL,
219 NULL,
220 g_cclosure_marshal_VOID__VOID,
221 G_TYPE_NONE,
222 0);
223
224 gbemol_mpd_signals [SONG_CHANGED_SIGNAL] =
225 g_signal_new ("song_changed",
226 G_TYPE_FROM_CLASS (g_class),
227 G_SIGNAL_RUN_LAST,
228 0,
229 NULL,
230 NULL,
231 g_cclosure_marshal_VOID__VOID,
232 G_TYPE_NONE,
233 0);
234 gbemol_mpd_signals [PLAYLIST_CHANGED_SIGNAL] =
235 g_signal_new ("playlist_changed",
236 G_TYPE_FROM_CLASS (g_class),
237 G_SIGNAL_RUN_LAST,
238 0,
239 NULL,
240 NULL,
241 g_cclosure_marshal_VOID__VOID,
242 G_TYPE_NONE,
243 0);
244 gbemol_mpd_signals [REFRESH_SIGNAL] =
245 g_signal_new ("refresh",
246 G_TYPE_FROM_CLASS (g_class),
247 G_SIGNAL_RUN_LAST,
248 0,
249 NULL,
250 NULL,
251 g_cclosure_marshal_VOID__VOID,
252 G_TYPE_NONE,
253 0);
254 gbemol_mpd_signals [ERROR_SIGNAL] =
255 g_signal_new ("error",
256 G_TYPE_FROM_CLASS (g_class),
257 G_SIGNAL_RUN_LAST,
258 0,
259 NULL,
260 NULL,
261 gbemol_cclosure_VOID__INT_INT_STRING,
262 G_TYPE_NONE,
263 3,
264 G_TYPE_INT,
265 G_TYPE_INT,
266 G_TYPE_STRING);
267
268 }
269
gbemol_mpd_get_status(GbemolMpd * obj)270 static GbemolMpdStatus* gbemol_mpd_get_status (GbemolMpd* obj)
271 {
272 if (!gbemol_mpd_check_permission (obj, "status"))
273 return NULL;
274
275 mpd_sendCurrentSongCommand (obj->priv->conn);
276
277 if (gbemol_mpd_finish_and_handle (obj))
278 return NULL;
279
280 mpd_sendStatusCommand (obj->priv->conn);
281 return mpd_getStatus (obj->priv->conn);
282 }
283
284
285
286 static void
gbemol_mpd_finalize(GObject * obj)287 gbemol_mpd_finalize (GObject *obj)
288 {
289 GbemolMpd *mpd = GBEMOL_MPD (obj);
290
291 mpd_closeConnection (mpd->priv->conn);
292 g_free (mpd->priv->host);
293 g_free (mpd->priv->pass);
294
295 g_free (GBEMOL_MPD (obj)->priv);
296 }
297
gbemol_mpd_refresh(GbemolMpd * obj)298 static gboolean gbemol_mpd_refresh (GbemolMpd *obj)
299 {
300 GbemolMpdStatus* status;
301 gboolean signals [LAST_SIGNAL] = { FALSE }; /* Signals to be emitted */
302 int i;
303
304 if (!gbemol_mpd_check_permission (obj, "status"))
305 return TRUE;
306
307 status = gbemol_mpd_get_status (obj);
308
309 signals [REFRESH_SIGNAL] = TRUE;
310
311 if (status)
312 {
313 /* If there wasn't a status before, update everything */
314 if (!obj->status)
315 {
316 signals [SONG_CHANGED_SIGNAL] = TRUE;
317 signals [PLAYLIST_CHANGED_SIGNAL] = TRUE;
318 signals [STATE_CHANGED_SIGNAL] = TRUE;
319 }
320 else
321 {
322 /* Check if song has changed */
323 if ((status->song < 0) || (status->songid != obj->status->songid))
324 signals [SONG_CHANGED_SIGNAL] = TRUE;
325
326 /* Check if playlist has changed */
327 if (status->playlist != obj->status->playlist)
328 signals [PLAYLIST_CHANGED_SIGNAL] = TRUE;
329
330 /* State has changed? */
331 if (status->state != obj->status->state)
332 signals [STATE_CHANGED_SIGNAL] = TRUE;
333
334 mpd_freeStatus (obj->status);
335 }
336 }
337
338 obj->status = status;
339
340 /* Emit the signals */
341 for (i = 0; i < LAST_SIGNAL; i++)
342 if (signals[i])
343 g_signal_emit (obj, gbemol_mpd_signals [i], 0, NULL);
344
345 return TRUE;
346
347 }
348
gbemol_mpd_new(const gchar * host,const gchar * pass,int port,float timeout)349 GbemolMpd* gbemol_mpd_new (const gchar *host, const gchar *pass, int port, float timeout)
350 {
351 GbemolMpd *obj;
352
353 obj = gbemol_mpd_new_with_defaults ();
354
355 g_object_set (G_OBJECT (obj),
356 "host", host,
357 "pass", pass,
358 "port", port,
359 "timeout", timeout,
360 NULL);
361 return obj;
362 }
363
364 GbemolMpd*
gbemol_mpd_new_with_defaults(void)365 gbemol_mpd_new_with_defaults (void)
366 {
367 GbemolMpd* obj;
368
369 obj = GBEMOL_MPD (g_object_new (GBEMOL_TYPE_MPD, NULL));
370
371 /* Add refresh function to the main loop */
372 g_timeout_add (500, (GSourceFunc) gbemol_mpd_refresh, (gpointer) obj);
373
374 return obj;
375 }
376
gbemol_mpd_is_connected(GbemolMpd * obj)377 gboolean gbemol_mpd_is_connected (GbemolMpd *obj)
378 {
379 return obj->priv->connected;
380 }
381
gbemol_mpd_get_version(GbemolMpd * obj)382 gchar* gbemol_mpd_get_version (GbemolMpd* obj)
383 {
384 gchar* str;
385
386 str = g_strdup_printf ("%d.%d.%d", obj->priv->conn->version[0], obj->priv->conn->version[1],
387 obj->priv->conn->version[2]);
388 return str;
389 }
390
gbemol_mpd_free_song(GbemolMpdSong * song)391 void gbemol_mpd_free_song (GbemolMpdSong *song)
392 {
393 if (song)
394 mpd_freeSong (song);
395 song = NULL;
396 }
397
gbemol_mpd_free_song_list(GList * songs)398 void gbemol_mpd_free_song_list (GList *songs)
399 {
400 if (songs)
401 {
402 g_list_foreach (songs, (GFunc) mpd_freeSong, NULL);
403 g_list_free (songs);
404 }
405 songs = NULL;
406 }
407
gbemol_mpd_free_char_list(GList * l)408 void gbemol_mpd_free_char_list (GList *l)
409 {
410 if (l)
411 {
412 g_list_foreach (l, (GFunc) g_free, NULL);
413 g_list_free (l);
414 }
415 l = NULL;
416 }
417
gbemol_mpd_free_output_list(GList * l)418 void gbemol_mpd_free_output_list (GList *l)
419 {
420 if (l)
421 {
422 g_list_foreach (l, (GFunc) mpd_freeOutputElement, NULL);
423 g_list_free (l);
424 }
425 l = NULL;
426 }
427
428 /* Property related methods */
gbemol_mpd_set_host(GbemolMpd * obj,const gchar * host)429 void gbemol_mpd_set_host (GbemolMpd *obj, const gchar *host)
430 {
431 g_object_set (G_OBJECT (obj), "host", host, NULL);
432 }
433
gbemol_mpd_set_pass(GbemolMpd * obj,const gchar * pass)434 void gbemol_mpd_set_pass (GbemolMpd *obj, const gchar *pass)
435 {
436 g_object_set (G_OBJECT (obj), "pass", pass, NULL);
437 }
438
gbemol_mpd_set_port(GbemolMpd * obj,guint port)439 void gbemol_mpd_set_port (GbemolMpd *obj, guint port)
440 {
441 g_object_set (G_OBJECT (obj), "port", port, NULL);
442 }
443
gbemol_mpd_set_timeout(GbemolMpd * obj,gfloat timeout)444 void gbemol_mpd_set_timeout (GbemolMpd *obj, gfloat timeout)
445 {
446 g_object_set (G_OBJECT (obj), "timeout", timeout, NULL);
447 }
448
gbemol_mpd_connect(GbemolMpd * obj)449 gboolean gbemol_mpd_connect (GbemolMpd* obj)
450 {
451 if (obj->priv->conn)
452 mpd_closeConnection (obj->priv->conn);
453
454 obj->priv->conn = mpd_newConnection (obj->priv->host, obj->priv->port, obj->priv->timeout);
455
456 if (gbemol_mpd_finish_and_handle (obj))
457 obj->priv->connected = FALSE;
458 else
459 {
460 gbemol_mpd_get_not_commands_list (obj);
461 if (obj->status)
462 mpd_freeStatus (obj->status);
463 obj->status = gbemol_mpd_get_status (obj);
464 obj->priv->connected = TRUE;
465 /* Emit a song-changed signal */
466 g_signal_emit (obj, gbemol_mpd_signals [SONG_CHANGED_SIGNAL], 0, NULL);
467 }
468
469 return obj->priv->connected;
470 }
471
472 /* Connect */
gbemol_mpd_connect_and_authenticate(GbemolMpd * obj)473 gboolean gbemol_mpd_connect_and_authenticate (GbemolMpd* obj)
474 {
475 if (obj->priv->conn)
476 mpd_closeConnection (obj->priv->conn);
477
478 obj->priv->conn = mpd_newConnection (obj->priv->host, obj->priv->port, obj->priv->timeout);
479
480 if (gbemol_mpd_finish_and_handle (obj))
481 {
482 obj->priv->connected = FALSE;
483 return FALSE;
484 }
485 else
486 obj->priv->connected = TRUE;
487
488 /* Not authenticated, yet connected, so return TRUE, but mark as disconnected */
489 if (!gbemol_mpd_authenticate (obj))
490 obj->priv->connected = FALSE;
491 else
492 {
493 gbemol_mpd_get_not_commands_list (obj);
494 if (obj->status)
495 mpd_freeStatus (obj->status);
496 obj->status = gbemol_mpd_get_status (obj);
497 /* Emit a song-changed signal */
498 g_signal_emit (obj, gbemol_mpd_signals [SONG_CHANGED_SIGNAL], 0, NULL);
499 }
500
501 return TRUE;
502 }
503
gbemol_mpd_disconnect(GbemolMpd * obj)504 void gbemol_mpd_disconnect (GbemolMpd *obj)
505 {
506 if (obj->priv->not_commands)
507 gbemol_mpd_free_char_list (obj->priv->not_commands);
508 obj->priv->not_commands = NULL;
509
510 obj->priv->connected = FALSE;
511 if (obj->priv->conn)
512 mpd_closeConnection (obj->priv->conn);
513 obj->priv->conn = NULL;
514 }
515
gbemol_mpd_authenticate(GbemolMpd * obj)516 gboolean gbemol_mpd_authenticate (GbemolMpd *obj)
517 {
518 mpd_sendPasswordCommand (obj->priv->conn, obj->priv->pass);
519 return !gbemol_mpd_finish_and_handle (obj);
520 }
521
522
523 /*
524 * Get the list of not allowed commands
525 */
gbemol_mpd_get_not_commands_list(GbemolMpd * obj)526 static void gbemol_mpd_get_not_commands_list (GbemolMpd *obj)
527 {
528 gchar* command;
529
530 /* if there's a previous list, free it first */
531 mpd_sendNotCommandsCommand (obj->priv->conn);
532 while ((command = mpd_getNextCommand (obj->priv->conn)))
533 obj->priv->not_commands = g_list_append (obj->priv->not_commands, command);
534
535 gbemol_mpd_finish_and_handle (obj);
536 }
537
538 /*
539 * Finish a command and checks for errors, emits a signal for the error
540 */
gbemol_mpd_finish_and_handle(GbemolMpd * obj)541 gboolean gbemol_mpd_finish_and_handle (GbemolMpd* obj)
542 {
543 if (gbemol_mpd_is_connected (obj))
544 mpd_finishCommand (obj->priv->conn);
545
546 if (obj->priv->conn->error)
547 {
548 switch (obj->priv->conn->error)
549 {
550 case MPD_ERROR_CONNCLOSED:
551 obj->priv->connected = FALSE;
552 break;
553 case MPD_ERROR_TIMEOUT:
554 obj->priv->connected = FALSE;
555 break;
556 case MPD_ERROR_UNKHOST:
557 obj->priv->connected = FALSE;
558 break;
559 case MPD_ERROR_NORESPONSE:
560 obj->priv->connected = FALSE;
561 break;
562 case MPD_ERROR_CONNPORT:
563 obj->priv->connected = FALSE;
564 break;
565 case MPD_ERROR_NOTMPD:
566 obj->priv->connected = FALSE;
567 break;
568 case MPD_ERROR_SYSTEM:
569 obj->priv->connected = FALSE;
570 break;
571 }
572 g_signal_emit (obj, gbemol_mpd_signals [ERROR_SIGNAL], 0,
573 obj->priv->conn->error, obj->priv->conn->errorCode, obj->priv->conn->errorStr, NULL);
574 mpd_clearError (obj->priv->conn);
575 return TRUE;
576 }
577 else
578 {
579 mpd_finishCommand (obj->priv->conn);
580 return FALSE;
581 }
582 }
583
584 /*
585 * Finishes a command and return TRUE if there are no errors, FALSE if there are
586 * but doesn't treat them
587 */
gbemol_mpd_finish_and_check(GbemolMpd * obj)588 gboolean gbemol_mpd_finish_and_check (GbemolMpd *obj)
589 {
590 mpd_finishCommand (obj->priv->conn);
591
592 if (obj->priv->conn->error)
593 return FALSE;
594 else
595 return TRUE;
596 }
597
598 /*
599 * Check if user is allowed to execute command
600 */
gbemol_mpd_check_permission(GbemolMpd * obj,gchar * command)601 gboolean gbemol_mpd_check_permission (GbemolMpd *obj, gchar *command)
602 {
603 GList* l = g_list_first(obj->priv->not_commands);
604
605 if (!gbemol_mpd_is_connected (obj))
606 return FALSE;
607
608 while ((l = g_list_next (l)))
609 {
610 if (g_str_equal ((gchar *) l->data, command))
611 {
612 g_message ("DENIED: %s", (gchar *) l->data);
613 return FALSE;
614 }
615 }
616 return TRUE;
617 }
618
gbemol_mpd_player_next(GbemolMpd * obj)619 void gbemol_mpd_player_next (GbemolMpd *obj)
620 {
621 if (!gbemol_mpd_check_permission (obj, "next"))
622 return;
623
624 mpd_sendNextCommand (obj->priv->conn);
625 gbemol_mpd_finish_and_handle (obj);
626 }
627
gbemol_mpd_player_previous(GbemolMpd * obj)628 void gbemol_mpd_player_previous (GbemolMpd *obj)
629 {
630 if (!gbemol_mpd_check_permission (obj, "previous"))
631 return;
632
633 mpd_sendPrevCommand (obj->priv->conn);
634 gbemol_mpd_finish_and_handle (obj);
635 }
636
gbemol_mpd_player_stop(GbemolMpd * obj)637 void gbemol_mpd_player_stop (GbemolMpd *obj)
638 {
639 if (!gbemol_mpd_check_permission (obj, "stop"))
640 return;
641
642 mpd_sendStopCommand (obj->priv->conn);
643 gbemol_mpd_finish_and_handle (obj);
644 }
645
gbemol_mpd_player_pause(GbemolMpd * obj)646 void gbemol_mpd_player_pause (GbemolMpd *obj)
647 {
648 if (!gbemol_mpd_check_permission (obj, "pause"))
649 return;
650
651 if (obj->status->state == MPD_STATUS_STATE_PLAY)
652 mpd_sendPauseCommand (obj->priv->conn, 1);
653 else
654 mpd_sendPauseCommand (obj->priv->conn, 0);
655 gbemol_mpd_finish_and_handle (obj);
656 }
657
gbemol_mpd_player_play_song_by_id(GbemolMpd * obj,int id)658 void gbemol_mpd_player_play_song_by_id (GbemolMpd *obj, int id)
659 {
660
661 if (!gbemol_mpd_check_permission (obj, "playid"))
662 return;
663
664 mpd_sendPlayIdCommand (obj->priv->conn, id);
665 gbemol_mpd_finish_and_handle (obj);
666 }
667
gbemol_mpd_player_play_song_by_pos(GbemolMpd * obj,int pos)668 void gbemol_mpd_player_play_song_by_pos (GbemolMpd *obj, int pos)
669 {
670 if (!gbemol_mpd_check_permission (obj, "play"))
671 return;
672
673 mpd_sendPlayCommand (obj->priv->conn, pos);
674 gbemol_mpd_finish_and_handle (obj);
675 }
676
gbemol_mpd_set_random(GbemolMpd * obj,gboolean random)677 void gbemol_mpd_set_random (GbemolMpd *obj, gboolean random)
678 {
679 if (!gbemol_mpd_check_permission (obj, "random"))
680 return;
681
682 mpd_sendRandomCommand (obj->priv->conn, random);
683 gbemol_mpd_finish_and_handle (obj);
684 }
685
gbemol_mpd_set_repeat(GbemolMpd * obj,gboolean repeat)686 void gbemol_mpd_set_repeat (GbemolMpd *obj, gboolean repeat)
687 {
688 if (!gbemol_mpd_check_permission (obj, "repeat"))
689 return;
690
691 mpd_sendRepeatCommand (obj->priv->conn, repeat);
692 gbemol_mpd_finish_and_handle (obj);
693 }
694
gbemol_mpd_seek(GbemolMpd * obj,int id,int sec)695 void gbemol_mpd_seek (GbemolMpd *obj, int id, int sec)
696 {
697 if (!gbemol_mpd_check_permission (obj, "seekid"))
698 return;
699
700 mpd_sendSeekIdCommand (obj->priv->conn, id, sec);
701 gbemol_mpd_finish_and_handle (obj);
702 }
703
gbemol_mpd_crossfade(GbemolMpd * obj,int fade)704 void gbemol_mpd_crossfade (GbemolMpd *obj, int fade)
705 {
706 if (!gbemol_mpd_check_permission (obj, "crossfade"))
707 return;
708
709 mpd_sendCrossfadeCommand (obj->priv->conn, fade);
710 gbemol_mpd_finish_and_handle (obj);
711 }
712
gbemol_mpd_set_volume(GbemolMpd * obj,int volume)713 void gbemol_mpd_set_volume (GbemolMpd *obj, int volume)
714 {
715 if (!gbemol_mpd_check_permission (obj, "setvol"))
716 return;
717 mpd_sendSetvolCommand (obj->priv->conn, volume);
718 gbemol_mpd_finish_and_handle (obj);
719 }
720
721 GbemolMpdSong*
gbemol_mpd_get_current_song(GbemolMpd * obj)722 gbemol_mpd_get_current_song (GbemolMpd* obj)
723 {
724 if (!gbemol_mpd_check_permission (obj, "status") || !obj->status)
725 return NULL;
726
727 if (obj->status->state == MPD_STATUS_STATE_STOP)
728 return NULL;
729
730 if (obj->status->songid >= 0)
731 return gbemol_mpd_playlist_get_song_by_id (obj, obj->status->songid);
732 return NULL;
733 }
734
gbemol_mpd_playlist_get_songs(GbemolMpd * obj)735 GList* gbemol_mpd_playlist_get_songs (GbemolMpd *obj)
736 {
737 GList* songs = NULL;
738 GbemolMpdInfo *info;
739 GbemolMpdSong *song;
740
741 if (!gbemol_mpd_check_permission (obj, "playlistinfo"))
742 return NULL;
743
744 mpd_sendPlaylistInfoCommand (obj->priv->conn, -1);
745
746 while ((info = mpd_getNextInfoEntity (obj->priv->conn)))
747 {
748 if (info->type == MPD_INFO_ENTITY_TYPE_SONG)
749 {
750 song = mpd_songDup (info->info.song);
751 songs = g_list_prepend (songs, (gpointer) song);
752 }
753 mpd_freeInfoEntity (info);
754 }
755
756 if (gbemol_mpd_finish_and_handle (obj))
757 return NULL;
758 else
759 return g_list_reverse (songs);
760 }
761
gbemol_mpd_playlist_get_song_by_id(GbemolMpd * obj,gint id)762 GbemolMpdSong* gbemol_mpd_playlist_get_song_by_id (GbemolMpd *obj, gint id)
763 {
764 GbemolMpdInfo *info;
765 GbemolMpdSong *song;
766
767 if ((id < 0) || !gbemol_mpd_check_permission (obj, "playlistid"))
768 return NULL;
769
770 mpd_sendPlaylistIdCommand (obj->priv->conn, id);
771 info = mpd_getNextInfoEntity (obj->priv->conn);
772
773 if (gbemol_mpd_finish_and_handle (obj) || !info)
774 return NULL;
775
776 if (info->type == MPD_INFO_ENTITY_TYPE_SONG)
777 {
778 song = info->info.song;
779 info->info.song = NULL;
780 } else
781 song = NULL;
782
783 mpd_freeInfoEntity (info);
784
785 return song;
786 }
787
788 /*
789 * Return the current selected song (referenced by status->song)
790 */
gbemol_mpd_playlist_get_selected_song(GbemolMpd * obj)791 GbemolMpdSong* gbemol_mpd_playlist_get_selected_song (GbemolMpd *obj)
792 {
793 GbemolMpdSong *song = NULL;
794 GbemolMpdInfo *info;
795
796 if (!gbemol_mpd_check_permission (obj, "status"))
797 return NULL;
798
799 mpd_sendCurrentSongCommand (obj->priv->conn);
800 info = mpd_getNextInfoEntity (obj->priv->conn);
801
802 if (info && (info->type == MPD_INFO_ENTITY_TYPE_SONG))
803 song = mpd_songDup (info->info.song);
804
805 mpd_freeInfoEntity (info);
806
807 gbemol_mpd_finish_and_handle (obj);
808
809 return song;
810 }
811
gbemol_mpd_playlist_clear(GbemolMpd * obj)812 void gbemol_mpd_playlist_clear (GbemolMpd *obj)
813 {
814 if (!gbemol_mpd_check_permission (obj, "clear"))
815 return;
816
817 mpd_sendClearCommand (obj->priv->conn);
818 gbemol_mpd_finish_and_handle (obj);
819 }
820
gbemol_mpd_playlist_shuffle(GbemolMpd * obj)821 void gbemol_mpd_playlist_shuffle (GbemolMpd *obj)
822 {
823 if (!gbemol_mpd_check_permission (obj, "shuffle"))
824 return;
825
826 mpd_sendShuffleCommand (obj->priv->conn);
827 gbemol_mpd_finish_and_handle (obj);
828 }
829
gbemol_mpd_playlist_remove_song_by_id(GbemolMpd * obj,gint id)830 void gbemol_mpd_playlist_remove_song_by_id (GbemolMpd *obj, gint id)
831 {
832 if (!gbemol_mpd_check_permission (obj, "deleteid"))
833 return;
834
835 mpd_sendDeleteIdCommand (obj->priv->conn, id);
836 gbemol_mpd_finish_and_handle (obj);
837 }
838
gbemol_mpd_playlist_remove_song_by_pos(GbemolMpd * obj,gint pos)839 void gbemol_mpd_playlist_remove_song_by_pos (GbemolMpd *obj, gint pos)
840 {
841 if (!gbemol_mpd_check_permission (obj, "delete"))
842 return;
843
844 mpd_sendDeleteCommand (obj->priv->conn, pos);
845 gbemol_mpd_finish_and_handle (obj);
846 }
847
gbemol_mpd_playlist_add_song(GbemolMpd * obj,gchar * path)848 void gbemol_mpd_playlist_add_song (GbemolMpd* obj, gchar* path)
849 {
850 if (!gbemol_mpd_check_permission (obj, "add"))
851 return;
852
853 mpd_sendAddCommand (obj->priv->conn, path);
854 gbemol_mpd_finish_and_handle (obj);
855 }
856
857 /*
858 * TRUE if the song is actually a stream
859 */
gbemol_mpd_song_is_stream(GbemolMpdSong * song)860 gboolean gbemol_mpd_song_is_stream (GbemolMpdSong* song)
861 {
862 if (song->name && !song->artist && (song->time == MPD_SONG_NO_TIME))
863 return TRUE;
864 else
865 return FALSE;
866 }
867
gbemol_mpd_preview_playlist(GbemolMpd * obj,gchar * path)868 GList* gbemol_mpd_preview_playlist (GbemolMpd *obj, gchar *path)
869 {
870 GList *songs = NULL;
871 GbemolMpdSong* song;
872 GbemolMpdInfo* info;
873
874 if (!gbemol_mpd_check_permission (obj, "listplaylistinfo"))
875 return NULL;
876
877 mpd_sendListPlaylistInfoCommand (obj->priv->conn, path);
878
879 while ((info = mpd_getNextInfoEntity (obj->priv->conn)))
880 {
881 if (info->type == MPD_INFO_ENTITY_TYPE_SONG)
882 {
883 song = info->info.song;
884 info->info.song = NULL;
885 songs = g_list_prepend (songs, song);
886 }
887 mpd_freeInfoEntity (info);
888 }
889
890 if (gbemol_mpd_finish_and_handle (obj))
891 return NULL;
892 else
893 return g_list_reverse (songs);
894
895 }
896
gbemol_mpd_load_playlist(GbemolMpd * obj,gchar * playlist)897 void gbemol_mpd_load_playlist (GbemolMpd *obj, gchar *playlist)
898 {
899 if (!gbemol_mpd_check_permission (obj, "load"))
900 return;
901
902 mpd_sendLoadCommand (obj->priv->conn, playlist);
903 gbemol_mpd_finish_and_handle (obj);
904 }
905
gbemol_mpd_delete_playlist(GbemolMpd * obj,gchar * path)906 void gbemol_mpd_delete_playlist (GbemolMpd *obj, gchar *path)
907 {
908 if (!gbemol_mpd_check_permission (obj, "rm"))
909 return;
910
911 mpd_sendRmCommand (obj->priv->conn, path);
912 gbemol_mpd_finish_and_handle (obj);
913 }
914
gbemol_mpd_save_playlist(GbemolMpd * obj,gchar * path)915 gboolean gbemol_mpd_save_playlist (GbemolMpd *obj, gchar *path)
916 {
917 if (!gbemol_mpd_check_permission (obj, "save"))
918 return FALSE;
919
920 mpd_sendSaveCommand (obj->priv->conn, path);
921 if (!gbemol_mpd_finish_and_check (obj))
922 {
923 /* Playlist already exists (probably) */
924 gbemol_mpd_delete_playlist (obj, path);
925 mpd_sendSaveCommand (obj->priv->conn, path);
926 return gbemol_mpd_finish_and_handle (obj);
927 }
928
929 return TRUE;
930 }
931
gbemol_mpd_get_playlists(GbemolMpd * obj)932 GList* gbemol_mpd_get_playlists (GbemolMpd *obj)
933 {
934 GList* pls = NULL;
935 GbemolMpdInfo *info;
936 gchar *list;
937
938 if (!gbemol_mpd_check_permission (obj, "lsinfo"))
939 return NULL;
940
941 mpd_sendLsInfoCommand (obj->priv->conn, "/");
942
943 while ((info = mpd_getNextInfoEntity (obj->priv->conn)))
944 {
945 if (info->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
946 {
947 list = g_strdup (info->info.playlistFile->path);
948 pls = g_list_prepend (pls, (gpointer) list);
949 }
950 mpd_freeInfoEntity (info);
951 }
952
953 if (gbemol_mpd_finish_and_handle (obj))
954 return NULL;
955 else
956 return g_list_reverse (pls);
957 }
958
959 /*
960 * Begin a queue of commands
961 */
gbemol_mpd_queue_start(GbemolMpd * obj)962 void gbemol_mpd_queue_start (GbemolMpd* obj)
963 {
964 if (!gbemol_mpd_is_connected (obj))
965 return;
966
967 mpd_sendCommandListOkBegin (obj->priv->conn);
968 }
969
970 /*
971 * Execute the queue
972 */
gbemol_mpd_queue_finish(GbemolMpd * obj)973 void gbemol_mpd_queue_finish (GbemolMpd* obj)
974 {
975 if (!gbemol_mpd_is_connected (obj))
976 return;
977
978 mpd_sendCommandListEnd (obj->priv->conn);
979 gbemol_mpd_finish_and_handle (obj);
980 }
981
982 /*
983 * Queue removing a song
984 */
gbemol_mpd_queue_remove_song(GbemolMpd * obj,gint id)985 void gbemol_mpd_queue_remove_song (GbemolMpd* obj, gint id)
986 {
987 if (!gbemol_mpd_check_permission (obj, "deleteid"))
988 return;
989
990 mpd_sendDeleteIdCommand (obj->priv->conn, id);
991 }
992
gbemol_mpd_queue_add_song(GbemolMpd * obj,gchar * path)993 void gbemol_mpd_queue_add_song (GbemolMpd* obj, gchar* path)
994 {
995 if (!gbemol_mpd_check_permission (obj, "add"))
996 return;
997
998 mpd_sendAddCommand (obj->priv->conn, path);
999 }
1000
1001 /*
1002 * Start field search
1003 */
gbemol_mpd_search_field_start(GbemolMpd * obj,gint field)1004 void gbemol_mpd_search_field_start (GbemolMpd* obj, gint field)
1005 {
1006 if (!gbemol_mpd_is_connected (obj))
1007 return;
1008
1009 mpd_startFieldSearch (obj->priv->conn, field);
1010 }
1011
gbemol_mpd_search_start(GbemolMpd * obj)1012 void gbemol_mpd_search_start (GbemolMpd* obj)
1013 {
1014 if (!gbemol_mpd_is_connected (obj))
1015 return;
1016
1017 mpd_startSearch (obj->priv->conn, TRUE);
1018 }
1019
1020
1021 /*
1022 * Add constraint to the search
1023 */
gbemol_mpd_search_add_constraint(GbemolMpd * obj,gint tag,gchar * value)1024 void gbemol_mpd_search_add_constraint (GbemolMpd* obj, gint tag, gchar* value)
1025 {
1026 if (!gbemol_mpd_is_connected (obj))
1027 return;
1028
1029 mpd_addConstraintSearch (obj->priv->conn, tag, value);
1030 }
1031
1032 /*
1033 * Get the search results
1034 */
gbemol_mpd_search_field_get_results(GbemolMpd * obj,gint tag)1035 GList* gbemol_mpd_search_field_get_results (GbemolMpd* obj, gint tag)
1036 {
1037 GList* results = NULL;
1038 gchar* str;
1039
1040 if (!gbemol_mpd_is_connected (obj))
1041 return NULL;
1042
1043 mpd_commitSearch (obj->priv->conn);
1044 while ((str = mpd_getNextTag (obj->priv->conn, tag)) != NULL)
1045 results = g_list_append (results, str);
1046
1047 return results;
1048 }
1049
gbemol_mpd_search_get_results(GbemolMpd * obj)1050 GList* gbemol_mpd_search_get_results (GbemolMpd* obj)
1051 {
1052 GList* results = NULL;
1053 GbemolMpdInfo *info;
1054 GbemolMpdSong *song;
1055
1056 if (!gbemol_mpd_is_connected (obj))
1057 return NULL;
1058
1059 gbemol_mpd_search_commit (obj);
1060
1061 while ((info = mpd_getNextInfoEntity (obj->priv->conn)) != NULL)
1062 {
1063 if (info->type == MPD_INFO_ENTITY_TYPE_SONG)
1064 {
1065 song = mpd_songDup (info->info.song);
1066 results = g_list_append (results, song);
1067 }
1068 mpd_freeInfoEntity (info);
1069 }
1070
1071 return results;
1072 }
1073
gbemol_mpd_search_commit(GbemolMpd * obj)1074 void gbemol_mpd_search_commit (GbemolMpd* obj)
1075 {
1076 if (!gbemol_mpd_is_connected (obj))
1077 return;
1078
1079 mpd_commitSearch (obj->priv->conn);
1080 }
1081
gbemol_mpd_database_get_all_songs(GbemolMpd * obj)1082 GList* gbemol_mpd_database_get_all_songs (GbemolMpd* obj)
1083 {
1084 GList* results = NULL;
1085 GbemolMpdInfo *info;
1086 GbemolMpdSong *song;
1087
1088 if (!gbemol_mpd_is_connected (obj))
1089 return NULL;
1090
1091 mpd_sendListallInfoCommand (obj->priv->conn, "/");
1092
1093 while ((info = mpd_getNextInfoEntity (obj->priv->conn)) != NULL)
1094 {
1095 if (info->type == MPD_INFO_ENTITY_TYPE_SONG)
1096 {
1097 song = mpd_songDup (info->info.song);
1098 results = g_list_append (results, song);
1099 }
1100 mpd_freeInfoEntity (info);
1101 }
1102
1103 if (gbemol_mpd_finish_and_handle (obj))
1104 return NULL;
1105 else
1106 return results;
1107 }
1108
gbemol_mpd_database_update(GbemolMpd * obj,gchar * path)1109 void gbemol_mpd_database_update (GbemolMpd* obj, gchar *path)
1110 {
1111 mpd_sendUpdateCommand (obj->priv->conn, path);
1112 gbemol_mpd_finish_and_handle (obj);
1113 }
1114
gbemol_mpd_output_get_list(GbemolMpd * obj)1115 GList* gbemol_mpd_output_get_list (GbemolMpd* obj)
1116 {
1117 GList *l = NULL;
1118 GbemolMpdOutput* out;
1119
1120 mpd_sendOutputsCommand (obj->priv->conn);
1121
1122 while ((out = mpd_getNextOutput (obj->priv->conn)))
1123 l = g_list_append (l, out);
1124
1125 if (gbemol_mpd_finish_and_handle (obj))
1126 return NULL;
1127 else
1128 return l;
1129 }
1130
gbemol_mpd_output_set_active(GbemolMpd * obj,gint id,gboolean active)1131 void gbemol_mpd_output_set_active (GbemolMpd* obj, gint id, gboolean active)
1132 {
1133 if (active)
1134 mpd_sendEnableOutputCommand (obj->priv->conn, id);
1135 else
1136 mpd_sendDisableOutputCommand (obj->priv->conn, id);
1137
1138 gbemol_mpd_finish_and_handle (obj);
1139 }
1140
gbemol_mpd_get_crossfade(GbemolMpd * obj)1141 gint gbemol_mpd_get_crossfade (GbemolMpd* obj)
1142 {
1143 if (obj->status && gbemol_mpd_check_permission (obj, "status"))
1144 return obj->status->crossfade;
1145 else
1146 return -1;
1147 }
1148
gbemol_mpd_get_state(GbemolMpd * obj)1149 gint gbemol_mpd_get_state (GbemolMpd* obj)
1150 {
1151 if (obj->status && gbemol_mpd_check_permission (obj, "status"))
1152 return obj->status->state;
1153 else
1154 return -1;
1155 }
1156
gbemol_mpd_get_current_id(GbemolMpd * obj)1157 gint gbemol_mpd_get_current_id (GbemolMpd* obj)
1158 {
1159 if (obj->status && gbemol_mpd_check_permission (obj, "status"))
1160 return obj->status->songid;
1161 else
1162 return -1;
1163 }
1164
gbemol_mpd_get_total_time(GbemolMpd * obj)1165 gint gbemol_mpd_get_total_time (GbemolMpd* obj)
1166 {
1167 if (obj->status && gbemol_mpd_check_permission (obj, "status"))
1168 return obj->status->totalTime;
1169 else
1170 return -1;
1171 }
1172
gbemol_mpd_songdup(GbemolMpdSong * song)1173 GbemolMpdSong* gbemol_mpd_songdup(GbemolMpdSong* song)
1174 {
1175 return mpd_songDup(song);
1176 }
1177