1 /*
2 * $Id$
3 *
4 * (c) 2004 by Kalle Wallin <kaw@linux.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <time.h>
25 #include <string.h>
26 #include <glib.h>
28 #include "config.h"
29 #include "ncmpc.h"
30 #include "support.h"
31 #include "libmpdclient.h"
32 #include "mpc.h"
33 #include "options.h"
35 #define MAX_SONG_LENGTH 1024
37 int
38 mpc_close(mpd_client_t *c)
39 {
40 if( c->connection )
41 mpd_closeConnection(c->connection);
42 if( c->cwd )
43 g_free( c->cwd );
45 return 0;
46 }
48 mpd_client_t *
49 mpc_connect(char *host, int port, char *password)
50 {
51 mpd_Connection *connection;
52 mpd_client_t *c;
54 connection = mpd_newConnection(host, port, 10);
55 if( connection==NULL )
56 {
57 fprintf(stderr, "mpd_newConnection to %s:%d failed!\n", host, port);
58 exit(EXIT_FAILURE);
59 }
61 c = g_malloc(sizeof(mpd_client_t));
62 memset(c, 0, sizeof(mpd_client_t));
63 c->connection = connection;
64 c->cwd = g_strdup("");
66 if( password )
67 {
68 mpd_sendPasswordCommand(connection, password);
69 mpd_finishCommand(connection);
70 }
72 return c;
73 }
75 int
76 mpc_reconnect(mpd_client_t *c, char *host, int port, char *password)
77 {
78 mpd_Connection *connection;
80 connection = mpd_newConnection(host, port, 10);
81 if( connection==NULL )
82 return -1;
83 if( connection->error )
84 {
85 mpd_closeConnection(connection);
86 return -1;
87 }
89 c->connection = connection;
91 if( password )
92 {
93 mpd_sendPasswordCommand(connection, password);
94 mpd_finishCommand(connection);
95 }
97 return 0;
98 }
101 int
102 mpc_error(mpd_client_t *c)
103 {
104 if( c == NULL || c->connection == NULL )
105 return 1;
106 if( c->connection->error )
107 return c->connection->error;
109 return 0;
110 }
112 char *
113 mpc_error_str(mpd_client_t *c)
114 {
115 if( c == NULL || c->connection == NULL )
116 return "Not connected";
118 if( c->connection && c->connection->errorStr )
119 return c->connection->errorStr;
121 return NULL;
122 }
126 int
127 mpc_free_playlist(mpd_client_t *c)
128 {
129 GList *list;
131 if( c==NULL || c->playlist==NULL )
132 return -1;
134 list=g_list_first(c->playlist);
136 while( list!=NULL )
137 {
138 mpd_Song *song = (mpd_Song *) list->data;
140 mpd_freeSong(song);
141 list=list->next;
142 }
143 g_list_free(c->playlist);
144 c->playlist=NULL;
145 c->playlist_length=0;
147 c->song_id = -1;
148 c->song = NULL;
150 return 0;
151 }
153 int
154 mpc_get_playlist(mpd_client_t *c)
155 {
156 mpd_InfoEntity *entity;
158 D(fprintf(stderr, "mpc_get_playlist() [%lld]\n", c->status->playlist));
160 if( mpc_error(c) )
161 return -1;
163 if( c->playlist )
164 mpc_free_playlist(c);
166 c->playlist_length=0;
167 mpd_sendPlaylistInfoCommand(c->connection,-1);
168 if( mpc_error(c) )
169 return -1;
170 while( (entity=mpd_getNextInfoEntity(c->connection)) )
171 {
172 if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
173 {
174 mpd_Song *song = mpd_songDup(entity->info.song);
176 c->playlist = g_list_append(c->playlist, (gpointer) song);
177 c->playlist_length++;
178 }
179 mpd_freeInfoEntity(entity);
180 }
181 mpd_finishCommand(c->connection);
182 c->playlist_id = c->status->playlist;
183 c->playlist_updated = 1;
184 c->song_id = -1;
185 c->song = NULL;
187 mpc_filelist_set_selected(c);
189 return 0;
190 }
192 int
193 mpc_update_playlist(mpd_client_t *c)
194 {
195 mpd_InfoEntity *entity;
197 D(fprintf(stderr, "mpc_update_playlist() [%lld]\n", c->status->playlist));
199 if( mpc_error(c) )
200 return -1;
202 mpd_sendPlChangesCommand(c->connection, c->playlist_id);
203 if( mpc_error(c) )
204 return -1;
205 if( (entity=mpd_getNextInfoEntity(c->connection)) == NULL )
206 return mpc_get_playlist(c);
207 while( entity )
208 {
209 if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
210 {
211 mpd_Song *song;
212 GList *item;
214 if( (song=mpd_songDup(entity->info.song)) == NULL )
215 return mpc_get_playlist(c);
217 item = g_list_nth(c->playlist, song->num);
218 if( item && item->data)
219 {
220 mpd_freeSong((mpd_Song *) item->data);
221 item->data = song;
222 if( c->song_id == song->num )
223 c->song = song;
224 D(fprintf(stderr, "Changing num %d to %s\n",
225 song->num, mpc_get_song_name(song)));
226 }
227 else
228 {
229 D(fprintf(stderr, "Adding num %d - %s\n",
230 song->num, mpc_get_song_name(song)));
231 c->playlist = g_list_append(c->playlist,
232 (gpointer) song);
233 c->playlist_length++;
234 }
235 }
236 mpd_freeInfoEntity(entity);
237 entity=mpd_getNextInfoEntity(c->connection);
238 }
239 mpd_finishCommand(c->connection);
241 c->playlist_id = c->status->playlist;
242 c->playlist_updated = 1;
243 mpc_filelist_set_selected(c);
245 return 0;
246 }
248 int
249 mpc_playlist_get_song_index(mpd_client_t *c, char *filename)
250 {
251 GList *list = c->playlist;
252 int i=0;
254 while( list )
255 {
256 mpd_Song *song = (mpd_Song *) list->data;
257 if( strcmp(song->file, filename ) == 0 )
258 return i;
259 list=list->next;
260 i++;
261 }
262 return -1;
263 }
265 mpd_Song *
266 mpc_playlist_get_song(mpd_client_t *c, int n)
267 {
268 return (mpd_Song *) g_list_nth_data(c->playlist, n);
269 }
272 char *
273 mpc_get_song_name(mpd_Song *song)
274 {
275 static char buf[MAX_SONG_LENGTH];
276 char *name;
278 if( song->title )
279 {
280 if( song->artist )
281 {
282 snprintf(buf, MAX_SONG_LENGTH, "%s - %s", song->artist, song->title);
283 name = utf8_to_locale(buf);
284 strncpy(buf, name, MAX_SONG_LENGTH);
285 g_free(name);
286 return buf;
287 }
288 else
289 {
290 name = utf8_to_locale(song->title);
291 strncpy(buf, name, MAX_SONG_LENGTH);
292 g_free(name);
293 return buf;
294 }
295 }
296 name = utf8_to_locale(basename(song->file));
297 strncpy(buf, name, MAX_SONG_LENGTH);
298 g_free(name);
299 return buf;
300 }
302 char *
303 mpc_get_song_name2(mpd_Song *song)
304 {
305 static char buf[MAX_SONG_LENGTH];
306 char *name;
308 if( song->name )
309 {
310 name = utf8_to_locale(song->name);
311 strncpy(buf, name, MAX_SONG_LENGTH);
312 g_free(name);
313 return buf;
314 }
316 if( song->title )
317 {
318 if( song->artist )
319 {
320 snprintf(buf, MAX_SONG_LENGTH, "%s - %s", song->artist, song->title);
321 name = utf8_to_locale(buf);
322 strncpy(buf, name, MAX_SONG_LENGTH);
323 g_free(name);
324 return buf;
325 }
326 else
327 {
328 name = utf8_to_locale(song->title);
329 strncpy(buf, name, MAX_SONG_LENGTH);
330 g_free(name);
331 return buf;
332 }
333 }
334 name = utf8_to_locale(basename(song->file));
335 strncpy(buf, name, MAX_SONG_LENGTH);
336 g_free(name);
337 return buf;
338 }
340 #if 0
341 size_t
342 strfsong(char *s, size_t max, const char *format, mpd_Song *song)
343 {
344 size_t i, len, format_len;
345 char prev;
347 void sappend(char *utfstr) {
348 char *tmp = utf8_to_locale(utfstr);
349 size_t tmplen = strlen(tmp);
350 if( i+tmplen < max )
351 strcat(s, tmp);
352 else
353 strncat(s, tmp, max-i);
354 i = strlen(s);
355 g_free(tmp);
356 }
358 i = 0;
359 len = 0;
360 format_len = strlen(format);
361 memset(s, 0, max);
362 while(i<format_len && len<max)
363 {
364 if( i>0 && format[i-1]=='%' )
365 {
366 char *tmp;
367 size_t tmplen;
369 switch(format[i])
370 {
371 case '%':
372 s[len++] = format[i];
373 break;
374 case 'a':
375 sappend(song->artist);
376 break;
377 case 't':
378 sappend(song->title);
379 break;
380 case 'n':
381 sappend(song->name);
382 break;
383 case 'f':
384 sappend(song->file);
385 break;
386 }
387 }
388 else if( format[i]!='%' )
389 {
390 s[len] = format[i++];
391 }
392 len++;
393 }
395 return len;
396 }
397 #endif
400 int
401 mpc_update(mpd_client_t *c)
402 {
403 if( mpc_error(c) )
404 return -1;
406 if( c->status )
407 {
408 mpd_freeStatus(c->status);
409 }
411 c->status = mpd_getStatus(c->connection);
412 if( mpc_error(c) )
413 return -1;
415 if( c->playlist_id!=c->status->playlist )
416 {
417 if( c->playlist_length<2 )
418 mpc_get_playlist(c);
419 else
420 mpc_update_playlist(c);
421 }
423 if( !c->song || c->status->song != c->song_id )
424 {
425 c->song = mpc_playlist_get_song(c, c->status->song);
426 c->song_id = c->status->song;
427 c->song_updated = 1;
428 }
430 return 0;
431 }
438 int
439 mpc_free_filelist(mpd_client_t *c)
440 {
441 GList *list;
443 if( c==NULL || c->filelist==NULL )
444 return -1;
446 list=g_list_first(c->filelist);
448 while( list!=NULL )
449 {
450 filelist_entry_t *entry = list->data;
452 if( entry->entity )
453 mpd_freeInfoEntity(entry->entity);
454 g_free(entry);
455 list=list->next;
456 }
457 g_list_free(c->filelist);
458 c->filelist=NULL;
459 c->filelist_length=0;
461 return 0;
462 }
466 int
467 mpc_update_filelist(mpd_client_t *c)
468 {
469 mpd_InfoEntity *entity;
471 if( mpc_error(c) )
472 return -1;
474 if( c->filelist )
475 mpc_free_filelist(c);
477 c->filelist_length=0;
479 // mpd_sendListallCommand(conn,"");
480 mpd_sendLsInfoCommand(c->connection, c->cwd);
482 if( c->cwd && c->cwd[0] )
483 {
484 /* add a dummy entry for ./.. */
485 filelist_entry_t *entry = g_malloc(sizeof(filelist_entry_t));
486 memset(entry, 0, sizeof(filelist_entry_t));
487 entry->entity = NULL;
488 c->filelist = g_list_append(c->filelist, (gpointer) entry);
489 c->filelist_length++;
490 }
492 while( (entity=mpd_getNextInfoEntity(c->connection)) )
493 {
494 filelist_entry_t *entry = g_malloc(sizeof(filelist_entry_t));
496 memset(entry, 0, sizeof(filelist_entry_t));
497 entry->entity = entity;
498 c->filelist = g_list_append(c->filelist, (gpointer) entry);
499 c->filelist_length++;
500 }
502 c->filelist_updated = 1;
504 mpd_finishCommand(c->connection);
506 mpc_filelist_set_selected(c);
508 return 0;
509 }
511 int
512 mpc_filelist_set_selected(mpd_client_t *c)
513 {
514 GList *list = c->filelist;
516 while( list )
517 {
518 filelist_entry_t *entry = list->data;
519 mpd_InfoEntity *entity = entry->entity ;
521 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
522 {
523 mpd_Song *song = entity->info.song;
525 if( mpc_playlist_get_song_index(c, song->file) >= 0 )
526 entry->selected = 1;
527 else
528 entry->selected = 0;
529 }
531 list=list->next;
532 }
533 return 0;
534 }