[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#767846: marked as done (unblock: mpd/0.19.2-1)



Your message dated Thu, 20 Nov 2014 19:07:13 +0000
with message-id <20141120190713.GU6216@lupin.home.powdarrmonkey.net>
and subject line Re: Bug#767846: unblock: mpd/0.19.2-1
has caused the Debian Bug report #767846,
regarding unblock: mpd/0.19.2-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
767846: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=767846
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock / pre-approve package mpd

mpd 0.19.2 is a bugfix release in the stable mpd series. It fixes a
number of issues that would be good to have fixed in a stable Debian
release, only one of which (#767684, "Stack smashing
detected in faad_decoder_init", important) has appeared in the Debian
BTS yet.

mpd will need an unblock to fix a license incompatibility issue
(#767504, serious), and I would like to fix as many important or
yet-to-be filed important bugs in the same upload. I realize the 0.19.1
to 0.19.2 diff (attached) is not very short and not strictly limited to
important bugs, so I'm asking for pre-approval before uploading to
unstable and hope for a favourable decision given that the freeze hasn't
technically started yet.

The full upstream changelog is as follows:

    ver 0.19.2 (2014/11/02)
    * input
      - curl: fix redirected streams
    * playlist
      - don't allow empty playlist name
      - m3u: don't ignore unterminated last line
      - m3u: recognize the file suffix ".m3u8"
    * decoder
      - ignore URI query string for plugin detection
      - faad: remove workaround for ancient libfaad2 ABI bug
      - ffmpeg: recognize MIME type audio/aacp
      - mad: fix negative replay gain values
    * output
      - fix memory leak after filter initialization error
      - fall back to PCM if given DSD sample rate is not supported
    * fix assertion failure on unsupported PCM conversion
    * auto-disable plugins that require GLib when --disable-glib is used


unblock mpd/0.19.2-1
diff --git a/Makefile.am b/Makefile.am
index 2f3ab90..dac3e17 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -130,7 +130,6 @@ libmpd_a_SOURCES = \
 	src/IOThread.cxx src/IOThread.hxx \
 	src/Instance.cxx src/Instance.hxx \
 	src/win32/Win32Main.cxx \
-	src/osx/OSXMain.cxx \
 	src/GlobalEvents.cxx src/GlobalEvents.hxx \
 	src/MixRampInfo.hxx \
 	src/MusicBuffer.cxx src/MusicBuffer.hxx \
@@ -2141,19 +2140,11 @@ user_DATA = $(wildcard doc/user/*.html)
 developerdir = $(docdir)/developer
 developer_DATA = $(wildcard doc/developer/*.html)
 
-if HAVE_XMLTO
-
 DOCBOOK_HTML = $(patsubst %.xml,%/index.html,$(DOCBOOK_FILES))
 
 $(DOCBOOK_HTML): %/index.html: %.xml
 	$(XMLTO) -o $(@D) --stringparam chunker.output.encoding=utf-8 html --stringparam use.id.as.filename=1 $<
 
-else
-
-DOCBOOK_HTML =
-
-endif
-
 doc/api/html/index.html: doc/doxygen.conf
 	@$(MKDIR_P) $(@D)
 	$(DOXYGEN) $<
diff --git a/NEWS b/NEWS
index 5a24844..e8e84ff 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,21 @@
+ver 0.19.2 (2014/11/02)
+* input
+  - curl: fix redirected streams
+* playlist
+  - don't allow empty playlist name
+  - m3u: don't ignore unterminated last line
+  - m3u: recognize the file suffix ".m3u8"
+* decoder
+  - ignore URI query string for plugin detection
+  - faad: remove workaround for ancient libfaad2 ABI bug
+  - ffmpeg: recognize MIME type audio/aacp
+  - mad: fix negative replay gain values
+* output
+  - fix memory leak after filter initialization error
+  - fall back to PCM if given DSD sample rate is not supported
+* fix assertion failure on unsupported PCM conversion
+* auto-disable plugins that require GLib when --disable-glib is used
+
 ver 0.19.1 (2014/10/19)
 * input
   - mms: fix deadlock bug
@@ -85,6 +103,15 @@ ver 0.19 (2014/10/10)
 * install systemd unit for socket activation
 * Android port
 
+ver 0.18.17 (2014/11/02)
+* playlist
+  - don't allow empty playlist name
+  - m3u: recognize the file suffix ".m3u8"
+* decoder
+  - ignore URI query string for plugin detection
+  - faad: remove workaround for ancient libfaad2 ABI bug
+  - ffmpeg: recognize MIME type audio/aacp
+
 ver 0.18.16 (2014/09/26)
 * fix DSD breakage due to typo in configure.ac
 
diff --git a/configure.ac b/configure.ac
index 3f90bb6..f689a9f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
 AC_PREREQ(2.60)
 
-AC_INIT(mpd, 0.19.1, musicpd-dev-team@lists.sourceforge.net)
+AC_INIT(mpd, 0.19.2, musicpd-dev-team@lists.sourceforge.net)
 
 VERSION_MAJOR=0
 VERSION_MINOR=19
-VERSION_REVISION=0
+VERSION_REVISION=2
 VERSION_EXTRA=0
 
 AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -293,7 +293,9 @@ fi
 AC_ARG_ENABLE(libmpdclient,
 	AS_HELP_STRING([--enable-libmpdclient],
 		[enable support for the MPD client]),,
-	enable_libmpdclient=$database_auto)
+	enable_libmpdclient=auto)
+MPD_DEPENDS([enable_libmpdclient], [enable_database],
+	[Cannot use --enable-libmpdclient with --disable-database])
 
 AC_ARG_ENABLE(expat,
 	AS_HELP_STRING([--enable-expat],
@@ -303,7 +305,9 @@ AC_ARG_ENABLE(expat,
 AC_ARG_ENABLE(upnp,
 	AS_HELP_STRING([--enable-upnp],
 		[enable UPnP client support (default: auto)]),,
-	enable_upnp=$database_auto)
+	enable_upnp=auto)
+MPD_DEPENDS([enable_upnp], [enable_database],
+	[Cannot use --enable-upnp with --disable-database])
 
 AC_ARG_ENABLE(adplug,
 	AS_HELP_STRING([--enable-adplug],
@@ -323,6 +327,8 @@ AC_ARG_ENABLE(ao,
 	AS_HELP_STRING([--enable-ao],
 		[enable support for libao]),,
 	enable_ao=auto)
+MPD_DEPENDS([enable_ao], [enable_glib],
+	[Cannot use --enable-ao with --disable-glib])
 
 AC_ARG_ENABLE(audiofile,
 	AS_HELP_STRING([--enable-audiofile],
@@ -343,6 +349,8 @@ AC_ARG_ENABLE(cdio-paranoia,
 	AS_HELP_STRING([--enable-cdio-paranoia],
 		[enable support for audio CD support]),,
 	enable_cdio_paranoia=auto)
+MPD_DEPENDS([enable_cdio_paranoia], [enable_glib],
+	[Cannot use --enable-cdio-paranoia with --disable-glib])
 
 AC_ARG_ENABLE(curl,
 	AS_HELP_STRING([--enable-curl],
@@ -398,11 +406,15 @@ AC_ARG_ENABLE(gme,
 	AS_HELP_STRING([--enable-gme],
 		[enable Blargg's game music emulator plugin]),,
 	enable_gme=auto)
+MPD_DEPENDS([enable_gme], [enable_glib],
+	[Cannot use --enable-gme with --disable-glib])
 
 AC_ARG_ENABLE(httpd-output,
 	AS_HELP_STRING([--enable-httpd-output],
 		[enables the HTTP server output]),,
 	[enable_httpd_output=auto])
+MPD_DEPENDS([enable_httpd_output], [enable_glib],
+	[Cannot use --enable-httpd-output with --disable-glib])
 
 AC_ARG_ENABLE(id3,
 	AS_HELP_STRING([--enable-id3],
@@ -428,6 +440,8 @@ AC_ARG_ENABLE(jack,
 	AS_HELP_STRING([--enable-jack],
 		[enable jack support]),,
 	enable_jack=auto)
+MPD_DEPENDS([enable_jack], [enable_glib],
+	[Cannot use --enable-jack with --disable-glib])
 
 AC_SYS_LARGEFILE
 
@@ -440,6 +454,8 @@ AC_ARG_ENABLE(soundcloud,
 	AS_HELP_STRING([--enable-soundcloud],
 		[enable support for soundcloud.com]),,
 	[enable_soundcloud=auto])
+MPD_DEPENDS([enable_soundcloud], [enable_glib],
+	[Cannot use --enable-soundcloud with --disable-glib])
 
 AC_ARG_ENABLE(lame-encoder,
 	AS_HELP_STRING([--enable-lame-encoder],
@@ -534,6 +550,8 @@ AC_ARG_ENABLE(sidplay,
 	AS_HELP_STRING([--enable-sidplay],
 		[enable C64 SID support via libsidplay2]),,
 	enable_sidplay=auto)
+MPD_DEPENDS([enable_sidplay], [enable_glib],
+	[Cannot use --enable-sidplay with --disable-glib])
 
 AC_ARG_ENABLE(shine-encoder,
 	AS_HELP_STRING([--enable-shine-encoder],
@@ -559,6 +577,8 @@ AC_ARG_ENABLE(sqlite,
 	AS_HELP_STRING([--enable-sqlite],
 		[enable support for the SQLite database]),,
 	[enable_sqlite=$database_auto])
+MPD_DEPENDS([enable_sqlite], [enable_glib],
+	[Cannot use --enable-sqlite with --disable-glib])
 
 AC_ARG_ENABLE(systemd-daemon,
 	AS_HELP_STRING([--enable-systemd-daemon],
@@ -599,6 +619,8 @@ AC_ARG_ENABLE(vorbis-encoder,
 	AS_HELP_STRING([--enable-vorbis-encoder],
 		[enable the Ogg Vorbis encoder]),,
 	[enable_vorbis_encoder=auto])
+MPD_DEPENDS([enable_vorbis_encoder], [enable_glib],
+	[Cannot use --enable-vorbis-encoder with --disable-glib])
 
 AC_ARG_ENABLE(wave-encoder,
 	AS_HELP_STRING([--enable-wave-encoder],
@@ -609,6 +631,8 @@ AC_ARG_ENABLE(wavpack,
 	AS_HELP_STRING([--enable-wavpack],
 		[enable WavPack support]),,
 	enable_wavpack=auto)
+MPD_DEPENDS([enable_wavpack], [enable_glib],
+	[Cannot use --enable-wavpack with --disable-glib])
 
 AC_ARG_ENABLE(werror,
 	AS_HELP_STRING([--enable-werror],
@@ -1709,8 +1733,11 @@ dnl Documentation
 dnl ---------------------------------------------------------------------------
 if test x$enable_documentation = xyes; then
 	AC_PATH_PROG(XMLTO, xmlto)
+	if test x$XMLTO = x; then
+		AC_MSG_ERROR([xmlto not found])
+	fi
+
 	AC_SUBST(XMLTO)
-	AM_CONDITIONAL(HAVE_XMLTO, test x$XMLTO != x)
 
 	AC_PATH_PROG(DOXYGEN, doxygen)
 	if test x$DOXYGEN = x; then
@@ -1718,8 +1745,6 @@ if test x$enable_documentation = xyes; then
 	fi
 
 	AC_SUBST(DOXYGEN)
-else
-	AM_CONDITIONAL(HAVE_XMLTO, false)
 fi
 
 AM_CONDITIONAL(ENABLE_DOCUMENTATION, test x$enable_documentation = xyes)
@@ -1826,9 +1851,14 @@ results(ipv6, "IPv6")
 results(tcp, "TCP")
 results(un,[UNIX Domain Sockets])
 
+printf '\nStorage support:\n\t'
+results(nfs, [NFS])
+results(smbclient, [SMB])
+
 printf '\nFile format support:\n\t'
 results(aac, [AAC])
 results(adplug, [AdPlug])
+results(dsd, [DSD])
 results(sidplay, [C64 SID])
 results(ffmpeg, [FFMPEG])
 results(flac, [FLAC])
diff --git a/m4/faad.m4 b/m4/faad.m4
index 5ca520e..9dcb1cc 100644
--- a/m4/faad.m4
+++ b/m4/faad.m4
@@ -62,36 +62,7 @@ int main() {
 	CPPFLAGS=$oldcppflags
 fi
 
-if test x$enable_aac = xyes; then
-	oldcflags=$CFLAGS
-	oldlibs=$LIBS
-	oldcppflags=$CPPFLAGS
-	CFLAGS="$CFLAGS $FAAD_CFLAGS -Werror"
-	LIBS="$LIBS $FAAD_LIBS"
-	CPPFLAGS=$CFLAGS
-
-	AC_MSG_CHECKING(for broken libfaad headers)
-	AC_COMPILE_IFELSE([AC_LANG_SOURCE([
-#include <faad.h>
-#include <stddef.h>
-#include <stdint.h>
-
-int main() {
-	unsigned char channels;
-	uint32_t sample_rate;
-
-	NeAACDecInit2(NULL, NULL, 0, &sample_rate, &channels);
-	return 0;
-}
-	])],
-		[AC_MSG_RESULT(correct)],
-		[AC_MSG_RESULT(broken);
-		AC_DEFINE(HAVE_FAAD_LONG, 1, [Define if faad.h uses the broken "unsigned long" pointers])])
-
-	CFLAGS=$oldcflags
-	LIBS=$oldlibs
-	CPPFLAGS=$oldcppflags
-else
+if test x$enable_aac = xno; then
 	FAAD_LIBS=""
 	FAAD_CFLAGS=""
 fi
diff --git a/m4/mpd_depends.m4 b/m4/mpd_depends.m4
new file mode 100644
index 0000000..4898f90
--- /dev/null
+++ b/m4/mpd_depends.m4
@@ -0,0 +1,9 @@
+AC_DEFUN([MPD_DEPENDS], [
+	if test x$$2 = xno; then
+		if test x$$1 = xauto; then
+			$1=no
+		elif test x$$1 = xyes; then
+			AC_MSG_ERROR([$3])
+		fi
+	fi
+])
diff --git a/src/Main.cxx b/src/Main.cxx
index d17590e..2719c05 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -114,6 +114,10 @@
 #include <ws2tcpip.h>
 #endif
 
+#ifdef __APPLE__
+#include <dispatch/dispatch.h>
+#endif
+
 #include <limits.h>
 
 static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
@@ -401,8 +405,6 @@ int main(int argc, char *argv[])
 {
 #ifdef WIN32
 	return win32_main(argc, argv);
-#elif __APPLE__
-	return osx_main(argc, argv);
 #else
 	return mpd_main(argc, argv);
 #endif
@@ -410,6 +412,8 @@ int main(int argc, char *argv[])
 
 #endif
 
+static int mpd_main_after_fork(struct options);
+
 #ifdef ANDROID
 static inline
 #endif
@@ -513,6 +517,27 @@ int mpd_main(int argc, char *argv[])
 	daemonize_begin(options.daemon);
 #endif
 
+#ifdef __APPLE__
+	/* Runs the OS X native event loop in the main thread, and runs
+	   the rest of mpd_main on a new thread. This lets CoreAudio receive
+	   route change notifications (e.g. plugging or unplugging headphones).
+	   All hardware output on OS X ultimately uses CoreAudio internally.
+	   This must be run after forking; if dispatch is called before forking,
+	   the child process will have a broken internal dispatch state. */
+	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+		exit(mpd_main_after_fork(options));
+	});
+	dispatch_main();
+	return EXIT_FAILURE; // unreachable, because dispatch_main never returns
+#else
+	return mpd_main_after_fork(options);
+#endif
+}
+
+static int mpd_main_after_fork(struct options options)
+{
+	Error error;
+
 	GlobalEvents::Initialize(*instance->event_loop);
 	GlobalEvents::Register(GlobalEvents::IDLE, idle_event_emitted);
 #ifdef WIN32
diff --git a/src/Main.hxx b/src/Main.hxx
index dae7a50..7e3fecd 100644
--- a/src/Main.hxx
+++ b/src/Main.hxx
@@ -75,15 +75,4 @@ win32_app_stopping(void);
 
 #endif
 
-#ifdef __APPLE__
-
-/* Runs the OS X native event loop in the main thread, and runs
- * mpd_main on a new thread. This lets CoreAudio receive route
- * change notifications (e.g. plugging or unplugging headphones).
- * All hardware output on OS X ultimately uses CoreAudio internally.
- */
-int osx_main(int argc, char *argv[]);
-
-#endif
-
 #endif
diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx
index f0aa2d2..ab26937 100644
--- a/src/PlaylistFile.cxx
+++ b/src/PlaylistFile.cxx
@@ -64,6 +64,10 @@ spl_global_init(void)
 bool
 spl_valid_name(const char *name_utf8)
 {
+	if (*name_utf8 == 0)
+		/* empty name not allowed */
+		return false;
+
 	/*
 	 * Not supporting '/' was done out of laziness, and we should
 	 * really strive to support it in the future.
diff --git a/src/TagStream.cxx b/src/TagStream.cxx
index 6397633..6201028 100644
--- a/src/TagStream.cxx
+++ b/src/TagStream.cxx
@@ -46,7 +46,8 @@ tag_stream_scan(InputStream &is, const tag_handler &handler, void *ctx)
 {
 	assert(is.IsReady());
 
-	const char *const suffix = uri_get_suffix(is.GetURI());
+	UriSuffixBuffer suffix_buffer;
+	const char *const suffix = uri_get_suffix(is.GetURI(), suffix_buffer);
 	const char *const mime = is.GetMimeType();
 
 	if (suffix == nullptr && mime == nullptr)
diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx
index a39cfa6..dd5518b 100644
--- a/src/decoder/DecoderThread.cxx
+++ b/src/decoder/DecoderThread.cxx
@@ -237,7 +237,8 @@ static bool
 decoder_run_stream_locked(Decoder &decoder, InputStream &is,
 			  const char *uri, bool &tried_r)
 {
-	const char *const suffix = uri_get_suffix(uri);
+	UriSuffixBuffer suffix_buffer;
+	const char *const suffix = uri_get_suffix(uri, suffix_buffer);
 
 	using namespace std::placeholders;
 	const auto f = std::bind(decoder_run_stream_plugin,
diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx
index 793ab10..add23aa 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.cxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.cxx
@@ -255,20 +255,12 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer &buffer,
 	}
 
 	uint8_t channels;
-	uint32_t sample_rate;
-#ifdef HAVE_FAAD_LONG
-	/* neaacdec.h declares all arguments as "unsigned long", but
-	   internally expects uint32_t pointers.  To avoid gcc
-	   warnings, use this workaround. */
-	unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
-#else
-	uint32_t *sample_rate_p = &sample_rate;
-#endif
+	unsigned long sample_rate;
 	long nbytes = NeAACDecInit(decoder,
 				   /* deconst hack, libfaad requires this */
 				   const_cast<unsigned char *>(data.data),
 				   data.size,
-				   sample_rate_p, &channels);
+				   &sample_rate, &channels);
 	if (nbytes < 0) {
 		error.Set(faad_decoder_domain, "Not an AAC stream");
 		return false;
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 904e21a..2e72269 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -680,6 +680,7 @@ static const char *const ffmpeg_mime_types[] = {
 	"audio/8svx",
 	"audio/16sv",
 	"audio/aac",
+	"audio/aacp",
 	"audio/ac3",
 	"audio/aiff"
 	"audio/amr",
diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx
index 41efb59..de6c9b1 100644
--- a/src/decoder/plugins/MadDecoderPlugin.cxx
+++ b/src/decoder/plugins/MadDecoderPlugin.cxx
@@ -657,7 +657,7 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
 	unsigned name = mad_bit_read(ptr, 3); /* gain name */
 	unsigned orig = mad_bit_read(ptr, 3); /* gain originator */
 	unsigned sign = mad_bit_read(ptr, 1); /* sign bit */
-	unsigned gain = mad_bit_read(ptr, 9); /* gain*10 */
+	int gain = mad_bit_read(ptr, 9); /* gain*10 */
 	if (gain && name == 1 && orig != 0) {
 		lame->track_gain = ((sign ? -gain : gain) / 10.0) + adj;
 		FormatDebug(mad_domain, "LAME track gain found: %f",
diff --git a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
index bf97763..34bccd2 100644
--- a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
+++ b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
@@ -39,15 +39,7 @@ static MP4TrackId
 mp4_get_aac_track(MP4FileHandle handle, NeAACDecHandle decoder,
 		  AudioFormat &audio_format, Error &error)
 {
-	uint32_t sample_rate;
-#ifdef HAVE_FAAD_LONG
-	/* neaacdec.h declares all arguments as "unsigned long", but
-	   internally expects uint32_t pointers.  To avoid gcc
-	   warnings, use this workaround. */
-	unsigned long *sample_rate_r = (unsigned long*)&sample_rate;
-#else
-	uint32_t *sample_rate_r = sample_rate;
-#endif
+	unsigned long sample_rate;
 
 	const MP4TrackId tracks = MP4GetNumberOfTracks(handle);
 
@@ -80,7 +72,7 @@ mp4_get_aac_track(MP4FileHandle handle, NeAACDecHandle decoder,
 
 		uint8_t channels;
 		int32_t nbytes = NeAACDecInit(decoder, buff, buff_size,
-				       sample_rate_r, &channels);
+					      &sample_rate, &channels);
 
 		free(buff);
 
diff --git a/src/fs/Charset.cxx b/src/fs/Charset.cxx
index 2d289c3..abf4d82 100644
--- a/src/fs/Charset.cxx
+++ b/src/fs/Charset.cxx
@@ -34,6 +34,8 @@
 #include <assert.h>
 #include <string.h>
 
+#ifdef HAVE_GLIB
+
 /**
  * Maximal number of bytes required to represent path name in UTF-8
  * (including nul-terminator).
@@ -44,7 +46,6 @@
  */
 static constexpr size_t MPD_PATH_MAX_UTF8 = (MPD_PATH_MAX - 1) * 4 + 1;
 
-#ifdef HAVE_GLIB
 static std::string fs_charset;
 
 gcc_pure
diff --git a/src/input/AsyncInputStream.hxx b/src/input/AsyncInputStream.hxx
index 7935f1a..d1f0c3b 100644
--- a/src/input/AsyncInputStream.hxx
+++ b/src/input/AsyncInputStream.hxx
@@ -83,6 +83,10 @@ protected:
 	 */
 	void SetTag(Tag *_tag);
 
+	void ClearTag() {
+		SetTag(nullptr);
+	}
+
 	void Pause();
 
 	bool IsPaused() const {
diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx
index 15c3501..81b903b 100644
--- a/src/input/InputStream.hxx
+++ b/src/input/InputStream.hxx
@@ -200,6 +200,10 @@ public:
 		return mime.empty() ? nullptr : mime.c_str();
 	}
 
+	void ClearMimeType() {
+		mime.clear();
+	}
+
 	gcc_nonnull_all
 	void SetMimeType(const char *_mime) {
 		assert(!ready);
diff --git a/src/input/TextInputStream.cxx b/src/input/TextInputStream.cxx
index b79f64b..5a8dcc0 100644
--- a/src/input/TextInputStream.cxx
+++ b/src/input/TextInputStream.cxx
@@ -38,8 +38,8 @@ TextInputStream::ReadLine()
 	while (true) {
 		auto dest = buffer.Write();
 		if (dest.size < 2) {
-			/* end of file (or line too long): terminate
-			   the current line */
+			/* line too long: terminate the current
+			   line */
 
 			assert(!dest.IsEmpty());
 			dest[0] = 0;
@@ -66,7 +66,19 @@ TextInputStream::ReadLine()
 		if (line != nullptr)
 			return line;
 
-		if (nbytes == 0)
-			return nullptr;
+		if (nbytes == 0) {
+			/* end of file: see if there's an unterminated
+			   line */
+
+			dest = buffer.Write();
+			assert(!dest.IsEmpty());
+			dest[0] = 0;
+
+			auto r = buffer.Read();
+			buffer.Clear();
+			return r.IsEmpty()
+				? nullptr
+				: r.data;
+		}
 	}
 }
diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx
index 617805e..1e1a461 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -109,6 +109,13 @@ struct CurlInputStream final : public AsyncInputStream {
 	 */
 	void FreeEasyIndirect();
 
+	/**
+	 * Called when a new response begins.  This is used to discard
+	 * headers from previous responses (for example authentication
+	 * and redirects).
+	 */
+	void ResponseBoundary();
+
 	void HeaderReceived(const char *name, std::string &&value);
 
 	size_t DataReceived(const void *ptr, size_t size);
@@ -598,6 +605,20 @@ CurlInputStream::~CurlInputStream()
 }
 
 inline void
+CurlInputStream::ResponseBoundary()
+{
+	/* undo all effects of HeaderReceived() because the previous
+	   response was not applicable for this stream */
+
+	seekable = false;
+	size = UNKNOWN_SIZE;
+	ClearMimeType();
+	ClearTag();
+
+	// TODO: reset the IcyInputStream?
+}
+
+inline void
 CurlInputStream::HeaderReceived(const char *name, std::string &&value)
 {
 	if (IsSeekPending())
@@ -645,6 +666,11 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
 	size *= nmemb;
 
 	const char *header = (const char *)ptr;
+	if (size > 5 && memcmp(header, "HTTP/", 5) == 0) {
+		c.ResponseBoundary();
+		return size;
+	}
+
 	const char *end = header + size;
 
 	char name[64];
@@ -720,10 +746,10 @@ CurlInputStream::InitEasy(Error &error)
 			 input_curl_writefunction);
 	curl_easy_setopt(easy, CURLOPT_WRITEDATA, this);
 	curl_easy_setopt(easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
-	curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1);
-	curl_easy_setopt(easy, CURLOPT_NETRC, 1);
-	curl_easy_setopt(easy, CURLOPT_MAXREDIRS, 5);
-	curl_easy_setopt(easy, CURLOPT_FAILONERROR, true);
+	curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1l);
+	curl_easy_setopt(easy, CURLOPT_NETRC, 1l);
+	curl_easy_setopt(easy, CURLOPT_MAXREDIRS, 5l);
+	curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1l);
 	curl_easy_setopt(easy, CURLOPT_ERRORBUFFER, error_buffer);
 	curl_easy_setopt(easy, CURLOPT_NOPROGRESS, 1l);
 	curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1l);
diff --git a/src/lib/upnp/Discovery.cxx b/src/lib/upnp/Discovery.cxx
index 9ea78c6..1539e15 100644
--- a/src/lib/upnp/Discovery.cxx
+++ b/src/lib/upnp/Discovery.cxx
@@ -26,6 +26,7 @@
 
 #include <upnp/upnptools.h>
 
+#include <stdlib.h>
 #include <string.h>
 
 // The service type string we are looking for.
diff --git a/src/osx/OSXMain.cxx b/src/osx/OSXMain.cxx
deleted file mode 100644
index 1ac9aec..0000000
--- a/src/osx/OSXMain.cxx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * 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 2 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "Main.hxx"
-
-#ifdef __APPLE__
-
-#include <stdlib.h>
-#include <dispatch/dispatch.h>
-
-int osx_main(int argc, char *argv[])
-{
-	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-		exit(mpd_main(argc, argv));
-	});
-	dispatch_main();
-	return EXIT_FAILURE; // unreachable, because dispatch_main never returns
-}
-
-#endif
diff --git a/src/output/Internal.hxx b/src/output/Internal.hxx
index 658ebd4..6e6ffb4 100644
--- a/src/output/Internal.hxx
+++ b/src/output/Internal.hxx
@@ -383,7 +383,12 @@ private:
 	void Reopen();
 
 	AudioFormat OpenFilter(AudioFormat &format, Error &error_r);
+
+	/**
+	 * Mutex must not be locked.
+	 */
 	void CloseFilter();
+
 	void ReopenFilter();
 
 	/**
diff --git a/src/output/OutputThread.cxx b/src/output/OutputThread.cxx
index e464250..2ec0670 100644
--- a/src/output/OutputThread.cxx
+++ b/src/output/OutputThread.cxx
@@ -22,6 +22,7 @@
 #include "OutputAPI.hxx"
 #include "Domain.hxx"
 #include "pcm/PcmMix.hxx"
+#include "pcm/Domain.hxx"
 #include "notify.hxx"
 #include "filter/FilterInternal.hxx"
 #include "filter/plugins/ConvertFilterPlugin.hxx"
@@ -165,6 +166,10 @@ AudioOutput::Open()
 	out_audio_format.ApplyMask(config_audio_format);
 
 	mutex.unlock();
+
+	const AudioFormat retry_audio_format = out_audio_format;
+
+ retry_without_dsd:
 	success = ao_plugin_open(this, out_audio_format, error);
 	mutex.lock();
 
@@ -174,7 +179,10 @@ AudioOutput::Open()
 		FormatError(error, "Failed to open \"%s\" [%s]",
 			    name, plugin.name);
 
+		mutex.unlock();
 		CloseFilter();
+		mutex.lock();
+
 		fail_timer.Update();
 		return;
 	}
@@ -184,7 +192,36 @@ AudioOutput::Open()
 		FormatError(error, "Failed to convert for \"%s\" [%s]",
 			    name, plugin.name);
 
+		mutex.unlock();
+		ao_plugin_close(this);
+
+		if (error.IsDomain(pcm_domain) &&
+		    out_audio_format.format == SampleFormat::DSD) {
+			/* if the audio output supports DSD, but not
+			   the given sample rate, it asks MPD to
+			   resample; resampling DSD however is not
+			   implemented; our last resort is to give up
+			   DSD and fall back to PCM */
+
+			// TODO: clean up this workaround
+
+			FormatError(output_domain, "Retrying without DSD");
+
+			out_audio_format = retry_audio_format;
+			out_audio_format.format = SampleFormat::FLOAT;
+
+			/* clear the Error to allow reusing it */
+			error.Clear();
+
+			/* sorry for the "goto" - this is a workaround
+			   for the stable branch that should be as
+			   unintrusive as possible */
+			goto retry_without_dsd;
+		}
+
 		CloseFilter();
+		mutex.lock();
+
 		fail_timer.Update();
 		return;
 	}
@@ -233,7 +270,10 @@ AudioOutput::ReopenFilter()
 {
 	Error error;
 
+	mutex.unlock();
 	CloseFilter();
+	mutex.lock();
+
 	const AudioFormat filter_audio_format =
 		OpenFilter(in_audio_format, error);
 	if (!filter_audio_format.IsDefined() ||
diff --git a/src/output/plugins/RoarOutputPlugin.cxx b/src/output/plugins/RoarOutputPlugin.cxx
index 508e147..aa37c91 100644
--- a/src/output/plugins/RoarOutputPlugin.cxx
+++ b/src/output/plugins/RoarOutputPlugin.cxx
@@ -46,7 +46,7 @@ class RoarOutput {
 	struct roar_connection con;
 	struct roar_audio_info info;
 	mutable Mutex mutex;
-	volatile bool alive;
+	bool alive;
 
 public:
 	RoarOutput()
diff --git a/src/pcm/ChannelsConverter.cxx b/src/pcm/ChannelsConverter.cxx
index f93f4f6..7146137 100644
--- a/src/pcm/ChannelsConverter.cxx
+++ b/src/pcm/ChannelsConverter.cxx
@@ -43,7 +43,7 @@ PcmChannelsConverter::Open(SampleFormat _format,
 	default:
 		error.Format(pcm_domain,
 			     "PCM channel conversion for %s is not implemented",
-			     sample_format_to_string(format));
+			     sample_format_to_string(_format));
 		return false;
 	}
 
diff --git a/src/pcm/FormatConverter.cxx b/src/pcm/FormatConverter.cxx
index 64e2d85..b058b32 100644
--- a/src/pcm/FormatConverter.cxx
+++ b/src/pcm/FormatConverter.cxx
@@ -28,11 +28,31 @@
 
 bool
 PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
-			 gcc_unused Error &error)
+			 Error &error)
 {
 	assert(_src_format != SampleFormat::UNDEFINED);
 	assert(_dest_format != SampleFormat::UNDEFINED);
 
+	switch (_dest_format) {
+	case SampleFormat::UNDEFINED:
+		assert(false);
+		gcc_unreachable();
+
+	case SampleFormat::S8:
+	case SampleFormat::DSD:
+		error.Format(pcm_domain,
+			     "PCM conversion from %s to %s is not implemented",
+			     sample_format_to_string(_src_format),
+			     sample_format_to_string(_dest_format));
+		return nullptr;
+
+	case SampleFormat::S16:
+	case SampleFormat::S24_P32:
+	case SampleFormat::S32:
+	case SampleFormat::FLOAT:
+		break;
+	}
+
 	src_format = _src_format;
 	dest_format = _dest_format;
 	return true;
@@ -48,20 +68,14 @@ PcmFormatConverter::Close()
 }
 
 ConstBuffer<void>
-PcmFormatConverter::Convert(ConstBuffer<void> src, Error &error)
+PcmFormatConverter::Convert(ConstBuffer<void> src, gcc_unused Error &error)
 {
 	switch (dest_format) {
 	case SampleFormat::UNDEFINED:
-		assert(false);
-		gcc_unreachable();
-
 	case SampleFormat::S8:
 	case SampleFormat::DSD:
-		error.Format(pcm_domain,
-			     "PCM conversion from %s to %s is not implemented",
-			     sample_format_to_string(src_format),
-			     sample_format_to_string(dest_format));
-		return nullptr;
+		assert(false);
+		gcc_unreachable();
 
 	case SampleFormat::S16:
 		return pcm_convert_to_16(buffer, dither,
diff --git a/src/pcm/PcmConvert.cxx b/src/pcm/PcmConvert.cxx
index 2b7cfe7..4385667 100644
--- a/src/pcm/PcmConvert.cxx
+++ b/src/pcm/PcmConvert.cxx
@@ -51,7 +51,7 @@ PcmConvert::~PcmConvert()
 }
 
 bool
-PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format,
+PcmConvert::Open(const AudioFormat _src_format, const AudioFormat _dest_format,
 		 Error &error)
 {
 	assert(!src_format.IsValid());
@@ -59,36 +59,34 @@ PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format,
 	assert(_src_format.IsValid());
 	assert(_dest_format.IsValid());
 
-	src_format = _src_format;
-	dest_format = _dest_format;
-
-	AudioFormat format = src_format;
+	AudioFormat format = _src_format;
 	if (format.format == SampleFormat::DSD)
 		format.format = SampleFormat::FLOAT;
 
-	enable_resampler = format.sample_rate != dest_format.sample_rate;
+	enable_resampler = format.sample_rate != _dest_format.sample_rate;
 	if (enable_resampler) {
-		if (!resampler.Open(format, dest_format.sample_rate, error))
+		if (!resampler.Open(format, _dest_format.sample_rate, error))
 			return false;
 
 		format.format = resampler.GetOutputSampleFormat();
-		format.sample_rate = dest_format.sample_rate;
+		format.sample_rate = _dest_format.sample_rate;
 	}
 
-	enable_format = format.format != dest_format.format;
+	enable_format = format.format != _dest_format.format;
 	if (enable_format &&
-	    !format_converter.Open(format.format, dest_format.format, error)) {
+	    !format_converter.Open(format.format, _dest_format.format,
+				   error)) {
 		if (enable_resampler)
 			resampler.Close();
 		return false;
 	}
 
-	format.format = dest_format.format;
+	format.format = _dest_format.format;
 
-	enable_channels = format.channels != dest_format.channels;
+	enable_channels = format.channels != _dest_format.channels;
 	if (enable_channels &&
 	    !channels_converter.Open(format.format, format.channels,
-				     dest_format.channels, error)) {
+				     _dest_format.channels, error)) {
 		if (enable_format)
 			format_converter.Close();
 		if (enable_resampler)
@@ -96,6 +94,9 @@ PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format,
 		return false;
 	}
 
+	src_format = _src_format;
+	dest_format = _dest_format;
+
 	return true;
 }
 
diff --git a/src/playlist/PlaylistRegistry.cxx b/src/playlist/PlaylistRegistry.cxx
index bc5932d..4e9ef89 100644
--- a/src/playlist/PlaylistRegistry.cxx
+++ b/src/playlist/PlaylistRegistry.cxx
@@ -139,12 +139,12 @@ static SongEnumerator *
 playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
 			      const bool *tried)
 {
-	const char *suffix;
 	SongEnumerator *playlist = nullptr;
 
 	assert(uri != nullptr);
 
-	suffix = uri_get_suffix(uri);
+	UriSuffixBuffer suffix_buffer;
+	const char *const suffix = uri_get_suffix(uri, suffix_buffer);
 	if (suffix == nullptr)
 		return nullptr;
 
@@ -257,7 +257,10 @@ playlist_list_open_stream(InputStream &is, const char *uri)
 			return playlist;
 	}
 
-	const char *suffix = uri != nullptr ? uri_get_suffix(uri) : nullptr;
+	UriSuffixBuffer suffix_buffer;
+	const char *suffix = uri != nullptr
+		? uri_get_suffix(uri, suffix_buffer)
+		: nullptr;
 	if (suffix != nullptr) {
 		auto playlist = playlist_list_open_stream_suffix(is, suffix);
 		if (playlist != nullptr)
diff --git a/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx b/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
index fdd4357..93316ca 100644
--- a/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
+++ b/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
@@ -130,6 +130,7 @@ ExtM3uPlaylist::NextSong()
 
 static const char *const extm3u_suffixes[] = {
 	"m3u",
+	"m3u8",
 	nullptr
 };
 
diff --git a/src/playlist/plugins/M3uPlaylistPlugin.cxx b/src/playlist/plugins/M3uPlaylistPlugin.cxx
index a4125bc..0428d29 100644
--- a/src/playlist/plugins/M3uPlaylistPlugin.cxx
+++ b/src/playlist/plugins/M3uPlaylistPlugin.cxx
@@ -60,6 +60,7 @@ M3uPlaylist::NextSong()
 
 static const char *const m3u_suffixes[] = {
 	"m3u",
+	"m3u8",
 	nullptr
 };
 
diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx
index fdca47c..62977e9 100644
--- a/src/util/UriUtil.cxx
+++ b/src/util/UriUtil.cxx
@@ -54,6 +54,23 @@ uri_get_suffix(const char *uri)
 	return suffix;
 }
 
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer)
+{
+	const char *suffix = uri_get_suffix(uri);
+	if (suffix == nullptr)
+		return nullptr;
+
+	const char *q = strchr(suffix, '?');
+	if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
+		memcpy(buffer.data, suffix, q - suffix);
+		buffer.data[q - suffix] = 0;
+		suffix = buffer.data;
+	}
+
+	return suffix;
+}
+
 static const char *
 verify_uri_segment(const char *p)
 {
diff --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx
index c2cc97a..d478d5b 100644
--- a/src/util/UriUtil.hxx
+++ b/src/util/UriUtil.hxx
@@ -42,6 +42,17 @@ gcc_pure
 const char *
 uri_get_suffix(const char *uri);
 
+struct UriSuffixBuffer {
+	char data[8];
+};
+
+/**
+ * Returns the file name suffix, ignoring the query string.
+ */
+gcc_pure
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer);
+
 /**
  * Returns true if this is a safe "local" URI:
  *
diff --git a/test/DumpDatabase.cxx b/test/DumpDatabase.cxx
index d5b6f22..07f3423 100644
--- a/test/DumpDatabase.cxx
+++ b/test/DumpDatabase.cxx
@@ -33,7 +33,9 @@
 #include "event/Loop.hxx"
 #include "util/Error.hxx"
 
+#ifdef HAVE_GLIB
 #include <glib.h>
+#endif
 
 #include <iostream>
 using std::cout;
@@ -107,9 +109,11 @@ main(int argc, char **argv)
 
 	/* initialize GLib */
 
+#ifdef HAVE_GLIB
 #if !GLIB_CHECK_VERSION(2,32,0)
 	g_thread_init(nullptr);
 #endif
+#endif
 
 	/* initialize MPD */
 
diff --git a/test/read_mixer.cxx b/test/read_mixer.cxx
index 9752905..de77a00 100644
--- a/test/read_mixer.cxx
+++ b/test/read_mixer.cxx
@@ -28,7 +28,9 @@
 #include "util/Error.hxx"
 #include "Log.hxx"
 
+#ifdef HAVE_GLIB
 #include <glib.h>
+#endif
 
 #include <assert.h>
 #include <string.h>
@@ -50,9 +52,11 @@ int main(int argc, gcc_unused char **argv)
 		return EXIT_FAILURE;
 	}
 
+#ifdef HAVE_GLIB
 #if !GLIB_CHECK_VERSION(2,32,0)
 	g_thread_init(NULL);
 #endif
+#endif
 
 	EventLoop event_loop;
 
diff --git a/test/test_archive.cxx b/test/test_archive.cxx
index 3536995..1b15e30 100644
--- a/test/test_archive.cxx
+++ b/test/test_archive.cxx
@@ -7,8 +7,6 @@
 #include <cppunit/ui/text/TestRunner.h>
 #include <cppunit/extensions/HelperMacros.h>
 
-#include <glib.h>
-
 #include <string.h>
 #include <stdlib.h>
 
@@ -29,22 +27,22 @@ ArchiveLookupTest::TestArchiveLookup()
 	char *path = strdup("");
 	CPPUNIT_ASSERT_EQUAL(false,
 			     archive_lookup(path, &archive, &inpath, &suffix));
-	g_free(path);
+	free(path);
 
 	path = strdup(".");
 	CPPUNIT_ASSERT_EQUAL(false,
 			     archive_lookup(path, &archive, &inpath, &suffix));
-	g_free(path);
+	free(path);
 
 	path = strdup("config.h");
 	CPPUNIT_ASSERT_EQUAL(false,
 			     archive_lookup(path, &archive, &inpath, &suffix));
-	g_free(path);
+	free(path);
 
 	path = strdup("src/foo/bar");
 	CPPUNIT_ASSERT_EQUAL(false,
 			     archive_lookup(path, &archive, &inpath, &suffix));
-	g_free(path);
+	free(path);
 
 	path = strdup("Makefile/foo/bar");
 	CPPUNIT_ASSERT_EQUAL(true,
@@ -53,7 +51,7 @@ ArchiveLookupTest::TestArchiveLookup()
 	CPPUNIT_ASSERT_EQUAL(0, strcmp(archive, "Makefile"));
 	CPPUNIT_ASSERT_EQUAL(0, strcmp(inpath, "foo/bar"));
 	CPPUNIT_ASSERT_EQUAL((const char *)nullptr, suffix);
-	g_free(path);
+	free(path);
 
 	path = strdup("config.h/foo/bar");
 	CPPUNIT_ASSERT_EQUAL(true,
@@ -62,7 +60,7 @@ ArchiveLookupTest::TestArchiveLookup()
 	CPPUNIT_ASSERT_EQUAL(0, strcmp(archive, "config.h"));
 	CPPUNIT_ASSERT_EQUAL(0, strcmp(inpath, "foo/bar"));
 	CPPUNIT_ASSERT_EQUAL(0, strcmp(suffix, "h"));
-	g_free(path);
+	free(path);
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveLookupTest);
diff --git a/test/test_util.cxx b/test/test_util.cxx
index aaadec6..3e79aec 100644
--- a/test/test_util.cxx
+++ b/test/test_util.cxx
@@ -34,6 +34,25 @@ public:
 				     uri_get_suffix(".jpg"));
 		CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
 				     uri_get_suffix("/foo/.jpg"));
+
+		/* the first overload does not eliminate the query
+		   string */
+		CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string"),
+					       "jpg?query_string"));
+
+		/* ... but the second one does */
+		UriSuffixBuffer buffer;
+		CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string",
+							      buffer),
+					       "jpg"));
+
+		/* repeat some of the above tests with the second overload */
+		CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
+				     uri_get_suffix("/foo/bar", buffer));
+		CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
+				     uri_get_suffix("/foo.jpg/bar", buffer));
+		CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg", buffer),
+					       "jpg"));
 	}
 
 	void TestRemoveAuth() {
diff --git a/test/visit_archive.cxx b/test/visit_archive.cxx
index f5dba5c..1ff3ba4 100644
--- a/test/visit_archive.cxx
+++ b/test/visit_archive.cxx
@@ -30,7 +30,9 @@
 #include "fs/Path.hxx"
 #include "util/Error.hxx"
 
+#ifdef HAVE_GLIB
 #include <glib.h>
+#endif
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -57,9 +59,11 @@ main(int argc, char **argv)
 
 	/* initialize GLib */
 
+#ifdef HAVE_GLIB
 #if !GLIB_CHECK_VERSION(2,32,0)
 	g_thread_init(NULL);
 #endif
+#endif
 
 	/* initialize MPD */
 

--- End Message ---
--- Begin Message ---
Control: tag -1 wontfix

On Sun, Nov 02, 2014 at 11:05:59PM +0100, Florian Schlichting wrote:
> Package: release.debian.org
> Severity: normal
> User: release.debian.org@packages.debian.org
> Usertags: unblock
> 
> Please unblock / pre-approve package mpd
> 
> mpd 0.19.2 is a bugfix release in the stable mpd series. It fixes a
> number of issues that would be good to have fixed in a stable Debian
> release, only one of which (#767684, "Stack smashing
> detected in faad_decoder_init", important) has appeared in the Debian
> BTS yet.
> 
> mpd will need an unblock to fix a license incompatibility issue
> (#767504, serious), and I would like to fix as many important or
> yet-to-be filed important bugs in the same upload. I realize the 0.19.1
> to 0.19.2 diff (attached) is not very short and not strictly limited to
> important bugs, so I'm asking for pre-approval before uploading to
> unstable and hope for a favourable decision given that the freeze hasn't
> technically started yet.

No, sorry. I'm open to targetted fixes for freeze-compliant bugs, but not
this or the new proposed debdiff.

-- 
Jonathan Wiltshire                                      jmw@debian.org
Debian Developer                         http://people.debian.org/~jmw

4096R: 0xD3524C51 / 0A55 B7C5 1223 3942 86EC  74C3 5394 479D D352 4C51

Attachment: signature.asc
Description: Digital signature


--- End Message ---

Reply to: