1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-11-20 03:51:18 +00:00
conky/src/mpd.c
Phil Sutter 363bed34ac fix temporary printing of "(null)" for mpd vars
To minimise the chance of printing variables in an undefined state, call
free() as late as possible (i.e., right before strdup()'ing the new
value).
2009-03-23 23:46:10 +01:00

304 lines
6.8 KiB
C

/* Conky, a system monitor, based on torsmo
*
* Any original torsmo code is licensed under the BSD license
*
* All code written since the fork of torsmo is licensed under the GPL
*
* Please see COPYING for details
*
* Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al.
* (see AUTHORS)
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "conky.h"
#include "logging.h"
#include "timed_thread.h"
#include "libmpdclient.h"
#include "mpd.h"
/* server connection data */
static char mpd_host[128];
static char mpd_password[128];
static int mpd_port;
/* global mpd information */
static struct mpd_s mpd_info;
/* number of users of the above struct */
static int refcount = 0;
void mpd_set_host(const char *host)
{
snprintf(mpd_host, 128, "%s", host);
}
void mpd_set_password(const char *password)
{
snprintf(mpd_password, 128, "%s", password);
}
void mpd_clear_password(void)
{
*mpd_password = '\0';
}
int mpd_set_port(const char *port)
{
int val;
val = strtol(port, 0, 0);
if (val < 1 || val > 0xffff)
return 1;
mpd_port = val;
return 0;
}
void init_mpd(void)
{
if (!(refcount++)) /* first client */
memset(&mpd_info, 0, sizeof(struct mpd_s));
refcount++;
}
struct mpd_s *mpd_get_info(void)
{
return &mpd_info;
}
static void clear_mpd(void)
{
#define xfree(x) if (x) free(x)
xfree(mpd_info.title);
xfree(mpd_info.artist);
xfree(mpd_info.album);
/* do not free() the const char *status! */
/* do not free() the const char *random! */
/* do not free() the const char *repeat! */
xfree(mpd_info.track);
xfree(mpd_info.name);
xfree(mpd_info.file);
#undef xfree
memset(&mpd_info, 0, sizeof(struct mpd_s));
}
void free_mpd(void)
{
if (!(--refcount)) /* last client */
clear_mpd();
}
static void *update_mpd_thread(void *) __attribute__((noreturn));
void update_mpd(void)
{
int interval;
static timed_thread *thread = NULL;
if (thread)
return;
interval = info.music_player_interval * 1000000;
thread = timed_thread_create(&update_mpd_thread, &thread, interval);
if (!thread) {
ERR("Failed to create MPD timed thread");
return;
}
timed_thread_register(thread, &thread);
if (timed_thread_run(thread))
ERR("Failed to run MPD timed thread");
}
/* stringMAXdup dups at most text_buffer_size bytes */
#define strmdup(x) strndup(x, text_buffer_size - 1)
static void *update_mpd_thread(void *arg)
{
static mpd_Connection *conn = NULL;
mpd_Status *status;
mpd_InfoEntity *entity;
timed_thread *me = *(timed_thread **)arg;
const char *emptystr = "";
while (1) {
if (!conn)
conn = mpd_newConnection(mpd_host, mpd_port, 10);
if (*mpd_password) {
mpd_sendPasswordCommand(conn, mpd_password);
mpd_finishCommand(conn);
}
timed_thread_lock(me);
if (conn->error || conn == NULL) {
ERR("MPD error: %s\n", conn->errorStr);
mpd_closeConnection(conn);
conn = 0;
clear_mpd();
mpd_info.status = "MPD not responding";
timed_thread_unlock(me);
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
mpd_sendStatusCommand(conn);
if ((status = mpd_getStatus(conn)) == NULL) {
ERR("MPD error: %s\n", conn->errorStr);
mpd_closeConnection(conn);
conn = 0;
clear_mpd();
mpd_info.status = "MPD not responding";
timed_thread_unlock(me);
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
mpd_finishCommand(conn);
if (conn->error) {
// fprintf(stderr, "%s\n", conn->errorStr);
mpd_closeConnection(conn);
conn = 0;
timed_thread_unlock(me);
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
mpd_info.volume = status->volume;
/* if (status->error) {
printf("error: %s\n", status->error);
} */
switch(status->state) {
case MPD_STATUS_STATE_PLAY:
mpd_info.status = "Playing";
break;
case MPD_STATUS_STATE_STOP:
mpd_info.status = "Stopped";
break;
case MPD_STATUS_STATE_PAUSE:
mpd_info.status = "Paused";
break;
default:
mpd_info.status = "";
clear_mpd();
break;
}
if (status->state == MPD_STATUS_STATE_PLAY ||
status->state == MPD_STATUS_STATE_PAUSE) {
mpd_info.is_playing = 1;
mpd_info.bitrate = status->bitRate;
mpd_info.progress = (float) status->elapsedTime /
status->totalTime;
mpd_info.elapsed = status->elapsedTime;
mpd_info.length = status->totalTime;
if (status->random == 0) {
mpd_info.random = "Off";
} else if (status->random == 1) {
mpd_info.random = "On";
} else {
mpd_info.random = "";
}
if (status->repeat == 0) {
mpd_info.repeat = "Off";
} else if (status->repeat == 1) {
mpd_info.repeat = "On";
} else {
mpd_info.repeat = "";
}
}
if (conn->error) {
// fprintf(stderr, "%s\n", conn->errorStr);
mpd_closeConnection(conn);
conn = 0;
timed_thread_unlock(me);
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
mpd_sendCurrentSongCommand(conn);
while ((entity = mpd_getNextInfoEntity(conn))) {
mpd_Song *song = entity->info.song;
if (entity->type != MPD_INFO_ENTITY_TYPE_SONG) {
mpd_freeInfoEntity(entity);
continue;
}
#define SONGSET(x) { \
free(mpd_info.x); \
if(song->x) \
mpd_info.x = strmdup(song->x); \
else \
mpd_info.x = strmdup(emptystr); \
}
SONGSET(artist);
SONGSET(album);
SONGSET(title);
SONGSET(track);
SONGSET(name);
SONGSET(file);
#undef SONGSET
if (entity != NULL) {
mpd_freeInfoEntity(entity);
entity = NULL;
}
}
mpd_finishCommand(conn);
if (conn->error) {
// fprintf(stderr, "%s\n", conn->errorStr);
mpd_closeConnection(conn);
conn = 0;
timed_thread_unlock(me);
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
timed_thread_unlock(me);
if (conn->error) {
// fprintf(stderr, "%s\n", conn->errorStr);
mpd_closeConnection(conn);
conn = 0;
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
mpd_freeStatus(status);
/* if (conn) {
mpd_closeConnection(conn);
conn = 0;
} */
if (timed_thread_test(me, 0)) {
timed_thread_exit(me);
}
continue;
}
/* never reached */
}