* _Really_ fix mpd SIGPIPE issues
[monky] / src / mpd.c
1 /*
2  * Conky, a system monitor, based on torsmo
3  *
4  * Any original torsmo code is licensed under the BSD license
5  *
6  * All code written since the fork of torsmo is licensed under the GPL
7  *
8  * Please see COPYING for details
9  *
10  * Copyright (c) 2005-2007 Brenden Matthews, Philip Kovacs, et. al. (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
28 #include "conky.h"
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include "libmpdclient.h"
33
34 timed_thread *mpd_timed_thread = NULL;
35
36 void clear_mpd_stats(struct information *current_info)
37 {
38         if (current_info->mpd.artist == NULL)
39                 current_info->mpd.artist = malloc(TEXT_BUFFER_SIZE);
40         if (current_info->mpd.album == NULL)
41                 current_info->mpd.album = malloc(TEXT_BUFFER_SIZE);
42         if (current_info->mpd.title == NULL)
43                 current_info->mpd.title = malloc(TEXT_BUFFER_SIZE);
44         if (current_info->mpd.random == NULL)
45                 current_info->mpd.random = malloc(TEXT_BUFFER_SIZE);
46         if (current_info->mpd.repeat == NULL)
47                 current_info->mpd.repeat = malloc(TEXT_BUFFER_SIZE);
48         if (current_info->mpd.track == NULL)
49                 current_info->mpd.track = malloc(TEXT_BUFFER_SIZE);
50         if (current_info->mpd.status == NULL)
51                 current_info->mpd.status = malloc(TEXT_BUFFER_SIZE);
52         if (current_info->mpd.name == NULL)
53                 current_info->mpd.name = malloc(TEXT_BUFFER_SIZE);
54         if (current_info->mpd.file == NULL)
55                 current_info->mpd.file = malloc(TEXT_BUFFER_SIZE);
56
57         *current_info->mpd.name=0;
58         *current_info->mpd.file=0;
59         *current_info->mpd.artist=0;
60         *current_info->mpd.album=0;
61         *current_info->mpd.title=0;
62         *current_info->mpd.random=0;
63         *current_info->mpd.repeat=0;
64         *current_info->mpd.track=0;
65         *current_info->mpd.status=0;
66         current_info->mpd.bitrate = 0;
67         current_info->mpd.progress = 0;
68         current_info->mpd.elapsed = 0;
69         current_info->mpd.length = 0;
70 }
71
72 void *update_mpd(void)
73 {
74         struct information *current_info = &info;
75         while (1) {
76                 if (!current_info->conn) {
77                         current_info->conn = mpd_newConnection(current_info->mpd.host, current_info->mpd.port, 10);
78                 }
79                 if (strlen(current_info->mpd.password) > 1) {
80                         mpd_sendPasswordCommand(current_info->conn,
81                                         current_info->mpd.password);
82                         mpd_finishCommand(current_info->conn);
83                 }
84
85                 if (current_info->conn->error || current_info->conn == NULL) {
86                         //ERR("%MPD error: s\n", current_info->conn->errorStr);
87                         mpd_closeConnection(current_info->conn);
88                         current_info->conn = 0;
89
90                         strncpy(current_info->mpd.status, "MPD not responding", TEXT_BUFFER_SIZE - 1);
91                         if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
92                         continue;
93                 }
94
95                 timed_thread_lock(mpd_timed_thread);
96                 mpd_Status *status;
97                 mpd_InfoEntity *entity;
98                 mpd_sendStatusCommand(current_info->conn);
99                 if ((status = mpd_getStatus(current_info->conn)) == NULL) {
100                         //ERR("MPD error: %s\n", current_info->conn->errorStr);
101                         mpd_closeConnection(current_info->conn);
102                         current_info->conn = 0;
103
104                         strncpy(current_info->mpd.status, "MPD not responding", TEXT_BUFFER_SIZE - 1);
105                         timed_thread_unlock(mpd_timed_thread);
106                         if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
107                         continue;
108                 }
109                 mpd_finishCommand(current_info->conn);
110                 if (current_info->conn->error) {
111                         //fprintf(stderr, "%s\n", current_info->conn->errorStr);
112                         mpd_closeConnection(current_info->conn);
113                         current_info->conn = 0;
114                         if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
115                         continue;
116                 }
117
118                 current_info->mpd.volume = status->volume;
119                 //if (status->error)
120                 //printf("error: %s\n", status->error);
121
122                 if (status->state == MPD_STATUS_STATE_PLAY) {
123                         strncpy(current_info->mpd.status, "Playing",
124                                         TEXT_BUFFER_SIZE - 1);
125                 }
126                 if (status->state == MPD_STATUS_STATE_STOP) {
127                         strncpy(current_info->mpd.status, "Stopped",
128                                         TEXT_BUFFER_SIZE - 1);
129                 }
130                 if (status->state == MPD_STATUS_STATE_PAUSE) {
131                         strncpy(current_info->mpd.status, "Paused",
132                                         TEXT_BUFFER_SIZE - 1);
133                 }
134                 if (status->state == MPD_STATUS_STATE_UNKNOWN) {
135                         // current_info was already cleaned up by clear_mpd_stats()
136                 }
137                 if (status->state == MPD_STATUS_STATE_PLAY ||
138                                 status->state == MPD_STATUS_STATE_PAUSE) {
139                         current_info->mpd.bitrate = status->bitRate;
140                         current_info->mpd.progress =
141                                 (float) status->elapsedTime / status->totalTime;
142                         current_info->mpd.elapsed = status->elapsedTime;
143                         current_info->mpd.length = status->totalTime;
144                         if (status->random == 0) {
145                                 strcpy(current_info->mpd.random, "Off");
146                         } else if (status->random == 1) {
147                                 strcpy(current_info->mpd.random, "On");
148                         } else {
149                                 *current_info->mpd.random=0;
150                         }
151                         if (status->repeat == 0) {
152                                 strcpy(current_info->mpd.repeat, "Off");
153                         } else if (status->repeat == 1) {
154                                 strcpy(current_info->mpd.repeat, "On");
155                         } else {
156                                 *current_info->mpd.repeat=0;
157                         }
158                 }
159
160                 if (current_info->conn->error) {
161                         //fprintf(stderr, "%s\n", current_info->conn->errorStr);
162                         mpd_closeConnection(current_info->conn);
163                         current_info->conn = 0;
164                         timed_thread_unlock(mpd_timed_thread);
165                         if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
166                         continue;
167                 }
168
169                 mpd_sendCurrentSongCommand(current_info->conn);
170                 while ((entity = mpd_getNextInfoEntity(current_info->conn))) {
171                         mpd_Song *song = entity->info.song;
172                         if (entity->type != MPD_INFO_ENTITY_TYPE_SONG) {
173                                 mpd_freeInfoEntity(entity);
174                                 continue;
175                         }
176
177                         if (song->artist) {
178                                 strncpy(current_info->mpd.artist, song->artist,
179                                                 TEXT_BUFFER_SIZE - 1);
180                         } else {
181                                 *current_info->mpd.artist=0;
182                         }
183                         if (song->album) {
184                                 strncpy(current_info->mpd.album, song->album,
185                                                 TEXT_BUFFER_SIZE - 1);
186                         } else {
187                                 *current_info->mpd.album=0;
188                         }
189                         if (song->title) {
190                                 strncpy(current_info->mpd.title, song->title,
191                                                 TEXT_BUFFER_SIZE - 1);
192                         } else {
193                                 *current_info->mpd.title=0;
194                         }
195                         if (song->track) {
196                                 strncpy(current_info->mpd.track, song->track,
197                                                 TEXT_BUFFER_SIZE - 1);
198                         } else {
199                                 *current_info->mpd.track=0;
200                         }
201                         if (song->name) {
202                                 strncpy(current_info->mpd.name, song->name,
203                                                 TEXT_BUFFER_SIZE - 1);
204                         } else {
205                                 *current_info->mpd.name=0;
206                         }
207                         if (song->file) {
208                                 strncpy(current_info->mpd.file,
209                                                 song->file, TEXT_BUFFER_SIZE - 1);
210                         } else {
211                                 *current_info->mpd.file=0;
212                         }
213                         if (entity != NULL) {
214                                 mpd_freeInfoEntity(entity);
215                                 entity = NULL;
216                         }
217                 }
218                 if (entity != NULL) {
219                         mpd_freeInfoEntity(entity);
220                         entity = NULL;
221                 }
222                 mpd_finishCommand(current_info->conn);
223                 if (current_info->conn->error) {
224                         //fprintf(stderr, "%s\n", current_info->conn->errorStr);
225                         mpd_closeConnection(current_info->conn);
226                         current_info->conn = 0;
227                         if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
228                         continue;
229                 }
230
231                 timed_thread_unlock(mpd_timed_thread);
232                 if (current_info->conn->error) {
233                         //fprintf(stderr, "%s\n", current_info->conn->errorStr);
234                         mpd_closeConnection(current_info->conn);
235                         current_info->conn = 0;
236                         if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
237                         continue;
238                 }
239
240                 mpd_freeStatus(status);
241 /*              if (current_info->conn) {
242                         mpd_closeConnection(current_info->conn);
243                         current_info->conn = 0;
244                 }*/
245                 if (timed_thread_test(mpd_timed_thread)) timed_thread_exit(mpd_timed_thread);
246                 continue;
247         }
248         return 0;
249 }