Fix XMMS2 related crash (sf.net #2806111 and #2805310, thanks Lassi).
[monky] / src / xmms2.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
10  *      (see AUTHORS)
11  * All rights reserved.
12  *
13  * This program is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  *
25  */
26
27 #include "conky.h"
28
29 xmmsc_connection_t *xmms2_conn;
30
31 #define CONN_INIT       0
32 #define CONN_OK         1
33 #define CONN_NO         2
34
35 static void xmms_alloc(struct information *ptr)
36 {
37
38         if (ptr->xmms2.artist == NULL) {
39                 ptr->xmms2.artist = malloc(text_buffer_size);
40         }
41
42         if (ptr->xmms2.album == NULL) {
43                 ptr->xmms2.album = malloc(text_buffer_size);
44         }
45
46         if (ptr->xmms2.title == NULL) {
47                 ptr->xmms2.title = malloc(text_buffer_size);
48         }
49
50         if (ptr->xmms2.genre == NULL) {
51                 ptr->xmms2.genre = malloc(text_buffer_size);
52         }
53
54         if (ptr->xmms2.comment == NULL) {
55                 ptr->xmms2.comment = malloc(text_buffer_size);
56         }
57
58         if (ptr->xmms2.url == NULL) {
59                 ptr->xmms2.url = malloc(text_buffer_size);
60         }
61
62         if (ptr->xmms2.date == NULL) {
63                 ptr->xmms2.date = malloc(text_buffer_size);
64         }
65
66         ptr->xmms2.artist[0] = '\0';
67         ptr->xmms2.album[0] = '\0';
68         ptr->xmms2.title[0] = '\0';
69         ptr->xmms2.genre[0] = '\0';
70         ptr->xmms2.comment[0] = '\0';
71         ptr->xmms2.url[0] = '\0';
72         ptr->xmms2.date[0] = '\0';
73
74         ptr->xmms2.tracknr = 0;
75         ptr->xmms2.id = 0;
76         ptr->xmms2.bitrate = 0;
77         ptr->xmms2.duration = 0;
78         ptr->xmms2.elapsed = 0;
79         ptr->xmms2.size = 0;
80         ptr->xmms2.progress = 0;
81         ptr->xmms2.timesplayed = -1;
82 }
83
84 void connection_lost(void *p)
85 {
86         struct information *ptr = p;
87          ptr->xmms2.conn_state = CONN_NO;
88
89          fprintf(stderr,"XMMS2 connection failed. %s\n", xmmsc_get_last_error(xmms2_conn));
90
91          xmms_alloc(ptr);
92          strncpy(ptr->xmms2.status, "Disocnnected", text_buffer_size - 1);
93          ptr->xmms2.playlist[0] = '\0';
94          ptr->xmms2.id = 0;
95 }
96
97
98 int handle_curent_id(xmmsv_t *value, void *p)
99 {
100         struct information *ptr = p;
101         xmmsv_t *val, *infos, *dict_entry;
102         xmmsc_result_t *res;
103         const char *errbuf;
104         int current_id;
105
106         const char *charval;
107         int intval;
108
109
110         if (xmmsv_get_error(value, &errbuf)) {
111                 fprintf(stderr,"XMMS2 server error. %s\n", errbuf);
112                 return TRUE;
113                 }
114
115         if (xmmsv_get_int(value, &current_id) && current_id > 0) {
116
117                 res = xmmsc_medialib_get_info(xmms2_conn, current_id);
118                 xmmsc_result_wait(res);
119                 val = xmmsc_result_get_value(res);
120
121                 if (xmmsv_get_error(val, &errbuf)) {
122                         fprintf(stderr,"XMMS2 server error. %s\n", errbuf);
123                         return TRUE;
124                 }
125
126                 xmms_alloc(ptr);
127
128
129                 ptr->xmms2.id = current_id;
130
131                 infos = xmmsv_propdict_to_dict(val, NULL);
132
133                 if (xmmsv_dict_get(infos, "artist", &dict_entry) && xmmsv_get_string(dict_entry, &charval))
134                         strncpy(ptr->xmms2.artist, charval, text_buffer_size - 1);
135
136                 if (xmmsv_dict_get(infos, "title", &dict_entry) && xmmsv_get_string(dict_entry, &charval)) 
137                         strncpy(ptr->xmms2.title, charval, text_buffer_size - 1);
138         
139                 if (xmmsv_dict_get(infos, "album", &dict_entry) && xmmsv_get_string(dict_entry, &charval)) 
140                         strncpy(ptr->xmms2.album, charval, text_buffer_size - 1);
141                 
142                 if (xmmsv_dict_get(infos, "genre", &dict_entry) && xmmsv_get_string(dict_entry, &charval))
143                         strncpy(ptr->xmms2.genre, charval, text_buffer_size - 1);
144
145                 if (xmmsv_dict_get(infos, "comment", &dict_entry) && xmmsv_get_string(dict_entry, &charval))
146                         strncpy(ptr->xmms2.comment, charval, text_buffer_size - 1);
147
148                 if (xmmsv_dict_get(infos, "url", &dict_entry) && xmmsv_get_string(dict_entry, &charval))
149                         strncpy(ptr->xmms2.url, charval, text_buffer_size - 1);
150
151                 if (xmmsv_dict_get(infos, "date", &dict_entry) && xmmsv_get_string(dict_entry, &charval))
152                         strncpy(ptr->xmms2.date, charval, text_buffer_size - 1);
153                 
154
155
156                 if (xmmsv_dict_get(infos, "tracknr", &dict_entry) && xmmsv_get_int(dict_entry, &intval))
157                         ptr->xmms2.tracknr = intval;
158
159                 if (xmmsv_dict_get(infos, "duration", &dict_entry) && xmmsv_get_int(dict_entry, &intval))
160                         ptr->xmms2.duration = intval;
161
162                 if (xmmsv_dict_get(infos, "bitrate", &dict_entry) && xmmsv_get_int(dict_entry, &intval))
163                         ptr->xmms2.bitrate = intval / 1000;
164
165                 if (xmmsv_dict_get(infos, "size", &dict_entry) && xmmsv_get_int(dict_entry, &intval))
166                         ptr->xmms2.size = (float) intval / 1048576;
167
168                 if (xmmsv_dict_get(infos, "timesplayed", &dict_entry) && xmmsv_get_int(dict_entry, &intval))
169                         ptr->xmms2.timesplayed = intval;
170
171
172                 xmmsv_unref(infos);
173                 xmmsc_result_unref(res);
174         }
175         return TRUE;
176 }
177
178 int handle_playtime(xmmsv_t *value, void *p)
179 {
180         struct information *ptr = p;
181         int play_time;
182         const char *errbuf;
183
184         if (xmmsv_get_error(value, &errbuf)) {
185                 fprintf(stderr,"XMMS2 server error. %s\n", errbuf);
186                 return TRUE;
187         }
188
189         if (xmmsv_get_int(value, &play_time)) {
190                 ptr->xmms2.elapsed = play_time;
191                 ptr->xmms2.progress = (float) play_time / ptr->xmms2.duration;
192         }
193
194         return TRUE;
195 }
196
197 int handle_playback_state_change(xmmsv_t *value, void *p)
198 {
199         struct information *ptr = p;
200         int pb_state = 0;
201         const char *errbuf;
202
203         if (xmmsv_get_error(value, &errbuf)) {
204                 fprintf(stderr,"XMMS2 server error. %s\n", errbuf);
205                 return TRUE;
206         }
207
208         if (ptr->xmms2.status == NULL) {
209                 ptr->xmms2.status = malloc(text_buffer_size);
210                 ptr->xmms2.status[0] = '\0';
211         }
212
213         if (xmmsv_get_int(value, &pb_state)) {
214         switch (pb_state) {
215                 case XMMS_PLAYBACK_STATUS_PLAY:
216                         strncpy(ptr->xmms2.status, "Playing", text_buffer_size - 1);
217                         break;
218                 case XMMS_PLAYBACK_STATUS_PAUSE:
219                         strncpy(ptr->xmms2.status, "Paused", text_buffer_size - 1);
220                         break;
221                 case XMMS_PLAYBACK_STATUS_STOP:
222                         strncpy(ptr->xmms2.status, "Stopped", text_buffer_size - 1);
223                         break;
224                 default:
225                         strncpy(ptr->xmms2.status, "Unknown", text_buffer_size - 1);
226         }
227         }
228         return TRUE;
229 }
230
231 int handle_playlist_loaded(xmmsv_t *value, void *p) 
232 {
233         struct information *ptr = p;
234         const char *c, *errbuf;
235
236         if (xmmsv_get_error(value, &errbuf)) {
237                 fprintf(stderr,"XMMS2 server error. %s\n", errbuf);
238                 return TRUE;
239         }
240
241         if (ptr->xmms2.playlist == NULL) {
242                 ptr->xmms2.playlist = malloc(text_buffer_size);
243                 ptr->xmms2.playlist[0] = '\0';
244         }
245
246         if (xmmsv_get_string(value, &c))  {
247                 strncpy(ptr->xmms2.playlist, c, text_buffer_size - 1);
248         }
249         return TRUE;
250 }
251
252 void update_xmms2(void)
253 {
254         struct information *current_info = &info;
255
256         /* initialize connection */
257         if (current_info->xmms2.conn_state == CONN_INIT) {
258
259                 if (xmms2_conn == NULL) {
260                         xmms2_conn = xmmsc_init(PACKAGE);
261                 }
262
263                 /* did init fail? */
264                 if (xmms2_conn == NULL) {
265                         fprintf(stderr,"XMMS2 init failed. %s\n", xmmsc_get_last_error(xmms2_conn));
266                         return;
267                 }
268
269                 /* init ok but not connected yet.. */
270                 current_info->xmms2.conn_state = CONN_NO;
271
272                 /* clear all values */
273                 xmms_alloc(current_info);
274         }
275
276         /* connect */
277         if (current_info->xmms2.conn_state == CONN_NO) {
278
279                 char *path = getenv("XMMS_PATH");
280
281                 if (!xmmsc_connect(xmms2_conn, path)) {
282                         fprintf(stderr,"XMMS2 connection failed. %s\n", xmmsc_get_last_error(xmms2_conn));
283                         current_info->xmms2.conn_state = CONN_NO;
284                         return;
285                 }
286
287                 /* set callbacks */
288                 xmmsc_disconnect_callback_set(xmms2_conn, connection_lost, current_info);
289                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_broadcast_playback_current_id, 
290                                 handle_curent_id, current_info);
291                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_signal_playback_playtime, 
292                                 handle_playtime, current_info);
293                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_broadcast_playback_status, 
294                                 handle_playback_state_change, current_info);
295                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_broadcast_playlist_loaded, 
296                                 handle_playlist_loaded, current_info);
297
298                 /* get playback status, current id and active playlist */
299                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_playback_current_id, 
300                                 handle_curent_id, current_info);
301                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_playback_status, 
302                                 handle_playback_state_change, current_info);
303                 XMMS_CALLBACK_SET(xmms2_conn, xmmsc_playlist_current_active, 
304                                 handle_playlist_loaded, current_info);
305
306                 /* everything seems to be ok */
307                 current_info->xmms2.conn_state = CONN_OK;
308         }
309
310         /* handle callbacks */
311         if (current_info->xmms2.conn_state == CONN_OK) {
312
313                 xmmsc_io_in_handle(xmms2_conn);
314                 if (xmmsc_io_want_out(xmms2_conn))
315                         xmmsc_io_out_handle(xmms2_conn);
316
317                 }
318         }
319
320