[xiph-cvs] r6610 - in icecast/trunk/icecast: admin conf doc src web win32

oddsock at xiph.org oddsock at xiph.org
Tue May 4 21:30:33 PDT 2004



Author: oddsock
Date: 2004-04-30 10:36:07 -0400 (Fri, 30 Apr 2004)
New Revision: 6610

Modified:
   icecast/trunk/icecast/admin/Makefile.am
   icecast/trunk/icecast/admin/listclients.xsl
   icecast/trunk/icecast/admin/listmounts.xsl
   icecast/trunk/icecast/admin/stats.xsl
   icecast/trunk/icecast/conf/icecast.xml.in
   icecast/trunk/icecast/doc/icecast2_config_file.html
   icecast/trunk/icecast/src/admin.c
   icecast/trunk/icecast/src/auth.c
   icecast/trunk/icecast/src/auth.h
   icecast/trunk/icecast/src/cfgfile.c
   icecast/trunk/icecast/src/source.c
   icecast/trunk/icecast/web/Makefile.am
   icecast/trunk/icecast/win32/icecast2.iss
Log:
added web based interface to htpasswd client authentication

<p>Modified: icecast/trunk/icecast/admin/Makefile.am
===================================================================
--- icecast/trunk/icecast/admin/Makefile.am	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/admin/Makefile.am	2004-04-30 14:36:07 UTC (rev 6610)
@@ -4,5 +4,5 @@
 
 admindir = $(pkgdatadir)/admin
 dist_admin_DATA = listclients.xsl listmounts.xsl moveclients.xsl response.xsl \
-	stats.xsl
+	stats.xsl manageauth.xsl
 

Modified: icecast/trunk/icecast/admin/listclients.xsl
===================================================================
--- icecast/trunk/icecast/admin/listclients.xsl	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/admin/listclients.xsl	2004-04-30 14:36:07 UTC (rev 6610)
@@ -51,7 +51,7 @@
 <xsl:variable name = "themount" ><xsl:value-of select="@mount" /></xsl:variable>
 <xsl:for-each select="listener">
                 <tr>
-				<td><xsl:value-of select="IP" /></td>
+				<td><xsl:value-of select="IP" /><xsl:if test="username"> (<xsl:value-of select="username" />)</xsl:if></td>
                                 <td><xsl:value-of select="Connected" /> seconds</td>
                                 <td><xsl:value-of select="UserAgent" /></td>
                                 <td><a class="nav2" href="killclient.xsl?mount={$themount}&amp;id={ID}">kill</a></td>

Modified: icecast/trunk/icecast/admin/listmounts.xsl
===================================================================
--- icecast/trunk/icecast/admin/listmounts.xsl	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/admin/listmounts.xsl	2004-04-30 14:36:07 UTC (rev 6610)
@@ -31,13 +31,16 @@
 <xsl:for-each select="source">
 <h3>
 <xsl:if test="server_name"><xsl:value-of select="server_name" /> </xsl:if>
-(<xsl:value-of select="@mount" />)</h3>
+(<xsl:value-of select="@mount" />)
+<xsl:if test="authenticator"> <a href="manageauth.xsl?mount={@mount}"><img border="0" src="/key.gif"/></a> </xsl:if>
+</h3>
         <table border="0" cellpadding="1" cellspacing="5" bgcolor="444444">
         <tr>        
             <td align="center">
                 <a class="nav2" href="listclients.xsl?mount={@mount}">Show Listeners</a> | 
                 <a class="nav2" href="moveclients.xsl?mount={@mount}">Move Listeners</a> | 
                 <a class="nav2" href="killsource.xsl?mount={@mount}">Kill Source</a>
+                <xsl:if test="authenticator"> | <a class="nav2" href="manageauth.xsl?mount={@mount}">Manage Authentication</a></xsl:if>
             </td></tr>
         </table>
 <br></br>

Modified: icecast/trunk/icecast/admin/stats.xsl
===================================================================
--- icecast/trunk/icecast/admin/stats.xsl	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/admin/stats.xsl	2004-04-30 14:36:07 UTC (rev 6610)
@@ -58,13 +58,16 @@
 <xsl:if test = "listeners!=''"> 
 <h3>
 <xsl:if test="server_name"><xsl:value-of select="server_name" /> </xsl:if>
-(<xsl:value-of select="@mount" />)</h3>
+(<xsl:value-of select="@mount" />)
+<xsl:if test="authenticator"> <a href="manageauth.xsl?mount={@mount}"><img border="0" src="/key.gif"/></a> </xsl:if>
+</h3>
         <table border="0" cellpadding="1" cellspacing="5" bgcolor="444444">
         <tr>        
             <td align="center">
                 <a class="nav2" href="listclients.xsl?mount={@mount}">List Clients</a> | 
                 <a class="nav2" href="moveclients.xsl?mount={@mount}">Move MountPoints</a> | 
                 <a class="nav2" href="killsource.xsl?mount={@mount}">Kill Source</a>
+                <xsl:if test="authenticator"> | <a class="nav2" href="manageauth.xsl?mount={@mount}">Manage Authentication</a></xsl:if>
             </td></tr>
         </table>
 <br></br>

Modified: icecast/trunk/icecast/conf/icecast.xml.in
===================================================================
--- icecast/trunk/icecast/conf/icecast.xml.in	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/conf/icecast.xml.in	2004-04-30 14:36:07 UTC (rev 6610)
@@ -84,6 +84,9 @@
         <max-listeners>1</max-listeners>
         <dump-file>/tmp/dump-example1.ogg</dump-file>
         <fallback-mount>/example2.ogg</fallback-mount>
+        <authentication type="htpasswd">
+                <option name="filename" value="myauth"/>
+        </authentication>
     </mount>
     -->
 

Modified: icecast/trunk/icecast/doc/icecast2_config_file.html
===================================================================
--- icecast/trunk/icecast/doc/icecast2_config_file.html	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/doc/icecast2_config_file.html	2004-04-30 14:36:07 UTC (rev 6610)
@@ -271,6 +271,10 @@
         &lt;max-listeners&gt;1&lt;max-listeners&gt;
         &lt;dump-file&gt;/tmp/dump-example1.ogg&lt;dump-file&gt;
         &lt;fallback-mount&gt;example2.ogg&lt;fallback-mount&gt;
+        &lt;authentication type="htpasswd"&gt;
+                &lt;option name="filename" value="myauth"/&gt;
+        &lt;/authentication&gt;
+
     &lt;mount&gt;
 </pre>
 <p>This section contains settings which apply only to a specific mountpoint.  Within this section you can reserve a specific mountpoint and set a source username/password for that mountpoint (not yet implemented) as well as specify individual settings which will apply only to the supplied mountpoint.
@@ -299,6 +303,10 @@
 <div class=indentedbox>
 This specifies a mountpoint that is used in the case of a source disconnect.  If listeners are connected to the mount specified by the &lt;mount-name&gt; config value, then if the source is disconnected; all currently connected clients will be moved to the fallback-mount.
 </div>
+<h4>authentication</h4>
+<div class=indentedbox>
+This specifies that the named mount point will require listener authentication.  Currently, we only support a file-based authentication scheme (type=htpasswd).  Users and encrypted password are placed in this file (separated by a :) and all requests for this mountpoint will require that a user and password be supplied for authentication purposes.  These values are passed in via normal HTTP Basic Authentication means (i.e. http://user:password@stream:port/mountpoint.ogg).  Users and Passwords are maintained via the web admin interface.  A mountpoint configured with an authenticator will display a red key next to the mount point name on the admin screens.
+</div>
 <br>
 <br>
 <br>

Modified: icecast/trunk/icecast/src/admin.c
===================================================================
--- icecast/trunk/icecast/src/admin.c	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/src/admin.c	2004-04-30 14:36:07 UTC (rev 6610)
@@ -37,6 +37,7 @@
 #include "format_mp3.h"
 
 #include "logging.h"
+#include "auth.h"
 #ifdef _WIN32
 #define snprintf _snprintf
 #endif
@@ -50,10 +51,12 @@
 #define COMMAND_METADATA_UPDATE     2
 #define COMMAND_RAW_SHOW_LISTENERS  3
 #define COMMAND_RAW_MOVE_CLIENTS    4
+#define COMMAND_RAW_MANAGEAUTH      5
 
 #define COMMAND_TRANSFORMED_FALLBACK        50
 #define COMMAND_TRANSFORMED_SHOW_LISTENERS  53
 #define COMMAND_TRANSFORMED_MOVE_CLIENTS    54
+#define COMMAND_TRANSFORMED_MANAGEAUTH      55
 
 /* Global commands */
 #define COMMAND_RAW_LIST_MOUNTS             101
@@ -89,6 +92,8 @@
 #define KILLSOURCE_RAW_REQUEST "killsource"
 #define KILLSOURCE_TRANSFORMED_REQUEST "killsource.xsl"
 #define ADMIN_XSL_RESPONSE "response.xsl"
+#define MANAGEAUTH_RAW_REQUEST "manageauth"
+#define MANAGEAUTH_TRANSFORMED_REQUEST "manageauth.xsl"
 #define DEFAULT_RAW_REQUEST ""
 #define DEFAULT_TRANSFORMED_REQUEST ""
 
@@ -133,6 +138,10 @@
         return COMMAND_RAW_KILL_SOURCE;
     else if(!strcmp(command, KILLSOURCE_TRANSFORMED_REQUEST))
         return COMMAND_TRANSFORMED_KILL_SOURCE;
+    else if(!strcmp(command, MANAGEAUTH_RAW_REQUEST))
+        return COMMAND_RAW_MANAGEAUTH;
+    else if(!strcmp(command, MANAGEAUTH_TRANSFORMED_REQUEST))
+        return COMMAND_TRANSFORMED_MANAGEAUTH;
     else if(!strcmp(command, DEFAULT_TRANSFORMED_REQUEST))
         return COMMAND_TRANSFORMED_STATS;
     else if(!strcmp(command, DEFAULT_RAW_REQUEST))
@@ -151,6 +160,8 @@
 static void command_list_mounts(client_t *client, int response);
 static void command_kill_client(client_t *client, source_t *source,
         int response);
+static void command_manageauth(client_t *client, source_t *source,
+        int response);
 static void command_kill_source(client_t *client, source_t *source,
         int response);
 static void admin_handle_mount_request(client_t *client, source_t *source,
@@ -195,6 +206,10 @@
             xmlNewChild(srcnode, NULL, "Connected", buf);
             xmlNewChild(srcnode, NULL, "Format", 
                     source->format->format_description);
+            if (source->authenticator) {
+                xmlNewChild(srcnode, NULL, "authenticator", 
+                    source->authenticator->type);
+            }
         }
         node = avl_get_next(node);
     }
@@ -402,6 +417,12 @@
         case COMMAND_TRANSFORMED_KILL_SOURCE:
             command_kill_source(client, source, TRANSFORMED);
             break;
+        case COMMAND_TRANSFORMED_MANAGEAUTH:
+            command_manageauth(client, source, TRANSFORMED);
+            break;
+        case COMMAND_RAW_MANAGEAUTH:
+            command_manageauth(client, source, RAW);
+            break;
         default:
             WARN0("Mount request not recognised");
             client_send_400(client, "Mount request unknown");
@@ -547,6 +568,9 @@
         memset(buf, '\000', sizeof(buf));
         snprintf(buf, sizeof(buf)-1, "%lu", current->con->id);
         xmlNewChild(listenernode, NULL, "ID", buf);
+        if (current->username) {
+            xmlNewChild(listenernode, NULL, "username", current->username);
+        }
         client_node = avl_get_next(client_node);
     }
 
@@ -557,6 +581,67 @@
     client_destroy(client);
 }
 
+static void command_manageauth(client_t *client, source_t *source,
+    int response)
+{
+    xmlDocPtr doc;
+    xmlNodePtr node, srcnode, msgnode;
+    char *action = NULL;
+    char *username = NULL;
+    char *password = NULL;
+    char *message = NULL;
+    int ret = AUTH_OK;
+
+    if((COMMAND_OPTIONAL(client, "action", action))) {
+        if (!strcmp(action, "add")) {
+            COMMAND_REQUIRE(client, "username", username);
+            COMMAND_REQUIRE(client, "password", password);
+            ret = auth_adduser(source, username, password);
+            if (ret == AUTH_FAILED) {
+                message = strdup("User add failed - check the icecast error log");
+            }
+            if (ret == AUTH_USERADDED) {
+                message = strdup("User added");
+            }
+            if (ret == AUTH_USEREXISTS) {
+                message = strdup("User already exists - not added");
+            }
+        }
+        if (!strcmp(action, "delete")) {
+            COMMAND_REQUIRE(client, "username", username);
+            ret = auth_deleteuser(source, username);
+            if (ret == AUTH_FAILED) {
+                message = strdup("User delete failed - check the icecast error log");
+            }
+            if (ret == AUTH_USERDELETED) {
+                message = strdup("User deleted");
+            }
+        }
+    }
+
+    doc = xmlNewDoc("1.0");
+    node = xmlNewDocNode(doc, NULL, "icestats", NULL);
+    srcnode = xmlNewChild(node, NULL, "source", NULL);
+    xmlSetProp(srcnode, "mount", source->mount);
+
+    if (message) {
+        msgnode = xmlNewChild(node, NULL, "iceresponse", NULL);
+        xmlNewChild(msgnode, NULL, "message", message);
+    }
+
+    xmlDocSetRootElement(doc, node);
+
+    auth_get_userlist(source, srcnode);
+
+    admin_send_response(doc, client, response, 
+        MANAGEAUTH_TRANSFORMED_REQUEST);
+    if (message) {
+        free(message);
+    }
+    xmlFreeDoc(doc);
+    client_destroy(client);
+}
+
 static void command_kill_source(client_t *client, source_t *source,
     int response)
 {

Modified: icecast/trunk/icecast/src/auth.c
===================================================================
--- icecast/trunk/icecast/src/auth.c	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/src/auth.c	2004-04-30 14:36:07 UTC (rev 6610)
@@ -33,6 +33,7 @@
 #include "logging.h"
 #define CATMODULE "auth"
 
+
 auth_result auth_check_client(source_t *source, client_t *client)
 {
     auth_t *authenticator = source->authenticator;
@@ -90,6 +91,7 @@
     auth_t *auth = NULL;
     if(!strcmp(type, "htpasswd")) {
         auth = auth_get_htpasswd_auth(options);
+        auth->type = strdup(type);
     }
     else {
         ERROR1("Unrecognised authenticator type: \"%s\"", type);
@@ -104,12 +106,15 @@
 
 typedef struct {
     char *filename;
+    rwlock_t file_rwlock;
 } htpasswd_auth_state;
 
 static void htpasswd_clear(auth_t *self) {
     htpasswd_auth_state *state = self->state;
     free(state->filename);
+    thread_rwlock_destroy(&state->file_rwlock);
     free(state);
+    free(self->type);
     free(self);
 }
 
@@ -152,9 +157,11 @@
     char line[MAX_LINE_LEN];
     char *sep;
 
+    thread_rwlock_rlock(&state->file_rwlock);
     if(passwdfile == NULL) {
         WARN2("Failed to open authentication database \"%s\": %s", 
                 state->filename, strerror(errno));
+        thread_rwlock_unlock(&state->file_rwlock);
         return AUTH_FAILED;
     }
 
@@ -176,6 +183,7 @@
             if(!strcmp(hash, hashed_password)) {
                 fclose(passwdfile);
                 free(hashed_password);
+                thread_rwlock_unlock(&state->file_rwlock);
                 return AUTH_OK;
             }
             free(hashed_password);
@@ -186,6 +194,7 @@
 
     fclose(passwdfile);
 
+    thread_rwlock_unlock(&state->file_rwlock);
     return AUTH_FAILED;
 }
 
@@ -216,6 +225,224 @@
     DEBUG1("Configured htpasswd authentication using password file %s", 
             state->filename);
 
+    thread_rwlock_create(&state->file_rwlock);
+
     return authenticator;
 }
 
+int auth_htpasswd_existing_user(auth_t *auth, char *username)
+{
+    FILE *passwdfile;
+    htpasswd_auth_state *state;
+    int ret = AUTH_OK;
+    char line[MAX_LINE_LEN];
+    char *sep;
+
+    state = auth->state;
+    passwdfile = fopen(state->filename, "rb");
+
+    if(passwdfile == NULL) {
+        WARN2("Failed to open authentication database \"%s\": %s", 
+                state->filename, strerror(errno));
+        return AUTH_FAILED;
+    }
+    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+        if(!line[0] || line[0] == '#')
+            continue;
+        sep = strchr(line, ':');
+        if(sep == NULL) {
+            DEBUG0("No seperator in line");
+            continue;
+        }
+        *sep = 0;
+        if (!strcmp(username, line)) {
+            /* We found the user, break out of the loop */
+            ret = AUTH_USEREXISTS;
+            break;
+        }
+    }
+
+    fclose(passwdfile);
+    return ret;
+
+}
+int auth_htpasswd_adduser(auth_t *auth, char *username, char *password)
+{
+    FILE *passwdfile;
+    char *hashed_password = NULL;
+    htpasswd_auth_state *state;
+
+    if (auth_htpasswd_existing_user(auth, username) == AUTH_USEREXISTS) {
+        return AUTH_USEREXISTS;
+    }
+    state = auth->state;
+    passwdfile = fopen(state->filename, "ab");
+
+    if(passwdfile == NULL) {
+        WARN2("Failed to open authentication database \"%s\": %s", 
+                state->filename, strerror(errno));
+        return AUTH_FAILED;
+    }
+
+    hashed_password = get_hash(password, strlen(password));
+    if (hashed_password) {
+        fprintf(passwdfile, "%s:%s\n", username, hashed_password);
+        free(hashed_password);
+    }
+
+    fclose(passwdfile);
+    return AUTH_USERADDED;
+}
+
+int auth_adduser(source_t *source, char *username, char *password)
+{
+    int ret = 0;
+    htpasswd_auth_state *state;
+
+    if (source->authenticator) {
+        if (!strcmp(source->authenticator->type, "htpasswd")) {
+            state = source->authenticator->state;
+            thread_rwlock_wlock(&state->file_rwlock);
+            ret = auth_htpasswd_adduser(source->authenticator, username, password);
+            thread_rwlock_unlock(&state->file_rwlock);
+        }
+    }
+    return ret;
+}
+
+int auth_htpasswd_deleteuser(auth_t *auth, char *username)
+{
+    FILE *passwdfile;
+    FILE *tmp_passwdfile;
+    htpasswd_auth_state *state;
+    char line[MAX_LINE_LEN];
+    char *sep;
+    char *tmpfile = NULL;
+    int tmpfile_len = 0;
+
+    state = auth->state;
+    passwdfile = fopen(state->filename, "rb");
+
+    if(passwdfile == NULL) {
+        WARN2("Failed to open authentication database \"%s\": %s", 
+                state->filename, strerror(errno));
+        return AUTH_FAILED;
+    }
+    tmpfile_len = strlen(state->filename) + 6;
+    tmpfile = calloc(1, tmpfile_len);
+    sprintf(tmpfile, ".%s.tmp", state->filename);
+
+    tmp_passwdfile = fopen(tmpfile, "wb");
+
+    if(tmp_passwdfile == NULL) {
+        WARN2("Failed to open temporary authentication database \"%s\": %s", 
+                tmpfile, strerror(errno));
+        fclose(passwdfile);
+        free(tmpfile);
+        return AUTH_FAILED;
+    }
+
+
+    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+        if(!line[0] || line[0] == '#')
+            continue;
+
+        sep = strchr(line, ':');
+        if(sep == NULL) {
+            DEBUG0("No seperator in line");
+            continue;
+        }
+
+        *sep = 0;
+        if (strcmp(username, line)) {
+            /* We did not match on the user, so copy it to the temp file */
+            /* and put the : back in */
+            *sep = ':';
+            fprintf(tmp_passwdfile, "%s\n", line);
+        }
+    }
+
+    fclose(tmp_passwdfile);
+    fclose(passwdfile);
+
+    /* Now move the contents of the tmp file to the original */
+    if (rename(tmpfile, state->filename) != 0) {
+        ERROR3("Problem moving temp authentication file to original \"%s\" - \"%s\": %s", 
+                tmpfile, state->filename, strerror(errno));
+    }
+
+    free(tmpfile);
+
+    return AUTH_USERDELETED;
+}
+int auth_deleteuser(source_t *source, char *username)
+{
+    htpasswd_auth_state *state;
+
+    int ret = 0;
+    if (source->authenticator) {
+        if (!strcmp(source->authenticator->type, "htpasswd")) {
+            state = source->authenticator->state;
+            thread_rwlock_wlock(&state->file_rwlock);
+            ret = auth_htpasswd_deleteuser(source->authenticator, username);
+            thread_rwlock_unlock(&state->file_rwlock);
+        }
+    }
+    return ret;
+}
+
+int auth_get_htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode)
+{
+    htpasswd_auth_state *state;
+    FILE *passwdfile;
+    char line[MAX_LINE_LEN];
+    char *sep;
+    char *passwd;
+    xmlNodePtr newnode;
+
+    state = auth->state;
+
+    passwdfile = fopen(state->filename, "rb");
+
+    if(passwdfile == NULL) {
+        WARN2("Failed to open authentication database \"%s\": %s", 
+                state->filename, strerror(errno));
+        return AUTH_FAILED;
+    }
+
+    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+        if(!line[0] || line[0] == '#')
+            continue;
+
+        sep = strchr(line, ':');
+        if(sep == NULL) {
+            DEBUG0("No seperator in line");
+            continue;
+        }
+
+        *sep = 0;
+        newnode = xmlNewChild(srcnode, NULL, "User", NULL);
+        xmlNewChild(newnode, NULL, "username", line);
+        passwd = sep+1;
+        xmlNewChild(newnode, NULL, "password", passwd);
+    }
+
+    fclose(passwdfile);
+    return AUTH_OK;
+}
+
+int auth_get_userlist(source_t *source, xmlNodePtr srcnode)
+{
+    int ret = 0;
+    htpasswd_auth_state *state;
+
+    if (source->authenticator) {
+        if (!strcmp(source->authenticator->type, "htpasswd")) {
+            state = source->authenticator->state;
+            thread_rwlock_rlock(&state->file_rwlock);
+            ret = auth_get_htpasswd_userlist(source->authenticator, srcnode);
+            thread_rwlock_unlock(&state->file_rwlock);
+        }
+    }
+    return ret;
+}

Modified: icecast/trunk/icecast/src/auth.h
===================================================================
--- icecast/trunk/icecast/src/auth.h	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/src/auth.h	2004-04-30 14:36:07 UTC (rev 6610)
@@ -16,11 +16,17 @@
 #include "source.h"
 #include "client.h"
 #include "config.h"
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
 
 typedef enum
 {
     AUTH_OK,
     AUTH_FAILED,
+    AUTH_USERADDED,
+    AUTH_USEREXISTS,
+    AUTH_USERDELETED,
 } auth_result;
 
 typedef struct auth_tag
@@ -30,12 +36,16 @@
             char *username, char *password);
     void (*free)(struct auth_tag *self);
     void *state;
+    void *type;
 } auth_t;
 
 auth_result auth_check_client(source_t *source, client_t *client);
 
 auth_t *auth_get_authenticator(char *type, config_options_t *options);
 void *auth_clear(auth_t *authenticator);
+int auth_get_userlist(source_t *source, xmlNodePtr srcnode);
+int auth_adduser(source_t *source, char *username, char *password);
+int auth_deleteuser(source_t *source, char *username);
 
 #endif
 

Modified: icecast/trunk/icecast/src/cfgfile.c
===================================================================
--- icecast/trunk/icecast/src/cfgfile.c	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/src/cfgfile.c	2004-04-30 14:36:07 UTC (rev 6610)
@@ -551,6 +551,7 @@
                         option = option->next;
                         continue;
                     }
+                    opt->next = NULL;
 
                     if(last_option)
                         last_option->next = opt;

Modified: icecast/trunk/icecast/src/source.c
===================================================================
--- icecast/trunk/icecast/src/source.c	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/src/source.c	2004-04-30 14:36:07 UTC (rev 6610)
@@ -978,6 +978,7 @@
     {
         source->authenticator = auth_get_authenticator(
                 mountinfo->auth_type, mountinfo->auth_options);
+        stats_event(source->mount, "authenticator", mountinfo->auth_type);
     }
     if (mountinfo->dumpfile)
     {

Modified: icecast/trunk/icecast/web/Makefile.am
===================================================================
--- icecast/trunk/icecast/web/Makefile.am	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/web/Makefile.am	2004-04-30 14:36:07 UTC (rev 6610)
@@ -10,4 +10,5 @@
                 corner_topleft.jpg \
                 corner_topright.jpg \
                 icecast.png \
+                key.gif \
                 style.css

Modified: icecast/trunk/icecast/win32/icecast2.iss
===================================================================
--- icecast/trunk/icecast/win32/icecast2.iss	2004-04-30 05:57:54 UTC (rev 6609)
+++ icecast/trunk/icecast/win32/icecast2.iss	2004-04-30 14:36:07 UTC (rev 6610)
@@ -32,13 +32,22 @@
 Source: "Release\Icecast2.exe"; DestDir: "{app}"; Flags: ignoreversion
 Source: "Release\icecast2console.exe"; DestDir: "{app}"; Flags: ignoreversion
 Source: "..\doc\icecast2.chm"; DestDir: "{app}\doc"; Flags: ignoreversion
+Source: "..\web\corner_bottomleft.jpg"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\corner_bottomright.jpg"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\corner_topleft.jpg"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\corner_topright.jpg"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\icecast.png"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\key.gif"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\status2.xsl"; DestDir: "{app}\web"; Flags: ignoreversion
 Source: "..\web\status.xsl"; DestDir: "{app}\web"; Flags: ignoreversion
-Source: "..\web\status2.xsl"; DestDir: "{app}\web"; Flags: ignoreversion
+Source: "..\web\style.css"; DestDir: "{app}\web"; Flags: ignoreversion
+
 Source: "..\admin\listclients.xsl"; DestDir: "{app}\admin"; Flags: ignoreversion
 Source: "..\admin\listmounts.xsl"; DestDir: "{app}\admin"; Flags: ignoreversion
 Source: "..\admin\moveclients.xsl"; DestDir: "{app}\admin"; Flags: ignoreversion
 Source: "..\admin\response.xsl"; DestDir: "{app}\admin"; Flags: ignoreversion
 Source: "..\admin\stats.xsl"; DestDir: "{app}\admin"; Flags: ignoreversion
+Source: "..\admin\manageauth.xsl"; DestDir: "{app}\admin"; Flags: ignoreversion
 Source: "..\..\pthreads\pthreadVSE.dll"; DestDir: "{app}"; Flags: ignoreversion
 Source: "..\conf\icecast.xml"; DestDir: "{app}"; Flags: ignoreversion
 Source: "..\..\iconv\lib\iconv.dll"; DestDir: "{app}"; Flags: ignoreversion

--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list