[xiph-commits] r11146 - icecast/branches/kh/icecast/src

karl at svn.xiph.org karl at svn.xiph.org
Sun Apr 16 16:22:31 PDT 2006


Author: karl
Date: 2006-04-16 16:22:20 -0700 (Sun, 16 Apr 2006)
New Revision: 11146

Modified:
   icecast/branches/kh/icecast/src/admin.c
   icecast/branches/kh/icecast/src/auth.c
   icecast/branches/kh/icecast/src/auth.h
   icecast/branches/kh/icecast/src/auth_url.c
   icecast/branches/kh/icecast/src/cfgfile.c
   icecast/branches/kh/icecast/src/cfgfile.h
   icecast/branches/kh/icecast/src/connection.c
   icecast/branches/kh/icecast/src/format_flac.c
   icecast/branches/kh/icecast/src/format_midi.c
   icecast/branches/kh/icecast/src/format_mp3.c
   icecast/branches/kh/icecast/src/format_mp3.h
   icecast/branches/kh/icecast/src/format_ogg.c
   icecast/branches/kh/icecast/src/format_ogg.h
   icecast/branches/kh/icecast/src/format_speex.c
   icecast/branches/kh/icecast/src/format_theora.c
   icecast/branches/kh/icecast/src/format_vorbis.c
   icecast/branches/kh/icecast/src/slave.c
   icecast/branches/kh/icecast/src/source.c
   icecast/branches/kh/icecast/src/xslt.c
Log:
various bits collected, so better commit -
. allow filtering of a theora logical stream before pushing onto queue.
. allow conversion of mp3 metadata from a specified charset to UTF8 for stats/log
. handle content type better from xsl pages.
. handle 403 return from auth url backend, also allow the message header to contain
a '403 message' for the listener.
. allow a port-based shoutcast-mount, allows multiple sc source clients and removes
the need to define a second port.
. xml parsing re-organised. lets see how this works out


Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/admin.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -394,27 +394,29 @@
     if (strcmp (uri, "/admin.cgi") != 0 && strncmp("/admin/", uri, 7) != 0)
         return -1;
 
+    mount = httpp_get_query_param(client->parser, "mount");
+
     if (strcmp (uri, "/admin.cgi") == 0)
     {
-        ice_config_t *config;
         char *pass = httpp_get_query_param (client->parser, "pass");
         if (pass == NULL)
         {
             client_send_400 (client, "missing pass parameter");
             return 0;
         }
-        config = config_get_config ();
-        httpp_set_query_param (client->parser, "mount", config->shoutcast_mount);
+        if (mount)
+        {
+            ice_config_t *config = config_get_config ();
+            httpp_set_query_param (client->parser, "mount", config->shoutcast_mount);
+            config_release_config ();
+        }
         httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY");
         httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass);
-        config_release_config ();
     }
 
     if (connection_check_admin_pass (client->parser))
         client->authenticated = 1;
 
-    mount = httpp_get_query_param(client->parser, "mount");
-
     if (mount)
     {
         /* certain commands may not need auth */

Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/auth.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -370,6 +370,7 @@
     source->active_clients = client;
     source->listeners++;
     stats_event_inc (NULL, "listener_connections");
+    stats_event_inc (source->mount, "listener_connections");
 
     thread_mutex_unlock (&source->lock);
 
@@ -585,15 +586,16 @@
 }
 
 
-auth_t *auth_get_authenticator (xmlNodePtr node)
+int auth_get_authenticator (xmlNodePtr node, void *x)
 {
     auth_t *auth = calloc (1, sizeof (auth_t));
     config_options_t *options = NULL, **next_option = &options;
     xmlNodePtr option;
 
     if (auth == NULL)
-        return NULL;
+        return -1;
 
+    *(auth_t**)x = auth;
     option = node->xmlChildrenNode;
     while (option)
     {
@@ -633,7 +635,7 @@
         xmlFree (opt->value);
         free (opt);
     }
-    return auth;
+    return 0;
 }
 
 

Modified: icecast/branches/kh/icecast/src/auth.h
===================================================================
--- icecast/branches/kh/icecast/src/auth.h	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/auth.h	2006-04-16 23:22:20 UTC (rev 11146)
@@ -86,7 +86,7 @@
 void auth_initialise (void);
 void auth_shutdown (void);
 
-auth_t  *auth_get_authenticator (xmlNodePtr node);
+int auth_get_authenticator (xmlNodePtr node, void *x);
 void    auth_release (auth_t *authenticator);
 
 /* call to send a url request when source starts */

Modified: icecast/branches/kh/icecast/src/auth_url.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/auth_url.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -132,6 +132,18 @@
     {
         auth_t *auth = client->auth;
         auth_url *url = auth->state;
+        int retcode = 0;
+
+        if (sscanf (ptr, "HTTP/%*u.%*u %3d %*c", &retcode) == 1)
+        {
+            if (retcode == 403)
+            {
+                char *p = strchr (ptr, ' ') + 1;
+                snprintf (url->errormsg, sizeof(url->errormsg), p);
+                p = strchr (url->errormsg, '\r');
+                if (p) *p='\0';
+            }
+        }
         if (strncasecmp (ptr, url->auth_header, url->auth_header_len) == 0)
             client->authenticated = 1;
         if (strncasecmp (ptr, url->timelimit_header, url->timelimit_header_len) == 0)
@@ -332,6 +344,11 @@
     /* we received a response, lets see what it is */
     if (client->authenticated)
         return AUTH_OK;
+    if (atoi (url->errormsg) == 403)
+    {
+        client_send_403 (client, url->errormsg+4);
+        auth_user->client = NULL;
+    }
     INFO2 ("client auth (%s) failed with \"%s\"", url->addurl, url->errormsg);
     return AUTH_FAILED;
 }

Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/cfgfile.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -72,19 +72,7 @@
 static ice_config_locks _locks;
 
 static void _set_defaults(ice_config_t *c);
-static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, 
-        ice_config_t *c);
-static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
-static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, 
-        ice_config_t *c);
-static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
+static int  _parse_root (xmlNodePtr node, ice_config_t *config);
 
 static void create_locks(void) {
     thread_mutex_create("relay lock", &_locks.relay_lock);
@@ -96,6 +84,85 @@
     thread_rwlock_destroy(&_locks.config_lock);
 }
 
+/* 
+ */
+struct cfg_tag
+{
+    const char *name;
+    int (*retrieve) (xmlNodePtr node, void *x);
+    void *storage;
+};
+
+
+/* Process xml node for boolean value, it may be true, yes, or 1
+ */
+int config_get_bool (xmlNodePtr node, void *x)
+{   
+    char *str = (char *)xmlNodeListGetString (node->doc, node->xmlChildrenNode, 1);
+    if (str == NULL)
+        return -1;
+    if (strcasecmp (str, "true") == 0)
+        *(int*)x = 1;
+    else
+        if (strcasecmp (str, "yes") == 0)
+            *(int*)x = 1;
+        else
+            *(int*)x = strtol (str, NULL, 0)==0 ? 0 : 1;
+    xmlFree (str);
+    return 0;
+}
+
+int config_get_str (xmlNodePtr node, void *x)
+{
+    xmlChar *str = xmlNodeListGetString (node->doc, node->xmlChildrenNode, 1);
+    xmlChar *p = *(xmlChar**)x;
+    if (str == NULL)
+        return -1;
+    if (p)
+        xmlFree (p);
+    *(char **)x = str;
+    return 0;
+}
+
+int config_get_int (xmlNodePtr node, void *x)
+{
+    xmlChar *str = xmlNodeListGetString (node->doc, node->xmlChildrenNode, 1);
+    if (str == NULL)
+        return -1;
+    *(int*)x = strtol ((char*)str, NULL, 0);
+    return 0;
+}
+
+
+int parse_xml_tags (xmlNodePtr parent, const struct cfg_tag *args)
+{
+    int ret = 0;
+    xmlNodePtr node = parent->xmlChildrenNode;
+
+    for (; node != NULL && ret == 0; node = node->next)
+    {
+        const struct cfg_tag *argp;
+
+        if (xmlIsBlankNode (node) || strcmp ((char*)node->name, "comment") == 0 ||
+                strcmp ((char*)node->name, "text") == 0)
+            continue;
+        argp = args;
+        while (argp->name)
+        {
+            if (strcmp ((const char*)node->name, argp->name) == 0)
+            {
+                ret = argp->retrieve (node, argp->storage);
+                break;
+            }
+            argp++;
+        }
+        if (argp->name == NULL)
+            WARN2 ("unknown element \"%s\" parsing \"%s\"\n", node->name, parent->name);
+    }
+    return ret;
+}
+
+
 void config_initialize(void) {
     create_locks();
 }
@@ -293,7 +360,7 @@
 
     configuration->config_filename = (char *)strdup(filename);
 
-    _parse_root(doc, node->xmlChildrenNode, configuration);
+    _parse_root (node, configuration);
 
     xmlFreeDoc(doc);
 
@@ -339,7 +406,7 @@
 
 static void _set_defaults(ice_config_t *configuration)
 {
-    configuration->location = CONFIG_DEFAULT_LOCATION;
+    configuration->location = xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
     configuration->server_id = (char *)xmlCharStrdup (ICECAST_VERSION_STRING);
     configuration->admin = CONFIG_DEFAULT_ADMIN;
     configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT;
@@ -350,13 +417,13 @@
     configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
     configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
     configuration->source_password = CONFIG_DEFAULT_SOURCE_PASSWORD;
-    configuration->shoutcast_mount = CONFIG_DEFAULT_SHOUTCAST_MOUNT;
+    configuration->shoutcast_mount = xmlCharStrdup (CONFIG_DEFAULT_SHOUTCAST_MOUNT);
     configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
     configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
     configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
     configuration->on_demand = 0;
     configuration->dir_list = NULL;
-    configuration->hostname = CONFIG_DEFAULT_HOSTNAME;
+    configuration->hostname = xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
     configuration->port = 0;
     configuration->listeners[0].port = 0;
     configuration->listeners[0].bind_address = NULL;
@@ -367,13 +434,13 @@
     configuration->master_username = (char*)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
     configuration->master_password = NULL;
     configuration->master_relay_auth = 0;
-    configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
-    configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
-    configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
-    configuration->adminroot_dir = CONFIG_DEFAULT_ADMINROOT_DIR;
-    configuration->playlist_log = CONFIG_DEFAULT_PLAYLIST_LOG;
-    configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
-    configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
+    configuration->base_dir = xmlCharStrdup (CONFIG_DEFAULT_BASE_DIR);
+    configuration->log_dir = xmlCharStrdup (CONFIG_DEFAULT_LOG_DIR);
+    configuration->webroot_dir = xmlCharStrdup (CONFIG_DEFAULT_WEBROOT_DIR);
+    configuration->adminroot_dir = xmlCharStrdup (CONFIG_DEFAULT_ADMINROOT_DIR);
+    configuration->playlist_log = xmlCharStrdup (CONFIG_DEFAULT_PLAYLIST_LOG);
+    configuration->access_log = xmlCharStrdup (CONFIG_DEFAULT_ACCESS_LOG);
+    configuration->error_log = xmlCharStrdup (CONFIG_DEFAULT_ERROR_LOG);
     configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
     configuration->chroot = CONFIG_DEFAULT_CHROOT;
     configuration->chuid = CONFIG_DEFAULT_CHUID;
@@ -387,719 +454,374 @@
     configuration->burst_size = CONFIG_DEFAULT_BURST_SIZE;
 }
 
-static void _parse_root(xmlDocPtr doc, xmlNodePtr node, 
-        ice_config_t *configuration)
+
+static int _parse_alias (xmlNodePtr node, void *arg)
 {
-    char *tmp;
+    ice_config_t *config = arg;
+    aliases **cur, *alias = calloc (1, sizeof (aliases));
+    xmlChar *temp;
+    
+    alias->source = xmlGetProp (node, "source");
+    alias->destination = xmlGetProp (node, "dest");
+    if (alias->source == NULL || alias->destination == NULL)
+    {
+        if (alias->source) xmlFree (alias->source);
+        if (alias->destination) xmlFree (alias->destination);
+        free (alias);
+        WARN0 ("incomplete alias definition");
+        return -1;
+    }
+    alias->bind_address = xmlGetProp (node, "bind-address");
+    temp = xmlGetProp(node, "port");
+    alias->port = -1;
+    if (temp)
+    {
+        alias->port = atoi ((char*)temp);
+        xmlFree (temp);
+    }
+    cur = &config->aliases;
+    while (*cur) cur = &((*cur)->next);
+    *cur = alias;
+    return 0;
+}
 
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
+static int _parse_authentication (xmlNodePtr node, void *arg)
+{
+    ice_config_t *config = arg;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "source-password",    config_get_str,     &config->source_password },
+        { "admin-user",         config_get_str,     &config->admin_username },
+        { "admin-password",     config_get_str,     &config->admin_password },
+        { "relay-user",         config_get_str,     &config->relay_username },
+        { "relay-password",     config_get_str,     &config->relay_password },
+        { NULL, NULL, NULL }
+    };
 
-        if (xmlStrcmp(node->name, XMLSTR ("location")) == 0) {
-            if (configuration->location && configuration->location != CONFIG_DEFAULT_LOCATION) xmlFree(configuration->location);
-            configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("admin")) == 0) {
-            if (configuration->admin && configuration->admin != CONFIG_DEFAULT_ADMIN) xmlFree(configuration->admin);
-            configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("server_id")) == 0) {
-            xmlFree (configuration->server_id);
-            configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if(xmlStrcmp(node->name, XMLSTR ("authentication")) == 0) {
-            _parse_authentication(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("source-password")) == 0) {
-            /* TODO: This is the backwards-compatibility location */
-            char *mount, *pass;
-            if ((mount = (char *)xmlGetProp(node, XMLSTR ("mount"))) != NULL) {
-                pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-                /* FIXME: This is a placeholder for per-mount passwords */
-            }
-            else {
-                if (configuration->source_password && configuration->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) xmlFree(configuration->source_password);
-                configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            }
-        } else if (xmlStrcmp(node->name, XMLSTR ("icelogin")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->ice_login = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("fileserve")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->fileserve = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("relays-on-demand")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->on_demand = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("hostname")) == 0) {
-            if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname);
-            configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("listen-socket")) == 0) {
-            _parse_listen_socket(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("port")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->port = atoi(tmp);
-            configuration->listeners[0].port = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("bind-address")) == 0) {
-            if (configuration->listeners[0].bind_address) 
-                xmlFree(configuration->listeners[0].bind_address);
-            configuration->listeners[0].bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-server")) == 0) {
-            if (configuration->master_server) xmlFree(configuration->master_server);
-            configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-username")) == 0) {
-            if (configuration->master_username) xmlFree(configuration->master_username);
-            configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-password")) == 0) {
-            if (configuration->master_password) xmlFree(configuration->master_password);
-            configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-server-port")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->master_server_port = atoi(tmp);
-            xmlFree (tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-update-interval")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->master_update_interval = atoi(tmp);
-            xmlFree (tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-relay-auth")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->master_relay_auth = atoi(tmp);
-            xmlFree (tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-ssl-port")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->master_ssl_port = atoi(tmp);
-            xmlFree (tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("master-redirect")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->master_redirect = atoi(tmp);
-            xmlFree (tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("max-redirect-slaves")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->max_redirects = atoi(tmp);
-            xmlFree (tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("shoutcast-mount")) == 0) {
-            if (configuration->shoutcast_mount &&
-                    configuration->shoutcast_mount != CONFIG_DEFAULT_SHOUTCAST_MOUNT)
-                xmlFree(configuration->shoutcast_mount);
-            configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("limits")) == 0) {
-            _parse_limits(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("relay")) == 0) {
-            _parse_relay(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("mount")) == 0) {
-            _parse_mount(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("directory")) == 0) {
-            _parse_directory(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("paths")) == 0) {
-            _parse_paths(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("logging")) == 0) {
-            _parse_logging(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("security")) == 0) {
-            _parse_security(doc, node->xmlChildrenNode, configuration);
-        }
-    } while ((node = node->next));
-    if (configuration->max_redirects == 0 && configuration->master_redirect)
-        configuration->max_redirects = 1;
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    return 0;
 }
 
-static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, 
-        ice_config_t *configuration)
+static int _parse_chown (xmlNodePtr node, void *arg)
 {
-    char *tmp;
+    ice_config_t *config = arg;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "user",   config_get_str, &config->user },
+        { "group",  config_get_str, &config->group },
+        { NULL, NULL, NULL }
+    };
 
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    return 0;
+}
 
-        if (xmlStrcmp(node->name, XMLSTR ("clients")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->client_limit = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("sources")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->source_limit = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("queue-size")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->queue_size_limit = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("client-timeout")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->client_timeout = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("header-timeout")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->header_timeout = atoi(tmp);
-            if (configuration->header_timeout < 0 || configuration->header_timeout > 60)
-                configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR("source-timeout")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->source_timeout = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR("burst-on-connect")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            if (atoi(tmp) == 0)
-                configuration->burst_size = 0;
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR("burst-size")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->burst_size = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        }
-    } while ((node = node->next));
+static int _parse_security (xmlNodePtr node, void *arg)
+{
+    ice_config_t *config = arg;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "chroot",         config_get_bool,    &config->chroot },
+        { "changeowner",    _parse_chown,       config },
+        { NULL, NULL, NULL }
+    };
+
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    return 0;
 }
 
-static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, 
-        ice_config_t *configuration)
+static int _parse_logging (xmlNodePtr node, void *arg)
 {
-    char *tmp;
+    ice_config_t *config = arg;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "accesslog",      config_get_str,     &config->access_log },
+        { "accesslog_lines",
+                            config_get_int,     &config->access_log_lines },
+        { "errorlog",       config_get_str,     &config->error_log },
+        { "errorlog_lines", config_get_int,     &config->error_log_lines },
+        { "playlistlog",    config_get_str,     &config->access_log },
+        { "playlistlog_lines",
+                            config_get_int,     &config->playlist_log_lines },
+        { "logsize",        config_get_int,     &config->logsize },
+        { "loglevel",       config_get_int,     &config->loglevel },
+        { "logarchive",     config_get_bool,    &config->logarchive },
+        { NULL, NULL, NULL }
+    };
+
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    return 0;
+}
+
+static int _parse_paths (xmlNodePtr node, void *arg)
+{
+    ice_config_t *config = arg;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "basedir",    config_get_str, &config->base_dir },
+        { "logdir",     config_get_str, &config->log_dir },
+        { "pidfile",    config_get_str, &config->pidfile },
+        { "ssl_certificate",
+                        config_get_str, &config->cert_file },
+        { "webroot",    config_get_str, &config->webroot_dir },
+        { "adminroot",  config_get_str, &config->adminroot_dir },
+        { "alias",      _parse_alias,   config },
+        { NULL, NULL, NULL }
+    };
+
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    return 0;
+}
+
+static int _parse_directory (xmlNodePtr node, void *arg)
+{
+    ice_config_t *config = arg;
+
+    struct cfg_tag icecast_tags[] =
+    {
+        { "yp-url",         config_get_str, &config->yp_url [config->num_yp_directories]},
+        { "yp-url-timeout", config_get_int, &config->yp_url_timeout [config->num_yp_directories]},
+        { "touch-interval", config_get_int, &config->yp_touch_interval [config->num_yp_directories]},
+        { NULL, NULL, NULL }
+    };
+
+    if (config->num_yp_directories >= MAX_YP_DIRECTORIES)
+    {
+        ERROR0("Maximum number of yp directories exceeded!");
+        return -1;
+    }
+
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    config->num_yp_directories++;
+    return 0;
+}
+
+
+static int _parse_mount (xmlNodePtr node, void *arg)
+{
+    ice_config_t *config = arg;
     mount_proxy *mount = calloc(1, sizeof(mount_proxy));
-    mount_proxy *current = configuration->mounts;
-    mount_proxy *last=NULL;
-    
+
+    struct cfg_tag icecast_tags[] =
+    {
+        { "mount-name",     config_get_str,     &mount->mountname },
+        { "source-timeout", config_get_int,     &mount->source_timeout },
+        { "queue-size",     config_get_int,     &mount->queue_size_limit },
+        { "burst-size",     config_get_int,     &mount->burst_size},
+        { "username",       config_get_str,     &mount->username },
+        { "password",       config_get_str,     &mount->password },
+        { "dump-file",      config_get_str,     &mount->dumpfile },
+        { "intro",          config_get_str,     &mount->intro_filename },
+        { "fallback-mount", config_get_str,     &mount->fallback_mount },
+        { "fallback-override",
+                            config_get_bool,    &mount->fallback_override },
+        { "fallback-when-full",
+                            config_get_bool,    &mount->fallback_when_full },
+        { "max-listeners",  config_get_int,     &mount->max_listeners },
+        { "filter-theora",  config_get_bool,    &mount->filter_theora },
+        { "mp3-metadata-charset",
+                            config_get_str,     &mount->mp3_charset },
+        { "mp3-metadata-interval",
+                            config_get_int,     &mount->mp3_meta_interval },
+        { "no-mount",       config_get_bool,    &mount->no_mount },
+        { "hidden",         config_get_bool,    &mount->hidden },
+        { "authentication", auth_get_authenticator,
+                                                &mount->auth },
+        { "on-connect",     config_get_str,     &mount->on_connect },
+        { "on-disconnect",  config_get_str,     &mount->on_disconnect },
+        { "max-listener-duration",
+                            config_get_int,     &mount->max_listener_duration },
+        /* YP settings */
+        { "cluster-password",
+                            config_get_str,     &mount->cluster_password },
+        { "stream-name",    config_get_str,     &mount->stream_name },
+        { "stream-description",
+                            config_get_str,     &mount->stream_description },
+        { "stream-url",     config_get_str,     &mount->stream_url },
+        { "genre",          config_get_str,     &mount->stream_genre },
+        { "bitrate",        config_get_str,     &mount->bitrate },
+        { "public",         config_get_bool,    &mount->yp_public },
+        { "type",           config_get_str,     &mount->type },
+        { "subtype",        config_get_str,     &mount->subtype },
+        { NULL, NULL, NULL },
+    };
+
     /* default <mount> settings */
     mount->max_listeners = -1;
     mount->burst_size = -1;
     mount->mp3_meta_interval = -1;
     mount->yp_public = -1;
-    mount->next = NULL;
 
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
-
-        if (xmlStrcmp(node->name, XMLSTR ("mount-name")) == 0) {
-            mount->mountname = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("username")) == 0) {
-            mount->username = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("password")) == 0) {
-            mount->password = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("dump-file")) == 0) {
-            mount->dumpfile = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("intro")) == 0) {
-            mount->intro_filename = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("fallback-mount")) == 0) {
-            mount->fallback_mount = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("fallback-when-full")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->fallback_when_full = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("max-listeners")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->max_listeners = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("mp3-metadata-interval")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->mp3_meta_interval = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("fallback-override")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->fallback_override = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("no-mount")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->no_mount = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("no-yp")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->yp_public = atoi(tmp)==0 ? -1 : 0;
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("hidden")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->hidden = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("authentication")) == 0) {
-            mount->auth = auth_get_authenticator (node);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("on-connect")) == 0) {
-            mount->on_connect = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("on-disconnect")) == 0) {
-            mount->on_disconnect = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("max-listener-duration")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->max_listener_duration = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("queue-size")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->queue_size_limit = atoi (tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("source-timeout")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            if (tmp)
-            {
-                mount->source_timeout = atoi (tmp);
-                xmlFree(tmp);
-            }
-        } else if (xmlStrcmp(node->name, XMLSTR ("burst-size")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->burst_size = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("cluster-password")) == 0) {
-            mount->cluster_password = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("stream-name")) == 0) {
-            mount->stream_name = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("stream-description")) == 0) {
-            mount->stream_description = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("stream-url")) == 0) {
-            mount->stream_url = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("genre")) == 0) {
-            mount->stream_genre = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("bitrate")) == 0) {
-            mount->bitrate = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("public")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            mount->yp_public = atoi (tmp);
-            if(tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("type")) == 0) {
-            mount->type = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("subtype")) == 0) {
-            mount->subtype = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-    } while ((node = node->next));
-
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    
     if (mount->mountname == NULL)
     {
         config_clear_mount (mount);
-        return;
+        return -1;
     }
-    while(current) {
-        last = current;
-        current = current->next;
-    }
 
-    if(last)
-        last->next = mount;
-    else
-        configuration->mounts = mount;
+    mount->next = config->mounts;
+    config->mounts = mount;
+
+    return 0;
 }
 
 
-static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
+static int _parse_relay (xmlNodePtr node, void *arg)
 {
-    char *tmp;
+    ice_config_t *config = arg;
     relay_server *relay = calloc(1, sizeof(relay_server));
 
-    relay->next = NULL;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "server",         config_get_str,     &relay->server },
+        { "port",           config_get_int,     &relay->port },
+        { "mount",          config_get_str,     &relay->mount },
+        { "local-mount",    config_get_str,     &relay->localmount },
+        { "on-demand",      config_get_bool,    &relay->on_demand },
+        { "relay-shoutcast-metadata",
+                            config_get_bool,    &relay->mp3metadata },
+        { "username",       config_get_str,     &relay->username },
+        { "password",       config_get_str,     &relay->password },
+        { "enable",         config_get_bool,    &relay->enable },
+        { NULL, NULL, NULL },
+    };
+
     relay->mp3metadata = 1;
     relay->enable = 1;
-    relay->on_demand = configuration->on_demand;
-    relay->port = 8000;
+    relay->on_demand = config->on_demand;
+    relay->port = config->port;
 
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
 
-        if (xmlStrcmp(node->name, XMLSTR ("server")) == 0) {
-            relay->server = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("port")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            relay->port = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("mount")) == 0) {
-            relay->mount = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("local-mount")) == 0) {
-            relay->localmount = (char *)xmlNodeListGetString(
-                    doc, node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("relay-shoutcast-metadata")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            relay->mp3metadata = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("username")) == 0) {
-            relay->username = (char *)xmlNodeListGetString(doc,
-                    node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("password")) == 0) {
-            relay->password = (char *)xmlNodeListGetString(doc,
-                    node->xmlChildrenNode, 1);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("on-demand")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            relay->on_demand = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("enable")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            relay->enable = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        }
-    } while ((node = node->next));
-
+    /* check for undefined entries */
     if (relay->server == NULL)
-    {
-        config_clear_relay (relay);
-        return;
-    }
+        relay->server = (char *)xmlCharStrdup ("127.0.0.1");
     if (relay->mount == NULL)
         relay->mount = (char*)xmlCharStrdup ("/");
-
     if (relay->localmount == NULL)
         relay->localmount = (char*)xmlCharStrdup (relay->mount);
 
-    relay->next = configuration->relay;
-    configuration->relay = relay;
-}
+    relay->next = config->relay;
+    config->relay = relay;
 
-static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
-{
-    listener_t *listener = NULL;
-    int i;
-    char *tmp;
-
-    for(i=0; i < MAX_LISTEN_SOCKETS; i++) {
-        if(configuration->listeners[i].port <= 0) {
-            listener = &(configuration->listeners[i]);
-            break;
-        }
-    }
-
-    if (listener == NULL)
-        return;
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
-
-        if (xmlStrcmp(node->name, XMLSTR ("port")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            if(configuration->port == 0)
-                configuration->port = atoi(tmp);
-            listener->port = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("shoutcast-compat")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            listener->shoutcast_compat = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("ssl")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            listener->ssl = atoi(tmp);
-            if(tmp) xmlFree(tmp);
-        }
-        else if (xmlStrcmp(node->name, XMLSTR ("bind-address")) == 0) {
-            listener->bind_address = (char *)xmlNodeListGetString(doc, 
-                    node->xmlChildrenNode, 1);
-        }
-    } while ((node = node->next));
+    return 0;
 }
 
-static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
+static int _parse_limits (xmlNodePtr node, void *arg)
 {
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
+    ice_config_t *config = arg;
 
-        if (xmlStrcmp(node->name, XMLSTR ("source-password")) == 0) {
-            char *mount, *pass;
-            if ((mount = (char *)xmlGetProp(node, XMLSTR ("mount"))) != NULL) {
-                pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-                /* FIXME: This is a placeholder for per-mount passwords */
-            }
-            else {
-                if (configuration->source_password && 
-                        configuration->source_password != 
-                        CONFIG_DEFAULT_SOURCE_PASSWORD) 
-                    xmlFree(configuration->source_password);
-                configuration->source_password = 
-                    (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            }
-        } else if (xmlStrcmp(node->name, XMLSTR ("admin-password")) == 0) {
-            if(configuration->admin_password)
-                xmlFree(configuration->admin_password);
-            configuration->admin_password =
-                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("admin-user")) == 0) {
-            if(configuration->admin_username)
-                xmlFree(configuration->admin_username);
-            configuration->admin_username =
-                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("relay-password")) == 0) {
-            if(configuration->relay_password)
-                xmlFree(configuration->relay_password);
-            configuration->relay_password =
-                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("relay-user")) == 0) {
-            if(configuration->relay_username)
-                xmlFree(configuration->relay_username);
-            configuration->relay_username =
-                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        }
-    } while ((node = node->next));
+    struct cfg_tag icecast_tags[] =
+    {
+        { "clients",        config_get_int,    &config->client_limit },
+        { "sources",        config_get_int,    &config->source_limit },
+        { "queue-size",     config_get_int,    &config->queue_size_limit },
+        { "burst-size",     config_get_int,    &config->burst_size },
+        { "client-timeout", config_get_int,    &config->client_timeout },
+        { "header-timeout", config_get_int,    &config->header_timeout },
+        { "source-timeout", config_get_int,    &config->source_timeout },
+        { NULL, NULL, NULL },
+    };
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
+    return 0;
 }
 
-static void _parse_directory(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
-{
-    char *tmp;
 
-    if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
-        ERROR0("Maximum number of yp directories exceeded!");
-        return;
-    }
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
-
-        if (xmlStrcmp(node->name, XMLSTR ("yp-url")) == 0) {
-            if (configuration->yp_url[configuration->num_yp_directories]) 
-                xmlFree(configuration->yp_url[configuration->num_yp_directories]);
-            configuration->yp_url[configuration->num_yp_directories] = 
-                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("yp-url-timeout")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->yp_url_timeout[configuration->num_yp_directories] = 
-                atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("server")) == 0) {
-            _add_server(doc, node->xmlChildrenNode, configuration);
-        } else if (xmlStrcmp(node->name, XMLSTR ("touch-interval")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->yp_touch_interval[configuration->num_yp_directories] =
-                atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        }
-    } while ((node = node->next));
-    configuration->num_yp_directories++;
-}
-
-static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
+static int _parse_listen_sock (xmlNodePtr node, void *arg)
 {
-    char *temp;
-    aliases *alias, *current, *last;
+    ice_config_t *config = arg;
+    listener_t *listener = &config->listeners[0];
+    int i;
 
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
-
-        if (xmlStrcmp(node->name, XMLSTR ("basedir")) == 0) {
-            if (configuration->base_dir && configuration->base_dir != CONFIG_DEFAULT_BASE_DIR) xmlFree(configuration->base_dir);
-            configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("logdir")) == 0) {
-            if (configuration->log_dir && configuration->log_dir != CONFIG_DEFAULT_LOG_DIR) xmlFree(configuration->log_dir);
-            configuration->log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("pidfile")) == 0) {
-            if (configuration->pidfile) xmlFree(configuration->pidfile);
-            configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("ssl_certificate")) == 0) {
-            if (configuration->cert_file) xmlFree(configuration->cert_file);
-            configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("webroot")) == 0) {
-            if (configuration->webroot_dir && configuration->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(configuration->webroot_dir);
-            configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
-                configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
-        } else if (xmlStrcmp(node->name, XMLSTR ("adminroot")) == 0) {
-            if (configuration->adminroot_dir && configuration->adminroot_dir != CONFIG_DEFAULT_ADMINROOT_DIR) 
-                xmlFree(configuration->adminroot_dir);
-            configuration->adminroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
-                configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
-        } else if (xmlStrcmp(node->name, XMLSTR ("alias")) == 0) {
-            alias = malloc(sizeof(aliases));
-            alias->next = NULL;
-            alias->source = (char*)xmlGetProp(node, XMLSTR ("source"));
-            if(alias->source == NULL) {
-                free(alias);
-                continue;
+    for (i=0; i < MAX_LISTEN_SOCKETS; i++)
+    {
+        if (listener->port <= 0)
+        {
+            struct cfg_tag icecast_tags[] =
+            {
+                { "port",               config_get_int,     &listener->port },
+                { "shoutcast-compat",   config_get_bool,    &listener->shoutcast_compat },
+                { "bind-address",       config_get_str,     &listener->bind_address },
+                { "shoutcast-mount",    config_get_str,     &listener->shoutcast_mount },
+                { NULL, NULL, NULL },
+            };
+            if (parse_xml_tags (node, icecast_tags))
+                break;
+            if (listener->shoutcast_mount)
+            {
+                listener_t *sc_port = listener+1;
+                if (i+1 < MAX_LISTEN_SOCKETS && sc_port->port <= 0)
+                {
+                    sc_port->port = listener->port+1;
+                    sc_port->shoutcast_compat = 1;
+                    sc_port->bind_address = xmlStrdup (listener->bind_address);
+                    sc_port->shoutcast_mount= xmlStrdup (listener->shoutcast_mount);
+                }
             }
-            alias->destination = (char*)xmlGetProp(node, XMLSTR ("dest"));
-            if(alias->destination == NULL) {
-                xmlFree(alias->source);
-                free(alias);
-                continue;
-            }
-            temp = (char *)xmlGetProp(node, XMLSTR("port"));
-            if(temp != NULL) {
-                alias->port = atoi(temp);
-                xmlFree(temp);
-            }
-            else
-                alias->port = -1;
-            alias->bind_address = (char*)xmlGetProp(node, XMLSTR("bind-address"));
-            current = configuration->aliases;
-            last = NULL;
-            while(current) {
-                last = current;
-                current = current->next;
-            }
-            if(last)
-                last->next = alias;
-            else
-                configuration->aliases = alias;
+            if (config->port == 0)
+                config->port = listener->port;
+            return 0;
         }
-    } while ((node = node->next));
+        listener++;
+    }
+    return -1;
 }
 
-static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
-{
-    configuration->access_log_lines = 100;
-    configuration->error_log_lines = 100;
-    configuration->playlist_log_lines = 10;
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
 
-        if (xmlStrcmp(node->name, XMLSTR ("accesslog")) == 0) {
-            if (configuration->access_log && configuration->access_log != CONFIG_DEFAULT_ACCESS_LOG) xmlFree(configuration->access_log);
-            configuration->access_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("accesslog_lines")) == 0) {
-           char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-           configuration->access_log_lines = atoi(tmp);
-           if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("errorlog")) == 0) {
-            if (configuration->error_log && configuration->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(configuration->error_log);
-            configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("errorlog_lines")) == 0) {
-           char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-           configuration->error_log_lines = atoi(tmp);
-           if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("playlistlog")) == 0) {
-            if (configuration->playlist_log && configuration->playlist_log != CONFIG_DEFAULT_PLAYLIST_LOG) xmlFree(configuration->playlist_log);
-            configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-        } else if (xmlStrcmp(node->name, XMLSTR ("playlistlog_lines")) == 0) {
-           char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-           configuration->playlist_log_lines = atoi(tmp);
-           if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("logsize")) == 0) {
-           char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-           configuration->logsize = atoi(tmp);
-           if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("loglevel")) == 0) {
-           char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-           configuration->loglevel = atoi(tmp);
-           if (tmp) xmlFree(tmp);
-        } else if (xmlStrcmp(node->name, XMLSTR ("logarchive")) == 0) {
-            char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            configuration->logarchive = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        }
-    } while ((node = node->next));
-}
-
-static void _parse_security(xmlDocPtr doc, xmlNodePtr node,
-        ice_config_t *configuration)
+static int _parse_root (xmlNodePtr node, ice_config_t *config)
 {
-   char *tmp;
-   xmlNodePtr oldnode;
+    struct cfg_tag icecast_tags[] =
+    {
+        { "location",           config_get_str,     &config->location },
+        { "admin",              config_get_str,     &config->admin },
+        { "server_id",          config_get_str,     &config->server_id },
+        { "source-password",    config_get_str,     &config->source_password },
+        { "hostname",           config_get_str,     &config->hostname },
+        { "port",               config_get_int,     &config->port },
+        { "fileserve",          config_get_bool,    &config->fileserve },
+        { "relays-on-demand",   config_get_bool,    &config->on_demand },
+        { "master-server",      config_get_str,     &config->master_server },
+        { "master-username",    config_get_str,     &config->master_username },
+        { "master-password",    config_get_str,     &config->master_password },
+        { "master-server-port", config_get_int,     &config->master_server_port },
+        { "master-update-interval",
+                                config_get_int,     &config->master_update_interval },
+        { "master-relay-auth",  config_get_bool,    &config->master_relay_auth },
+        { "master-ssl-port",    config_get_int,     &config->master_ssl_port },
+        { "master-redirect",    config_get_bool,    &config->master_redirect },
+        { "max-redirect-slaves",
+                                config_get_int,     &config->max_redirects },
+        { "shoutcast-mount",    config_get_str,     &config->shoutcast_mount },
+        { "listen-socket",      _parse_listen_sock, config },
+        { "limits",             _parse_limits,      config },
+        { "relay",              _parse_relay,       config },
+        { "mount",              _parse_mount,       config },
+        { "directory",          _parse_directory,   config },
+        { "paths",              _parse_paths,       config },
+        { "logging",            _parse_logging,     config },
+        { "security",           _parse_security,    config },
+        { "authentication",     _parse_authentication, config},
+        { NULL, NULL, NULL }
+    };
+    if (parse_xml_tags (node, icecast_tags))
+        return -1;
 
-   do {
-       if (node == NULL) break;
-       if (xmlIsBlankNode(node)) continue;
-
-       if (xmlStrcmp(node->name, XMLSTR ("chroot")) == 0) {
-           tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-           configuration->chroot = atoi(tmp);
-           if (tmp) xmlFree(tmp);
-       } else if (xmlStrcmp(node->name, XMLSTR ("changeowner")) == 0) {
-           configuration->chuid = 1;
-           oldnode = node;
-           node = node->xmlChildrenNode;
-           do {
-               if(node == NULL) break;
-               if(xmlIsBlankNode(node)) continue;
-               if(xmlStrcmp(node->name, XMLSTR ("user")) == 0) {
-                   if(configuration->user) xmlFree(configuration->user);
-                   configuration->user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-               } else if(xmlStrcmp(node->name, XMLSTR ("group")) == 0) {
-                   if(configuration->group) xmlFree(configuration->group);
-                   configuration->group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-               }
-           } while((node = node->next));
-           node = oldnode;
-       }
-   } while ((node = node->next));
+    if (config->max_redirects == 0 && config->master_redirect)
+        config->max_redirects = 1;
+    return 0;
 }
 
-static void _add_server(xmlDocPtr doc, xmlNodePtr node, 
-        ice_config_t *configuration)
-{
-    ice_config_dir_t *dirnode, *server;
-    int addnode;
-    char *tmp;
 
-    server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t));
-    server->touch_interval = configuration->touch_interval;
-    server->host = NULL;
-    addnode = 0;
-    
-    do {
-        if (node == NULL) break;
-        if (xmlIsBlankNode(node)) continue;
-
-        if (xmlStrcmp(node->name, XMLSTR ("host")) == 0) {
-            server->host = (char *)xmlNodeListGetString(doc, 
-                    node->xmlChildrenNode, 1);
-            addnode = 1;
-        } else if (xmlStrcmp(node->name, XMLSTR ("touch-interval")) == 0) {
-            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
-            server->touch_interval = atoi(tmp);
-            if (tmp) xmlFree(tmp);
-        }
-        server->next = NULL;
-    } while ((node = node->next));
-
-    if (addnode) {
-        dirnode = configuration->dir_list;
-        if (dirnode == NULL) {
-            configuration->dir_list = server;
-        } else {
-            while (dirnode->next) dirnode = dirnode->next;
-            
-            dirnode->next = server;
-        }
-        
-        server = NULL;
-        addnode = 0;
-    }
-    
-}
-
-
 /* return the mount details that match the supplied mountpoint */
 mount_proxy *config_find_mount (ice_config_t *config, const char *mount)
 {

Modified: icecast/branches/kh/icecast/src/cfgfile.h
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.h	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/cfgfile.h	2006-04-16 23:22:20 UTC (rev 11146)
@@ -66,7 +66,9 @@
     unsigned int queue_size_limit;
     int hidden; /* Do we list this on the xsl pages */
     unsigned int source_timeout;  /* source timeout in seconds */
+    char *mp3_charset;  /* character set for metadata */
     int mp3_meta_interval; /* outgoing per-stream metadata interval */
+    int filter_theora; /* prevent theora pages getting queued */
 
     char *auth_type; /* Authentication type */
     struct auth_tag *auth;
@@ -100,6 +102,7 @@
     int port;
     char *bind_address;
     int shoutcast_compat;
+    char *shoutcast_mount;
     int ssl;
 } listener_t;
 

Modified: icecast/branches/kh/icecast/src/connection.c
===================================================================
--- icecast/branches/kh/icecast/src/connection.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/connection.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -82,6 +82,7 @@
     int offset;
     int stream_offset;
     int shoutcast;
+    char *shoutcast_mount;
     struct client_queue_tag *next;
 } client_queue_t;
 
@@ -604,6 +605,8 @@
                         node->shoutcast = 1;
                     if (config->listeners[i].ssl && ssl_ok)
                         connection_uses_ssl (client->con);
+                    if (config->listeners[i].shoutcast_mount)
+                        node->shoutcast_mount = strdup (config->listeners[i].shoutcast_mount);
                 }
             }
             config_release_config();
@@ -1059,11 +1062,18 @@
     char *shoutcast_mount;
     client_t *client = node->client;
 
+    if (node->shoutcast_mount)
+        shoutcast_mount = node->shoutcast_mount;
+    else
+        shoutcast_mount = config->shoutcast_mount;
+
     if (node->shoutcast == 1)
     {
         char *source_password, *ptr, *headers;
-        mount_proxy *mountinfo = config_find_mount (config, config->shoutcast_mount);
+        mount_proxy *mountinfo;
 
+        mountinfo = config_find_mount (config, shoutcast_mount);
+
         if (mountinfo && mountinfo->password)
             source_password = strdup (mountinfo->password);
         else
@@ -1091,6 +1101,7 @@
         {
             client_destroy (client);
             free (source_password);
+            free (node->shoutcast_mount);
             free (node);
             return;
         }
@@ -1113,10 +1124,12 @@
         else
             INFO1 ("password does not match \"%s\"", client->refbuf->data);
         client_destroy (client);
+        free (node->shoutcast_mount);
         free (node);
         return;
     }
-    shoutcast_mount = strdup (config->shoutcast_mount);
+    /* actually make a copy as we are dropping the config lock */
+    shoutcast_mount = strdup (shoutcast_mount);
     config_release_config();
     /* Here we create a valid HTTP request based of the information
        that was passed in via the non-HTTP style protocol above. This
@@ -1148,6 +1161,7 @@
     }
     free (http_compliant);
     free (shoutcast_mount);
+    free (node->shoutcast_mount);
     free (node);
     return;
 }
@@ -1192,6 +1206,14 @@
                     client->refbuf->len = node->offset - node->stream_offset;
                     memmove (ptr, ptr + node->stream_offset, client->refbuf->len);
                 }
+
+                rawuri = httpp_getvar (parser, HTTPP_VAR_URI);
+
+                /* assign a port-based shoutcast mountpoint if required */
+                if (node->shoutcast_mount && strcmp (rawuri, "/admin.cgi") == 0)
+                    httpp_set_query_param (client->parser, "mount", node->shoutcast_mount);
+
+                free (node->shoutcast_mount);
                 free (node);
                 
                 if (strcmp("ICE",  httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) &&
@@ -1201,7 +1223,6 @@
                     continue;
                 }
 
-                rawuri = httpp_getvar(parser, HTTPP_VAR_URI);
                 uri = util_normalise_uri(rawuri);
 
                 if (uri == NULL)

Modified: icecast/branches/kh/icecast/src/format_flac.c
===================================================================
--- icecast/branches/kh/icecast/src/format_flac.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_flac.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -71,11 +71,11 @@
         }
         if (codec->headers)
         {
-            format_ogg_attach_header (ogg_info, page);
+            format_ogg_attach_header (codec, page);
             return NULL;
         }
     }
-    refbuf = make_refbuf_with_page (page);
+    refbuf = make_refbuf_with_page (codec, page);
     return refbuf;
 }
 
@@ -113,9 +113,10 @@
         codec->process_page = process_flac_page;
         codec->codec_free = flac_codec_free;
         codec->headers = 1;
+        codec->parent = ogg_info;
         codec->name = "FLAC";
 
-        format_ogg_attach_header (ogg_info, page);
+        format_ogg_attach_header (codec, page);
         return codec;
     } while (0);
 

Modified: icecast/branches/kh/icecast/src/format_midi.c
===================================================================
--- icecast/branches/kh/icecast/src/format_midi.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_midi.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -50,7 +50,7 @@
         ogg_info->error = 1;
         return NULL;
     }
-    refbuf = make_refbuf_with_page (page);
+    refbuf = make_refbuf_with_page (codec, page);
     return refbuf;
 }
 
@@ -82,9 +82,10 @@
         codec->process_page = process_midi_page;
         codec->codec_free = midi_codec_free;
         codec->headers = 1;
+        codec->parent = ogg_info;
         codec->name = "MIDI";
 
-        format_ogg_attach_header (ogg_info, page);
+        format_ogg_attach_header (codec, page);
         return codec;
     } while (0);
 

Modified: icecast/branches/kh/icecast/src/format_mp3.c
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_mp3.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -182,9 +182,35 @@
             p = calloc (1, len+1);
             if (p)
             {
+                mp3_state *source_mp3 = source->format->_state;
+
                 memcpy (p, metadata+13, len);
-                logging_playlist (source->mount, p, source->listeners);
-                stats_event (source->mount, "title", p);
+
+                if (source_mp3->charset)
+                {
+                    xmlBufferPtr raw = xmlBufferCreate ();
+                    xmlBufferPtr buf = xmlBufferCreate ();
+
+                    xmlCharEncodingHandlerPtr handle =
+                        xmlFindCharEncodingHandler (source_mp3->charset);
+                    xmlBufferAdd (raw, (const xmlChar *) p, len);
+                    if (xmlCharEncInFunc (handle, buf, raw) > 0)
+                    {
+                        stats_event (source->mount, "title", xmlBufferContent (buf));
+                        logging_playlist (source->mount,
+                                xmlBufferContent (buf), source->listeners);
+                    }
+                    else
+                        logging_playlist (source->mount, p, source->listeners);
+                    xmlFree (raw);
+                    xmlFree (buf);
+                }
+                else
+                {
+                    stats_event (source->mount, "title", p);
+                    logging_playlist (source->mount, p, source->listeners);
+                }
+
                 yp_touch (source->mount);
                 free (p);
             }
@@ -211,6 +237,17 @@
     else
         source_mp3->interval = mount->mp3_meta_interval;
     DEBUG1 ("mp3 interval %d", source_mp3->interval);
+
+    if (source_mp3->charset)
+    {
+        xmlFree (source_mp3->charset);
+        source_mp3->charset = NULL;
+    }
+    if (mount)
+    {
+        source_mp3->charset = xmlStrdup (mount->mp3_charset);
+        DEBUG1 ("mp3 charset %s", source_mp3->charset);
+    }
 }
 
 

Modified: icecast/branches/kh/icecast/src/format_mp3.h
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.h	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_mp3.h	2006-04-16 23:22:20 UTC (rev 11146)
@@ -25,6 +25,7 @@
     int interval;
     char *url_artist;
     char *url_title;
+    char *charset;
     int update_metadata;
 
     refbuf_t *metadata;

Modified: icecast/branches/kh/icecast/src/format_ogg.c
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_ogg.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -59,6 +59,8 @@
 static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf);
 static refbuf_t *ogg_get_buffer (source_t *source);
 static int write_buf_to_client (client_t *client);
+static void apply_ogg_settings (client_t *client,
+        format_plugin_t *format, mount_proxy *mount);
 
 
 struct ogg_client
@@ -70,10 +72,14 @@
 };
 
 
-refbuf_t *make_refbuf_with_page (ogg_page *page)
+refbuf_t *make_refbuf_with_page (ogg_codec_t *codec, ogg_page *page)
 {
-    refbuf_t *refbuf = refbuf_new (page->header_len + page->body_len);
+    refbuf_t *refbuf;
 
+    if (codec && codec->filtered)
+        return NULL;
+    refbuf = refbuf_new (page->header_len + page->body_len);
+
     memcpy (refbuf->data, page->header, page->header_len);
     memcpy (refbuf->data+page->header_len, page->body, page->body_len);
     return refbuf;
@@ -83,10 +89,16 @@
 /* routine for taking the provided page (should be a header page) and
  * placing it on the collection of header pages
  */
-void format_ogg_attach_header (ogg_state_t *ogg_info, ogg_page *page)
+void format_ogg_attach_header (ogg_codec_t *codec, ogg_page *page)
 {
-    refbuf_t *refbuf = make_refbuf_with_page (page);
+    ogg_state_t *ogg_info = codec->parent;
+    refbuf_t *refbuf;
+    
+    if (codec->filtered)
+        return;
 
+    refbuf = make_refbuf_with_page (codec, page);
+
     if (ogg_page_bos (page))
     {
         DEBUG0 ("attaching BOS page");
@@ -168,6 +180,7 @@
     plugin->create_client_data = create_ogg_client_data;
     plugin->free_plugin = format_ogg_free_plugin;
     plugin->set_tag = NULL;
+    plugin->apply_settings = apply_ogg_settings;
     plugin->contenttype = "application/ogg";
 
     ogg_sync_init (&state->oy);
@@ -197,6 +210,19 @@
 }
 
 
+static void apply_ogg_settings (client_t *client,
+        format_plugin_t *format, mount_proxy *mount)
+{
+    ogg_state_t *ogg_info = format->_state;
+
+    if (mount == NULL)
+        return;
+    if (mount->filter_theora)
+        ogg_info->filter_theora = 1;
+    DEBUG1 ("filter for theora is %d", ogg_info->filter_theora);
+}
+
+
 /* a new BOS page has been seen so check which codec it is */
 static int process_initial_page (format_plugin_t *plugin, ogg_page *page)
 {
@@ -249,6 +275,7 @@
         codec->next = ogg_info->codecs;
         ogg_info->codecs = codec;
         ogg_info->codec_count++;
+        DEBUG2 ("%s codec has filter mark %d", codec->name, codec->filtered);
     }
 
     return 0;

Modified: icecast/branches/kh/icecast/src/format_ogg.h
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.h	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_ogg.h	2006-04-16 23:22:20 UTC (rev 11146)
@@ -39,6 +39,7 @@
     refbuf_t **bos_end;
     int bos_completed;
     long bitrate;
+    int filter_theora;
     struct ogg_codec_tag *current;
     struct ogg_codec_tag *codec_sync;
 } ogg_state_t;
@@ -48,9 +49,11 @@
 typedef struct ogg_codec_tag
 {
     struct ogg_codec_tag *next;
+    ogg_state_t *parent;
     ogg_stream_state os;
     unsigned headers;
     const char *name;
+    int filtered;
     void *specific;
     refbuf_t        *possible_start;
     refbuf_t        *page;
@@ -62,8 +65,8 @@
 } ogg_codec_t;
 
 
-refbuf_t *make_refbuf_with_page (ogg_page *page);
-void format_ogg_attach_header (ogg_state_t *ogg_info, ogg_page *page);
+refbuf_t *make_refbuf_with_page (ogg_codec_t *codec, ogg_page *page);
+void format_ogg_attach_header (ogg_codec_t *codec, ogg_page *page);
 void format_ogg_free_headers (ogg_state_t *ogg_info);
 int format_ogg_get_plugin (source_t *source);
 

Modified: icecast/branches/kh/icecast/src/format_speex.c
===================================================================
--- icecast/branches/kh/icecast/src/format_speex.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_speex.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -53,10 +53,10 @@
            codec->headers++;
         }
         /* add header page to associated list */
-        format_ogg_attach_header (ogg_info, page);
+        format_ogg_attach_header (codec, page);
         return NULL;
     }
-    refbuf = make_refbuf_with_page (page);
+    refbuf = make_refbuf_with_page (codec, page);
     return refbuf;
 }
 
@@ -86,7 +86,8 @@
     codec->process_page = process_speex_page;
     codec->codec_free = speex_codec_free;
     codec->headers = 1;
-    format_ogg_attach_header (ogg_info, page);
+    codec->parent = ogg_info;
+    format_ogg_attach_header (codec, page);
     free (header);
     return codec;
 }

Modified: icecast/branches/kh/icecast/src/format_theora.c
===================================================================
--- icecast/branches/kh/icecast/src/format_theora.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_theora.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -117,11 +117,11 @@
     }
     if (header_page)
     {
-        format_ogg_attach_header (ogg_info, page);
+        format_ogg_attach_header (codec, page);
         return NULL;
     }
 
-    refbuf = make_refbuf_with_page (page);
+    refbuf = make_refbuf_with_page (codec, page);
     /* DEBUG3 ("refbuf %p has pageno %ld, %llu", refbuf, ogg_page_pageno (page), (uint64_t)granulepos); */
 
     if (has_keyframe && codec->possible_start)
@@ -134,8 +134,11 @@
     {
         if (codec->possible_start)
             refbuf_release (codec->possible_start);
-        refbuf_addref (refbuf);
-        codec->possible_start = refbuf;
+        if (refbuf)
+        {
+            refbuf_addref (refbuf);
+            codec->possible_start = refbuf;
+        }
     }
     theora->prev_granulepos = granulepos;
 
@@ -176,11 +179,15 @@
     codec->specific = theora_codec;
     codec->process_page = process_theora_page;
     codec->codec_free = theora_codec_free;
+    codec->parent = ogg_info;
     codec->headers = 1;
+    if (ogg_info->filter_theora)
+        codec->filtered = 1;
     codec->name = "Theora";
 
-    format_ogg_attach_header (ogg_info, page);
-    ogg_info->codec_sync = codec;
+    format_ogg_attach_header (codec, page);
+    if (codec->filtered == 0)
+        ogg_info->codec_sync = codec;
     return codec;
 }
 

Modified: icecast/branches/kh/icecast/src/format_vorbis.c
===================================================================
--- icecast/branches/kh/icecast/src/format_vorbis.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/format_vorbis.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -158,7 +158,7 @@
         source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
         source_vorbis->prev_page_samples = ogg_page_granulepos (&page);
 
-        refbuf = make_refbuf_with_page (&page);
+        refbuf = make_refbuf_with_page (codec, &page);
     }
     return refbuf;
 }
@@ -172,7 +172,7 @@
 
     while (ogg_stream_flush (&source_vorbis->new_os, &page) > 0)
     {
-        format_ogg_attach_header (ogg_info, &page);
+        format_ogg_attach_header (codec, &page);
         headers_flushed = 1;
     }
     if (headers_flushed)
@@ -194,8 +194,7 @@
         source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
         source_vorbis->prev_page_samples = ogg_page_granulepos (&page);
 
-        refbuf = make_refbuf_with_page (&page);
-        DEBUG0 ("flushing page");
+        refbuf = make_refbuf_with_page (codec, &page);
         return refbuf;
     }
     ogg_stream_clear (&source_vorbis->new_os);
@@ -357,6 +356,7 @@
  */
 ogg_codec_t *initial_vorbis_page (format_plugin_t *plugin, ogg_page *page)
 {
+    ogg_state_t *ogg_info = plugin->_state;
     ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
     ogg_packet packet;
 
@@ -384,6 +384,7 @@
     codec->specific = vorbis;
     codec->codec_free = vorbis_codec_free;
     codec->headers = 1;
+    codec->parent = ogg_info;
     codec->name = "Vorbis";
 
     free_ogg_packet (vorbis->header[0]);
@@ -497,7 +498,7 @@
 static refbuf_t *process_vorbis_passthru_page (ogg_state_t *ogg_info,
         ogg_codec_t *codec, ogg_page *page)
 {
-    return make_refbuf_with_page (page);
+    return make_refbuf_with_page (codec, page);
 }
 
 
@@ -534,7 +535,7 @@
         if (ogg_stream_packetout (&codec->os, &header) <= 0)
         {
             if (ogg_info->codecs->next)
-                format_ogg_attach_header (ogg_info, page);
+                format_ogg_attach_header (codec, page);
             return NULL;
         }
 
@@ -561,8 +562,8 @@
     }
     else
     {
-        format_ogg_attach_header (ogg_info, &source_vorbis->bos_page);
-        format_ogg_attach_header (ogg_info, page);
+        format_ogg_attach_header (codec, &source_vorbis->bos_page);
+        format_ogg_attach_header (codec, page);
         codec->process_page = process_vorbis_passthru_page;
     }
 

Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/slave.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -448,7 +448,7 @@
             slave_rebuild_mounts();
             return;
         }
-        if (relay->on_demand)
+        if (relay->on_demand && relay->source)
         {
             ice_config_t *config = config_get_config ();
             mount_proxy *mountinfo = config_find_mount (config, relay->localmount);

Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/source.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -702,6 +702,7 @@
     /* start off the statistics */
     stats_event_inc (NULL, "source_total_connections");
     stats_event (source->mount, "slow_listeners", "0");
+    stats_event (source->mount, "listener_connections", "0");
     stats_event (source->mount, "server_type", source->format->contenttype);
     stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
     stats_event_time (source->mount, "stream_start");

Modified: icecast/branches/kh/icecast/src/xslt.c
===================================================================
--- icecast/branches/kh/icecast/src/xslt.c	2006-04-16 15:29:18 UTC (rev 11145)
+++ icecast/branches/kh/icecast/src/xslt.c	2006-04-16 23:22:20 UTC (rev 11146)
@@ -189,6 +189,7 @@
     xsltStylesheetPtr cur;
     xmlChar *string;
     int len, problem = 0;
+    const char *mediatype = NULL;
 
     xmlSetGenericErrorFunc ("", log_parse_failure);
     xsltSetGenericErrorFunc ("", log_parse_failure);
@@ -208,19 +209,34 @@
 
     if (xsltSaveResultToString (&string, &len, res, cur) < 0)
         problem = 1;
-    thread_mutex_unlock(&xsltlock);
+
+    /* lets find out the content type to use */
+    if (cur->mediaType)
+        mediatype = (char *)cur->mediaType;
+    else
+    {
+        /* check method for the default, a missing method assumes xml */
+        if (cur->method && xmlStrcmp (cur->method, "html") == 0)
+            mediatype = "text/html";
+        else
+            if (cur->method && xmlStrcmp (cur->method, "text") == 0)
+                mediatype = "text/plain";
+            else
+                mediatype = "text/xml";
+    }
     if (problem == 0)
     {
-        const char *http = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: ";
-        size_t buf_len = strlen (http) + 20 + len;
+        /* the 100 is to allow for the hardcoded headers */
+        unsigned int header_len = strlen (mediatype) + len + 100;
+        refbuf_t *refbuf = refbuf_new (header_len);
 
-        if (string == NULL)
-            string = xmlCharStrdup ("");
+        len = snprintf (refbuf->data, header_len,
+                "HTTP/1.0 200 OK\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
+                mediatype, len, string);
+
         client->respcode = 200;
-        client_set_queue (client, NULL);
-        client->refbuf = refbuf_new (buf_len);
-        len = snprintf (client->refbuf->data, buf_len, "%s%d\r\n\r\n%s", http, len, string);
-        client->refbuf->len = len;
+        client_set_queue (client, refbuf);
+        refbuf->len = strlen (refbuf->data);
         fserve_add_client (client, NULL);
         xmlFree (string);
     }
@@ -229,6 +245,7 @@
         WARN1 ("problem applying stylesheet \"%s\"", xslfilename);
         client_send_404 (client, "XSLT problem");
     }
+    thread_mutex_unlock (&xsltlock);
     xmlFreeDoc(res);
 }
 



More information about the commits mailing list