From e2950a7e4d9bdc36a207023fc55ec03dfae0d7af Mon Sep 17 00:00:00 2001
From: Avuton Olrich <avuton@gmail.com>
Date: Sat, 4 Jun 2011 07:37:33 -0700
Subject: [PATCH 01/21] mpd version 0.16.3

---
 NEWS         | 2 +-
 configure.ac | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index f56e2e872..31169a85c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-ver 0.16.3 (2011/??/??)
+ver 0.16.3 (2011/06/04)
 * fix assertion failure in audio format mask parser
 * fix NULL pointer dereference in playlist parser
 * fix playlist files in base music directory
diff --git a/configure.ac b/configure.ac
index 184f0dcb0..0aed23bf2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(mpd, 0.16.3~git, musicpd-dev-team@lists.sourceforge.net)
+AC_INIT(mpd, 0.16.3, musicpd-dev-team@lists.sourceforge.net)
 AC_CONFIG_SRCDIR([src/main.c])
 AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects])
 AM_CONFIG_HEADER(config.h)

From 3c4f4793b517a3bf8803d39818a94ac727b5f5a1 Mon Sep 17 00:00:00 2001
From: Avuton Olrich <avuton@gmail.com>
Date: Sat, 4 Jun 2011 07:37:34 -0700
Subject: [PATCH 02/21] Modify version string to post-release version
 0.16.4~git

---
 NEWS         | 3 +++
 configure.ac | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 31169a85c..f38358a83 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+ver 0.16.4 (2010/??/??)
+
+
 ver 0.16.3 (2011/06/04)
 * fix assertion failure in audio format mask parser
 * fix NULL pointer dereference in playlist parser
diff --git a/configure.ac b/configure.ac
index 0aed23bf2..0618bd413 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(mpd, 0.16.3, musicpd-dev-team@lists.sourceforge.net)
+AC_INIT(mpd, 0.16.4~git, musicpd-dev-team@lists.sourceforge.net)
 AC_CONFIG_SRCDIR([src/main.c])
 AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects])
 AM_CONFIG_HEADER(config.h)

From 52b8e0f9ecdc15c90266d6a50a5ebd9a1038ebdb Mon Sep 17 00:00:00 2001
From: Tony Miller <mcfiredrill@gmail.com>
Date: Sun, 26 Jun 2011 15:00:48 -0700
Subject: [PATCH 03/21] doc/user: Typo in playlist plugin documentation,
 'playlist plugin' not 'filter'.

This patch fixes a typo in doc/user about playlist plugins.

Its in the top commit in my repository in a branch called 'doc_fix':
git://github.com/mcfiredrill/mpd.git
---
 doc/user.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/user.xml b/doc/user.xml
index 17bbdf91f..6a9871007 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -446,7 +446,7 @@ cd mpd-version</programlisting>
       </para>
 
       <para>
-        To configure a filter, add a
+        To configure a playlist plugin, add a
         <varname>playlist_plugin</varname> block to
         <filename>mpd.conf</filename>:
       </para>

From 8d1c7ca2065444dfe2da432a30c95782e3ead48d Mon Sep 17 00:00:00 2001
From: oblique <psyberbits@gmail.com>
Date: Sun, 3 Jul 2011 14:54:56 +0200
Subject: [PATCH 04/21] ffmpeg: workaround for semantic API change in recent
 ffmpeg versions

---
 NEWS                                | 2 ++
 src/decoder/ffmpeg_decoder_plugin.c | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index f38358a83..208ba1069 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.16.4 (2010/??/??)
+* decoder:
+  - ffmpeg: workaround for semantic API change in recent ffmpeg versions
 
 
 ver 0.16.3 (2011/06/04)
diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c
index 6d794db49..156853faf 100644
--- a/src/decoder/ffmpeg_decoder_plugin.c
+++ b/src/decoder/ffmpeg_decoder_plugin.c
@@ -321,7 +321,7 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
 	}
 
 	//ffmpeg works with ours "fileops" helper
-	AVFormatContext *format_context;
+	AVFormatContext *format_context = NULL;
 	if (av_open_input_stream(&format_context, stream->io, input->uri,
 				 input_format, NULL) != 0) {
 		g_warning("Open failed\n");
@@ -470,7 +470,7 @@ ffmpeg_stream_tag(struct input_stream *is)
 	if (stream == NULL)
 		return NULL;
 
-	AVFormatContext *f;
+	AVFormatContext *f = NULL;
 	if (av_open_input_stream(&f, stream->io, is->uri,
 				 input_format, NULL) != 0) {
 		mpd_ffmpeg_stream_close(stream);

From 6aa6a9c2727c863239d6396a40a781e98e922565 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 3 Jul 2011 14:57:56 +0200
Subject: [PATCH 05/21] decoder/flac: validate the sample rate when scanning
 the tag

Don't calculate the song duration when the sample rate is 0 (division
by zero crash).
---
 NEWS                        | 1 +
 src/decoder/flac_metadata.c | 3 ++-
 src/decoder/flac_metadata.h | 3 +++
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 208ba1069..138630967 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 ver 0.16.4 (2010/??/??)
 * decoder:
   - ffmpeg: workaround for semantic API change in recent ffmpeg versions
+  - flac: validate the sample rate when scanning the tag
 
 
 ver 0.16.3 (2011/06/04)
diff --git a/src/decoder/flac_metadata.c b/src/decoder/flac_metadata.c
index f2f2f954d..5b94fd426 100644
--- a/src/decoder/flac_metadata.c
+++ b/src/decoder/flac_metadata.c
@@ -224,7 +224,8 @@ flac_tag_apply_metadata(struct tag *tag, const char *track,
 		break;
 
 	case FLAC__METADATA_TYPE_STREAMINFO:
-		tag->time = flac_duration(&block->data.stream_info);
+		if (block->data.stream_info.sample_rate > 0)
+			tag->time = flac_duration(&block->data.stream_info);
 		break;
 
 	default:
diff --git a/src/decoder/flac_metadata.h b/src/decoder/flac_metadata.h
index 06e691d1d..e52b0fb82 100644
--- a/src/decoder/flac_metadata.h
+++ b/src/decoder/flac_metadata.h
@@ -20,6 +20,7 @@
 #ifndef MPD_FLAC_METADATA_H
 #define MPD_FLAC_METADATA_H
 
+#include <assert.h>
 #include <stdbool.h>
 #include <FLAC/metadata.h>
 
@@ -29,6 +30,8 @@ struct replay_gain_info;
 static inline unsigned
 flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info)
 {
+	assert(stream_info->sample_rate > 0);
+
 	return (stream_info->total_samples + stream_info->sample_rate - 1) /
 		stream_info->sample_rate;
 }

From 3680a6bbbb6c2ae26d5c9bf361bc2feea362b553 Mon Sep 17 00:00:00 2001
From: Jonathan Ballet <jon@multani.info>
Date: Sun, 3 Jul 2011 15:05:04 +0200
Subject: [PATCH 06/21] doc/protocol: add some missing specifications

---
 doc/protocol.xml | 134 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 127 insertions(+), 7 deletions(-)

diff --git a/doc/protocol.xml b/doc/protocol.xml
index 3eb5aa932..0b4f0d175 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -8,18 +8,54 @@
     <title>General protocol syntax</title>
 
     <section>
-      <title>Requests</title>
+      <title>Protocol overview</title>
 
       <para>
-        If arguments contain spaces, they should be surrounded by double quotation
-        marks.
+        The MPD command protocol exchanges line-based text records
+        between client and server over TCP.  Once the client is
+        connected to the server, they conduct a conversation until the
+        client closes the connection. The conversation flow is always
+        initiated by the client.
       </para>
 
+      <para>
+        The client transmits a command sequence, terminated by the
+        newline character <constant>\n</constant>.  The server will
+        respond with one or more lines, the last of which will be a
+        completion code.
+      </para>
+
+      <para>
+        When the client connects to the server, the server will answer
+        with the following line:
+
+        <synopsis>OK MPD version</synopsis>
+
+        where <varname>version</varname> is a version identifier such as
+        0.12.2.  This version identifier is the version of the protocol
+        spoken, not the real version of the daemon.  (There is no way to
+        retrieve this real version identifier from the connection.)
+      </para>
+    </section>
+
+    <section>
+      <title>Requests</title>
+
       <cmdsynopsis>
         <command>COMMAND</command>
         <arg rep="repeat"><replaceable>ARG</replaceable></arg>
       </cmdsynopsis>
 
+      <para>
+        If arguments contain spaces, they should be surrounded by double
+        quotation marks.
+      </para>
+
+      <para>
+        Argument strings are separated from the command and any other
+        arguments by linear white-space (' ' or '\t').
+      </para>
+
       <para>
         All data between the client and the server is encoded in
         UTF-8. (Note: In UTF-8 all standard ansi characters, 0-127 are
@@ -38,13 +74,97 @@
       <title>Responses</title>
 
       <para>
-        A command returns <returnvalue>OK</returnvalue> on completion
-        or <returnvalue>ACK some error</returnvalue> on failure.
-        These denote the end of command execution.
+        A command returns <returnvalue>OK</returnvalue> on completion or
+        <returnvalue>ACK some error</returnvalue> on failure.  These
+        denote the end of command execution.
       </para>
+
+      <section>
+        <title>Failure responses</title>
+
+        <para>
+          The nature of the error can be gleaned from the information
+          that follows the <returnvalue>ACK</returnvalue>.
+          <returnvalue>ACK</returnvalue> lines are of the form:
+
+          <synopsis>ACK [error@command_listNum] {current_command} message_text\n</synopsis>
+
+          These responses are generated by a call to
+          <function>commandError</function>. They contain four separate
+          terms. Let's look at each of them:
+
+          <itemizedlist>
+            <listitem>
+              <para>
+                <returnvalue>error</returnvalue>: numeric value of one
+                of the <constant>ACK_ERROR</constant> constants defined
+                in <filename>ack.h</filename>.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <returnvalue>command_listNum</returnvalue>:
+                offset of the command that caused the error in a <link
+                  linkend="command_lists">Command List</link>.
+                An error will always cause a command list to terminate
+                at the command that causes the error.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <returnvalue>current_command</returnvalue>:
+                name of the command, in a <link
+                  linkend="command_lists">Command List</link>,
+                that was executing when the error occurred.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <returnvalue>message_text</returnvalue>:
+                some (hopefully) informative text that describes the
+                nature of the error.
+              </para>
+            </listitem>
+          </itemizedlist>
+        </para>
+
+        <example>
+          <title>foo</title>
+          <para>
+            An example might help. Consider the following sequence
+            sent from the client to the server.
+
+            <synopsis>
+              command_list_begin
+              volume 86
+              play 10240
+              status
+              command_list_end
+            </synopsis>
+          </para>
+
+          <para>
+            The server responds with:
+
+            <returnvalue>
+              ACK [50@1] {play} song doesn't exist: "10240"
+            </returnvalue>
+          </para>
+
+          <para>
+            This tells us that the play command, which was the
+            second in the list (the first or only command is
+            numbered 0), failed with error 50.  The number 50
+            translates to <constant>ACK_ERROR_NO_EXIST</constant>--the
+            song doesn't exist.  This is reiterated by the message text
+            which also tells us which song doesn't exist.
+          </para>
+
+        </example>
+      </section>
     </section>
 
-    <section>
+    <section id="command_lists">
       <title>Command lists</title>
 
       <para>

From dca405a746e0b86e37659bdb112358324fc48d28 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 3 Jul 2011 15:20:28 +0200
Subject: [PATCH 07/21] test/read_conf: fix -Wunused-but-set-variable

---
 test/read_conf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/read_conf.c b/test/read_conf.c
index 4f43e6a2e..e96bd9046 100644
--- a/test/read_conf.c
+++ b/test/read_conf.c
@@ -70,5 +70,5 @@ int main(int argc, char **argv)
 	}
 
 	config_global_finish();
-	return 0;
+	return ret;
 }

From 52e2fa91c4c322bc0d8a12a825370f91aa7fecc6 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 3 Jul 2011 15:20:39 +0200
Subject: [PATCH 08/21] test/read_conf: make variables more local

---
 test/read_conf.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/test/read_conf.c b/test/read_conf.c
index e96bd9046..f1b38cafe 100644
--- a/test/read_conf.c
+++ b/test/read_conf.c
@@ -37,30 +37,28 @@ my_log_func(G_GNUC_UNUSED const gchar *log_domain,
 
 int main(int argc, char **argv)
 {
-	const char *path, *name, *value;
-	GError *error = NULL;
-	bool success;
-	int ret;
-
 	if (argc != 3) {
 		g_printerr("Usage: read_conf FILE SETTING\n");
 		return 1;
 	}
 
-	path = argv[1];
-	name = argv[2];
+	const char *path = argv[1];
+	const char *name = argv[2];
 
 	g_log_set_default_handler(my_log_func, NULL);
 
 	config_global_init();
-	success = config_read_file(path, &error);
+
+	GError *error = NULL;
+	bool success = config_read_file(path, &error);
 	if (!success) {
 		g_printerr("%s:", error->message);
 		g_error_free(error);
 		return 1;
 	}
 
-	value = config_get_string(name, NULL);
+	const char *value = config_get_string(name, NULL);
+	int ret;
 	if (value != NULL) {
 		g_print("%s\n", value);
 		ret = 0;

From cca2c2f4ca42f1c6a15d16bd2e8384971dad811d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 3 Jul 2011 15:21:40 +0200
Subject: [PATCH 09/21] test/run_filter: remove unused variable "frame_size"

---
 test/run_filter.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/test/run_filter.c b/test/run_filter.c
index ee2445eac..3758eb5bb 100644
--- a/test/run_filter.c
+++ b/test/run_filter.c
@@ -106,7 +106,6 @@ int main(int argc, char **argv)
 	struct filter *filter;
 	const struct audio_format *out_audio_format;
 	char buffer[4096];
-	size_t frame_size;
 
 	if (argc < 3 || argc > 4) {
 		g_printerr("Usage: run_filter CONFIG NAME [FORMAT] <IN\n");
@@ -162,8 +161,6 @@ int main(int argc, char **argv)
 	g_printerr("audio_format=%s\n",
 		   audio_format_to_string(out_audio_format, &af_string));
 
-	frame_size = audio_format_frame_size(&audio_format);
-
 	/* play */
 
 	while (true) {

From 65772a74e08af4b29466b3d41d42ec75d7e58788 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 3 Jul 2011 15:42:22 +0200
Subject: [PATCH 10/21] configure: correct avahi/bonjour state on result page

Was always displayed as "no", even if one was found.
---
 configure.ac | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0618bd413..b362592cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -537,15 +537,16 @@ no|avahi|bonjour)
 	;;
 esac
 
+enable_avahi=no
+enable_bounjour=no
 if test x$with_zeroconf != xno; then
 	if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then
 		PKG_CHECK_MODULES([AVAHI], [avahi-client avahi-glib],
-			 [found_avahi=1;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]
-			 MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS",
-			 [found_avahi=0])
+			 [enable_avahi=yes;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]
+			 MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS")
 	fi
 
-	if test x$found_avahi = x1; then
+	if test x$enable_avahi = xyes; then
 		with_zeroconf=avahi
 	elif test x$with_zeroconf = xavahi; then
 		AC_MSG_ERROR([Avahi support requested but not found])
@@ -553,13 +554,12 @@ if test x$with_zeroconf != xno; then
 
 	if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then
 		AC_CHECK_HEADER(dns_sd.h,
-			[found_bonjour=1;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])],
-			[found_bonjour=0])
+			[enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])])
 		AC_CHECK_LIB(dns_sd, DNSServiceRegister,
 			MPD_LIBS="$MPD_LIBS -ldns_sd")
 	fi
 
-	if test x$found_bonjour = x1; then
+	if test x$enable_bonjour = xyes; then
 		with_zeroconf=bonjour
 	elif test x$with_zeroconf = xbonjour; then
 		AC_MSG_ERROR([Bonjour support requested but not found])

From affb4bd923492913ffebb71c4f977a6bbf9ed257 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 12:37:25 +0200
Subject: [PATCH 11/21] ape: add missing g_free in error path

---
 src/ape.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/ape.c b/src/ape.c
index 5fca98e28..5f4da3f2e 100644
--- a/src/ape.c
+++ b/src/ape.c
@@ -60,8 +60,10 @@ ape_scan_internal(FILE *fp, tag_ape_callback_t callback, void *ctx)
 	assert(remaining > 10);
 
 	char *buffer = g_malloc(remaining);
-	if (fread(buffer, 1, remaining, fp) != remaining)
+	if (fread(buffer, 1, remaining, fp) != remaining) {
+		g_free(buffer);
 		return false;
+	}
 
 	/* read tags */
 	unsigned n = GUINT32_FROM_LE(footer.count);

From d5684f74440fec77b3bc7c80a8396c79e4e489ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 12:47:06 +0200
Subject: [PATCH 12/21] sticker: fix a memory leak

---
 src/sticker.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/sticker.c b/src/sticker.c
index c59cdd078..f6cd04346 100644
--- a/src/sticker.c
+++ b/src/sticker.c
@@ -579,8 +579,10 @@ sticker_load(const char *type, const char *uri)
 	bool success;
 
 	success = sticker_list_values(sticker->table, type, uri);
-	if (!success)
+	if (!success) {
+		sticker_free(sticker);
 		return NULL;
+	}
 
 	if (g_hash_table_size(sticker->table) == 0) {
 		/* don't return empty sticker objects */

From c49c69d6ea0b7670f70066f0735fcffc69966d46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 12:38:43 +0200
Subject: [PATCH 13/21] conf: add missing fclose in error path

This patch seems a bit ugly, maybe it would be a bit cleaner with gotos.
---
 src/conf.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/conf.c b/src/conf.c
index 705942085..14dac93a6 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -367,6 +367,7 @@ config_read_file(const char *file, GError **error_r)
 			assert(*line != 0);
 			g_propagate_prefixed_error(error_r, error,
 						   "line %i: ", count);
+			fclose(fp);
 			return false;
 		}
 
@@ -378,6 +379,7 @@ config_read_file(const char *file, GError **error_r)
 			g_set_error(error_r, config_quark(), 0,
 				    "unrecognized parameter in config file at "
 				    "line %i: %s\n", count, name);
+			fclose(fp);
 			return false;
 		}
 
@@ -387,6 +389,7 @@ config_read_file(const char *file, GError **error_r)
 				    "config parameter \"%s\" is first defined "
 				    "on line %i and redefined on line %i\n",
 				    name, param->line, count);
+			fclose(fp);
 			return false;
 		}
 
@@ -398,6 +401,7 @@ config_read_file(const char *file, GError **error_r)
 			if (*line != '{') {
 				g_set_error(error_r, config_quark(), 0,
 					    "line %i: '{' expected", count);
+				fclose(fp);
 				return false;
 			}
 
@@ -406,12 +410,15 @@ config_read_file(const char *file, GError **error_r)
 				g_set_error(error_r, config_quark(), 0,
 					    "line %i: Unknown tokens after '{'",
 					    count);
+				fclose(fp);
 				return false;
 			}
 
 			param = config_read_block(fp, &count, string, error_r);
-			if (param == NULL)
+			if (param == NULL) {
+				fclose(fp);
 				return false;
+			}
 		} else {
 			/* a string value */
 
@@ -428,6 +435,7 @@ config_read_file(const char *file, GError **error_r)
 					g_error_free(error);
 				}
 
+				fclose(fp);
 				return false;
 			}
 
@@ -435,6 +443,7 @@ config_read_file(const char *file, GError **error_r)
 				g_set_error(error_r, config_quark(), 0,
 					    "line %i: Unknown tokens after value",
 					    count);
+				fclose(fp);
 				return false;
 			}
 

From 36aa8ce3c9f34d41aa7fd94d90f23ba62f5caafb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 13:38:46 +0200
Subject: [PATCH 14/21] output/ao: add missing g_free in error path

---
 src/output/ao_plugin.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/output/ao_plugin.c b/src/output/ao_plugin.c
index 6fedbc6e2..42ece5a3a 100644
--- a/src/output/ao_plugin.c
+++ b/src/output/ao_plugin.c
@@ -106,12 +106,14 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 		g_set_error(error, ao_output_quark(), 0,
 			    "\"%s\" is not a valid ao driver",
 			    value);
+		g_free(ad);
 		return NULL;
 	}
 
 	if ((ai = ao_driver_info(ad->driver)) == NULL) {
 		g_set_error(error, ao_output_quark(), 0,
 			    "problems getting driver info");
+		g_free(ad);
 		return NULL;
 	}
 
@@ -129,6 +131,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 				g_set_error(error, ao_output_quark(), 0,
 					    "problems parsing options \"%s\"",
 					    options[i]);
+				g_free(ad);
 				return NULL;
 			}
 

From 296085ff23f3992f0f45fc0325c5bdbab953e114 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 14:35:04 +0200
Subject: [PATCH 15/21] output/httpd: add missing g_free in error path

---
 src/output/httpd_output_plugin.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index 6650d89e3..b82dc0599 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -103,6 +103,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 	if (encoder_plugin == NULL) {
 		g_set_error(error, httpd_output_quark(), 0,
 			    "No such encoder: %s", encoder_name);
+		g_free(httpd);
 		return NULL;
 	}
 

From a6a8bdffc35c3b592ca9eb908ef010a27ddbb3ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 15:39:19 +0200
Subject: [PATCH 16/21] output/recorder: fix a memory leak

---
 src/output/recorder_output_plugin.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c
index c01d927c4..10d64106c 100644
--- a/src/output/recorder_output_plugin.c
+++ b/src/output/recorder_output_plugin.c
@@ -79,23 +79,27 @@ recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 	if (encoder_plugin == NULL) {
 		g_set_error(error_r, recorder_output_quark(), 0,
 			    "No such encoder: %s", encoder_name);
-		return NULL;
+		goto failure;
 	}
 
 	recorder->path = config_get_block_string(param, "path", NULL);
 	if (recorder->path == NULL) {
 		g_set_error(error_r, recorder_output_quark(), 0,
 			    "'path' not configured");
-		return NULL;
+		goto failure;
 	}
 
 	/* initialize encoder */
 
 	recorder->encoder = encoder_init(encoder_plugin, param, error_r);
 	if (recorder->encoder == NULL)
-		return NULL;
+		goto failure;
 
 	return recorder;
+
+failure:
+	g_free(recorder);
+	return NULL;
 }
 
 static void

From 7d6a605a859139dd1e22b6e7e91479b644d5f398 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= <j.neuschaefer@gmx.net>
Date: Mon, 18 Jul 2011 15:58:02 +0200
Subject: [PATCH 17/21] output/shout: fix a memory leak

---
 src/output/shout_plugin.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c
index baaeccf92..5e1ef762a 100644
--- a/src/output/shout_plugin.c
+++ b/src/output/shout_plugin.c
@@ -152,7 +152,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	if (port == 0) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "shout port must be configured");
-		return NULL;
+		goto failure;
 	}
 
 	check_block_param("password");
@@ -174,21 +174,21 @@ my_shout_init_driver(const struct audio_format *audio_format,
 				    "shout quality \"%s\" is not a number in the "
 				    "range -1 to 10, line %i",
 				    value, param->line);
-			return NULL;
+			goto failure;
 		}
 
 		if (config_get_block_string(param, "bitrate", NULL) != NULL) {
 			g_set_error(error, shout_output_quark(), 0,
 				    "quality and bitrate are "
 				    "both defined");
-			return NULL;
+			goto failure;
 		}
 	} else {
 		value = config_get_block_string(param, "bitrate", NULL);
 		if (value == NULL) {
 			g_set_error(error, shout_output_quark(), 0,
 				    "neither bitrate nor quality defined");
-			return NULL;
+			goto failure;
 		}
 
 		sd->bitrate = strtol(value, &test, 10);
@@ -196,7 +196,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 		if (*test != '\0' || sd->bitrate <= 0) {
 			g_set_error(error, shout_output_quark(), 0,
 				    "bitrate must be a positive integer");
-			return NULL;
+			goto failure;
 		}
 	}
 
@@ -206,12 +206,12 @@ my_shout_init_driver(const struct audio_format *audio_format,
 		g_set_error(error, shout_output_quark(), 0,
 			    "couldn't find shout encoder plugin \"%s\"",
 			    encoding);
-		return NULL;
+		goto failure;
 	}
 
 	sd->encoder = encoder_init(encoder_plugin, param, error);
 	if (sd->encoder == NULL)
-		return NULL;
+		goto failure;
 
 	if (strcmp(encoding, "mp3") == 0 || strcmp(encoding, "lame") == 0)
 		shout_format = SHOUT_FORMAT_MP3;
@@ -225,7 +225,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 			g_set_error(error, shout_output_quark(), 0,
 				    "you cannot stream \"%s\" to shoutcast, use mp3",
 				    encoding);
-			return NULL;
+			goto failure;
 		} else if (0 == strcmp(value, "shoutcast"))
 			protocol = SHOUT_PROTOCOL_ICY;
 		else if (0 == strcmp(value, "icecast1"))
@@ -237,7 +237,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 				    "shout protocol \"%s\" is not \"shoutcast\" or "
 				    "\"icecast1\"or \"icecast2\"",
 				    value);
-			return NULL;
+			goto failure;
 		}
 	} else {
 		protocol = SHOUT_PROTOCOL_HTTP;
@@ -256,7 +256,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	    shout_set_agent(sd->shout_conn, "MPD") != SHOUTERR_SUCCESS) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "%s", shout_get_error(sd->shout_conn));
-		return NULL;
+		goto failure;
 	}
 
 	/* optional paramters */
@@ -267,14 +267,14 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	if (value != NULL && shout_set_genre(sd->shout_conn, value)) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "%s", shout_get_error(sd->shout_conn));
-		return NULL;
+		goto failure;
 	}
 
 	value = config_get_block_string(param, "description", NULL);
 	if (value != NULL && shout_set_description(sd->shout_conn, value)) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "%s", shout_get_error(sd->shout_conn));
-		return NULL;
+		goto failure;
 	}
 
 	{
@@ -300,6 +300,10 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	}
 
 	return sd;
+
+failure:
+	free_shout_data(sd);
+	return NULL;
 }
 
 static bool

From 73f9e1795156fc7fd5e41de45f3acce24c71d874 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Mon, 18 Jul 2011 22:47:51 +0200
Subject: [PATCH 18/21] NEWS: fix memory leaks

---
 NEWS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 138630967..4756b64f6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,5 @@
-ver 0.16.4 (2010/??/??)
+ver 0.16.4 (2011/??/??)
+* fix memory leaks
 * decoder:
   - ffmpeg: workaround for semantic API change in recent ffmpeg versions
   - flac: validate the sample rate when scanning the tag

From 762712c756fe3041cc60cc4084ef505e56acf57c Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Fri, 8 Jul 2011 21:20:38 +0200
Subject: [PATCH 19/21] database: require X_OK on parent directory, not R_OK

For accessing the child of a directory, one needs X_OK on the
directory.
---
 src/database.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/database.c b/src/database.c
index f255d6ca5..9f29f95e1 100644
--- a/src/database.c
+++ b/src/database.c
@@ -180,7 +180,7 @@ db_check(void)
 		}
 
 		/* Check if we can write to the directory */
-		if (access(dirPath, R_OK | W_OK)) {
+		if (access(dirPath, X_OK | W_OK)) {
 			g_warning("Can't create db file in \"%s\": %s",
 				  dirPath, strerror(errno));
 			g_free(dirPath);

From 6592ca9f8805c3cf5154626087a01a183c38b6d5 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Mon, 18 Jul 2011 23:29:42 +0200
Subject: [PATCH 20/21] decoder: use AVDictionary instead of AVMetadata

AVMetadata has been deprecated.
---
 src/decoder/ffmpeg_decoder_plugin.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c
index 156853faf..15ea77f70 100644
--- a/src/decoder/ffmpeg_decoder_plugin.c
+++ b/src/decoder/ffmpeg_decoder_plugin.c
@@ -446,13 +446,26 @@ static const ffmpeg_tag_map ffmpeg_tag_maps[] = {
 };
 
 static bool
-ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m,
+ffmpeg_copy_metadata(struct tag *tag,
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
+		     AVDictionary *m,
+#else
+		     AVMetadata *m,
+#endif
 		     const ffmpeg_tag_map tag_map)
 {
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
+	AVDictionaryEntry *mt = NULL;
+
+	while ((mt = av_dict_get(m, tag_map.name, mt, 0)) != NULL)
+		tag_add_item(tag, tag_map.type, mt->value);
+#else
 	AVMetadataTag *mt = NULL;
 
 	while ((mt = av_metadata_get(m, tag_map.name, mt, 0)) != NULL)
 		tag_add_item(tag, tag_map.type, mt->value);
+#endif
+
 	return mt != NULL;
 }
 

From 736fd0e29326548152e91e4e3fb8c0ea9c1b50ac Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Mon, 18 Jul 2011 23:31:47 +0200
Subject: [PATCH 21/21] decoder/ffmpeg: use avformat_open_input() if available

av_open_input_stream() has been deprecated.
---
 src/decoder/ffmpeg_decoder_plugin.c | 39 ++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c
index 15ea77f70..70628df9d 100644
--- a/src/decoder/ffmpeg_decoder_plugin.c
+++ b/src/decoder/ffmpeg_decoder_plugin.c
@@ -89,7 +89,11 @@ struct mpd_ffmpeg_stream {
 	struct decoder *decoder;
 	struct input_stream *input;
 
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0)
+	AVIOContext *io;
+#else
 	ByteIOContext *io;
+#endif
 	unsigned char buffer[8192];
 };
 
@@ -135,6 +139,33 @@ mpd_ffmpeg_stream_open(struct decoder *decoder, struct input_stream *input)
 	return stream;
 }
 
+/**
+ * API compatibility wrapper for av_open_input_stream() and
+ * avformat_open_input().
+ */
+static int
+mpd_ffmpeg_open_input(AVFormatContext **ic_ptr,
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0)
+		      AVIOContext *pb,
+#else
+		      ByteIOContext *pb,
+#endif
+		      const char *filename,
+		      AVInputFormat *fmt)
+{
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,1,3)
+	AVFormatContext *context = avformat_alloc_context();
+	if (context == NULL)
+		return AVERROR(ENOMEM);
+
+	context->pb = pb;
+	*ic_ptr = context;
+	return avformat_open_input(ic_ptr, filename, fmt, NULL);
+#else
+	return av_open_input_stream(ic_ptr, pb, filename, fmt, NULL);
+#endif
+}
+
 static void
 mpd_ffmpeg_stream_close(struct mpd_ffmpeg_stream *stream)
 {
@@ -322,8 +353,8 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
 
 	//ffmpeg works with ours "fileops" helper
 	AVFormatContext *format_context = NULL;
-	if (av_open_input_stream(&format_context, stream->io, input->uri,
-				 input_format, NULL) != 0) {
+	if (mpd_ffmpeg_open_input(&format_context, stream->io, input->uri,
+				  input_format) != 0) {
 		g_warning("Open failed\n");
 		mpd_ffmpeg_stream_close(stream);
 		return;
@@ -484,8 +515,8 @@ ffmpeg_stream_tag(struct input_stream *is)
 		return NULL;
 
 	AVFormatContext *f = NULL;
-	if (av_open_input_stream(&f, stream->io, is->uri,
-				 input_format, NULL) != 0) {
+	if (mpd_ffmpeg_open_input(&f, stream->io, is->uri,
+				  input_format) != 0) {
 		mpd_ffmpeg_stream_close(stream);
 		return NULL;
 	}