1 /* simple-libmpd.c
2 *
3 * Copyright (c) 2006-2012 Landry Breuil <landry at xfce.org>
4 * This code is licenced under a BSD-style licence.
5 * (OpenBSD variant modeled after the ISC licence)
6 * All rights reserved.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* double inclusion ?*/
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include "simple-libmpd.h"
26
27 /* for DBG(..) macros */
28 #include <libxfce4util/libxfce4util.h>
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <netinet/in.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netdb.h>
37 #include <errno.h>
38 #include <fcntl.h>
39
40 int mpd_wait_for_answer(MpdObj *);
41 int mpd_send_single_cmd(MpdObj*, char*);
42 void send_complex_cmd(MpdObj*, char*, void (*)(), void *);
43 void parse_status_answer(MpdObj*, void*);
44 void parse_one_song(MpdObj*, void*);
45 void parse_playlistinfo_answer(MpdObj*, void*);
46 void parse_outputs_answer(MpdObj*, void*);
47
mpd_new(char * host,int port,char * pass)48 MpdObj* mpd_new(char* host, int port, char* pass)
49 {
50 MpdObj* mo = g_new0(MpdObj,1);
51
52 DBG("host=%s, port=%d, pass=%s", host, port, pass);
53
54 mo->host = g_strdup(host);
55 mo->port = port;
56 mo->pass = g_strdup(pass);
57 mo->socket = 0;
58 mo->status = 0;
59 mo->repeat = 0;
60 mo->random = 0;
61 mo->curvol = 0;
62 mo->song = 0;
63 mo->songid = 0;
64 mo->playlistlength = 0;
65 mo->cursong = NULL;
66 mo->error = 0;
67 mo->buffer[0] = '\0';
68 mo->buflen = 0;
69
70 return mo;
71 }
72
mpd_free(MpdObj * mo)73 void mpd_free(MpdObj* mo)
74 {
75 DBG("!");
76
77 if (mo->socket)
78 close(mo->socket);
79 g_free(mo->host);
80 g_free(mo->pass);
81 g_free(mo);
82 }
83
mpd_connect(MpdObj * mo)84 void mpd_connect(MpdObj* mo)
85 {
86 struct hostent* remote_he;
87 struct sockaddr* remote_sa;
88 struct sockaddr_in remote_si;
89 int err,nbread;
90 struct timeval tv;
91 fd_set fds;
92
93 mo->buffer[0] = '\0';
94 mo->buflen = 0;
95
96 /* ??? */
97 if (mo->socket) close(mo->socket);
98
99 DBG("!");
100
101 if (!(remote_he = (struct hostent*) gethostbyname(mo->host)))
102 {
103 mo->error = MPD_ERROR_UNKHOST;
104 DBG("ERROR @gethostbyname(), err=%s",strerror(errno));
105 return;
106 }
107 memset(&remote_si, 0, sizeof(struct sockaddr_in));
108 remote_si.sin_family = AF_INET;
109 remote_si.sin_port = htons(mo->port);
110 memcpy((char *)&remote_si.sin_addr.s_addr,( char *)remote_he->h_addr, remote_he->h_length);
111
112 remote_sa = (struct sockaddr *)&remote_si;
113
114 if ((mo->socket = socket(AF_INET,SOCK_STREAM,0)) < 0)
115 {
116 mo->error = MPD_ERROR_NOSOCK;
117 DBG("ERROR @socket(), err=%s",strerror(errno));
118 return;
119 }
120
121 if (connect(mo->socket,remote_sa, sizeof(struct sockaddr_in)) < 0)
122 {
123 mo->error = MPD_ERROR_CONNPORT;
124 DBG("ERROR @connect(), err=%s",strerror(errno));
125 return;
126 }
127
128 tv.tv_sec = 1;
129 tv.tv_usec = 0;
130 FD_ZERO(&fds);
131 FD_SET(mo->socket,&fds);
132 if((err = select(mo->socket+1,&fds,NULL,NULL,&tv)) == 1)
133 {
134 if ((nbread = recv(mo->socket, mo->buffer, MAXBUFLEN, 0)) < 0)
135 {
136 mo->error = MPD_ERROR_NORESPONSE;
137 DBG("ERROR @recv(), err=%s",strerror(errno));
138 return;
139 }
140 if (nbread == 0)
141 {
142 mo->error = MPD_ERROR_CONNCLOSED;
143 DBG("ERROR @recv(), connection closed by server");
144 return;
145 }
146 mo->buflen = nbread;
147 mo->buffer[mo->buflen] = '\0';
148 }
149 else if(err < 0)
150 {
151 mo->error = MPD_ERROR_CONNPORT;
152 DBG("ERROR @select(), err=%s",strerror(errno));
153 return;
154 }
155 else
156 {
157 mo->error = MPD_ERROR_NORESPONSE;
158 DBG("ERROR @select(), timeoute'ed -> err=%s",strerror(errno));
159 return;
160 }
161
162 if (strncmp(mo->buffer,MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE)))
163 {
164 mo->error = MPD_ERROR_NOTMPD;
165 DBG("ERROR @strncmp() -> answer didn't come from mpd");
166 return;
167 }
168
169 DBG("Received %d bytes = welcome message :\"%s\"", mo->buflen, mo->buffer);
170
171 *mo->buffer = '\0';
172 mo->buflen = 0;
173 mo->error = 0;
174 }
175
mpd_disconnect(MpdObj * mo)176 void mpd_disconnect(MpdObj* mo)
177 {
178 DBG("!");
179 if (mo->socket)
180 close(mo->socket);
181 }
182
mpd_status_get_volume(MpdObj * mo)183 int mpd_status_get_volume(MpdObj* mo)
184 {
185 DBG("! return %d",mo->curvol);
186 return mo->curvol;
187 }
188
mpd_wait_for_answer(MpdObj * mo)189 int mpd_wait_for_answer(MpdObj *mo)
190 {
191 struct timeval tv;
192 int err,nbread;
193 fd_set fds;
194 err = nbread = 0;
195
196 DBG("!");
197
198 tv.tv_sec = 1;
199 tv.tv_usec = 0;
200 FD_ZERO(&fds);
201 FD_SET(mo->socket,&fds);
202 if((err = select(mo->socket+1,&fds,NULL,NULL,&tv)) == 1)
203 {
204 if ((nbread = recv(mo->socket, mo->buffer, MAXBUFLEN, 0)) < 0)
205 {
206 mo->error = MPD_ERROR_NORESPONSE;
207 DBG("ERROR @recv(), err=%s",strerror(errno));
208 return -1;
209 }
210 if (nbread == 0)
211 {
212 mo->error = MPD_ERROR_CONNCLOSED;
213 DBG("ERROR @recv(), connection closed by server");
214 return -1;
215 }
216
217 mo->buflen = nbread;
218 mo->buffer[mo->buflen] = '\0';
219 DBG("Read %d bytes, buff=\"%s\"", nbread, mo->buffer);
220 }
221 else if(err < 0)
222 {
223 mo->error = MPD_ERROR_CONNPORT;
224 DBG("ERROR @select(), err=%s",strerror(errno));
225 return -1;
226 }
227 else
228 {
229 mo->error = MPD_ERROR_NORESPONSE;
230 DBG("ERROR @select(), timeoute'ed -> err=%s",strerror(errno));
231 return -1;
232 }
233 if (!strncmp(mo->buffer,"ACK",3))
234 mo->error = MPD_NOTOK;
235 else
236 mo->error = MPD_OK;
237 return nbread;
238 }
239
mpd_send_single_cmd(MpdObj * mo,char * cmd)240 int mpd_send_single_cmd(MpdObj*mo, char* cmd)
241 {
242 int nbwri = 0;
243
244 if (mo->socket)
245 {
246 DBG("Sending \"%s\"",cmd);
247 if ((nbwri = send(mo->socket, cmd, strlen(cmd), 0)) <= 0)
248 {
249 mo->error = MPD_ERROR_SENDING;
250 DBG("ERROR @send(), err=%s",strerror(errno));
251 }
252 DBG("Sent %d bytes",nbwri);
253 /* wait for OK */
254 mpd_wait_for_answer(mo);
255
256 if(!mo->error)
257 {
258 if (strcmp(mo->buffer,"OK\n") != 0)
259 {
260 mo->error = MPD_FAILED;
261 DBG("ERROR : did not received OK");
262 }
263 }
264 *mo->buffer = '\0';
265 mo->buflen = 0;
266 }
267 else
268 {
269 mo->error = MPD_ERROR_NOSOCK;
270 DBG("ERROR : socket == NULL ?");
271 }
272 return ((!mo->error) ? MPD_OK : MPD_FAILED);
273 }
274
send_complex_cmd(MpdObj * mo,char * cmd,void (* parse_answer_fct)(),void * res)275 void send_complex_cmd(MpdObj* mo, char* cmd, void (*parse_answer_fct)(), void *res)
276 {
277 int nbwri, nbread, tmp_bufsize;
278 char *ptr;
279 char *tmp_buffer, *tmp;
280 /* write 'cmd' to socket */
281 if (mo->socket)
282 {
283 DBG("Sending \"%s\"",cmd);
284 if ((nbwri = send(mo->socket, cmd, strlen(cmd), 0)) < 0)
285 {
286 mo->error = MPD_ERROR_SENDING;
287 DBG("ERROR @send(), err=%s",strerror(errno));
288 return;
289 }
290 DBG("Sent %d bytes",nbwri);
291
292 nbread = mpd_wait_for_answer(mo);
293 /* special case for long answers with 'playlistinfo' - hack to loop until we have received the final OK\n*/
294 while (!mo->error && ( nbread == MAXBUFLEN || 0 != strcmp(mo->buffer + strlen(mo->buffer) - 3,"OK\n")))
295 {
296 /* save the end of the buffer from last occurence of 'file:', and replace it with 'OK\n' */
297 ptr = g_strrstr(mo->buffer, "file:");
298 if (!ptr)
299 {
300 mo->error = MPD_ERROR_CONNCLOSED;
301 DBG("ERROR parsing reply");
302 *mo->buffer = '\0';
303 mo->buflen = 0;
304 return;
305 }
306
307 tmp_buffer = (char*) calloc (MAXBUFLEN*2, sizeof(char));
308 strcpy(tmp_buffer, ptr);
309 tmp_bufsize = strlen(tmp_buffer);
310 strcpy(ptr, "OK\n");
311 DBG("tmp_buffer contains \"%s\"", tmp_buffer);
312 DBG("buffer now contains \"%s\"", mo->buffer);
313 /* parse buffer */
314 (*parse_answer_fct)(mo, res);
315
316 /* re-read stuff */
317 nbread = mpd_wait_for_answer(mo);
318 /* append the saved end to the beginning of buffer */
319 /* ugly memory management. really. */
320 tmp = (char*) calloc (MAXBUFLEN*2, sizeof(char));
321 strcpy(tmp, mo->buffer);
322 strcpy(mo->buffer, tmp_buffer);
323 strcpy(mo->buffer + tmp_bufsize, tmp);
324 mo->buffer[tmp_bufsize + nbread] = '\0';
325 DBG("added tmp_buffer at the beginning of buffer, now contains \"%s\"", mo->buffer);
326 free(tmp_buffer);
327 free(tmp);
328 }
329 /* finally parse the end of the answer => 'currentsong' and 'status' parsing should jump directly here*/
330 if (!mo->error)
331 (*parse_answer_fct)(mo, res);
332
333 *mo->buffer = '\0';
334 mo->buflen = 0;
335 }
336 else
337 {
338 mo->error = MPD_ERROR_NOSOCK;
339 DBG("ERROR : socket == NULL ?");
340 }
341 }
342
parse_status_answer(MpdObj * mo,void * unused_param)343 void parse_status_answer(MpdObj *mo, void* unused_param)
344 {
345 gchar **lines, **tokens;
346 int i;
347 mo->songid = -1;
348 lines = g_strsplit(mo->buffer, "\n", 0);
349 for (i = 0 ; lines[i] && strncmp(lines[i], "OK", 2) ; i++)
350 {
351 tokens = g_strsplit(lines[i], ":", 2);
352 /* remove leading whitespace */
353 tokens[1] = g_strchug(tokens[1]);
354 DBG("key=\"%s\",value=\"%s\"", tokens[0], tokens[1]);
355 if (0 == strcmp("volume",tokens[0])) mo->curvol = atoi(tokens[1]);
356 else if (0 == strcmp("repeat",tokens[0])) mo->repeat = atoi(tokens[1]);
357 else if (0 == strcmp("random",tokens[0])) mo->random = atoi(tokens[1]);
358 else if (0 == strcmp("playlistlength",tokens[0])) mo->playlistlength = atoi(tokens[1]);
359 else if (0 == strcmp("state", tokens[0]))
360 {
361 if (0 == strcmp("play", tokens[1])) mo->status = MPD_PLAYER_PLAY;
362 else if (0 == strcmp("pause",tokens[1])) mo->status = MPD_PLAYER_PAUSE;
363 else if (0 == strcmp("stop", tokens[1])) mo->status = MPD_PLAYER_STOP;
364 }
365 else if (0 == strcmp("song",tokens[0])) mo->song = atoi(tokens[1]);
366 else if (0 == strcmp("songid",tokens[0])) mo->songid = atoi(tokens[1]);
367 g_strfreev(tokens);
368 }
369 g_strfreev(lines);
370 }
371
mpd_status_update(MpdObj * mo)372 int mpd_status_update(MpdObj* mo)
373 {
374 mo->status = 0;
375 DBG("!");
376 send_complex_cmd(mo, "status\n", parse_status_answer, NULL);
377 return ((!mo->error) ? MPD_OK : MPD_FAILED);
378 }
379
380
parse_one_song(MpdObj * mo,void * param)381 void parse_one_song(MpdObj *mo, void* param)
382 {
383 mpd_Song* ms = (mpd_Song*) param;
384 gchar **lines, **tokens;
385 int i;
386 ms->file = ms->artist = ms->album = ms->title = ms->track = NULL;
387 ms->id = ms->pos = -1;
388
389 lines = g_strsplit(mo->buffer, "\n", 0);
390 for (i = 0 ; lines[i] && strcmp(lines[i], "OK") ; i++)
391 {
392 tokens = g_strsplit(lines[i], ":", 2);
393 /* remove leading whitespace */
394 tokens[1] = g_strchug(tokens[1]);
395 DBG("key=\"%s\",value=\"%s\"", tokens[0], tokens[1]);
396 if (!ms->file && 0 == strcmp("file", tokens[0])) ms->file = g_strdup(tokens[1]);
397 else if (!ms->artist && 0 == strcmp("Artist",tokens[0])) ms->artist= g_strdup(tokens[1]);
398 else if (!ms->album && 0 == strcmp("Album", tokens[0])) ms->album = g_strdup(tokens[1]);
399 else if (!ms->title && 0 == strcmp("Title", tokens[0])) ms->title = g_strdup(tokens[1]);
400 else if (!ms->track && 0 == strcmp("Track", tokens[0])) ms->track = g_strdup(tokens[1]);
401 else if (ms->pos < 0 && 0 == strcmp("Pos", tokens[0])) ms->pos = atoi(tokens[1]);
402 else if (ms->id < 0 && 0 == strcmp("Id", tokens[0])) ms->id = atoi(tokens[1]);
403 g_strfreev(tokens);
404 }
405 if (ms->id < 0)
406 mo->error = MPD_FAILED;
407 g_strfreev(lines);
408 }
409
parse_playlistinfo_answer(MpdObj * mo,void * param)410 void parse_playlistinfo_answer(MpdObj *mo, void *param)
411 {
412 MpdData* md = (MpdData*) param;
413 mpd_Song* ms;
414 gchar **lines, **tokens;
415 int i = 0;
416
417 lines = g_strsplit(mo->buffer, "\n", 0);
418 while(lines[i] && strcmp(lines[i],"OK"))
419 {
420 ms = &md->allsongs[md->nb];
421 ms->file = ms->artist = ms->album = ms->title = ms->track = NULL;
422 ms->id = ms->pos = -1;
423 DBG("Going to parse song #%d", md->nb);
424
425 while(lines[i] && strcmp(lines[i],"OK") && ms->id < 0)
426 {
427 tokens = g_strsplit(lines[i], ":", 2);
428 /* remove leading whitespace */
429 tokens[1] = g_strchug(tokens[1]);
430 DBG("key=\"%s\",value=\"%s\"", tokens[0], tokens[1]);
431 if (!ms->file && 0 == strcmp("file", tokens[0])) ms->file = g_strdup(tokens[1]);
432 else if (!ms->artist && 0 == strcmp("Artist",tokens[0])) ms->artist= g_strdup(tokens[1]);
433 else if (!ms->album && 0 == strcmp("Album", tokens[0])) ms->album = g_strdup(tokens[1]);
434 else if (!ms->title && 0 == strcmp("Title", tokens[0])) ms->title = g_strdup(tokens[1]);
435 else if (!ms->track && 0 == strcmp("Track", tokens[0])) ms->track = g_strdup(tokens[1]);
436 else if (ms->pos < 0 && 0 == strcmp("Pos", tokens[0])) ms->pos = atoi(tokens[1]);
437 else if (ms->id < 0 && 0 == strcmp("Id", tokens[0])) ms->id = atoi(tokens[1]);
438 i++;
439 g_strfreev(tokens);
440 }
441 md->nb++;
442 }
443 g_strfreev(lines);
444 DBG("Got 'OK', md->nb = %d", md->nb);
445 }
446
parse_outputs_answer(MpdObj * mo,void * param)447 void parse_outputs_answer(MpdObj *mo, void *param)
448 {
449 MpdData* md = (MpdData*) param;
450 gchar **lines, **tokens;
451 int i = 0;
452 lines = g_strsplit(mo->buffer, "\n", 0);
453 while(lines[i] && strcmp(lines[i],"OK"))
454 {
455 md->alloutputs[md->nb] = g_new(mpd_Output, 1);
456 md->alloutputs[md->nb]->enabled = -1;
457 DBG("Going to parse output #%d", md->nb);
458 while(lines[i] && strcmp(lines[i],"OK") && md->alloutputs[md->nb]->enabled < 0)
459 {
460 tokens = g_strsplit(lines[i], ":", 2);
461 /* remove leading whitespace */
462 tokens[1] = g_strchug(tokens[1]);
463 DBG("key=\"%s\",value=\"%s\"", tokens[0], tokens[1]);
464 if (0 == strcmp("outputid",tokens[0])) md->alloutputs[md->nb]->id = atoi(tokens[1]);
465 else if (0 == strcmp("outputname",tokens[0])) md->alloutputs[md->nb]->name = g_strdup(tokens[1]);
466 else if (0 == strcmp("outputenabled",tokens[0])) md->alloutputs[md->nb]->enabled = atoi(tokens[1]);
467 i++;
468 g_strfreev(tokens);
469 }
470 md->nb++;
471 /* ignore extra lines with 'attribute:' */
472 while (lines[i] != NULL && strcmp(lines[i],"OK") && 0 == strncmp(lines[i], "attribute:", 10))
473 i++;
474 if (strcmp(lines[i],"OK")) {
475 /* make room for the next output ptr */
476 md->alloutputs = g_renew(mpd_Output*, md->alloutputs, md->nb + 1);
477 }
478 }
479 g_strfreev(lines);
480 }
481
mpd_playlist_get_current_song(MpdObj * mo)482 mpd_Song* mpd_playlist_get_current_song(MpdObj* mo)
483 {
484 DBG("!");
485 if (mo->cursong != NULL && mo->cursong->id != mo->songid)
486 {
487 if (mo->cursong->file) free(mo->cursong->file);
488 if (mo->cursong->artist) free(mo->cursong->artist);
489 if (mo->cursong->album) free(mo->cursong->album);
490 if (mo->cursong->title) free(mo->cursong->title);
491 if (mo->cursong->track) free(mo->cursong->track);
492 free(mo->cursong);
493 mo->cursong = NULL;
494 }
495 if (mo->cursong == NULL)
496 {
497 mo->cursong = g_new0(mpd_Song,1);
498 DBG("updating currentsong");
499 send_complex_cmd(mo, "currentsong\n", parse_one_song, (void*) mo->cursong);
500 }
501 return ((!mo->error) ? mo->cursong : NULL);
502 }
503
mpd_playlist_get_playlist_length(MpdObj * mo)504 int mpd_playlist_get_playlist_length(MpdObj* mo)
505 {
506 return mo->playlistlength;
507 }
508
mpd_player_get_current_song_pos(MpdObj * mo)509 int mpd_player_get_current_song_pos(MpdObj* mo)
510 {
511 DBG("!");
512 return ((mpd_status_update(mo) != MPD_OK) ? -1 : mo->song);
513 }
514
mpd_playlist_get_changes(MpdObj * mo,int old_playlist_id)515 MpdData* mpd_playlist_get_changes(MpdObj* mo, int old_playlist_id)
516 {
517 MpdData* md = g_new0(MpdData,1);
518 md->cur = md->nb = 0;
519 md->type = MPD_DATA_TYPE_SONG;
520 md->allsongs = g_new(mpd_Song, mo->playlistlength);
521 DBG("!");
522 send_complex_cmd(mo, "playlistinfo\n", parse_playlistinfo_answer, (void*) md);
523 md->song = &(md->allsongs[0]);
524 return ((!mo->error) ? md : NULL);
525 }
526
mpd_data_get_next(MpdData * md)527 MpdData* mpd_data_get_next(MpdData* md)
528 {
529 md->cur++;
530 /* free(md) and return NULL if after last */
531 if (md->cur == md->nb)
532 {
533 for (md->cur--; md->cur; md->cur--)
534 {
535 switch (md->type) {
536 case MPD_DATA_TYPE_OUTPUT_DEV:
537 if (md->alloutputs[md->cur]->name) free(md->alloutputs[md->cur]->name);
538 break;
539 case MPD_DATA_TYPE_SONG:
540 if (md->allsongs[md->cur].file) free(md->allsongs[md->cur].file);
541 if (md->allsongs[md->cur].artist) free(md->allsongs[md->cur].artist);
542 if (md->allsongs[md->cur].album) free(md->allsongs[md->cur].album);
543 if (md->allsongs[md->cur].title) free(md->allsongs[md->cur].title);
544 if (md->allsongs[md->cur].track) free(md->allsongs[md->cur].track);
545 break;
546 }
547 }
548 switch (md->type) {
549 case MPD_DATA_TYPE_OUTPUT_DEV:
550 g_free(md->alloutputs);
551 break;
552 case MPD_DATA_TYPE_SONG:
553 g_free(md->allsongs);
554 break;
555 }
556 g_free(md);
557 DBG("Free()'d md");
558 return NULL;
559 }
560 switch (md->type) {
561 case MPD_DATA_TYPE_OUTPUT_DEV:
562 md->output_dev = md->alloutputs[md->cur];
563 break;
564 case MPD_DATA_TYPE_SONG:
565 md->song = (&md->allsongs[md->cur]);
566 break;
567 }
568 return md;
569 }
570
mpd_server_get_output_devices(MpdObj * mo)571 MpdData* mpd_server_get_output_devices(MpdObj* mo)
572 {
573 MpdData* md = g_new0(MpdData,1);
574 DBG("!");
575 md->cur = md->nb = 0;
576 md->alloutputs = g_new(mpd_Output*,1);
577 md->type = MPD_DATA_TYPE_OUTPUT_DEV;
578 send_complex_cmd(mo, "outputs\n", parse_outputs_answer, (void*) md);
579 md->output_dev = md->alloutputs[0];
580 return ((!mo->error) ? md : NULL);
581 }
582
mpd_server_set_output_device(MpdObj * mo,int id,int state)583 int mpd_server_set_output_device (MpdObj* mo, int id, int state)
584 {
585 char outbuf[18];
586 /* write (enable|disable)output 'id' to socket */
587 DBG("!");
588 snprintf(outbuf, sizeof(outbuf), "%soutput %d\n",(state ? "enable" : "disable"), id);
589 return mpd_send_single_cmd(mo,outbuf);
590 }
591
mpd_status_set_volume(MpdObj * mo,int newvol)592 void mpd_status_set_volume(MpdObj* mo, int newvol)
593 {
594 char outbuf[15];
595 /* write setvol 'newvol' to socket */
596 DBG("!");
597 snprintf(outbuf, sizeof(outbuf), "setvol %d\n",newvol);
598 mpd_send_single_cmd(mo,outbuf);
599 }
600
mpd_player_get_state(MpdObj * mo)601 int mpd_player_get_state(MpdObj* mo)
602 {
603 DBG("! return %d",mo->status);
604 return mo->status;
605 }
606
mpd_player_get_random(MpdObj * mo)607 int mpd_player_get_random(MpdObj* mo)
608 {
609 DBG("! return %d",mo->random);
610 return mo->random;
611 }
612
mpd_player_set_random(MpdObj * mo,int random)613 int mpd_player_set_random(MpdObj* mo, int random)
614 {
615 char outbuf[15];
616 DBG("!");
617 snprintf(outbuf, sizeof(outbuf), "random %d\n",random);
618 return mpd_send_single_cmd(mo,outbuf);
619
620 }
621
mpd_player_set_repeat(MpdObj * mo,int repeat)622 int mpd_player_set_repeat(MpdObj* mo, int repeat)
623 {
624 char outbuf[15];
625 DBG("!");
626 snprintf(outbuf, sizeof(outbuf), "repeat %d\n",repeat);
627 return mpd_send_single_cmd(mo,outbuf);
628 }
629
mpd_player_get_repeat(MpdObj * mo)630 int mpd_player_get_repeat(MpdObj* mo)
631 {
632 DBG("! return %d",mo->repeat);
633 return mo->repeat;
634 }
635
mpd_player_prev(MpdObj * mo)636 int mpd_player_prev(MpdObj* mo)
637 {
638 DBG("!");
639 return mpd_send_single_cmd(mo,"previous\n");
640 }
641
mpd_player_next(MpdObj * mo)642 int mpd_player_next(MpdObj* mo)
643 {
644 DBG("!");
645 return mpd_send_single_cmd(mo,"next\n");
646 }
647
mpd_player_stop(MpdObj * mo)648 int mpd_player_stop(MpdObj* mo)
649 {
650 DBG("!");
651 return mpd_send_single_cmd(mo,"stop\n");
652 }
653
mpd_player_pause(MpdObj * mo)654 int mpd_player_pause(MpdObj* mo)
655 {
656 DBG("!");
657 if (mo->status != MPD_PLAYER_PLAY)
658 return mpd_send_single_cmd(mo,"pause 0\n");
659 else
660 return mpd_send_single_cmd(mo,"pause 1\n");
661 }
662
mpd_player_play(MpdObj * mo)663 int mpd_player_play(MpdObj* mo)
664 {
665 DBG("!");
666 return mpd_send_single_cmd(mo,"play\n");
667 }
668
mpd_player_play_id(MpdObj * mo,int id)669 int mpd_player_play_id(MpdObj* mo, int id)
670 {
671 char outbuf[15];
672 DBG("!");
673 snprintf(outbuf, sizeof(outbuf), "playid %d\n",id);
674 return mpd_send_single_cmd(mo,outbuf);
675 }
676
mpd_check_error(MpdObj * mo)677 int mpd_check_error(MpdObj* mo)
678 {
679 DBG("! return %d",mo->error);
680 return mo->error;
681 }
682
mpd_send_password(MpdObj * mo)683 void mpd_send_password(MpdObj* mo)
684 {
685 char outbuf[256];
686 int wrote;
687 DBG("!");
688 /* write password 'password' to socket */
689 wrote = snprintf(outbuf, sizeof(outbuf), "password %s\n",mo->pass);
690 if (wrote > 255) {
691 /* the password is too long to fit though there doesn't seem to be a
692 * nice way to report this error :-/ */
693 fprintf(stderr, "xfce4-mpc-plugin: password too long!\n");
694 mo->error = MPD_ERROR_SYSTEM;
695 return;
696 }
697 mpd_send_single_cmd(mo,outbuf);
698 }
699
mpd_set_hostname(MpdObj * mo,char * host)700 void mpd_set_hostname(MpdObj* mo, char* host)
701 {
702 DBG("! new hostname=%s",host);
703 g_free(mo->host);
704 mo->host = g_strdup(host);
705 }
706
mpd_set_password(MpdObj * mo,char * pass)707 void mpd_set_password(MpdObj* mo, char* pass)
708 {
709 DBG("! new password=%s",pass);
710 g_free(mo->pass);
711 mo->pass = g_strdup(pass);
712 }
713
mpd_set_port(MpdObj * mo,int port)714 void mpd_set_port(MpdObj* mo,int port)
715 {
716 DBG("! new port=%d",port);
717 mo->port = port;
718 }
719
720