Somebody claiming to be Max Kellermann wrote:
> On 2009/04/07 01:39, Stephen Paul Weber <singpol...@singpolyma.net> wrote:
> > Yes, this is exactly the functionality I had in mind :)
> 
> Be sure that old configuration files continue to work.

Attached please find 5 patch files, each the output of a git show for 5
commits that progressively implement this feature :)

-- 
Stephen Paul Weber, @singpolyma
Please see <http://singpolyma.net> for how I prefer to be contacted.
nerve perfume pogo.
commit 4134470abcc4d23e6c971056826036461882c4eb
Author: Stephen Paul Weber <singpol...@singpolyma.net>
Date:   Tue Apr 7 10:52:34 2009 -0400

    Don't assume last.fm AS_HOST + config parsing
    
    In fact, don't assume global state for username/password either.
    A lot of changes to as.c, conn.c, conn.h just to allow a pointer to a struct
    containing the state instead of assuming global.
    
    This patch still just uses the first as_host from the list.
    
    file.h and file.c have been modified to actually parse the new config
    file format and create a linked list of as_hosts.
    
    There is a memory leak in the config parser: the linked list is not freed.
    Since we need it all in memory until shutting down, this is likely not a problem,
    but a comment reminder has been added.

diff --git a/src/as.c b/src/as.c
index 545189c..c2fe75d 100644
--- a/src/as.c
+++ b/src/as.c
@@ -45,8 +45,6 @@
 #define MAX_VAR_SIZE 8192
 #define MAX_TIMESTAMP_SIZE 64
 
-#define AS_HOST "http://post.audioscrobbler.com/";
-
 /* don't submit more than this amount of songs in a batch. */
 #define MAX_SUBMIT_COUNT 10
 
@@ -128,13 +126,13 @@ add_var_i(GString * s, const char *key, signed char idx, const char *val)
 }
 
 static void
-as_schedule_handshake(void);
+as_schedule_handshake(struct config_as_host *as_host);
 
 static void
-as_submit(void);
+as_submit(struct config_as_host *as_host);
 
 static void
-as_schedule_submit(void);
+as_schedule_submit(struct config_as_host *as_host);
 
 static void as_increase_interval(void)
 {
@@ -217,7 +215,7 @@ static void as_song_cleanup(struct song *s, int free_struct)
 		free(s);
 }
 
-static void as_handshake_callback(size_t length, const char *response)
+static void as_handshake_callback(size_t length, const char *response, void *as_host)
 {
 	as_handshaking state = AS_COMMAND;
 	char *newline;
@@ -230,7 +228,7 @@ static void as_handshake_callback(size_t length, const char *response)
 	if (!length) {
 		g_warning("handshake timed out\n");
 		as_increase_interval();
-		as_schedule_handshake();
+		as_schedule_handshake(as_host);
 		return;
 	}
 
@@ -242,7 +240,7 @@ static void as_handshake_callback(size_t length, const char *response)
 			if (!ret) {
 				g_free(next);
 				as_increase_interval();
-				as_schedule_handshake();
+				as_schedule_handshake(as_host);
 				return;
 			}
 
@@ -268,7 +266,7 @@ static void as_handshake_callback(size_t length, const char *response)
 
 			/* handshake was successful: see if we have
 			   songs to submit */
-			as_submit();
+			as_submit(as_host);
 			return;
 		}
 
@@ -279,7 +277,7 @@ static void as_handshake_callback(size_t length, const char *response)
 	}
 
 	as_increase_interval();
-	as_schedule_handshake();
+	as_schedule_handshake(as_host);
 }
 
 static void as_queue_remove_oldest(unsigned count)
@@ -292,7 +290,7 @@ static void as_queue_remove_oldest(unsigned count)
 	}
 }
 
-static void as_submit_callback(size_t length, const char *response)
+static void as_submit_callback(size_t length, const char *response, void *as_host)
 {
 	char *newline;
 
@@ -303,7 +301,7 @@ static void as_submit_callback(size_t length, const char *response)
 		g_submit_pending = 0;
 		g_warning("submit timed out\n");
 		as_increase_interval();
-		as_schedule_submit();
+		as_schedule_submit(as_host);
 		return;
 	}
 
@@ -329,15 +327,15 @@ static void as_submit_callback(size_t length, const char *response)
 
 
 		/* submit the next chunk (if there is some left) */
-		as_submit();
+		as_submit(as_host);
 		break;
 	case AS_SUBMIT_FAILED:
 		as_increase_interval();
-		as_schedule_submit();
+		as_schedule_submit(as_host);
 		break;
 	case AS_SUBMIT_HANDSHAKE:
 		g_state = AS_NOTHING;
-		as_schedule_handshake();
+		as_schedule_handshake(as_host);
 		break;
 	}
 }
@@ -403,7 +401,7 @@ static char *as_md5(const char *password, const char *timestamp)
 	return result;
 }
 
-static void as_handshake(void)
+static void as_handshake(struct config_as_host *as_host)
 {
 	GString *url;
 	char *timestr, *md5;
@@ -411,15 +409,15 @@ static void as_handshake(void)
 	g_state = AS_HANDSHAKING;
 
 	timestr = as_timestamp();
-	md5 = as_md5(file_config.password, timestr);
+	md5 = as_md5(as_host->password, timestr);
 
 	/* construct the handshake url. */
-	url = g_string_new(AS_HOST);
+	url = g_string_new(as_host->url);
 	first_var(url, "hs", "true");
 	add_var(url, "p", "1.2");
 	add_var(url, "c", AS_CLIENT_ID);
 	add_var(url, "v", AS_CLIENT_VERSION);
-	add_var(url, "u", file_config.username);
+	add_var(url, "u", as_host->username);
 	add_var(url, "t", timestr);
 	add_var(url, "a", md5);
 
@@ -428,42 +426,42 @@ static void as_handshake(void)
 
 	//  notice ("handshake url:\n%s", url);
 
-	if (!conn_initiate(url->str, &as_handshake_callback, NULL)) {
+	if (!conn_initiate(url->str, &as_handshake_callback, NULL, as_host)) {
 		g_warning("something went wrong when trying to connect, "
 			  "probably a bug\n");
 
 		g_state = AS_NOTHING;
 		as_increase_interval();
-		as_schedule_handshake();
+		as_schedule_handshake(as_host);
 	}
 
 	g_string_free(url, true);
 }
 
 static gboolean
-as_handshake_timer(G_GNUC_UNUSED gpointer data)
+as_handshake_timer(gpointer data)
 {
 	assert(g_state == AS_NOTHING);
 
 	as_handshake_id = 0;
 
-	as_handshake();
+	as_handshake(data);
 	return false;
 }
 
 static void
-as_schedule_handshake(void)
+as_schedule_handshake(struct config_as_host *as_host)
 {
 	assert(g_state == AS_NOTHING);
 	assert(as_handshake_id == 0);
 
 	as_handshake_id = g_timeout_add_seconds(g_interval,
-						as_handshake_timer, NULL);
+						as_handshake_timer, as_host);
 }
 
 static void
 as_send_now_playing(const char *artist, const char *track,
-		    const char *album, const char *mbid, const int length)
+		    const char *album, const char *mbid, const int length, struct config_as_host *as_host)
 {
 	GString *post_data;
 	char len[MAX_VAR_SIZE];
@@ -487,12 +485,12 @@ as_send_now_playing(const char *artist, const char *track,
 	g_message("sending 'now playing' notification\n");
 
 	if (!conn_initiate(g_nowplay_url, as_submit_callback,
-			   post_data->str)) {
+			   post_data->str, as_host)) {
 		g_warning("failed to POST to %s\n", g_nowplay_url);
 
 		g_state = AS_READY;
 		as_increase_interval();
-		as_schedule_submit();
+		as_schedule_submit(as_host);
 	}
 
 	g_string_free(post_data, true);
@@ -511,10 +509,10 @@ as_now_playing(const char *artist, const char *track,
 	g_now_playing.length = length;
 
 	if (g_state == AS_READY && as_submit_id == 0)
-		as_schedule_submit();
+		as_schedule_submit(&file_config.as_hosts); /* TODO: actually iterate over all hosts */
 }
 
-static void as_submit(void)
+static void as_submit(struct config_as_host *as_host)
 {
 	//MAX_SUBMIT_COUNT
 	unsigned count = 0;
@@ -532,7 +530,8 @@ static void as_submit(void)
 					    g_now_playing.track,
 					    g_now_playing.album,
 					    g_now_playing.mbid,
-					    g_now_playing.length);
+					    g_now_playing.length,
+					    as_host);
 		}
 
 		return;
@@ -570,13 +569,13 @@ static void as_submit(void)
 
 	g_submit_pending = count;
 	if (!conn_initiate(g_submit_url, &as_submit_callback,
-			   post_data->str)) {
+			   post_data->str, as_host)) {
 		g_warning("something went wrong when trying to connect,"
 			  " probably a bug\n");
 
 		g_state = AS_READY;
 		as_increase_interval();
-		as_schedule_submit();
+		as_schedule_submit(as_host);
 	}
 
 	g_string_free(post_data, true);
@@ -624,7 +623,7 @@ as_songchange(const char *file, const char *artist, const char *track,
 	g_queue_push_tail(queue, current);
 
 	if (g_state == AS_READY && as_submit_id == 0)
-		as_schedule_submit();
+		as_schedule_submit(&file_config.as_hosts); /* TODO: actually iterate over all hosts */
 
 	return g_queue_get_length(queue);
 }
@@ -646,29 +645,29 @@ void as_init(void)
 
 	conn_setup();
 
-	as_schedule_handshake();
+	as_schedule_handshake(&file_config.as_hosts); /* TODO: actually handshake all the hosts */
 }
 
 static gboolean
-as_submit_timer(G_GNUC_UNUSED gpointer data)
+as_submit_timer(gpointer data)
 {
 	assert(g_state == AS_READY);
 
 	as_submit_id = 0;
 
-	as_submit();
+	as_submit(data);
 	return false;
 }
 
 static void
-as_schedule_submit(void)
+as_schedule_submit(struct config_as_host *as_host)
 {
 	assert(as_submit_id == 0);
 	assert(!g_queue_is_empty(queue) ||
 	       (g_now_playing.artist != NULL && g_now_playing.track != NULL));
 
 	as_submit_id = g_timeout_add_seconds(g_interval,
-					     as_submit_timer, NULL);
+					     as_submit_timer, as_host);
 }
 
 void as_save_cache(void)
diff --git a/src/conn.c b/src/conn.c
index c8510e4..e87a998 100644
--- a/src/conn.c
+++ b/src/conn.c
@@ -48,9 +48,9 @@ static struct global g;
 static void
 #ifdef HAVE_SOUP_24
 conn_callback(G_GNUC_UNUSED SoupSession * session,
-	      SoupMessage * msg, G_GNUC_UNUSED gpointer data)
+	      SoupMessage * msg, gpointer data)
 #else
-conn_callback(SoupMessage * msg, G_GNUC_UNUSED gpointer data)
+conn_callback(SoupMessage * msg, gpointer data)
 #endif
 {
 	assert(g.pending);
@@ -60,12 +60,12 @@ conn_callback(SoupMessage * msg, G_GNUC_UNUSED gpointer data)
 	if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
 #ifdef HAVE_SOUP_24
 		g.callback(msg->response_body->length,
-			   msg->response_body->data);
+			   msg->response_body->data, data);
 #else
-		g.callback(msg->response.length, msg->response.body);
+		g.callback(msg->response.length, msg->response.body, data);
 #endif
 	} else
-		g.callback(0, NULL);
+		g.callback(0, NULL, NULL);
 }
 
 void conn_setup(void)
@@ -81,7 +81,7 @@ void conn_setup(void)
 }
 
 int
-conn_initiate(char *url, callback_t * callback, char *post_data)
+conn_initiate(char *url, callback_t * callback, char *post_data, void *data)
 {
 	SoupMessage *msg;
 
@@ -125,7 +125,7 @@ conn_initiate(char *url, callback_t * callback, char *post_data)
 	soup_message_set_flags(msg, SOUP_MESSAGE_NO_REDIRECT);
 
 	g.pending = true;
-	soup_session_queue_message(g.session, msg, conn_callback, NULL);
+	soup_session_queue_message(g.session, msg, conn_callback, data);
 
 	return CONN_OK;
 }
diff --git a/src/conn.h b/src/conn.h
index ffea739..918e925 100644
--- a/src/conn.h
+++ b/src/conn.h
@@ -24,7 +24,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 
-typedef void callback_t(size_t, const char *);
+typedef void callback_t(size_t, const char *, void *);
 
 #define CONN_FAIL 0
 #define CONN_OK 1
@@ -35,7 +35,7 @@ typedef void callback_t(size_t, const char *);
 void conn_setup(void);
 void conn_cleanup(void);
 
-int conn_initiate(char *url, callback_t * callback, char *post_data);
+int conn_initiate(char *url, callback_t * callback, char *post_data, void *data);
 bool conn_pending(void);
 
 #endif /* CONN_H */
diff --git a/src/file.c b/src/file.c
index a2b0434..c6c3575 100644
--- a/src/file.c
+++ b/src/file.c
@@ -49,6 +49,8 @@
 #define FILE_DEFAULT_PORT 6600
 #define FILE_DEFAULT_HOST "localhost"
 
+#define AS_HOST "http://post.audioscrobbler.com/";
+
 struct config file_config = {
 	.loc = file_unknown,
 };
@@ -193,9 +195,17 @@ load_config_file(const char *path)
 {
 	bool ret;
 	char *data1, *data2;
+	char **groups;
+	struct config_as_host *current_host = &file_config.as_hosts;
+	int i = -1;
 	GKeyFile *file;
 	GError *error = NULL;
 
+	/* initialize host, in case there are none */
+	current_host->url = NULL;
+	current_host->username = NULL;
+	current_host->password = NULL;
+
 	ret = g_file_get_contents(path, &data1, NULL, &error);
 	if (!ret)
 		g_error("%s\n", error->message);
@@ -216,8 +226,6 @@ load_config_file(const char *path)
 
 	load_string(file, "pidfile", &file_config.pidfile);
 	load_string(file, "daemon_user", &file_config.daemon_user);
-	load_string(file, "username", &file_config.username);
-	load_string(file, "password", &file_config.password);
 	load_string(file, "log", &file_config.log);
 	load_string(file, "cache", &file_config.cache);
 	load_string(file, "host", &file_config.host);
@@ -228,6 +236,37 @@ load_config_file(const char *path)
 		     &file_config.cache_interval);
 	load_integer(file, "verbose", &file_config.verbose);
 
+	groups = g_key_file_get_groups(file, NULL);
+	while(groups[++i]) {
+		/* Use default host for mpdscribble group, for backward compatability */
+		if(strcmp(groups[i], "mpdscribble") == 0) {
+			current_host->url = strdup(AS_HOST);
+		} else {
+			current_host->url = strdup(groups[i]);
+		}
+
+		current_host->username = g_key_file_get_string(file, groups[i], "username", &error);
+		if (error != NULL)
+			g_error("%s\n", error->message);
+		if(current_host->username)
+			current_host->username = strdup(current_host->username);
+
+		current_host->password = g_key_file_get_string(file, groups[i], "password", &error);
+		if (error != NULL)
+			g_error("%s\n", error->message);
+		if(current_host->password)
+			current_host->password = strdup(current_host->password);
+
+		/* Only allocate a next element if there are more groups */
+		if(groups[i+1]) {
+			current_host->next = malloc(sizeof *current_host->next);
+			current_host = current_host->next;
+		} else {
+			current_host->next = NULL;
+		}
+	}
+	g_strfreev(groups);
+
 	g_key_file_free(file);
 }
 
@@ -257,11 +296,11 @@ int file_read_config(int argc, char **argv)
 	if (!file_config.conf)
 		g_error("cannot find configuration file\n");
 
-	if (file_config.username == NULL || *file_config.username == 0)
+	if (file_config.as_hosts.username == NULL || *file_config.as_hosts.username == 0)
 		g_error("no audioscrobbler username specified in %s\n",
 			file_config.conf);
 
-	if (file_config.password == NULL || *file_config.password == 0)
+	if (file_config.as_hosts.password == NULL || *file_config.as_hosts.password == 0)
 		g_error("no audioscrobbler password specified in %s\n",
 		      file_config.conf);
 
@@ -291,10 +330,9 @@ int file_read_config(int argc, char **argv)
 
 void file_cleanup(void)
 {
-	g_free(file_config.username);
-	g_free(file_config.password);
 	g_free(file_config.host);
 	g_free(file_config.log);
 	g_free(file_config.conf);
 	g_free(file_config.cache);
+	/* XXX: Free linked list */
 }
diff --git a/src/file.h b/src/file.h
index c750c43..25df572 100644
--- a/src/file.h
+++ b/src/file.h
@@ -24,6 +24,13 @@
 
 enum file_location { file_etc, file_home, file_unknown, };
 
+struct config_as_host {
+	char *url;
+	char *username;
+	char *password;
+	struct config_as_host *next; /* Linked list if more than one */
+};
+
 struct config {
 	/** don't daemonize the mpdscribble process */
 	gboolean no_daemon;
@@ -32,8 +39,6 @@ struct config {
 
 	char *daemon_user;
 
-	char *username;
-	char *password;
 	char *log;
 	char *cache;
 	char *conf;
@@ -44,6 +49,8 @@ struct config {
 	int cache_interval;
 	int verbose;
 	enum file_location loc;
+
+	struct config_as_host as_hosts;
 };
 
 extern struct config file_config;
commit d41bd4d4d8b71eb139e892ec3661985f28a62cdf
Author: Stephen Paul Weber <singpol...@singpolyma.net>
Date:   Tue Apr 7 11:19:57 2009 -0400

    Global state now in struct.
    
    All global state crap is now passed around in the as_host struct.

diff --git a/src/as.c b/src/as.c
index c2fe75d..036e274 100644
--- a/src/as.c
+++ b/src/as.c
@@ -53,14 +53,6 @@ static const char BADSESSION[] = "BADSESSION";
 static const char FAILED[] = "FAILED";
 
 typedef enum {
-	AS_NOTHING,
-	AS_HANDSHAKING,
-	AS_READY,
-	AS_SUBMITTING,
-	AS_BADAUTH,
-} as_state;
-
-typedef enum {
 	AS_COMMAND,
 	AS_SESSION,
 	AS_NOWPLAY,
@@ -73,19 +65,11 @@ typedef enum {
 	AS_SUBMIT_HANDSHAKE,
 } as_submitting;
 
-static char *g_session = NULL;
-static char *g_nowplay_url = NULL;
-static char *g_submit_url = NULL;
-static char *g_md5_response = NULL;
-static int g_interval = 1;
-static as_state g_state = AS_NOTHING;
 
 static struct song g_now_playing;
 static GQueue *queue;
 static unsigned g_submit_pending;
 
-static guint as_handshake_id, as_submit_id;
-
 static void
 add_var_internal(GString * s, char sep, const char *key,
 		 signed char idx, const char *val)
@@ -134,17 +118,17 @@ as_submit(struct config_as_host *as_host);
 static void
 as_schedule_submit(struct config_as_host *as_host);
 
-static void as_increase_interval(void)
+static void as_increase_interval(struct config_as_host *as_host)
 {
-	if (g_interval < 60)
-		g_interval = 60;
+	if (as_host->g_interval < 60)
+		as_host->g_interval = 60;
 	else
-		g_interval <<= 1;
+		as_host->g_interval <<= 1;
 
-	if (g_interval > 60 * 60 * 2)
-		g_interval = 60 * 60 * 2;
+	if (as_host->g_interval > 60 * 60 * 2)
+		as_host->g_interval = 60 * 60 * 2;
 
-	g_warning("waiting %i seconds before trying again\n", g_interval);
+	g_warning("waiting %i seconds before trying again\n", as_host->g_interval);
 }
 
 static int as_parse_submit_response(const char *line, size_t length)
@@ -173,7 +157,7 @@ static int as_parse_submit_response(const char *line, size_t length)
 }
 
 static bool
-as_parse_handshake_response(const char *line)
+as_parse_handshake_response(const char *line, struct config_as_host *as_host)
 {
 	static const char *BANNED = "BANNED";
 	static const char *BADAUTH = "BADAUTH";
@@ -186,15 +170,15 @@ as_parse_handshake_response(const char *line)
 		return true;
 	} else if (!strncmp(line, BANNED, strlen(BANNED))) {
 		g_warning("handshake failed, we're banned (%s)\n", line);
-		g_state = AS_BADAUTH;
+		as_host->g_state = AS_BADAUTH;
 	} else if (!strncmp(line, BADAUTH, strlen(BADAUTH))) {
 		g_warning("handshake failed, username or password incorrect (%s)\n",
 			  line);
-		g_state = AS_BADAUTH;
+		as_host->g_state = AS_BADAUTH;
 	} else if (!strncmp(line, BADTIME, strlen(BADTIME))) {
 		g_warning("handshake failed, clock not synchronized (%s)\n",
 			  line);
-		g_state = AS_BADAUTH;
+		as_host->g_state = AS_BADAUTH;
 	} else if (!strncmp(line, FAILED, strlen(FAILED))) {
 		g_warning("handshake failed (%s)\n", line);
 	} else {
@@ -215,19 +199,20 @@ static void as_song_cleanup(struct song *s, int free_struct)
 		free(s);
 }
 
-static void as_handshake_callback(size_t length, const char *response, void *as_host)
+static void as_handshake_callback(size_t length, const char *response, void *data)
 {
 	as_handshaking state = AS_COMMAND;
 	char *newline;
 	char *next;
 	bool ret;
+	struct config_as_host *as_host = data;
 
-	assert(g_state == AS_HANDSHAKING);
-	g_state = AS_NOTHING;
+	assert(as_host->g_state == AS_HANDSHAKING);
+	as_host->g_state = AS_NOTHING;
 
 	if (!length) {
 		g_warning("handshake timed out\n");
-		as_increase_interval();
+		as_increase_interval(data);
 		as_schedule_handshake(as_host);
 		return;
 	}
@@ -236,10 +221,10 @@ static void as_handshake_callback(size_t length, const char *response, void *as_
 		next = g_strndup(response, newline - response);
 		switch (state) {
 		case AS_COMMAND:
-			ret = as_parse_handshake_response(next);
+			ret = as_parse_handshake_response(next, as_host);
 			if (!ret) {
 				g_free(next);
-				as_increase_interval();
+				as_increase_interval(data);
 				as_schedule_handshake(as_host);
 				return;
 			}
@@ -247,22 +232,22 @@ static void as_handshake_callback(size_t length, const char *response, void *as_
 			state = AS_SESSION;
 			break;
 		case AS_SESSION:
-			g_session = next;
+			as_host->g_session = next;
 			next = NULL;
-			g_debug("session: %s\n", g_session);
+			g_debug("session: %s\n", as_host->g_session);
 			state = AS_NOWPLAY;
 			break;
 		case AS_NOWPLAY:
-			g_nowplay_url = next;
+			as_host->g_nowplay_url = next;
 			next = NULL;
-			g_debug("now playing url: %s\n", g_nowplay_url);
+			g_debug("now playing url: %s\n", as_host->g_nowplay_url);
 			state = AS_SUBMIT;
 			break;
 		case AS_SUBMIT:
-			g_submit_url = next;
-			g_debug("submit url: %s\n", g_submit_url);
-			g_state = AS_READY;
-			g_interval = 1;
+			as_host->g_submit_url = next;
+			g_debug("submit url: %s\n", as_host->g_submit_url);
+			as_host->g_state = AS_READY;
+			as_host->g_interval = 1;
 
 			/* handshake was successful: see if we have
 			   songs to submit */
@@ -276,7 +261,7 @@ static void as_handshake_callback(size_t length, const char *response, void *as_
 
 	}
 
-	as_increase_interval();
+	as_increase_interval(as_host);
 	as_schedule_handshake(as_host);
 }
 
@@ -290,17 +275,18 @@ static void as_queue_remove_oldest(unsigned count)
 	}
 }
 
-static void as_submit_callback(size_t length, const char *response, void *as_host)
+static void as_submit_callback(size_t length, const char *response, void *data)
 {
 	char *newline;
+	struct config_as_host *as_host = data;
 
-	assert(g_state == AS_SUBMITTING);
-	g_state = AS_READY;
+	assert(as_host->g_state == AS_SUBMITTING);
+	as_host->g_state = AS_READY;
 
 	if (!length) {
 		g_submit_pending = 0;
 		g_warning("submit timed out\n");
-		as_increase_interval();
+		as_increase_interval(as_host);
 		as_schedule_submit(as_host);
 		return;
 	}
@@ -311,7 +297,7 @@ static void as_submit_callback(size_t length, const char *response, void *as_hos
 
 	switch (as_parse_submit_response(response, length)) {
 	case AS_SUBMIT_OK:
-		g_interval = 1;
+		as_host->g_interval = 1;
 
 		/* submission was accepted, so clean up the cache. */
 		if (g_submit_pending > 0) {
@@ -330,11 +316,11 @@ static void as_submit_callback(size_t length, const char *response, void *as_hos
 		as_submit(as_host);
 		break;
 	case AS_SUBMIT_FAILED:
-		as_increase_interval();
+		as_increase_interval(as_host);
 		as_schedule_submit(as_host);
 		break;
 	case AS_SUBMIT_HANDSHAKE:
-		g_state = AS_NOTHING;
+		as_host->g_state = AS_NOTHING;
 		as_schedule_handshake(as_host);
 		break;
 	}
@@ -406,7 +392,7 @@ static void as_handshake(struct config_as_host *as_host)
 	GString *url;
 	char *timestr, *md5;
 
-	g_state = AS_HANDSHAKING;
+	as_host->g_state = AS_HANDSHAKING;
 
 	timestr = as_timestamp();
 	md5 = as_md5(as_host->password, timestr);
@@ -430,8 +416,8 @@ static void as_handshake(struct config_as_host *as_host)
 		g_warning("something went wrong when trying to connect, "
 			  "probably a bug\n");
 
-		g_state = AS_NOTHING;
-		as_increase_interval();
+		as_host->g_state = AS_NOTHING;
+		as_increase_interval(as_host);
 		as_schedule_handshake(as_host);
 	}
 
@@ -441,9 +427,9 @@ static void as_handshake(struct config_as_host *as_host)
 static gboolean
 as_handshake_timer(gpointer data)
 {
-	assert(g_state == AS_NOTHING);
+	assert(as_host->g_state == AS_NOTHING);
 
-	as_handshake_id = 0;
+	((struct config_as_host*)data)->as_handshake_id = 0;
 
 	as_handshake(data);
 	return false;
@@ -452,10 +438,10 @@ as_handshake_timer(gpointer data)
 static void
 as_schedule_handshake(struct config_as_host *as_host)
 {
-	assert(g_state == AS_NOTHING);
-	assert(as_handshake_id == 0);
+	assert(as_host->g_state == AS_NOTHING);
+	assert(as_host->as_handshake_id == 0);
 
-	as_handshake_id = g_timeout_add_seconds(g_interval,
+	as_host->as_handshake_id = g_timeout_add_seconds(as_host->g_interval,
 						as_handshake_timer, as_host);
 }
 
@@ -466,15 +452,15 @@ as_send_now_playing(const char *artist, const char *track,
 	GString *post_data;
 	char len[MAX_VAR_SIZE];
 
-	assert(g_state == AS_READY);
-	assert(as_submit_id == 0);
+	assert(as_host->g_state == AS_READY);
+	assert(as_host->as_submit_id == 0);
 
-	g_state = AS_SUBMITTING;
+	as_host->g_state = AS_SUBMITTING;
 
 	snprintf(len, MAX_VAR_SIZE, "%i", length);
 
 	post_data = g_string_new(NULL);
-	add_var(post_data, "s", g_session);
+	add_var(post_data, "s", as_host->g_session);
 	add_var(post_data, "a", artist);
 	add_var(post_data, "t", track);
 	add_var(post_data, "b", album);
@@ -484,12 +470,12 @@ as_send_now_playing(const char *artist, const char *track,
 
 	g_message("sending 'now playing' notification\n");
 
-	if (!conn_initiate(g_nowplay_url, as_submit_callback,
+	if (!conn_initiate(as_host->g_nowplay_url, as_submit_callback,
 			   post_data->str, as_host)) {
-		g_warning("failed to POST to %s\n", g_nowplay_url);
+		g_warning("failed to POST to %s\n", as_host->g_nowplay_url);
 
-		g_state = AS_READY;
-		as_increase_interval();
+		as_host->g_state = AS_READY;
+		as_increase_interval(as_host);
 		as_schedule_submit(as_host);
 	}
 
@@ -508,8 +494,9 @@ as_now_playing(const char *artist, const char *track,
 	g_now_playing.mbid = g_strdup(mbid);
 	g_now_playing.length = length;
 
-	if (g_state == AS_READY && as_submit_id == 0)
-		as_schedule_submit(&file_config.as_hosts); /* TODO: actually iterate over all hosts */
+	struct config_as_host *as_host = &file_config.as_hosts;	
+	if (as_host->g_state == AS_READY && as_host->as_submit_id == 0)
+		as_schedule_submit(as_host); /* TODO: actually iterate over all hosts */
 }
 
 static void as_submit(struct config_as_host *as_host)
@@ -519,8 +506,8 @@ static void as_submit(struct config_as_host *as_host)
 	GString *post_data;
 	char len[MAX_VAR_SIZE];
 
-	assert(g_state == AS_READY);
-	assert(as_submit_id == 0);
+	assert(as_host->g_state == AS_READY);
+	assert(as_host->as_submit_id == 0);
 
 	if (g_queue_is_empty(queue)) {
 		/* the submission queue is empty.  See if a "now playing" song is
@@ -537,11 +524,11 @@ static void as_submit(struct config_as_host *as_host)
 		return;
 	}
 
-	g_state = AS_SUBMITTING;
+	as_host->g_state = AS_SUBMITTING;
 
 	/* construct the handshake url. */
 	post_data = g_string_new(NULL);
-	add_var(post_data, "s", g_session);
+	add_var(post_data, "s", as_host->g_session);
 
 	for (GList *list = g_queue_peek_head_link(queue);
 	     list != NULL && count < MAX_SUBMIT_COUNT;
@@ -565,16 +552,16 @@ static void as_submit(struct config_as_host *as_host)
 
 	g_message("submitting %i song%s\n", count, count == 1 ? "" : "s");
 	g_debug("post data: %s\n", post_data->str);
-	g_debug("url: %s\n", g_submit_url);
+	g_debug("url: %s\n", as_host->g_submit_url);
 
 	g_submit_pending = count;
-	if (!conn_initiate(g_submit_url, &as_submit_callback,
+	if (!conn_initiate(as_host->g_submit_url, &as_submit_callback,
 			   post_data->str, as_host)) {
 		g_warning("something went wrong when trying to connect,"
 			  " probably a bug\n");
 
-		g_state = AS_READY;
-		as_increase_interval();
+		as_host->g_state = AS_READY;
+		as_increase_interval(as_host);
 		as_schedule_submit(as_host);
 	}
 
@@ -622,8 +609,9 @@ as_songchange(const char *file, const char *artist, const char *track,
 
 	g_queue_push_tail(queue, current);
 
-	if (g_state == AS_READY && as_submit_id == 0)
-		as_schedule_submit(&file_config.as_hosts); /* TODO: actually iterate over all hosts */
+	struct config_as_host *as_host = &file_config.as_hosts;
+	if (as_host->g_state == AS_READY && as_host->as_submit_id == 0)
+		as_schedule_submit(as_host); /* TODO: actually iterate over all hosts */
 
 	return g_queue_get_length(queue);
 }
@@ -632,8 +620,6 @@ void as_init(void)
 {
 	guint queue_length;
 
-	assert(g_state == AS_NOTHING);
-
 	g_message("starting mpdscribble (" AS_CLIENT_ID " " AS_CLIENT_VERSION ")\n");
 
 	queue = g_queue_new();
@@ -645,15 +631,20 @@ void as_init(void)
 
 	conn_setup();
 
+	file_config.as_hosts.g_session = NULL;
+	file_config.as_hosts.g_nowplay_url = NULL;
+	file_config.as_hosts.g_submit_url = NULL; /* XXX: this needs to get freed in file.c */
+	file_config.as_hosts.g_interval = 1;
+	file_config.as_hosts.g_state = AS_NOTHING;
 	as_schedule_handshake(&file_config.as_hosts); /* TODO: actually handshake all the hosts */
 }
 
 static gboolean
 as_submit_timer(gpointer data)
 {
-	assert(g_state == AS_READY);
+	assert(((struct config_as_host *)data)->g_state == AS_READY);
 
-	as_submit_id = 0;
+	((struct config_as_host *)data)->as_submit_id = 0;
 
 	as_submit(data);
 	return false;
@@ -662,11 +653,11 @@ as_submit_timer(gpointer data)
 static void
 as_schedule_submit(struct config_as_host *as_host)
 {
-	assert(as_submit_id == 0);
+	assert(as_host->as_submit_id == 0);
 	assert(!g_queue_is_empty(queue) ||
 	       (g_now_playing.artist != NULL && g_now_playing.track != NULL));
 
-	as_submit_id = g_timeout_add_seconds(g_interval,
+	as_host->as_submit_id = g_timeout_add_seconds(as_host->g_interval,
 					     as_submit_timer, as_host);
 }
 
@@ -695,8 +686,5 @@ void as_cleanup(void)
 	g_queue_foreach(queue, free_queue_song, NULL);
 	g_queue_free(queue);
 
-	g_free(g_submit_url);
-	g_free(g_md5_response);
-
 	conn_cleanup();
 }
diff --git a/src/file.h b/src/file.h
index 25df572..c0a54e5 100644
--- a/src/file.h
+++ b/src/file.h
@@ -24,11 +24,27 @@
 
 enum file_location { file_etc, file_home, file_unknown, };
 
+typedef enum {
+	AS_NOTHING,
+	AS_HANDSHAKING,
+	AS_READY,
+	AS_SUBMITTING,
+	AS_BADAUTH,
+} as_state;
+
 struct config_as_host {
 	char *url;
 	char *username;
 	char *password;
 	struct config_as_host *next; /* Linked list if more than one */
+	/* state stuff to get passed along in as.c */
+	guint as_handshake_id;
+	guint as_submit_id;
+	char *g_session;
+	char *g_nowplay_url;
+	char *g_submit_url;
+	int g_interval;
+	as_state g_state;
 };
 
 struct config {
commit 44dceb50ccc6cd307ba3dc5881224d418f585bcd
Author: Stephen Paul Weber <singpol...@singpolyma.net>
Date:   Tue Apr 7 11:27:24 2009 -0400

    Actually handshake and submit for all server.
    
    Replace code that took first element of linked list with do...while loops.

diff --git a/src/as.c b/src/as.c
index 036e274..0444341 100644
--- a/src/as.c
+++ b/src/as.c
@@ -486,6 +486,7 @@ void
 as_now_playing(const char *artist, const char *track,
 	       const char *album, const char *mbid, const int length)
 {
+	struct config_as_host *current_host = &file_config.as_hosts;
 	as_song_cleanup(&g_now_playing, false);
 
 	g_now_playing.artist = g_strdup(artist);
@@ -494,9 +495,10 @@ as_now_playing(const char *artist, const char *track,
 	g_now_playing.mbid = g_strdup(mbid);
 	g_now_playing.length = length;
 
-	struct config_as_host *as_host = &file_config.as_hosts;	
-	if (as_host->g_state == AS_READY && as_host->as_submit_id == 0)
-		as_schedule_submit(as_host); /* TODO: actually iterate over all hosts */
+	do {
+		if (current_host->g_state == AS_READY && current_host->as_submit_id == 0)
+			as_schedule_submit(current_host);
+	} while((current_host = current_host->next));
 }
 
 static void as_submit(struct config_as_host *as_host)
@@ -574,6 +576,7 @@ as_songchange(const char *file, const char *artist, const char *track,
 	      const char *time2)
 {
 	struct song *current;
+	struct config_as_host *current_host = &file_config.as_hosts;
 
 	/* from the 1.2 protocol draft:
 
@@ -609,9 +612,10 @@ as_songchange(const char *file, const char *artist, const char *track,
 
 	g_queue_push_tail(queue, current);
 
-	struct config_as_host *as_host = &file_config.as_hosts;
-	if (as_host->g_state == AS_READY && as_host->as_submit_id == 0)
-		as_schedule_submit(as_host); /* TODO: actually iterate over all hosts */
+	do {
+		if (current_host->g_state == AS_READY && current_host->as_submit_id == 0)
+			as_schedule_submit(current_host);
+	} while((current_host = current_host->next));
 
 	return g_queue_get_length(queue);
 }
@@ -619,6 +623,7 @@ as_songchange(const char *file, const char *artist, const char *track,
 void as_init(void)
 {
 	guint queue_length;
+	struct config_as_host *current_host = &file_config.as_hosts;
 
 	g_message("starting mpdscribble (" AS_CLIENT_ID " " AS_CLIENT_VERSION ")\n");
 
@@ -631,12 +636,14 @@ void as_init(void)
 
 	conn_setup();
 
-	file_config.as_hosts.g_session = NULL;
-	file_config.as_hosts.g_nowplay_url = NULL;
-	file_config.as_hosts.g_submit_url = NULL; /* XXX: this needs to get freed in file.c */
-	file_config.as_hosts.g_interval = 1;
-	file_config.as_hosts.g_state = AS_NOTHING;
-	as_schedule_handshake(&file_config.as_hosts); /* TODO: actually handshake all the hosts */
+	do {
+		current_host->g_session = NULL;
+		current_host->g_nowplay_url = NULL;
+		current_host->g_submit_url = NULL; /* XXX: this needs to get freed in file.c */
+		current_host->g_interval = 1;
+		current_host->g_state = AS_NOTHING;
+		as_schedule_handshake(current_host);
+	} while((current_host = current_host->next));
 }
 
 static gboolean
commit 4086d7ad39dc179c33478ddd320313d45fd54141
Author: Stephen Paul Weber <singpol...@singpolyma.net>
Date:   Tue Apr 7 12:09:53 2009 -0400

    Plug memory leak

diff --git a/src/file.c b/src/file.c
index c6c3575..ac4fae5 100644
--- a/src/file.c
+++ b/src/file.c
@@ -328,11 +328,32 @@ int file_read_config(int argc, char **argv)
 	return 1;
 }
 
+void free_as_host(struct config_as_host *current_host)
+{
+	if(current_host->url)
+		free(current_host->url);
+	if(current_host->username)
+		free(current_host->username);
+	if(current_host->password)
+		free(current_host->password);
+	if(current_host->g_session)
+		g_free(current_host->g_session);
+	if(current_host->g_nowplay_url)
+		g_free(current_host->g_nowplay_url);
+	if(current_host->g_submit_url)
+		g_free(current_host->g_submit_url);
+	if(current_host->next) {
+		free_as_host(current_host->next);
+		free(current_host->next);
+	}
+}
+
 void file_cleanup(void)
 {
 	g_free(file_config.host);
 	g_free(file_config.log);
 	g_free(file_config.conf);
 	g_free(file_config.cache);
-	/* XXX: Free linked list */
+
+	free_as_host(&file_config.as_hosts);
 }
commit 2c6cd95a7e8a168d85892fd45bcee4d9ada658cc
Author: Stephen Paul Weber <singpol...@singpolyma.net>
Date:   Tue Apr 7 12:10:17 2009 -0400

    Better logging, initialize all values

diff --git a/src/as.c b/src/as.c
index 0444341..0fb4959 100644
--- a/src/as.c
+++ b/src/as.c
@@ -166,7 +166,7 @@ as_parse_handshake_response(const char *line, struct config_as_host *as_host)
 	/* FIXME: some code duplication between this
 	   and as_parse_submit_response. */
 	if (!strncmp(line, OK, strlen(OK))) {
-		g_message("handshake ok\n");
+		g_message("handshake ok for '%s'\n", as_host->url);
 		return true;
 	} else if (!strncmp(line, BANNED, strlen(BANNED))) {
 		g_warning("handshake failed, we're banned (%s)\n", line);
@@ -468,7 +468,7 @@ as_send_now_playing(const char *artist, const char *track,
 	add_var(post_data, "n", "");
 	add_var(post_data, "m", mbid);
 
-	g_message("sending 'now playing' notification\n");
+	g_message("sending 'now playing' notification to '%s'\n", as_host->url);
 
 	if (!conn_initiate(as_host->g_nowplay_url, as_submit_callback,
 			   post_data->str, as_host)) {
@@ -639,9 +639,11 @@ void as_init(void)
 	do {
 		current_host->g_session = NULL;
 		current_host->g_nowplay_url = NULL;
-		current_host->g_submit_url = NULL; /* XXX: this needs to get freed in file.c */
+		current_host->g_submit_url = NULL;
 		current_host->g_interval = 1;
 		current_host->g_state = AS_NOTHING;
+		current_host->as_submit_id = 0;
+		current_host->as_handshake_id = 0;
 		as_schedule_handshake(current_host);
 	} while((current_host = current_host->next));
 }

Attachment: signature.asc
Description: Digital signature

------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com
_______________________________________________
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team

Reply via email to