From c71242d74362671af2da4bbfb3d92f69ee86f97d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 12 Mar 2020 20:40:18 +0100
Subject: [PATCH 1/5] playlist/asx: use tag_table to convert element name to
 TagType

---
 src/playlist/plugins/AsxPlaylistPlugin.cxx | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/src/playlist/plugins/AsxPlaylistPlugin.cxx b/src/playlist/plugins/AsxPlaylistPlugin.cxx
index 58c004b08..b4a198815 100644
--- a/src/playlist/plugins/AsxPlaylistPlugin.cxx
+++ b/src/playlist/plugins/AsxPlaylistPlugin.cxx
@@ -21,6 +21,7 @@
 #include "../PlaylistPlugin.hxx"
 #include "../MemorySongEnumerator.hxx"
 #include "tag/Builder.hxx"
+#include "tag/Table.hxx"
 #include "util/ASCII.hxx"
 #include "util/StringView.hxx"
 #include "lib/expat/ExpatParser.hxx"
@@ -62,6 +63,14 @@ struct AsxParser {
 
 };
 
+static constexpr struct tag_table asx_tag_elements[] = {
+	/* is that correct?  or should it be COMPOSER or PERFORMER? */
+	{ "author", TAG_ARTIST },
+
+	{ "title", TAG_TITLE },
+	{ nullptr, TAG_NUM_OF_ITEM_TYPES }
+};
+
 static void XMLCALL
 asx_start_element(void *user_data, const XML_Char *element_name,
 		  const XML_Char **atts)
@@ -84,12 +93,9 @@ asx_start_element(void *user_data, const XML_Char *element_name,
 				ExpatParser::GetAttributeCase(atts, "href");
 			if (href != nullptr)
 				parser->location = href;
-		} else if (StringEqualsCaseASCII(element_name, "author"))
-			/* is that correct?  or should it be COMPOSER
-			   or PERFORMER? */
-			parser->tag_type = TAG_ARTIST;
-		else if (StringEqualsCaseASCII(element_name, "title"))
-			parser->tag_type = TAG_TITLE;
+		} else
+			parser->tag_type = tag_table_lookup_i(asx_tag_elements,
+							      element_name);
 
 		break;
 	}

From 33694642bda981aa69f818fdc331f405df622443 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 12 Mar 2020 20:39:08 +0100
Subject: [PATCH 2/5] playlist/asx: add State::TAG

---
 src/playlist/plugins/AsxPlaylistPlugin.cxx | 26 ++++++++++++++--------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/src/playlist/plugins/AsxPlaylistPlugin.cxx b/src/playlist/plugins/AsxPlaylistPlugin.cxx
index b4a198815..daaaa18dd 100644
--- a/src/playlist/plugins/AsxPlaylistPlugin.cxx
+++ b/src/playlist/plugins/AsxPlaylistPlugin.cxx
@@ -42,6 +42,7 @@ struct AsxParser {
 	 */
 	enum {
 		ROOT, ENTRY,
+		TAG,
 	} state;
 
 	/**
@@ -82,7 +83,6 @@ asx_start_element(void *user_data, const XML_Char *element_name,
 		if (StringEqualsCaseASCII(element_name, "entry")) {
 			parser->state = AsxParser::ENTRY;
 			parser->location.clear();
-			parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
 		}
 
 		break;
@@ -93,11 +93,17 @@ asx_start_element(void *user_data, const XML_Char *element_name,
 				ExpatParser::GetAttributeCase(atts, "href");
 			if (href != nullptr)
 				parser->location = href;
-		} else
+		} else {
 			parser->tag_type = tag_table_lookup_i(asx_tag_elements,
 							      element_name);
+			if (parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
+				parser->state = AsxParser::TAG;
+		}
 
 		break;
+
+	case AsxParser::TAG:
+		break;
 	}
 }
 
@@ -117,10 +123,13 @@ asx_end_element(void *user_data, const XML_Char *element_name)
 							    parser->tag_builder.Commit());
 
 			parser->state = AsxParser::ROOT;
-		} else
-			parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
+		}
 
 		break;
+
+	case AsxParser::TAG:
+		parser->state = AsxParser::ENTRY;
+		break;
 	}
 }
 
@@ -131,13 +140,12 @@ asx_char_data(void *user_data, const XML_Char *s, int len)
 
 	switch (parser->state) {
 	case AsxParser::ROOT:
+	case AsxParser::ENTRY:
 		break;
 
-	case AsxParser::ENTRY:
-		if (parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
-			parser->tag_builder.AddItem(parser->tag_type,
-						    StringView(s, len));
-
+	case AsxParser::TAG:
+		parser->tag_builder.AddItem(parser->tag_type,
+					    StringView(s, len));
 		break;
 	}
 }

From 82743dfd025ffb6841f61559a5cea3d75f9fd3ce Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 12 Mar 2020 21:07:37 +0100
Subject: [PATCH 3/5] playlist/asx: concatenate multiple CharacterData
 fragments

Similar to c45f1138560b526649bf6e6433fa7d9ba8a6564b
---
 NEWS                                       |  2 +-
 src/playlist/plugins/AsxPlaylistPlugin.cxx | 12 ++++++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index 7cf1248d3..9a0ecc0c5 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,7 @@ ver 0.21.21 (not yet released)
 * configuration
   - fix bug in "metadata_to_use" setting
 * playlist
-  - xspf: fix corrupt tags in the presence of XML entities
+  - asx, xspf: fix corrupt tags in the presence of XML entities
 * archive
   - iso9660: skip empty file names to work around libcdio bug
 * decoder
diff --git a/src/playlist/plugins/AsxPlaylistPlugin.cxx b/src/playlist/plugins/AsxPlaylistPlugin.cxx
index daaaa18dd..ec365fe36 100644
--- a/src/playlist/plugins/AsxPlaylistPlugin.cxx
+++ b/src/playlist/plugins/AsxPlaylistPlugin.cxx
@@ -59,6 +59,8 @@ struct AsxParser {
 
 	TagBuilder tag_builder;
 
+	std::string value;
+
 	AsxParser()
 		:state(ROOT) {}
 
@@ -77,6 +79,7 @@ asx_start_element(void *user_data, const XML_Char *element_name,
 		  const XML_Char **atts)
 {
 	AsxParser *parser = (AsxParser *)user_data;
+	parser->value.clear();
 
 	switch (parser->state) {
 	case AsxParser::ROOT:
@@ -128,9 +131,15 @@ asx_end_element(void *user_data, const XML_Char *element_name)
 		break;
 
 	case AsxParser::TAG:
+		if (!parser->value.empty())
+			parser->tag_builder.AddItem(parser->tag_type,
+						    StringView(parser->value.data(),
+							       parser->value.length()));
 		parser->state = AsxParser::ENTRY;
 		break;
 	}
+
+	parser->value.clear();
 }
 
 static void XMLCALL
@@ -144,8 +153,7 @@ asx_char_data(void *user_data, const XML_Char *s, int len)
 		break;
 
 	case AsxParser::TAG:
-		parser->tag_builder.AddItem(parser->tag_type,
-					    StringView(s, len));
+		parser->value.append(s, len);
 		break;
 	}
 }

From 56c234b4105f56c77d10746ee2720bd8128569ee Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 19 Mar 2020 13:30:46 +0100
Subject: [PATCH 4/5] raise default "max_connections" value to 100

Documentation says the limit is 5, but it was really 10 (at least
since 2004).  But since MPD wants to promote using many small clients
idling around, and these clients consume only very few resources, it
seems reasonable to raise this limit's default value.
---
 NEWS         | 1 +
 doc/user.rst | 2 +-
 src/Main.cxx | 2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index 9a0ecc0c5..1ad372958 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ ver 0.21.21 (not yet released)
   - gme: ignore empty tags
 * output
   - solaris: port to NetBSD
+* raise default "max_connections" value to 100
 
 ver 0.21.20 (2020/02/16)
 * decoder
diff --git a/doc/user.rst b/doc/user.rst
index 3ddb35610..f2ea36697 100644
--- a/doc/user.rst
+++ b/doc/user.rst
@@ -695,7 +695,7 @@ These settings are various limitations to prevent :program:`MPD` from using too
    * - **connection_timeout SECONDS**
      - If a client does not send any new data in this time period, the connection is closed. Clients waiting in "idle" mode are excluded from this. Default is 60.
    * - **max_connections NUMBER**
-     - This specifies the maximum number of clients that can be connected to :program:`MPD` at the same time. Default is 5.
+     - This specifies the maximum number of clients that can be connected to :program:`MPD` at the same time. Default is 100.
    * - **max_playlist_length NUMBER**
      - The maximum number of songs that can be in the playlist. Default is 16384.
    * - **max_command_list_size KBYTES**
diff --git a/src/Main.cxx b/src/Main.cxx
index 686813c1c..7ca83c111 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -460,7 +460,7 @@ MainOrThrow(int argc, char *argv[])
 #endif
 
 	const unsigned max_clients =
-		raw_config.GetPositive(ConfigOption::MAX_CONN, 10);
+		raw_config.GetPositive(ConfigOption::MAX_CONN, 100);
 	instance->client_list = new ClientList(max_clients);
 
 	initialize_decoder_and_player(raw_config, config.replay_gain);

From c560ec8ea65f7640fbf05b6c129ed0ade393f1fd Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 19 Mar 2020 15:22:28 +0100
Subject: [PATCH 5/5] release v0.21.21

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

diff --git a/NEWS b/NEWS
index 1ad372958..47b6ff01d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-ver 0.21.21 (not yet released)
+ver 0.21.21 (2020/03/19)
 * configuration
   - fix bug in "metadata_to_use" setting
 * playlist