2008-03-19
[monky] / src / mpd.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-2007 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  * $Id$ */
26
27 #include "conky.h"
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "libmpdclient.h"
32
33 timed_thread *mpd_timed_thread = NULL;
34
35 void clear_mpd_stats(struct information *current_info);
36
37 void init_mpd_stats(struct information *current_info)
38 {
39         if (current_info->mpd.artist == NULL) {
40                 current_info->mpd.artist = malloc(small_text_buffer_size);
41         }
42         if (current_info->mpd.album == NULL) {
43                 current_info->mpd.album = malloc(small_text_buffer_size);
44         }
45         if (current_info->mpd.title == NULL) {
46                 current_info->mpd.title = malloc(small_text_buffer_size);
47         }
48         if (current_info->mpd.random == NULL) {
49                 current_info->mpd.random = malloc(small_text_buffer_size);
50         }
51         if (current_info->mpd.repeat == NULL) {
52                 current_info->mpd.repeat = malloc(small_text_buffer_size);
53         }
54         if (current_info->mpd.track == NULL) {
55                 current_info->mpd.track = malloc(small_text_buffer_size);
56         }
57         if (current_info->mpd.status == NULL) {
58                 current_info->mpd.status = malloc(small_text_buffer_size);
59         }
60         if (current_info->mpd.name == NULL) {
61                 current_info->mpd.name = malloc(small_text_buffer_size);
62         }
63         if (current_info->mpd.file == NULL) {
64                 current_info->mpd.file = malloc(small_text_buffer_size);
65         }
66         clear_mpd_stats(current_info);
67 }
68
69 void free_mpd_vars(struct information *current_info)
70 {
71         if (current_info->mpd.title) {
72                 free(current_info->mpd.title);
73                 current_info->mpd.title = NULL;
74         }
75         if (current_info->mpd.artist) {
76                 free(current_info->mpd.artist);
77                 current_info->mpd.artist = NULL;
78         }
79         if (current_info->mpd.album) {
80                 free(current_info->mpd.album);
81                 current_info->mpd.album = NULL;
82         }
83         if (current_info->mpd.random) {
84                 free(current_info->mpd.random);
85                 current_info->mpd.random = NULL;
86         }
87         if (current_info->mpd.repeat) {
88                 free(current_info->mpd.repeat);
89                 current_info->mpd.repeat = NULL;
90         }
91         if (current_info->mpd.track) {
92                 free(current_info->mpd.track);
93                 current_info->mpd.track = NULL;
94         }
95         if (current_info->mpd.name) {
96                 free(current_info->mpd.name);
97                 current_info->mpd.name = NULL;
98         }
99         if (current_info->mpd.file) {
100                 free(current_info->mpd.file);
101                 current_info->mpd.file = NULL;
102         }
103         if (current_info->mpd.status) {
104                 free(current_info->mpd.status);
105                 current_info->mpd.status = NULL;
106         }
107         if (current_info->conn) {
108                 mpd_closeConnection(current_info->conn);
109                 current_info->conn = 0;
110         }
111 }
112
113 void clear_mpd_stats(struct information *current_info)
114 {
115         *current_info->mpd.name = 0;
116         *current_info->mpd.file = 0;
117         *current_info->mpd.artist = 0;
118         *current_info->mpd.album = 0;
119         *current_info->mpd.title = 0;
120         *current_info->mpd.random = 0;
121         *current_info->mpd.repeat = 0;
122         *current_info->mpd.track = 0;
123         *current_info->mpd.status = 0;
124         current_info->mpd.bitrate = 0;
125         current_info->mpd.progress = 0;
126         current_info->mpd.elapsed = 0;
127         current_info->mpd.length = 0;
128 }
129
130 void *update_mpd(void)
131 {
132         struct information *current_info = &info;
133
134         while (1) {
135                 if (!current_info->conn) {
136                         current_info->conn = mpd_newConnection(current_info->mpd.host,
137                                 current_info->mpd.port, 10);
138                 }
139                 if (strlen(current_info->mpd.password) > 1) {
140                         mpd_sendPasswordCommand(current_info->conn,
141                                 current_info->mpd.password);
142                         mpd_finishCommand(current_info->conn);
143                 }
144
145                 timed_thread_lock(mpd_timed_thread);
146
147                 if (current_info->conn->error || current_info->conn == NULL) {
148                         // ERR("%MPD error: s\n", current_info->conn->errorStr);
149                         mpd_closeConnection(current_info->conn);
150                         current_info->conn = 0;
151                         clear_mpd_stats(current_info);
152
153                         strncpy(current_info->mpd.status, "MPD not responding",
154                                 small_text_buffer_size - 1);
155                         timed_thread_unlock(mpd_timed_thread);
156                         if (timed_thread_test(mpd_timed_thread)) {
157                                 timed_thread_exit(mpd_timed_thread);
158                         }
159                         continue;
160                 }
161
162                 mpd_Status *status;
163                 mpd_InfoEntity *entity;
164
165                 mpd_sendStatusCommand(current_info->conn);
166                 if ((status = mpd_getStatus(current_info->conn)) == NULL) {
167                         // ERR("MPD error: %s\n", current_info->conn->errorStr);
168                         mpd_closeConnection(current_info->conn);
169                         current_info->conn = 0;
170                         clear_mpd_stats(current_info);
171
172                         strncpy(current_info->mpd.status, "MPD not responding",
173                                 small_text_buffer_size - 1);
174                         timed_thread_unlock(mpd_timed_thread);
175                         if (timed_thread_test(mpd_timed_thread)) {
176                                 timed_thread_exit(mpd_timed_thread);
177                         }
178                         continue;
179                 }
180                 mpd_finishCommand(current_info->conn);
181                 if (current_info->conn->error) {
182                         // fprintf(stderr, "%s\n", current_info->conn->errorStr);
183                         mpd_closeConnection(current_info->conn);
184                         current_info->conn = 0;
185                         timed_thread_unlock(mpd_timed_thread);
186                         if (timed_thread_test(mpd_timed_thread)) {
187                                 timed_thread_exit(mpd_timed_thread);
188                         }
189                         continue;
190                 }
191
192                 current_info->mpd.volume = status->volume;
193                 /* if (status->error) {
194                         printf("error: %s\n", status->error);
195                 } */
196
197                 if (status->state == MPD_STATUS_STATE_PLAY) {
198                         strncpy(current_info->mpd.status, "Playing", small_text_buffer_size - 1);
199                 }
200                 if (status->state == MPD_STATUS_STATE_STOP) {
201                         clear_mpd_stats(current_info);
202                         strncpy(current_info->mpd.status, "Stopped", small_text_buffer_size - 1);
203                 }
204                 if (status->state == MPD_STATUS_STATE_PAUSE) {
205                         strncpy(current_info->mpd.status, "Paused", small_text_buffer_size - 1);
206                 }
207                 if (status->state == MPD_STATUS_STATE_UNKNOWN) {
208                         clear_mpd_stats(current_info);
209                         *current_info->mpd.status = 0;
210                 }
211                 if (status->state == MPD_STATUS_STATE_PLAY
212                                 || status->state == MPD_STATUS_STATE_PAUSE) {
213                         current_info->mpd.bitrate = status->bitRate;
214                         current_info->mpd.progress = (float) status->elapsedTime /
215                                 status->totalTime;
216                         current_info->mpd.elapsed = status->elapsedTime;
217                         current_info->mpd.length = status->totalTime;
218                         if (status->random == 0) {
219                                 strcpy(current_info->mpd.random, "Off");
220                         } else if (status->random == 1) {
221                                 strcpy(current_info->mpd.random, "On");
222                         } else {
223                                 *current_info->mpd.random = 0;
224                         }
225                         if (status->repeat == 0) {
226                                 strcpy(current_info->mpd.repeat, "Off");
227                         } else if (status->repeat == 1) {
228                                 strcpy(current_info->mpd.repeat, "On");
229                         } else {
230                                 *current_info->mpd.repeat = 0;
231                         }
232                 }
233
234                 if (current_info->conn->error) {
235                         // fprintf(stderr, "%s\n", current_info->conn->errorStr);
236                         mpd_closeConnection(current_info->conn);
237                         current_info->conn = 0;
238                         timed_thread_unlock(mpd_timed_thread);
239                         if (timed_thread_test(mpd_timed_thread)) {
240                                 timed_thread_exit(mpd_timed_thread);
241                         }
242                         continue;
243                 }
244
245                 mpd_sendCurrentSongCommand(current_info->conn);
246                 while ((entity = mpd_getNextInfoEntity(current_info->conn))) {
247                         mpd_Song *song = entity->info.song;
248
249                         if (entity->type != MPD_INFO_ENTITY_TYPE_SONG) {
250                                 mpd_freeInfoEntity(entity);
251                                 continue;
252                         }
253
254                         if (song->artist) {
255                                 strncpy(current_info->mpd.artist, song->artist,
256                                         small_text_buffer_size - 1);
257                         } else {
258                                 *current_info->mpd.artist = 0;
259                         }
260                         if (song->album) {
261                                 strncpy(current_info->mpd.album, song->album,
262                                         small_text_buffer_size - 1);
263                         } else {
264                                 *current_info->mpd.album = 0;
265                         }
266                         if (song->title) {
267                                 strncpy(current_info->mpd.title, song->title,
268                                         small_text_buffer_size - 1);
269                         } else {
270                                 *current_info->mpd.title = 0;
271                         }
272                         if (song->track) {
273                                 strncpy(current_info->mpd.track, song->track,
274                                         small_text_buffer_size - 1);
275                         } else {
276                                 *current_info->mpd.track = 0;
277                         }
278                         if (song->name) {
279                                 strncpy(current_info->mpd.name, song->name,
280                                         small_text_buffer_size - 1);
281                         } else {
282                                 *current_info->mpd.name = 0;
283                         }
284                         if (song->file) {
285                                 strncpy(current_info->mpd.file, song->file,
286                                         small_text_buffer_size - 1);
287                         } else {
288                                 *current_info->mpd.file = 0;
289                         }
290                         if (entity != NULL) {
291                                 mpd_freeInfoEntity(entity);
292                                 entity = NULL;
293                         }
294                 }
295                 if (entity != NULL) {
296                         mpd_freeInfoEntity(entity);
297                         entity = NULL;
298                 }
299                 mpd_finishCommand(current_info->conn);
300                 if (current_info->conn->error) {
301                         // fprintf(stderr, "%s\n", current_info->conn->errorStr);
302                         mpd_closeConnection(current_info->conn);
303                         current_info->conn = 0;
304                         timed_thread_unlock(mpd_timed_thread);
305                         if (timed_thread_test(mpd_timed_thread)) {
306                                 timed_thread_exit(mpd_timed_thread);
307                         }
308                         continue;
309                 }
310
311                 timed_thread_unlock(mpd_timed_thread);
312                 if (current_info->conn->error) {
313                         // fprintf(stderr, "%s\n", current_info->conn->errorStr);
314                         mpd_closeConnection(current_info->conn);
315                         current_info->conn = 0;
316                         if (timed_thread_test(mpd_timed_thread)) {
317                                 timed_thread_exit(mpd_timed_thread);
318                         }
319                         continue;
320                 }
321
322                 mpd_freeStatus(status);
323                 /* if (current_info->conn) {
324                         mpd_closeConnection(current_info->conn);
325                         current_info->conn = 0;
326                 } */
327                 if (timed_thread_test(mpd_timed_thread)) {
328                         timed_thread_exit(mpd_timed_thread);
329                 }
330                 continue;
331         }
332         return 0;
333 }