[asterisk-commits] branch oej/test-this-branch r17044 - in /team/oej/test-this-branch: ./ apps/ ...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Apr 3 01:02:55 MST 2006


Author: oej
Date: Mon Apr  3 03:02:40 2006
New Revision: 17044

URL: http://svn.digium.com/view/asterisk?rev=17044&view=rev
Log:
Update to trunk, resolve conflict

Added:
    team/oej/test-this-branch/doc/ajam.txt
      - copied unchanged from r17009, trunk/doc/ajam.txt
    team/oej/test-this-branch/static-http/
      - copied from r17009, trunk/static-http/
    team/oej/test-this-branch/static-http/ajamdemo.html
      - copied unchanged from r17009, trunk/static-http/ajamdemo.html
    team/oej/test-this-branch/static-http/astman.css
      - copied unchanged from r17009, trunk/static-http/astman.css
    team/oej/test-this-branch/static-http/astman.js
      - copied unchanged from r17009, trunk/static-http/astman.js
    team/oej/test-this-branch/static-http/prototype.js
      - copied unchanged from r17009, trunk/static-http/prototype.js
Modified:
    team/oej/test-this-branch/   (props changed)
    team/oej/test-this-branch/Makefile
    team/oej/test-this-branch/apps/app_rpt.c
    team/oej/test-this-branch/cli.c
    team/oej/test-this-branch/configs/http.conf.sample
    team/oej/test-this-branch/configs/manager.conf.sample
    team/oej/test-this-branch/http.c
    team/oej/test-this-branch/include/asterisk/http.h
    team/oej/test-this-branch/include/asterisk/manager.h
    team/oej/test-this-branch/loader.c
    team/oej/test-this-branch/manager.c

Propchange: team/oej/test-this-branch/
------------------------------------------------------------------------------
    automerge = http://edvina.net/training/

Propchange: team/oej/test-this-branch/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Apr  3 03:02:40 2006
@@ -1,1 +1,1 @@
-/trunk:1-16843
+/trunk:1-17025

Modified: team/oej/test-this-branch/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/Makefile?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/Makefile (original)
+++ team/oej/test-this-branch/Makefile Mon Apr  3 03:02:40 2006
@@ -568,6 +568,13 @@
 
 datafiles: all
 	if [ x`$(ID) -un` = xroot ]; then sh build_tools/mkpkgconfig $(DESTDIR)/usr/lib/pkgconfig; fi
+	# Should static HTTP be installed during make samples or even with its own target ala
+	# webvoicemail?  There are portions here that *could* be customized but might also be
+	# improved a lot.  I'll put it here for now.
+	mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/static-http
+	for x in static-http/*; do \
+		install -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/static-http ; \
+	done
 	mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/digits
 	mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/priv-callerintros
 	for x in sounds/digits/*.gsm; do \

Modified: team/oej/test-this-branch/apps/app_rpt.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/apps/app_rpt.c?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/apps/app_rpt.c (original)
+++ team/oej/test-this-branch/apps/app_rpt.c Mon Apr  3 03:02:40 2006
@@ -608,7 +608,6 @@
 /* Debug mode */
 static int rpt_do_debug(int fd, int argc, char *argv[]);
 static int rpt_do_dump(int fd, int argc, char *argv[]);
-static int rpt_do_frog(int fd, int argc, char *argv[]);
 
 static char debug_usage[] =
 "Usage: rpt debug level {0-7}\n"
@@ -618,10 +617,6 @@
 "Usage: rpt dump <nodename>\n"
 "       Dumps struct debug info to log\n";
 
-static char frog_usage[] =
-"Usage: frog [warp_factor]\n"
-"       Performs frog-in-a-blender calculations (Jacobsen Corollary)\n";
-
 static struct ast_cli_entry  cli_debug =
         { { "rpt", "debug", "level" }, rpt_do_debug, 
 		"Enable app_rpt debugging", debug_usage };
@@ -629,10 +624,6 @@
 static struct ast_cli_entry  cli_dump =
         { { "rpt", "dump" }, rpt_do_dump,
 		"Dump app_rpt structs for debugging", dump_usage };
-
-static struct ast_cli_entry  cli_frog =
-        { { "frog" }, rpt_do_frog,
-		"Perform frog-in-a-blender calculations", frog_usage };
 
 /*
 * Telemetry defaults
@@ -777,26 +768,6 @@
 		        return RESULT_SUCCESS;
 		}
 	}
-	return RESULT_FAILURE;
-}
-
-/*
-* Perform frong-in-a-blender calculations (Jacobsen Corollary) 
-*/
-                                                                                                                                 
-static int rpt_do_frog(int fd, int argc, char *argv[])
-{
-	double warpone = 75139293848.398696166028333356763;
-	double warpfactor = 1.0;
-
-        if (argc > 2) return RESULT_SHOWUSAGE;
-	if ((argc > 1) && (sscanf(argv[1],"%lf",&warpfactor) != 1))
-                return RESULT_SHOWUSAGE;
-
-        ast_cli(fd, "A frog in a blender with a base diameter of 3 inches going\n");
-        ast_cli(fd, "%lf RPM will be travelling at warp factor %lf,\n",
-		warpfactor * warpfactor * warpfactor * warpone,warpfactor);
-	ast_cli(fd,"based upon the Jacobsen Frog Corollary.\n");
 	return RESULT_FAILURE;
 }
 
@@ -7066,7 +7037,6 @@
 	/* Unregister cli extensions */
 	ast_cli_unregister(&cli_debug);
 	ast_cli_unregister(&cli_dump);
-	ast_cli_unregister(&cli_frog);
 
 	return i;
 }
@@ -7078,7 +7048,6 @@
 	/* Register cli extensions */
 	ast_cli_register(&cli_debug);
 	ast_cli_register(&cli_dump);
-	ast_cli_register(&cli_frog);
 
 	return ast_register_application(app, rpt_exec, synopsis, descrip);
 }

Modified: team/oej/test-this-branch/cli.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/cli.c?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/cli.c (original)
+++ team/oej/test-this-branch/cli.c Mon Apr  3 03:02:40 2006
@@ -138,6 +138,10 @@
 "       Optional regular expression pattern is matched to group names for each\n"
 "       channel.\n";
 
+static char frog_help[] =
+"Usage: frog [warp_factor]\n"
+"       Performs frog-in-a-blender calculations (Jacobsen Corollary)\n";
+
 static int handle_load(int fd, int argc, char *argv[])
 {
 	if (argc != 2)
@@ -257,6 +261,28 @@
 	}
 	return RESULT_SUCCESS;
 }
+
+/*
+* Perform frong-in-a-blender calculations (Jacobsen Corollary) 
+*/
+                                                                                                                                 
+static int handle_frog(int fd, int argc, char *argv[])
+{
+	double warpone = 75139293848.0;
+	double warpfactor = 1.0;
+
+	if (argc > 2)
+		return RESULT_SHOWUSAGE;
+	if (argc > 1 && sscanf(argv[1], "%lf", &warpfactor) != 1)
+		return RESULT_SHOWUSAGE;
+
+	ast_cli(fd, "A frog in a blender with a base diameter of 3 inches going\n");
+	ast_cli(fd, "%.0f RPM will be travelling at warp factor %f,\n",
+		warpfactor * warpfactor * warpfactor * warpone, warpfactor);
+	ast_cli(fd, "based upon the Jacobsen Frog Corollary.\n");
+	return RESULT_SUCCESS;
+}
+
 
 #define MODLIST_FORMAT  "%-30s %-40.40s %-10d\n"
 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
@@ -918,6 +944,7 @@
 	{ { "_command", "matchesarray", NULL }, handle_commandmatchesarray, "Returns command matches array", commandmatchesarray_help },
 	{ { "debug", "channel", NULL }, handle_debugchan, "Enable debugging on a channel", debugchan_help, complete_ch_3 },
 	{ { "debug", "level", NULL }, handle_debuglevel, "Set global debug level", debuglevel_help },
+	{ { "frog", NULL }, handle_frog,"Perform frog-in-a-blender calculations", frog_help },
 	{ { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", group_show_channels_help},
 	{ { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help, complete_help },
 	{ { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn },

Modified: team/oej/test-this-branch/configs/http.conf.sample
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/configs/http.conf.sample?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/configs/http.conf.sample (original)
+++ team/oej/test-this-branch/configs/http.conf.sample Mon Apr  3 03:02:40 2006
@@ -4,15 +4,20 @@
 ;
 [general]
 ;
-; Whether HTTP interface is enabled or not.
+; Whether HTTP interface is enabled or not.  Default is no.
 ;
-enabled=no
+;enabled=yes
 ;
-; Address to bind to
+; Whether Asterisk should serve static content from http-static
+; Default is no.
+;
+;enablestatic=yes
+;
+; Address to bind to.  Default is 0.0.0.0
 ;
 bindaddr=127.0.0.1
 ;
-; Port to bind to
+; Port to bind to (default is 8088)
 ;
 bindport=8088
 ;

Modified: team/oej/test-this-branch/configs/manager.conf.sample
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/configs/manager.conf.sample?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/configs/manager.conf.sample (original)
+++ team/oej/test-this-branch/configs/manager.conf.sample Mon Apr  3 03:02:40 2006
@@ -13,11 +13,18 @@
 ; ---------------------------- SECURITY NOTE -------------------------------
 ; Note that you should not enable the AMI on a public IP address. If needed,
 ; block this TCP port with iptables (or another FW software) and reach it
-; with IPsec, SSH, or SSL vpn tunnel
+; with IPsec, SSH, or SSL vpn tunnel.  You can also make the manager 
+; interface available over http if Asterisk's http server is enabled in
+; http.conf and if both "enabled" and "webenabled" are set to yes in
+; this file.  Both default to no.  httptimeout provides the maximum 
+; timeout in seconds before a web based session is discarded.  The 
+; default is 60 seconds.
 ;
 [general]
 enabled = no
+;webenabled = yes
 port = 5038
+;httptimeout = 60
 bindaddr = 0.0.0.0
 ;displayconnects = yes
 ;

Modified: team/oej/test-this-branch/http.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/http.c?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/http.c (original)
+++ team/oej/test-this-branch/http.c Mon Apr  3 03:02:40 2006
@@ -33,19 +33,23 @@
 #include <netinet/in.h>
 #include <sys/time.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/signal.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
 
+#include "asterisk.h"
 #include "asterisk/cli.h"
 #include "asterisk/http.h"
 #include "asterisk/utils.h"
 #include "asterisk/strings.h"
+#include "asterisk/options.h"
+#include "asterisk/config.h"
 
 #define MAX_PREFIX 80
-#define DEFAULT_PREFIX "asterisk"
+#define DEFAULT_PREFIX "/asterisk"
 
 struct ast_http_server_instance {
 	FILE *f;
@@ -61,6 +65,100 @@
 static char prefix[MAX_PREFIX];
 static int prefix_len = 0;
 static struct sockaddr_in oldsin;
+static int enablestatic=0;
+
+/* Limit the kinds of files we're willing to serve up */
+static struct {
+	char *ext;
+	char *mtype;
+} mimetypes[] = {
+	{ "png", "image/png" },
+	{ "jpg", "image/jpeg" },
+	{ "js", "application/x-javascript" },
+	{ "wav", "audio/x-wav" },
+	{ "mp3", "audio/mpeg" },
+};
+
+static char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
+{
+	int x;
+	if (ftype) {
+		for (x=0;x<sizeof(mimetypes) / sizeof(mimetypes[0]); x++) {
+			if (!strcasecmp(ftype, mimetypes[x].ext))
+				return mimetypes[x].mtype;
+		}
+	}
+	snprintf(wkspace, wkspacelen, "text/%s", ftype ? ftype : "plain");
+	return wkspace;
+}
+
+static char *static_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
+{
+	char result[4096];
+	char *c=result;
+	char *path;
+	char *ftype, *mtype;
+	char wkspace[80];
+	struct stat st;
+	int len;
+	int fd;
+	void *blob;
+
+	/* Yuck.  I'm not really sold on this, but if you don't deliver static content it makes your configuration 
+	   substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */
+	if (!enablestatic || ast_strlen_zero(uri))
+		goto out403;
+	/* Disallow any funny filenames at all */
+	if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0]))
+		goto out403;
+	if (strstr(uri, "/.."))
+		goto out403;
+		
+	if ((ftype = strrchr(uri, '.')))
+		ftype++;
+	mtype=ftype2mtype(ftype, wkspace, sizeof(wkspace));
+	
+	/* Cap maximum length */
+	len = strlen(uri) + strlen(ast_config_AST_VAR_DIR) + strlen("/static-http/") + 5;
+	if (len > 1024)
+		goto out403;
+		
+	path = alloca(len);
+	sprintf(path, "%s/static-http/%s", ast_config_AST_VAR_DIR, uri);
+	if (stat(path, &st))
+		goto out404;
+	if (S_ISDIR(st.st_mode))
+		goto out404;
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		goto out403;
+	
+	len = st.st_size + strlen(mtype) + 40;
+	
+	blob = malloc(len);
+	if (blob) {
+		c = blob;
+		sprintf(c, "Content-type: %s\r\n\r\n", mtype);
+		c += strlen(c);
+		*contentlength = read(fd, c, st.st_size);
+		if (*contentlength < 0) {
+			close(fd);
+			free(blob);
+			goto out403;
+		}
+	}
+	return blob;
+
+out404:
+	*status = 404;
+	*title = strdup("Not Found");
+	return ast_http_error(404, "Not Found", NULL, "Nothing to see here.  Move along.");
+
+out403:
+	*status = 403;
+	*title = strdup("Access Denied");
+	return ast_http_error(403, "Access Denied", NULL, "Sorry, I cannot let you do that, Dave.");
+}
 
 
 static char *httpstatus_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
@@ -86,7 +184,15 @@
 	ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
 	v = vars;
 	while(v) {
-		ast_build_string(&c, &reslen, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+		if (strncasecmp(v->name, "cookie_", 7))
+			ast_build_string(&c, &reslen, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+		v = v->next;
+	}
+	ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+	v = vars;
+	while(v) {
+		if (!strncasecmp(v->name, "cookie_", 7))
+			ast_build_string(&c, &reslen, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
 		v = v->next;
 	}
 	ast_build_string(&c, &reslen, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
@@ -98,6 +204,13 @@
 	.description = "Asterisk HTTP General Status",
 	.uri = "httpstatus",
 	.has_subtree = 0,
+};
+	
+static struct ast_http_uri staticuri = {
+	.callback = static_callback,
+	.description = "Asterisk HTTP Static Delivery",
+	.uri = "static",
+	.has_subtree = 1,
 };
 	
 char *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
@@ -153,7 +266,7 @@
 	}
 }
 
-static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength)
+static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies)
 {
 	char *c;
 	char *turi;
@@ -165,8 +278,6 @@
 	struct ast_variable *vars=NULL, *v, *prev = NULL;
 	
 	
-	if (*uri == '/')
-		uri++;
 	params = strchr(uri, '?');
 	if (params) {
 		*params = '\0';
@@ -176,9 +287,9 @@
 			if (val) {
 				*val = '\0';
 				val++;
+				ast_uri_decode(val);
 			} else 
 				val = "";
-			ast_uri_decode(val);
 			ast_uri_decode(var);
 			if ((v = ast_variable_new(var, val))) {
 				if (vars)
@@ -189,6 +300,11 @@
 			}
 		}
 	}
+	if (prev)
+		prev->next = *cookies;
+	else
+		vars = *cookies;
+	*cookies = NULL;
 	ast_uri_decode(uri);
 	if (!strncasecmp(uri, prefix, prefix_len)) {
 		uri += prefix_len;
@@ -216,6 +332,11 @@
 	if (urih) {
 		c = urih->callback(sin, uri, vars, status, title, contentlength);
 		ast_variables_destroy(vars);
+	} else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) {
+		/* Special case: If no prefix, and no URI, send to /static/index.html */
+		c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "This is not the page you are looking for...");
+		*status = 302;
+		*title = strdup("Moved Temporarily");
 	} else {
 		c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this serer.");
 		*status = 404;
@@ -227,9 +348,12 @@
 static void *ast_httpd_helper_thread(void *data)
 {
 	char buf[4096];
+	char cookie[4096];
 	char timebuf[256];
 	struct ast_http_server_instance *ser = data;
+	struct ast_variable *var, *prev=NULL, *vars=NULL;
 	char *uri, *c, *title=NULL;
+	char *vname, *vval;
 	int status = 200, contentlength = 0;
 	time_t t;
 
@@ -252,25 +376,68 @@
 				*c = '\0';
 			}
 		}
+
+		while (fgets(cookie, sizeof(cookie), ser->f)) {
+			/* Trim trailing characters */
+			while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) {
+				cookie[strlen(cookie) - 1] = '\0';
+			}
+			if (ast_strlen_zero(cookie))
+				break;
+			if (!strncasecmp(cookie, "Cookie: ", 8)) {
+				vname = cookie + 8;
+				vval = strchr(vname, '=');
+				if (vval) {
+					/* Ditch the = and the quotes */
+					*vval = '\0';
+					vval++;
+					if (*vval)
+						vval++;
+					if (strlen(vval))
+						vval[strlen(vval) - 1] = '\0';
+					var = ast_variable_new(vname, vval);
+					if (var) {
+						if (prev)
+							prev->next = var;
+						else
+							vars = var;
+						prev = var;
+					}
+				}
+			}
+		}
+
 		if (*uri) {
 			if (!strcasecmp(buf, "get")) 
-				c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength);
+				c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars);
 			else 
 				c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\
 		} else 
 			c = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
+
+		/* If they aren't mopped up already, clean up the cookies */
+		if (vars)
+			ast_variables_destroy(vars);
+
 		if (!c)
 			c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
 		if (c) {
 			time(&t);
 			strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
-			ast_cli(ser->fd, "HTTP/1.1 GET %d %s\r\n", status, title ? title : "OK");
+			ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK");
 			ast_cli(ser->fd, "Server: Asterisk\r\n");
 			ast_cli(ser->fd, "Date: %s\r\n", timebuf);
-			if (contentlength)
-				ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
 			ast_cli(ser->fd, "Connection: close\r\n");
-			ast_cli(ser->fd, "%s", c);
+			if (contentlength) {
+				char *tmp;
+				tmp = strstr(c, "\r\n\r\n");
+				if (tmp) {
+					ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
+					write(ser->fd, c, (tmp + 4 - c));
+					write(ser->fd, tmp + 4, contentlength);
+				}
+			} else
+				ast_cli(ser->fd, "%s", c);
 			free(c);
 		}
 		if (title)
@@ -288,6 +455,8 @@
 	int sinlen;
 	struct ast_http_server_instance *ser;
 	pthread_t launched;
+	pthread_attr_t attr;
+	
 	for (;;) {
 		ast_wait_for_input(httpfd, -1);
 		sinlen = sizeof(sin);
@@ -297,25 +466,43 @@
 				ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
 			continue;
 		}
-		if (!(ser = ast_calloc(1, sizeof(*ser)))) {
-			close(fd);
-			continue;
-		}
-		ser->fd = fd;
-		if ((ser->f = fdopen(ser->fd, "w+"))) {
-			if (ast_pthread_create(&launched, NULL, ast_httpd_helper_thread, ser)) {
-				ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
-				fclose(ser->f);
+		ser = ast_calloc(1, sizeof(*ser));
+		if (ser) {
+			ser->fd = fd;
+			memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
+			if ((ser->f = fdopen(ser->fd, "w+"))) {
+				pthread_attr_init(&attr);
+				pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+				
+				if (ast_pthread_create(&launched, &attr, ast_httpd_helper_thread, ser)) {
+					ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
+					fclose(ser->f);
+					free(ser);
+				}
+			} else {
+				ast_log(LOG_WARNING, "fdopen failed!\n");
+				close(ser->fd);
 				free(ser);
 			}
 		} else {
-			ast_log(LOG_WARNING, "fdopen failed!\n");
 			close(ser->fd);
 			free(ser);
 		}
 	}
 	return NULL;
 }
+
+char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, int buflen)
+{
+	char *c;
+	c = buf;
+	ast_build_string(&c, &buflen, "Set-Cookie: %s=\"%s\"; Version=\"1\"", var, val);
+	if (expires)
+		ast_build_string(&c, &buflen, "; Max-Age=%d", expires);
+	ast_build_string(&c, &buflen, "\r\n");
+	return buf;
+}
+
 
 static void http_server_start(struct sockaddr_in *sin)
 {
@@ -383,6 +570,7 @@
 	struct ast_config *cfg;
 	struct ast_variable *v;
 	int enabled=0;
+	int newenablestatic=0;
 	struct sockaddr_in sin;
 	struct hostent *hp;
 	struct ast_hostent ahp;
@@ -396,6 +584,8 @@
 		while(v) {
 			if (!strcasecmp(v->name, "enabled"))
 				enabled = ast_true(v->value);
+			else if (!strcasecmp(v->name, "enablestatic"))
+				newenablestatic = ast_true(v->value);
 			else if (!strcasecmp(v->name, "bindport"))
 				sin.sin_port = ntohs(atoi(v->value));
 			else if (!strcasecmp(v->name, "bindaddr")) {
@@ -404,8 +594,15 @@
 				} else {
 					ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
 				}
-			} else if (!strcasecmp(v->name, "prefix"))
-				ast_copy_string(newprefix, v->value, sizeof(newprefix));
+			} else if (!strcasecmp(v->name, "prefix")) {
+				if (!ast_strlen_zero(v->value)) {
+					newprefix[0] = '/';
+					ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
+				} else {
+					newprefix[0] = '\0';
+				}
+					
+			}
 			v = v->next;
 		}
 		ast_config_destroy(cfg);
@@ -416,6 +613,7 @@
 		ast_copy_string(prefix, newprefix, sizeof(prefix));
 		prefix_len = strlen(prefix);
 	}
+	enablestatic = newenablestatic;
 	http_server_start(&sin);
 	return 0;
 }
@@ -437,7 +635,7 @@
 	ast_cli(fd, "Enabled URI's:\n");
 	urih = uris;
 	while(urih){
-		ast_cli(fd, "/%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
+		ast_cli(fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
 		urih = urih->next;
 	}
 	if (!uris)
@@ -462,6 +660,7 @@
 int ast_http_init(void)
 {
 	ast_http_uri_link(&statusuri);
+	ast_http_uri_link(&staticuri);
 	ast_cli_register_multiple(http_cli, sizeof(http_cli) / sizeof(http_cli[0]));
 	return __ast_http_load(0);
 }

Modified: team/oej/test-this-branch/include/asterisk/http.h
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/include/asterisk/http.h?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/include/asterisk/http.h (original)
+++ team/oej/test-this-branch/include/asterisk/http.h Mon Apr  3 03:02:40 2006
@@ -58,6 +58,8 @@
 /* Destroy an HTTP server */
 void ast_http_uri_unlink(struct ast_http_uri *urihandler);
 
+char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, int buflen);
+
 int ast_http_init(void);
 int ast_http_reload(void);
 

Modified: team/oej/test-this-branch/include/asterisk/manager.h
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/include/asterisk/manager.h?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/include/asterisk/manager.h (original)
+++ team/oej/test-this-branch/include/asterisk/manager.h Mon Apr  3 03:02:40 2006
@@ -124,11 +124,6 @@
 /* Export manager structures */
 #define AST_MAX_MANHEADERS 80
 #define AST_MAX_MANHEADER_LEN 256
-
-struct eventqent {
-	struct eventqent *next;
-	char eventdata[1];
-};
 
 struct ast_manager_user {
 	char username[80];
@@ -141,8 +136,7 @@
 	struct ast_manager_user *next;
 };
 
-
-struct mansession {
+static struct mansession {
 	/*! Execution thread */
 	pthread_t t;
 	/*! Thread lock -- don't use in action callbacks, it's already taken care of  */
@@ -155,6 +149,18 @@
 	int busy;
 	/*! Whether or not we're "dead" */
 	int dead;
+	/*! Whether an HTTP manager is in use */
+	int inuse;
+	/*! Whether an HTTP session should be destroyed */
+	int needdestroy;
+	/*! Whether an HTTP session has someone waiting on events */
+	pthread_t waiting_thread;
+	/*! Unique manager identifer */
+	unsigned long managerid;
+	/*! Session timeout if HTTP */
+	time_t sessiontimeout;
+	/*! Output from manager interface */
+	char *outputstr;
 	/*! Logged in username */
 	char username[80];
 	/*! Authentication challenge */
@@ -174,7 +180,7 @@
 	/* Timeout for ast_carefulwrite() */
 	int writetimeout;
 	struct mansession *next;
-};
+} *sessions = NULL;
 
 struct message {
 	int hdrcount;

Modified: team/oej/test-this-branch/loader.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/loader.c?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/loader.c (original)
+++ team/oej/test-this-branch/loader.c Mon Apr  3 03:02:40 2006
@@ -375,18 +375,18 @@
 		/* print some debugging info for new modules */
 		if (m->state == MS_NEW &&
 		    (m->cb.exported_symbols || m->cb.required_symbols))
-			ast_log(LOG_WARNING,
+			ast_log(LOG_NOTICE,
 			    "module %-30s exports %p requires %p state %s(%d)\n",
 				m->resource, m->cb.exported_symbols,
 				m->cb.required_symbols,
 				st_name(m->state), m->state);
 	}
-	ast_log(LOG_WARNING, "---- fixup (%s): %d modules, %d new ---\n",
+	ast_log(LOG_DEBUG, "---- fixup (%s): %d modules, %d new ---\n",
 		caller, total, new);
 	for (;;cycle++) {
 		int again = 0;	/* set if we need another round */
 		
-		ast_log(LOG_WARNING, "---- fixup: cycle %d ---\n", cycle);
+		ast_log(LOG_DEBUG, "---- fixup: cycle %d ---\n", cycle);
 		AST_LIST_TRAVERSE(&module_list, m, next) {
 			if (resolve(m))
 				again = 1;	/* something changed */
@@ -417,7 +417,7 @@
 		if (!again)	/* we are done */
 			break;
 	}
-	ast_log(LOG_WARNING, "---- fixup complete ---\n");
+	ast_log(LOG_DEBUG, "---- fixup complete ---\n");
 	in_fixup--;
 	return 0;
 }

Modified: team/oej/test-this-branch/manager.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/manager.c?rev=17044&r1=17043&r2=17044&view=diff
==============================================================================
--- team/oej/test-this-branch/manager.c (original)
+++ team/oej/test-this-branch/manager.c Mon Apr  3 03:02:40 2006
@@ -35,6 +35,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <netdb.h>
@@ -64,6 +65,7 @@
 #include "asterisk/md5.h"
 #include "asterisk/acl.h"
 #include "asterisk/utils.h"
+#include "asterisk/http.h"
 
 struct fast_originate_helper {
 	char tech[AST_MAX_MANHEADER_LEN];
@@ -81,11 +83,20 @@
 	struct ast_variable *vars;
 };
 
+struct eventqent {
+	int usecount;
+	int category;
+	ast_mutex_t lock;
+	struct eventqent *next;
+	char eventdata[1];
+};
+
 static int enabled = 0;
 static int portno = DEFAULT_MANAGER_PORT;
 static int asock = -1;
 static int displayconnects = 1;
 static int timestampevents = 0;
+static int httptimeout = 60;
 
 static pthread_t t;
 AST_MUTEX_DEFINE_STATIC(sessionlock);
@@ -93,6 +104,8 @@
 static struct ast_manager_user *amus =NULL;
 AST_MUTEX_DEFINE_STATIC(amulock);
 static int block_sockets = 0;
+static int num_sessions = 0;
+struct eventqent *master_eventq = NULL;
 
 static struct permalias {
 	int num;
@@ -221,11 +234,168 @@
 	return ret;
 }
 
+static void xml_copy_escape(char **dst, int *maxlen, const char *src, int lower)
+{
+	while (*src && (*maxlen > 6)) {
+		switch(*src) {
+		case '<':
+			strcpy(*dst, "&lt;");
+			(*dst) += 4;
+			*maxlen -= 4;
+			break;
+		case '>':
+			strcpy(*dst, "&gt;");
+			(*dst) += 4;
+			*maxlen -= 4;
+			break;
+		case '\"':
+			strcpy(*dst, "&quot;");
+			(*dst) += 6;
+			*maxlen -= 6;
+			break;
+		case '\'':
+			strcpy(*dst, "&apos;");
+			(*dst) += 6;
+			*maxlen -= 6;
+			break;
+		case '&':
+			strcpy(*dst, "&amp;");
+			(*dst) += 4;
+			*maxlen -= 4;
+			break;		
+		default:
+			*(*dst)++ = lower ? tolower(*src) : *src;
+			(*maxlen)--;
+		}
+		src++;
+	}
+}
+static char *xml_translate(char *in, struct ast_variable *vars)
+{
+	struct ast_variable *v;
+	char *dest=NULL;
+	char *out, *tmp, *var, *val;
+	char *objtype=NULL;
+	int colons = 0;
+	int breaks = 0;
+	int len;
+	int count = 1;
+	int escaped = 0;
+	int inobj = 0;
+	int x;
+	v = vars;
+	while(v) {
+		if (!dest && !strcasecmp(v->name, "ajaxdest"))
+			dest = v->value;
+		else if (!objtype && !strcasecmp(v->name, "ajaxobjtype")) 
+			objtype = v->value;
+		v = v->next;
+	}
+	if (!dest)
+		dest = "unknown";
+	if (!objtype)
+		objtype = "generic";
+	for (x=0;in[x];x++) {
+		if (in[x] == ':')
+			colons++;
+		else if (in[x] == '\n')
+			breaks++;
+		else if (strchr("&\"<>", in[x]))
+			escaped++;
+	}
+	len = strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10; /* foo="bar", "<response type=\"object\" id=\"dest\"", "&amp;" */
+	out = malloc(len);
+	if (!out)
+		return 0;
+	tmp = out;
+	while(*in) {
+		var = in;
+		while (*in && (*in >= 32)) in++;
+		if (*in) {
+			if ((count > 3) && inobj) {
+				ast_build_string(&tmp, &len, " /></response>\n");
+				inobj = 0;
+			}
+			count = 0;
+			while (*in && (*in < 32)) {
+				*in = '\0';
+				in++;
+				count++;
+			}
+			val = strchr(var, ':');
+			if (val) {
+				*val = '\0';
+				val++;
+				if (*val == ' ')
+					val++;
+				if (!inobj) {
+					ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
+					inobj = 1;
+				}
+				ast_build_string(&tmp, &len, " ");				
+				xml_copy_escape(&tmp, &len, var, 1);
+				ast_build_string(&tmp, &len, "='");
+				xml_copy_escape(&tmp, &len, val, 0);
+				ast_build_string(&tmp, &len, "'");
+			}
+		}
+	}
+	if (inobj)
+		ast_build_string(&tmp, &len, " /></response>\n");
+	return out;
+}
+
+static char *html_translate(char *in)
+{
+	int x;
+	int colons = 0;
+	int breaks = 0;
+	int len;
+	int count=1;
+	char *tmp, *var, *val, *out;
+	for (x=0;in[x];x++) {
+		if (in[x] == ':')
+			colons++;
+		if (in[x] == '\n')
+			breaks++;
+	}
+	len = strlen(in) + colons * 40 + breaks * 40; /* <tr><td></td><td></td></tr>, "<tr><td colspan=\"2\"><hr></td></tr> */
+	out = malloc(len);
+	if (!out)
+		return 0;
+	tmp = out;
+	while(*in) {
+		var = in;
+		while (*in && (*in >= 32)) in++;
+		if (*in) {
+			if ((count % 4) == 0){
+				ast_build_string(&tmp, &len, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+			}
+			count = 0;
+			while (*in && (*in < 32)) {
+				*in = '\0';
+				in++;
+				count++;
+			}
+			val = strchr(var, ':');
+			if (val) {
+				*val = '\0';
+				val++;
+				if (*val == ' ')
+					val++;
+				ast_build_string(&tmp, &len, "<tr><td>%s</td><td>%s</td></tr>\r\n", var, val);
+			}
+		}
+	}
+	return out;
+}
+
 void astman_append(struct mansession *s, const char *fmt, ...)
 {
 	char *stuff;
 	int res;
 	va_list ap;
+	char *tmp;
 
 	va_start(ap, fmt);
 	res = vasprintf(&stuff, fmt, ap);
@@ -233,7 +403,17 @@
 	if (res == -1) {
 		ast_log(LOG_ERROR, "Memory allocation failure\n");
 	} else {
-		ast_carefulwrite(s->fd, stuff, strlen(stuff), 100);
+		if (s->fd > -1)
+			ast_carefulwrite(s->fd, stuff, strlen(stuff), 100);
+		else {
+			tmp = realloc(s->outputstr, (s->outputstr ? strlen(s->outputstr) : 0) + strlen(stuff) + 1);
+			if (tmp) {
+				if (!s->outputstr)
+					tmp[0] = '\0';
+				s->outputstr = tmp;
+				strcat(s->outputstr, stuff);
+			}
+		}
 		free(stuff);
 	}
 }
@@ -299,6 +479,23 @@
 	return RESULT_SUCCESS;
 }
 
+/*! \brief  handle_showmanconn: CLI command show manager connected */
+/* Should change to "manager show connected" */
+static int handle_showmaneventq(int fd, int argc, char *argv[])
+{
+	struct eventqent *s;
+	ast_mutex_lock(&sessionlock);
+	s = master_eventq;
+	while (s) {
+		ast_cli(fd, "Usecount: %d\n",s->usecount);
+		ast_cli(fd, "Category: %d\n", s->category);
+		ast_cli(fd, "Event:\n%s", s->eventdata);
+		s = s->next;
+	}
+	ast_mutex_unlock(&sessionlock);
+	return RESULT_SUCCESS;
+}
+
 static char showmancmd_help[] = 
 "Usage: show manager command <actionname>\n"
 "	Shows the detailed description for a specific Asterisk manager interface command.\n";
@@ -312,6 +509,11 @@
 "	Prints a listing of the users that are currently connected to the\n"
 "Asterisk manager interface.\n";
 
+static char showmaneventq_help[] = 
+"Usage: show manager eventq\n"
+"	Prints a listing of all events pending in the Asterisk manger\n"
+"event queue.\n";
+
 static struct ast_cli_entry show_mancmd_cli =
 	{ { "show", "manager", "command", NULL },
 	handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
@@ -324,6 +526,7 @@
 	{ { "show", "manager", "connected", NULL },
 	handle_showmanconn, "Show connected manager interface users", showmanconn_help };
 
+<<<<<<< .working
 
 static int handle_showmanager(int fd, int argc, char *argv[])
 {
@@ -415,16 +618,36 @@
 { { "manager", "show", "user" }, handle_showmanager, "Display information on a specific manager", showmanager_help};
 
 
+static struct ast_cli_entry show_maneventq_cli =
+	{ { "show", "manager", "eventq", NULL },
+	handle_showmaneventq, "Show manager interface queued events", showmaneventq_help };
+
+static void unuse_eventqent(struct eventqent *e)
+{
+	/* XXX Need to atomically decrement the users.  Change this to atomic_dec
+	       one day when we have such a beast XXX */
+	int val;
+	ast_mutex_lock(&e->lock);
+	e->usecount--;
+	val = !e->usecount && e->next;
+	ast_mutex_unlock(&e->lock);
+	/* Wake up sleeping beauty */
+	if (val)
+		pthread_kill(t, SIGURG);
+}
+
 static void free_session(struct mansession *s)
 {
 	struct eventqent *eqe;
 	if (s->fd > -1)
 		close(s->fd);
+	if (s->outputstr)
+		free(s->outputstr);
 	ast_mutex_destroy(&s->__lock);
 	while(s->eventq) {
 		eqe = s->eventq;
 		s->eventq = s->eventq->next;
-		free(eqe);
+		unuse_eventqent(eqe);
 	}
 	free(s);
 }
@@ -446,6 +669,7 @@
 		else
 			sessions = cur->next;
 		free_session(s);
+		num_sessions--;
 	} else
 		ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
 	ast_mutex_unlock(&sessionlock);
@@ -706,7 +930,7 @@
 							return -1;
 						}
 					}
-				} else if (password && !strcasecmp(password, pass)) {
+				} else if (password && !strcmp(password, pass)) {
 					break;
 				} else {
 					ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
@@ -733,13 +957,105 @@
 
 /*! \brief PING: Manager PING */
 static char mandescr_ping[] = 
-"Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the "
+"Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the\n"
 "  manager connection open.\n"
 "Variables: NONE\n";
 
 static int action_ping(struct mansession *s, struct message *m)
 {
 	astman_send_response(s, m, "Pong", NULL);
+	return 0;
+}
+
+/*! \brief WAITEVENT: Manager WAITEVENT */
+static char mandescr_waitevent[] = 
+"Description: A 'WaitEvent' action will ellicit a 'Success' response.  Whenever\n"
+"a manager event is queued.  Once WaitEvent has been called on an HTTP manager\n"
+"session, events will be generated and queued.\n"
+"Variables: \n"
+"   Timeout: Maximum time to wait for events\n";
+
+static int action_waitevent(struct mansession *s, struct message *m)
+{
+	char *timeouts = astman_get_header(m, "Timeout");
+	int timeout = -1, max;
+	int x;
+	int needexit = 0;
+	time_t now;
+	struct eventqent *eqe;
+	char *id = astman_get_header(m,"ActionID");
+	char idText[256]="";
+
+	if (!ast_strlen_zero(id))
+		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+
+	if (!ast_strlen_zero(timeouts)) {
+		sscanf(timeouts, "%i", &timeout);
+	}
+	
+	ast_mutex_lock(&s->__lock);
+	if (s->waiting_thread != AST_PTHREADT_NULL) {
+		pthread_kill(s->waiting_thread, SIGURG);
+	}
+	if (s->sessiontimeout) {
+		time(&now);
+		max = s->sessiontimeout - now - 10;
+		if (max < 0)
+			max = 0;
+		if ((timeout < 0) || (timeout > max))
+			timeout = max;
+		if (!s->send_events)
+			s->send_events = -1;
+		/* Once waitevent is called, always queue events from now on */
+		if (s->busy == 1)
+			s->busy = 2;
+	}
+	ast_mutex_unlock(&s->__lock);
+	s->waiting_thread = pthread_self();
+	if (option_debug)
+		ast_log(LOG_DEBUG, "Starting waiting for an event!\n");
+	for (x=0;((x<timeout) || (timeout < 0)); x++) {
+		ast_mutex_lock(&s->__lock);
+		if (s->eventq && s->eventq->next)
+			needexit = 1;
+		if (s->waiting_thread != pthread_self())
+			needexit = 1;
+		if (s->needdestroy)
+			needexit = 1;
+		ast_mutex_unlock(&s->__lock);
+		if (needexit)
+			break;
+		if (s->fd > 0) {
+			if (ast_wait_for_input(s->fd, 1000))
+				break;
+		} else {
+			sleep(1);
+		}
+	}
+	if (option_debug)
+		ast_log(LOG_DEBUG, "Finished waiting for an event!\n");
+	ast_mutex_lock(&s->__lock);
+	if (s->waiting_thread == pthread_self()) {
+		astman_send_response(s, m, "Success", "Waiting for Event...");
+		/* Only show events if we're the most recent waiter */
+		while(s->eventq->next) {
+			eqe = s->eventq->next;
+			if (((s->readperm & eqe->category) == eqe->category) &&
+			    ((s->send_events & eqe->category) == eqe->category)) {
+				astman_append(s, "%s", eqe->eventdata);
+			}
+			unuse_eventqent(s->eventq);
+			s->eventq = eqe;
+		}
+		astman_append(s,
+			"Event: WaitEventComplete\r\n"
+			"%s"
+			"\r\n",idText);
+		s->waiting_thread = AST_PTHREADT_NULL;
+	} else {
+		ast_log(LOG_DEBUG, "Abandoning event request!\n");
+	}
+	ast_mutex_unlock(&s->__lock);
 	return 0;
 }
 
@@ -1433,6 +1749,30 @@
 	return 0;
 }
 
+static int process_events(struct mansession *s)
+{
+	struct eventqent *eqe;
+	int ret = 0;
+	ast_mutex_lock(&s->__lock);
+	if (s->fd > -1) {
+		s->busy--;
+		if (!s->eventq)
+			s->eventq = master_eventq;
+		while(s->eventq->next) {
+			eqe = s->eventq->next;
+			if ((s->authenticated && (s->readperm & eqe->category) == eqe->category) &&
+			    ((s->send_events & eqe->category) == eqe->category)) {
+				if (!ret && ast_carefulwrite(s->fd, eqe->eventdata, strlen(eqe->eventdata), s->writetimeout) < 0)
+					ret = -1;
+			}
+			unuse_eventqent(s->eventq);
+			s->eventq = eqe;
+		}
+	}
+	ast_mutex_unlock(&s->__lock);
+	return ret;
+}
+
 static int process_message(struct mansession *s, struct message *m)
 {
 	char action[80] = "";
@@ -1440,6 +1780,7 @@
 	char *id = astman_get_header(m,"ActionID");
 	char idText[256] = "";
 	char iabuf[INET_ADDRSTRLEN];
+	int ret = 0;
 
 	ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
 	ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
@@ -1448,9 +1789,9 @@
 		astman_send_error(s, m, "Missing action in request");
 		return 0;
 	}
-        if (!ast_strlen_zero(id)) {
-                snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
-        }
+	if (!ast_strlen_zero(id)) {
+		snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
+	}
 	if (!s->authenticated) {
 		if (!strcasecmp(action, "Challenge")) {
 			char *authtype;
@@ -1478,10 +1819,10 @@
 				s->authenticated = 1;
 				if (option_verbose > 1) {
 					if ( displayconnects ) {
-						ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
+						ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n", (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
 					}
 				}
-				ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
+				ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
 				astman_send_ack(s, m, "Authentication accepted");
 			}

[... 570 lines stripped ...]


More information about the asterisk-commits mailing list