diff --git a/CHANGES b/CHANGES
index 945c568254cfc5fb52d9af4ffec4825c692fbc99..1cc225f023beea706215b0606c71334e6f7653d7 100755
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,38 @@
+Asterisk 0.1.8
+ -- Keep track of version information
+ -- Add -f to cause Asterisk not to fork
+ -- Keep important information in voicemail .txt file
+ -- Adtran Voice over Frame Relay updates
+ -- Implement option setting/querying of channel drivers
+ -- IAX performance improvements and protocol fixes
+ -- Substantial enhancement of console channel driver
+ -- Add IAX registration.  Now IAX can dynamically register
+ -- Add flash-hook transfer on tormenta channels
+ -- Added Three Way Calling on tormenta channels
+ -- Start on concept of zombie channel
+ -- Add Call Waiting CallerID
+ -- Keep track of who registeres contexts, includes, and extensions
+ -- Added Call Waiting(tm), *67, *70, and *82 codes
+ -- Move parked calls into "parkedcalls" context by default
+ -- Allow dialplan to be displayed
+ -- Allow "=>" instead of just "=" to make instantiation clearer
+ -- Asterisk forks if called with no arguments
+ -- Add remote control by running asterisk -vvvc
+ -- Adjust verboseness with "set verbose" now
+ -- No longer requires libaudiofile
+ -- Install beep
+ -- Make PBX Config module reload extensions on SIGHUP
+ -- Allow modules to be reloaded when SIGHUP is received
+ -- Variables now contain line numbers
+ -- Make dialer send in band signalling
+ -- Add record application
+ -- Added PRI signalling to Tormenta driver
+ -- Allow use of BYEXTENSION in "Goto"
+ -- Allow adjustment of gains on tormenta channels
+ -- Added raw PCM file format support
+ -- Add U-law translator
+ -- Fix DTMF handling in bridge code
+ -- Fix access control with IAX
 * Asterisk 0.1.7
  -- Update configuration files and add some missing sounds
  -- Added ability to include one context in another
diff --git a/Makefile b/Makefile
index 260d782c475650195f75e299a73ac75960db90d8..55b57b28086abead4c943b8e7a9f9d343e224e22 100755
--- a/Makefile
+++ b/Makefile
@@ -23,11 +23,14 @@ PROC=i586
 
 DEBUG=-g #-pg
 INCLUDE=-Iinclude -I../include
-CFLAGS=-pipe -Wall -Werror -Wmissing-prototypes -Wmissing-declarations -fomit-frame-pointer -O6 $(DEBUG) $(INCLUDE) -D_REENTRANT
+CFLAGS=-pipe  -Wall -Werror -Wmissing-prototypes -Wmissing-declarations -O6 $(DEBUG) $(INCLUDE) -D_REENTRANT
 CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
-CFLAGS += -DDO_CRASH
+ASTERISKVERSION=$(shell cat .version)
+CFLAGS+=-DASTERISK_VERSION=\"$(ASTERISKVERSION)\"
+CFLAGS+= -DDO_CRASH -DDEBUG_THREADS
+CFLAGS+=# -fomit-frame-pointer 
 SUBDIRS=channels pbx apps codecs formats
-LIBS=-ldl -lpthread -lreadline -lncurses -lm # -lefence
+LIBS=-ldl -lpthread -lreadline -lncurses -lm
 OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
 	translate.o file.o say.o pbx.o cli.o md5.o \
 	ulaw.o callerid.o fskmodem.o asterisk.o 
@@ -46,7 +49,13 @@ _all: all
 
 all: asterisk subdirs
 
-asterisk: $(OBJS)
+_version: 
+	if [ -d CVS ]; then echo "CVS-`date +"%D-%T"`" > .version; fi 
+
+build.h:
+	./make_build_h
+
+asterisk: _version build.h $(OBJS)
 	gcc -o asterisk -rdynamic $(OBJS) $(LIBS)
 
 subdirs: 
@@ -55,17 +64,20 @@ subdirs:
 clean:
 	for x in $(SUBDIRS); do $(MAKE) -C $$x clean || exit 1 ; done
 	rm -f *.o *.so asterisk
+	rm -f build.h
 
 datafiles: all
 	mkdir -p /var/lib/asterisk/sounds/digits
 	for x in sounds/digits/*; do \
 		install $$x /var/lib/asterisk/sounds/digits ; \
 	done
-	for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-*; do \
+	for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep*; do \
 		install $$x /var/lib/asterisk/sounds ; \
 	done
 install: all datafiles
 	mkdir -p $(MODULES_DIR)
+	mkdir -p /usr/sbin
+	install -m 755 asterisk /usr/sbin/
 	for x in $(SUBDIRS); do $(MAKE) -C $$x install || exit 1 ; done
 	install -d /usr/include/asterisk
 	install include/asterisk/*.h /usr/include/asterisk
diff --git a/asterisk.c b/asterisk.c
index 94e6802d060dccda6c32b2db142d9fae00849456..a73307be006e316e777ad4d47b120aa6a32f5ebb 100755
--- a/asterisk.c
+++ b/asterisk.c
@@ -19,34 +19,240 @@
 #include <asterisk/channel.h>
 #include <asterisk/ulaw.h>
 #include <asterisk/callerid.h>
+#include <asterisk/module.h>
 #include <stdio.h>
 #include <signal.h>
 #include <sched.h>
 #include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <string.h>
+#include <errno.h>
 #include <readline/readline.h>
 #include <readline/history.h>
 #include "asterisk.h"
 
+#define AST_MAX_CONNECTS 128
+#define NUM_MSGS 64
+
 int option_verbose=0;
 int option_debug=0;
 int option_nofork=0;
 int option_quiet=0;
 int option_console=0;
 int option_highpriority=0;
+int option_remote=0;
+int option_exec=0;
 int fully_booted = 0;
 
+static int ast_socket = -1;		/* UNIX Socket for allowing remote control */
+static int ast_consock = -1;		/* UNIX Socket for controlling another asterisk */
+static int mainpid;
+struct console {
+	int fd;					/* File descriptor */
+	int p[2];				/* Pipe */
+	pthread_t t;			/* Thread of handler */
+};
+
+struct console consoles[AST_MAX_CONNECTS];
+
 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
 
+static int fdprint(int fd, char *s)
+{
+	return write(fd, s, strlen(s) + 1);
+}
+
+static void network_verboser(char *s, int pos, int replace, int complete)
+{
+	int x;
+	for (x=0;x<AST_MAX_CONNECTS; x++) {
+		if (consoles[x].fd > -1) 
+			fdprint(consoles[x].p[1], s);
+	}
+}
+
+static pthread_t lthread;
+
+static void *netconsole(void *vconsole)
+{
+	struct console *con = vconsole;
+	char hostname[256];
+	char tmp[512];
+	int res;
+	int max;
+	fd_set rfds;
+	
+	if (gethostname(hostname, sizeof(hostname)))
+		strncpy(hostname, "<Unknown>", sizeof(hostname));
+	snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, mainpid, ASTERISK_VERSION);
+	fdprint(con->fd, tmp);
+	for(;;) {
+		FD_ZERO(&rfds);	
+		FD_SET(con->fd, &rfds);
+		FD_SET(con->p[0], &rfds);
+		max = con->fd;
+		if (con->p[0] > max)
+			max = con->p[0];
+		res = select(max + 1, &rfds, NULL, NULL, NULL);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "select returned < 0: %s\n", strerror(errno));
+			continue;
+		}
+		if (FD_ISSET(con->fd, &rfds)) {
+			res = read(con->fd, tmp, sizeof(tmp));
+			if (res < 1)
+				break;
+			tmp[res] = 0;
+			ast_cli_command(con->fd, tmp);
+		}
+		if (FD_ISSET(con->p[0], &rfds)) {
+			res = read(con->p[0], tmp, sizeof(tmp));
+			if (res < 1) {
+				ast_log(LOG_ERROR, "read returned %d\n", res);
+				break;
+			}
+			res = write(con->fd, tmp, res);
+			if (res < 1)
+				break;
+		}
+	}
+	if (option_verbose > 2) 
+		ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
+	close(con->fd);
+	close(con->p[0]);
+	close(con->p[1]);
+	con->fd = -1;
+	
+	return NULL;
+}
+
+static void *listener(void *unused)
+{
+	struct sockaddr_un sun;
+	int s;
+	int len;
+	int x;
+	pthread_attr_t attr;
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	for(;;) {
+		len = sizeof(sun);
+		s = accept(ast_socket, (struct sockaddr *)&sun, &len);
+		if (s < 0) {
+			ast_log(LOG_WARNING, "Accept retured %d: %s\n", s, strerror(errno));
+		} else {
+			for (x=0;x<AST_MAX_CONNECTS;x++) {
+				if (consoles[x].fd < 0) {
+					if (pipe(consoles[x].p)) {
+						ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
+						consoles[x].fd = -1;
+						fdprint(s, "Server failed to create pipe\n");
+						close(s);
+						break;
+					}
+					consoles[x].fd = s;
+					if (pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
+						ast_log(LOG_ERROR, "Unable to spawn thread to handle connection\n");
+						consoles[x].fd = -1;
+						fdprint(s, "Server failed to spawn thread\n");
+						close(s);
+					}
+					break;
+				}
+			}
+			if (x >= AST_MAX_CONNECTS) {
+				fdprint(s, "No more connections allowed\n");
+				ast_log(LOG_WARNING, "No more connections allowed\n");
+				close(s);
+			} else if (consoles[x].fd > -1) {
+				if (option_verbose > 2) 
+					ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
+			}
+		}
+	}
+	return NULL;
+}
+
+static int ast_makesocket(void)
+{
+	struct sockaddr_un sun;
+	int res;
+	int x;
+	for (x=0;x<AST_MAX_CONNECTS;x++)	
+		consoles[x].fd = -1;
+	unlink(AST_SOCKET);
+	ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (ast_socket < 0) {
+		ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
+		return -1;
+	}		
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_LOCAL;
+	strncpy(sun.sun_path, AST_SOCKET, sizeof(sun.sun_path));
+	res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
+	if (res) {
+		ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", AST_SOCKET, strerror(errno));
+		close(ast_socket);
+		ast_socket = -1;
+		return -1;
+	}
+	res = listen(ast_socket, 2);
+	if (res < 0) {
+		ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", AST_SOCKET, strerror(errno));
+		close(ast_socket);
+		ast_socket = -1;
+		return -1;
+	}
+	ast_register_verbose(network_verboser);
+	pthread_create(&lthread, NULL, listener, NULL);
+	return 0;
+}
+
+static int ast_tryconnect(void)
+{
+	struct sockaddr_un sun;
+	int res;
+	ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (ast_consock < 0) {
+		ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
+		return 0;
+	}
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_LOCAL;
+	strncpy(sun.sun_path, AST_SOCKET, sizeof(sun.sun_path));
+	res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
+	if (res) {
+		close(ast_consock);
+		ast_consock = -1;
+		return 0;
+	} else
+		return 1;
+}
+
 static void urg_handler(int num)
 {
 	/* Called by soft_hangup to interrupt the select, read, or other
 	   system call.  We don't actually need to do anything though.  */
-	if (option_debug)
+	if (option_debug) 
 		ast_log(LOG_DEBUG, "Urgent handler\n");
 	signal(num, urg_handler);
 	return;
 }
 
+static void hup_handler(int num)
+{
+	if (option_verbose > 1) 
+		ast_verbose(VERBOSE_PREFIX_2 "Received HUP signal -- Reloading configs\n");
+	ast_module_reload();
+}
+
+
+static void pipe_handler(int num)
+{
+	/* Ignore sigpipe */
+}
 static void set_title(char *text)
 {
 	/* Set an X-term or screen title */
@@ -86,19 +292,26 @@ static int set_priority(int pri)
 
 static void quit_handler(int num)
 {
-	static pthread_mutex_t quitlock = PTHREAD_MUTEX_INITIALIZER;
 	char filename[80] = "";
-	if (getenv("HOME")) 
-		snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
-	/* Quit only once */
-	pthread_mutex_lock(&quitlock);
+	if (option_console || option_remote) {
+		if (getenv("HOME")) 
+			snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
+		if (strlen(filename))
+			write_history(filename);
+		rl_callback_handler_remove();
+	}
 	/* Called on exit */
-	if (option_verbose)
+	if (option_verbose && option_console)
 		ast_verbose("Asterisk ending (%d).\n", num);
 	else if (option_debug)
 		ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
-	if (strlen(filename))
-		write_history(filename);
+	if (ast_socket > -1)
+		close(ast_socket);
+	if (ast_consock > -1)
+		close(ast_consock);
+	if (ast_socket > -1)
+		unlink(AST_SOCKET);
+	
 	exit(0);
 }
 
@@ -136,10 +349,39 @@ static void consolehandler(char *s)
 		fprintf(stdout, "\nUse \"quit\" to exit\n");
 }
 
+
+static char cmd[1024];
+
+static void remoteconsolehandler(char *s)
+{
+	/* Called when readline data is available */
+	if (s && strlen(s))
+		add_history(s);
+	/* Give the console access to the shell */
+	if (s) {
+		if (s[0] == '!') {
+			if (s[1])
+				system(s+1);
+			else
+				system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
+		} else 
+		strncpy(cmd, s, sizeof(cmd));
+		if (!strcasecmp(s, "help"))
+			fprintf(stdout, "          !<command>   Executes a given shell command\n");
+		if (!strcasecmp(s, "quit"))
+			quit_handler(0);
+	} else
+		fprintf(stdout, "\nUse \"quit\" to exit\n");
+}
+
 static char quit_help[] = 
 "Usage: quit\n"
 "       Exits Asterisk.\n";
 
+static char shutdown_help[] = 
+"Usage: shutdown\n"
+"       Shuts down a running Asterisk PBX.\n";
+
 static int handle_quit(int fd, int argc, char *argv[])
 {
 	if (argc != 1)
@@ -150,22 +392,135 @@ static int handle_quit(int fd, int argc, char *argv[])
 
 #define ASTERISK_PROMPT "*CLI> "
 
+#define ASTERISK_PROMPT2 "%s*CLI> "
+
 static struct ast_cli_entry quit = 	{ { "quit", NULL }, handle_quit, "Exit Asterisk", quit_help };
 
+static struct ast_cli_entry astshutdown = 	{ { "shutdown", NULL }, handle_quit, "Shut down an Asterisk PBX", shutdown_help };
+
 static char *cli_generator(char *text, int state)
 {
 	return ast_cli_generator(rl_line_buffer, text, state);
 }
 
+static char *console_cli_generator(char *text, int state)
+{
+	char buf[1024];
+	int res;
+#if 0
+	fprintf(stderr, "Searching for '%s', %s %d\n", rl_line_buffer, text, state);
+#endif	
+	snprintf(buf, sizeof(buf),"_COMMAND COMPLETE \"%s\" \"%s\" %d", rl_line_buffer, text, state); 
+	fdprint(ast_consock, buf);
+	res = read(ast_consock, buf, sizeof(buf));
+	buf[res] = '\0';
+#if 0
+	printf("res is %d, buf is '%s'\n", res, buf);
+#endif	
+	if (strncmp(buf, "NULL", 4))
+		return strdup(buf);
+	else
+		return NULL;
+}
+
+static void ast_remotecontrol(char * data)
+{
+	char buf[80];
+	int res;
+	int max;
+	int lastpos = 0;
+	fd_set rfds;
+	char filename[80] = "";
+	char *hostname;
+	char *cpid;
+	char *version;
+	int pid;
+	char tmp[80];
+	read(ast_consock, buf, sizeof(buf));
+	if (data) {
+			write(ast_consock, data, strlen(data) + 1);
+			return;
+	}
+	hostname = strtok(buf, "/");
+	cpid = strtok(NULL, "/");
+	version = strtok(NULL, "/");
+	if (!version)
+		version = "<Version Unknown>";
+	strtok(hostname, ".");
+	if (cpid)
+		pid = atoi(cpid);
+	else
+		pid = -1;
+	snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
+	fdprint(ast_consock, tmp);
+	ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
+	snprintf(tmp, sizeof(tmp), ASTERISK_PROMPT2, hostname);
+	if (getenv("HOME")) 
+		snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
+	if (strlen(filename))
+		read_history(filename);
+    ast_cli_register(&quit);
+    ast_cli_register(&astshutdown);
+	rl_callback_handler_install(tmp, remoteconsolehandler);
+	rl_completion_entry_function = (Function *)console_cli_generator;
+	for(;;) {
+		FD_ZERO(&rfds);
+		FD_SET(ast_consock, &rfds);
+		FD_SET(STDIN_FILENO, &rfds);
+		max = ast_consock;
+		if (STDIN_FILENO > max)
+			max = STDIN_FILENO;
+		res = select(max + 1, &rfds, NULL, NULL, NULL);
+		if (res < 0) {
+			if (errno == EINTR)
+				continue;
+			ast_log(LOG_ERROR, "select failed: %s\n", strerror(errno));
+			break;
+		}
+		if (FD_ISSET(STDIN_FILENO, &rfds)) {
+			rl_callback_read_char();
+			if (strlen(cmd)) {
+				res = write(ast_consock, cmd, strlen(cmd) + 1);
+				if (res < 1) {
+					ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
+					break;
+				}
+				strcpy(cmd, "");
+			}
+		}
+		if (FD_ISSET(ast_consock, &rfds)) {
+			res = read(ast_consock, buf, sizeof(buf));
+			if (res < 1)
+				break;
+			buf[res] = 0;
+			if (!lastpos)
+				write(STDOUT_FILENO, "\r", 2);
+			write(STDOUT_FILENO, buf, res);
+			if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
+				rl_forced_update_display();
+				lastpos = 0;
+			} else {
+				lastpos = 1;
+			}
+		}
+	}
+	printf("\nDisconnected from Asterisk server\n");
+}
+
 int main(int argc, char *argv[])
 {
 	char c;
 	fd_set rfds;
 	int res;
+	int pid;
 	char filename[80] = "";
 	char hostname[256];
+	char * xarg = NULL;
+	sigset_t sigs;
+
 	if (gethostname(hostname, sizeof(hostname)))
 		strncpy(hostname, "<Unknown>", sizeof(hostname));
+	mainpid = getpid();
 	ast_ulaw_init();
 	callerid_init();
 	if (getenv("HOME")) 
@@ -176,7 +531,7 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 	/* Check for options */
-	while((c=getopt(argc, argv, "dvqpc")) != EOF) {
+	while((c=getopt(argc, argv, "fdvqprcx:")) != EOF) {
 		switch(c) {
 		case 'd':
 			option_debug++;
@@ -186,6 +541,13 @@ int main(int argc, char *argv[])
 			option_console++;
 			option_nofork++;
 			break;
+		case 'f':
+			option_nofork++;
+			break;
+		case 'r':
+			option_remote++;
+			option_nofork++;
+			break;
 		case 'p':
 			option_highpriority++;
 			break;
@@ -196,14 +558,60 @@ int main(int argc, char *argv[])
 		case 'q':
 			option_quiet++;
 			break;
+		case 'x':
+			option_exec++;
+			xarg = optarg;
+			break;
 		case '?':
 			exit(1);
 		}
 	}
-	ast_register_verbose(console_verboser);
+	
+	if (ast_tryconnect()) {
+		/* One is already running */
+		if (option_remote) {
+			if (option_exec) {
+				ast_remotecontrol(xarg);
+				quit_handler(0);
+				exit(0);
+			}
+			ast_register_verbose(console_verboser);
+			ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
+			ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
+			ast_verbose( "=========================================================================\n");
+			ast_remotecontrol(NULL);
+			quit_handler(0);
+			exit(0);
+		} else {
+			ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", AST_SOCKET);
+			exit(1);
+		}
+	} else if (option_remote || option_exec) {
+		ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
+		exit(1);
+	}
+	if (!option_verbose && !option_console && !option_debug) {
+		pid = fork();
+		if (pid < 0) {
+			ast_log(LOG_ERROR, "Unable to fork(): %s\n", strerror(errno));
+			exit(1);
+		}
+		if (pid) 
+			exit(0);
+	}
+	ast_makesocket();
+	sigemptyset(&sigs);
+	sigaddset(&sigs, SIGHUP);
+	sigaddset(&sigs, SIGTERM);
+	sigaddset(&sigs, SIGINT);
+	sigaddset(&sigs, SIGPIPE);
+	sigaddset(&sigs, SIGWINCH);
+	pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+	if (option_console || option_verbose || option_remote)
+		ast_register_verbose(console_verboser);
 	/* Print a welcome message if desired */
 	if (option_verbose || option_console) {
-		ast_verbose( "Asterisk, Copyright (C) 1999 Mark Spencer\n");
+		ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
 		ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
 		ast_verbose( "=========================================================================\n");
 	}
@@ -212,7 +620,8 @@ int main(int argc, char *argv[])
 	signal(SIGURG, urg_handler);
 	signal(SIGINT, quit_handler);
 	signal(SIGTERM, quit_handler);
-	signal(SIGHUP, quit_handler);
+	signal(SIGHUP, hup_handler);
+	signal(SIGPIPE, pipe_handler);
 	if (set_priority(option_highpriority))
 		exit(1);
 	if (init_logger())
@@ -228,12 +637,14 @@ int main(int argc, char *argv[])
 	if (option_verbose || option_console)
 		ast_verbose( "Asterisk Ready.\n");
 	fully_booted = 1;
+	pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
+    ast_cli_register(&astshutdown);
 	if (option_console) {
 		/* Console stuff now... */
 		/* Register our quit function */
 		char title[256];
 		set_icon("Asterisk");
-		snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, getpid());
+		snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, mainpid);
 		set_title(title);
 	    ast_cli_register(&quit);
 		consolethread = pthread_self();
diff --git a/audiofile.patch b/audiofile.patch
deleted file mode 100755
index c0134895c1d793941bcd987cc42a5b65397745fa..0000000000000000000000000000000000000000
--- a/audiofile.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-diff -uNr audiofile-0.1.9.old/libaudiofile/audiofile.c audiofile-0.1.9/libaudiofile/audiofile.c
---- audiofile-0.1.9.old/libaudiofile/audiofile.c	Fri Jul 23 12:57:56 1999
-+++ audiofile-0.1.9/libaudiofile/audiofile.c	Fri Dec 10 18:43:30 1999
-@@ -488,6 +488,20 @@
- 	return afOpenVirtualFile(af_virtual_file_new_for_file(fp), mode, setup);
- }
- 
-+AFfilehandle afOpenFD(int fd, const char *mode, AFfilesetup setup)
-+{
-+	FILE			*fp;
-+
-+	fp = fdopen(fd, mode);
-+	if (fp == NULL)
-+	{
-+		_af_error(AF_BAD_OPEN);
-+		return AF_NULL_FILEHANDLE;
-+	}
-+
-+	return afOpenVirtualFile(af_virtual_file_new_for_file(fp), mode, setup);
-+}
-+
- int afGetFileFormat (AFfilehandle file, int *version)
- {
- 	assert(file);
diff --git a/cli.c b/cli.c
index aa41b0e7a7031b4e8b5c5e1e63427dce17c85efa..98e16a0c86f801a71db25f8ec17a0dd01ea1feb2 100755
--- a/cli.c
+++ b/cli.c
@@ -27,6 +27,11 @@
 #include <readline/readline.h>
 /* For module directory */
 #include "asterisk.h"
+#include "build.h"
+
+#define VERSION_INFO "Asterisk " ASTERISK_VERSION " built by " BUILD_USER "@" BUILD_HOSTNAME \
+	" on a " BUILD_MACHINE " running " BUILD_OS
+	
 
 void ast_cli(int fd, char *fmt, ...)
 {
@@ -66,6 +71,21 @@ static char chanlist_help[] =
 "       Lists currently defined channels and some information about\n"
 "       them.\n";
 
+static char reload_help[] = 
+"Usage: reload\n"
+"       Reloads configuration files for all modules which support\n"
+"       reloading.\n";
+
+static char set_verbose_help[] = 
+"Usage: set verbose <level>\n"
+"       Sets level of verbose messages to be displayed.  0 means\n"
+"       no messages should be displayed.\n";
+
+static char softhangup_help[] =
+"Usage: soft hangup <channel>\n"
+"       Request that a channel be hung up.  The hangup takes effect\n"
+"       the next time the driver reads or writes from the channel\n";
+
 static int handle_load(int fd, int argc, char *argv[])
 {
 	if (argc != 2)
@@ -77,6 +97,32 @@ static int handle_load(int fd, int argc, char *argv[])
 	return RESULT_SUCCESS;
 }
 
+static int handle_reload(int fd, int argc, char *argv[])
+{
+	if (argc != 1)
+		return RESULT_SHOWUSAGE;
+	ast_module_reload();
+	return RESULT_SUCCESS;
+}
+
+static int handle_set_verbose(int fd, int argc, char *argv[])
+{
+	int val;
+	/* Has a hidden 'at least' argument */
+	if ((argc != 3) && (argc != 4))
+		return RESULT_SHOWUSAGE;
+	if ((argc == 4) && strcasecmp(argv[2], "atleast"))
+		return RESULT_SHOWUSAGE;
+	if (argc == 3)
+		option_verbose = atoi(argv[2]);
+	else {
+		val = atoi(argv[3]);
+		if (val > option_verbose)
+			option_verbose = val;
+	}
+	return RESULT_SUCCESS;
+}
+
 static int handle_unload(int fd, int argc, char *argv[])
 {
 	int x;
@@ -122,30 +168,41 @@ static char modlist_help[] =
 "       Shows Asterisk modules currently in use, and usage "
 "statistics.\n";
 
+static char version_help[] =
+"Usage: show version\n"
+"       Shows Asterisk version information.\n ";
+
 static int handle_modlist(int fd, int argc, char *argv[])
 {
 	if (argc != 2)
 		return RESULT_SHOWUSAGE;
-	pthread_mutex_lock(&climodentrylock);
+	ast_pthread_mutex_lock(&climodentrylock);
 	climodentryfd = fd;
 	ast_cli(fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
 	ast_update_module_list(modlist_modentry);
 	climodentryfd = -1;
-	pthread_mutex_unlock(&climodentrylock);
+	ast_pthread_mutex_unlock(&climodentrylock);
 	return RESULT_SUCCESS;
 }
 
+static int handle_version(int fd, int argc, char *argv[])
+{
+	if (argc != 2)
+		return RESULT_SHOWUSAGE;
+	ast_cli(fd, VERSION_INFO);
+	return RESULT_SUCCESS;
+}
 static int handle_chanlist(int fd, int argc, char *argv[])
 {
-#define FORMAT_STRING  "%15s  (%-10s %-12s %-4d)  %-12s  %-15s\n"
-#define FORMAT_STRING2 "%15s  (%-10s %-12s %-4s)  %-12s  %-15s\n"
+#define FORMAT_STRING  "%15s  (%-10s %-12s %-4d) %7s %-12s  %-15s\n"
+#define FORMAT_STRING2 "%15s  (%-10s %-12s %-4s) %7s %-12s  %-15s\n"
 	struct ast_channel *c=NULL;
 	if (argc != 2)
 		return RESULT_SHOWUSAGE;
 	c = ast_channel_walk(NULL);
-	ast_cli(fd, FORMAT_STRING2, "Channel", "Context", "Extension", "Pri", "Appl.", "Data");
+	ast_cli(fd, FORMAT_STRING2, "Channel", "Context", "Extension", "Pri", "State", "Appl.", "Data");
 	while(c) {
-		ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority, 
+		ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->state),
 		c->appl ? c->appl : "(None)", c->data ? ( strlen(c->data) ? c->data : "(Empty)" ): "(None)");
 		c = ast_channel_walk(c);
 	}
@@ -156,6 +213,52 @@ static char showchan_help[] =
 "Usage: show channel <channel>\n"
 "       Shows lots of information about the specified channel.\n";
 
+static char commandcomplete_help[] = 
+"Usage: _command complete \"<line>\" text state\n"
+"       This function is used internally to help with command completion and should.\n"
+"       never be called by the user directly.\n";
+
+static int handle_softhangup(int fd, int argc, char *argv[])
+{
+	struct ast_channel *c=NULL;
+	if (argc != 3)
+		return RESULT_SHOWUSAGE;
+	c = ast_channel_walk(NULL);
+	while(c) {
+		if (!strcasecmp(c->name, argv[2])) {
+			ast_cli(fd, "Requested Hangup on channel '%s'\n", c->name);
+			c->softhangup = 1;
+			break;
+		}
+		c = ast_channel_walk(c);
+	}
+	if (!c) 
+		ast_cli(fd, "%s is not a known channel\n", argv[2]);
+	return RESULT_SUCCESS;
+}
+
+static char *__ast_cli_generator(char *text, char *word, int state, int lock);
+
+static int handle_commandcomplete(int fd, int argc, char *argv[])
+{
+	char *buf;
+#if 0
+	printf("Search for %d args: '%s', '%s', '%s', '%s'\n", argc, argv[0], argv[1], argv[2], argv[3]);
+#endif	
+	if (argc != 5)
+		return RESULT_SHOWUSAGE;
+	buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0);
+#if 0
+	printf("Search for '%s' %s %d got '%s'\n", argv[2], argv[3], atoi(argv[4]), buf);
+#endif	
+	if (buf) {
+		ast_cli(fd, buf);
+		free(buf);
+	} else
+		ast_cli(fd, "NULL\n");
+	return RESULT_SUCCESS;
+}
+
 static int handle_showchan(int fd, int argc, char *argv[])
 {
 	struct ast_channel *c=NULL;
@@ -170,12 +273,12 @@ static int handle_showchan(int fd, int argc, char *argv[])
 	"           Type: %s\n"
 	"      Caller ID: %s\n"
 	"    DNID Digits: %s\n"
-	"          State: %d\n"
+	"          State: %s (%d)\n"
 	"          Rings: %d\n"
 	"    WriteFormat: %d\n"
 	"     ReadFormat: %d\n"
 	"   NativeFormat: %d\n"
-	"File Descriptor: %d\n"
+	"1st File Descriptor: %d\n"
 	" --   PBX   --\n"
 	"        Context: %s\n"
 	"      Extension: %s\n"
@@ -186,8 +289,8 @@ static int handle_showchan(int fd, int argc, char *argv[])
 	"    Blocking in: %s\n",
 	c->name, c->type, 
 	(c->callerid ? c->callerid : "(N/A)"),
-	(c->dnid ? c->dnid : "(N/A)" ), c->state, c->rings, c->nativeformats, c->writeformat, c->readformat,
-	c->fd, c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ),
+	(c->dnid ? c->dnid : "(N/A)" ), ast_state2str(c->state), c->state, c->rings, c->nativeformats, c->writeformat, c->readformat,
+	c->fds[0], c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ),
 	( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"),
 	c->stack, (c->blocking ? c->blockproc : "(Not Blocking)"));
 	
@@ -206,8 +309,10 @@ static char *complete_ch(char *line, char *word, int pos, int state)
 	int which=0;
 	c = ast_channel_walk(NULL);
 	while(c) {
-		if (++which > state)
-			break;
+		if (!strncasecmp(word, c->name, strlen(word))) {
+			if (++which > state)
+				break;
+		}
 		c = ast_channel_walk(c);
 	}
 	return c ? strdup(c->name) : NULL;
@@ -223,7 +328,7 @@ static char *complete_fn(char *line, char *word, int pos, int state)
 		strncpy(filename, word, sizeof(filename));
 	else
 		snprintf(filename, sizeof(filename), "%s/%s", AST_MODULE_DIR, word);
-	c = filename_completion_function(filename, state);
+	c = (char*)filename_completion_function(filename, state);
 	if (c && word[0] != '/')
 		c += (strlen(AST_MODULE_DIR) + 1);
 	return c ? strdup(c) : c;
@@ -234,11 +339,16 @@ static int handle_help(int fd, int argc, char *argv[]);
 static struct ast_cli_entry builtins[] = {
 	/* Keep alphabetized */
 	{ { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help },
+	{ { "_command", "complete", NULL }, handle_commandcomplete, "Command complete", commandcomplete_help },
 	{ { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn },
+	{ { "reload", NULL }, handle_reload, "Reload configuration", reload_help },
+	{ { "set", "verbose", NULL }, handle_set_verbose, "Set level of verboseness", set_verbose_help },
 	{ { "show", "channel", NULL }, handle_showchan, "Display information on a specific channel", showchan_help, complete_ch },
 	{ { "show", "channels", NULL }, handle_chanlist, "Display information on channels", chanlist_help },
     { { "show", "modules", NULL }, handle_modlist, "List modules and info", modlist_help },
+	{ { "soft", "hangup", NULL }, handle_softhangup, "Request a hangup on a given channel", softhangup_help, complete_ch },
 	{ { "unload", NULL }, handle_unload, "Unload a dynamic module by name", unload_help, complete_fn },
+	{ { "version", NULL }, handle_version, "Display version info", version_help },
 	{ { NULL }, NULL, NULL, NULL }
 };
 
@@ -327,7 +437,7 @@ static char *find_best(char *argv[])
 int ast_cli_unregister(struct ast_cli_entry *e)
 {
 	struct ast_cli_entry *cur, *l=NULL;
-	pthread_mutex_lock(&clilock);
+	ast_pthread_mutex_lock(&clilock);
 	cur = helpers;
 	while(cur) {
 		if (e == cur) {
@@ -342,7 +452,7 @@ int ast_cli_unregister(struct ast_cli_entry *e)
 		l = cur;
 		cur = cur->next;
 	}
-	pthread_mutex_unlock(&clilock);
+	ast_pthread_mutex_unlock(&clilock);
 	return 0;
 }
 
@@ -351,11 +461,11 @@ int ast_cli_register(struct ast_cli_entry *e)
 	struct ast_cli_entry *cur, *l=NULL;
 	char fulle[80], fulltst[80];
 	static int len;
-	pthread_mutex_lock(&clilock);
+	ast_pthread_mutex_lock(&clilock);
 	join2(fulle, sizeof(fulle), e->cmda);
 	if (find_cli(e->cmda, -1)) {
 		ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", fulle);
-		pthread_mutex_unlock(&clilock);
+		ast_pthread_mutex_unlock(&clilock);
 		return -1;
 	}
 	cur = helpers;
@@ -384,7 +494,7 @@ int ast_cli_register(struct ast_cli_entry *e)
 			helpers = e;
 		e->next = NULL;
 	}
-	pthread_mutex_unlock(&clilock);
+	ast_pthread_mutex_unlock(&clilock);
 	return 0;
 }
 
@@ -417,6 +527,9 @@ static int help_workhorse(int fd, char *match[])
 			fullcmd = fullcmd1;
 			e1++;
 		}
+		/* Hide commands that start with '_' */
+		if (fullcmd[0] == '_')
+			continue;
 		if (match) {
 			if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
 				continue;
@@ -469,6 +582,11 @@ static char *parse_args(char *s, int *max, char *argv[])
 					goto normal;
 				else 
 					quoted = !quoted;
+				if (quoted && whitespace) {
+					/* If we're starting a quote, coming off white space start a new word, too */
+					argv[x++] = cur;
+					whitespace=0;
+				}
 				escaped = 0;
 				break;
 			case ' ':
@@ -514,7 +632,7 @@ normal:
 	return dup;
 }
 
-char *ast_cli_generator(char *text, char *word, int state)
+static char *__ast_cli_generator(char *text, char *word, int state, int lock)
 {
 	char *argv[AST_MAX_ARGS];
 	struct ast_cli_entry *e, *e1, *e2;
@@ -528,7 +646,8 @@ char *ast_cli_generator(char *text, char *word, int state)
 
 	if ((dup = parse_args(text, &x, argv))) {
 		join(matchstr, sizeof(matchstr), argv);
-		pthread_mutex_lock(&clilock);
+		if (lock)
+			ast_pthread_mutex_lock(&clilock);
 		e1 = builtins;
 		e2 = helpers;
 		while(e1->cmda[0] || e2) {
@@ -549,7 +668,7 @@ char *ast_cli_generator(char *text, char *word, int state)
 				fullcmd = fullcmd1;
 				e1++;
 			}
-			if (!strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
+			if ((fullcmd[0] != '_') && !strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
 				/* We contain the first part of one or more commands */
 				matchnum++;
 				if (matchnum > state) {
@@ -560,7 +679,8 @@ char *ast_cli_generator(char *text, char *word, int state)
 						res = e->cmda[x];
 					}
 					if (res) {
-						pthread_mutex_unlock(&clilock);
+						if (lock)
+							ast_pthread_mutex_unlock(&clilock);
 						return res ? strdup(res) : NULL;
 					}
 				}
@@ -569,17 +689,24 @@ char *ast_cli_generator(char *text, char *word, int state)
 				/* We have a command in its entirity within us -- theoretically only one
 				   command can have this occur */
 				fullcmd = e->generator(text, word, (strlen(word) ? (x - 1) : (x)), state);
-				pthread_mutex_unlock(&clilock);
+				if (lock)
+					ast_pthread_mutex_unlock(&clilock);
 				return fullcmd;
 			}
 			
 		}
-		pthread_mutex_unlock(&clilock);
+		if (lock)
+			ast_pthread_mutex_unlock(&clilock);
 		free(dup);
 	}
 	return NULL;
 }
 
+char *ast_cli_generator(char *text, char *word, int state)
+{
+	return __ast_cli_generator(text, word, state, 1);
+}
+
 int ast_cli_command(int fd, char *s)
 {
 	char *argv[AST_MAX_ARGS];
@@ -590,7 +717,7 @@ int ast_cli_command(int fd, char *s)
 	if ((dup = parse_args(s, &x, argv))) {
 		/* We need at least one entry, or ignore */
 		if (x > 0) {
-			pthread_mutex_lock(&clilock);
+			ast_pthread_mutex_lock(&clilock);
 			e = find_cli(argv, 0);
 			if (e) {
 				switch(e->handler(fd, x, argv)) {
@@ -601,7 +728,7 @@ int ast_cli_command(int fd, char *s)
 				}
 			} else 
 				ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(argv));
-			pthread_mutex_unlock(&clilock);
+			ast_pthread_mutex_unlock(&clilock);
 		}
 		free(dup);
 	} else {
diff --git a/make_build_h b/make_build_h
new file mode 100755
index 0000000000000000000000000000000000000000..f98f54991b7ad4f32ebaebcf5fba015a17a7007a
--- /dev/null
+++ b/make_build_h
@@ -0,0 +1,20 @@
+#!/bin/sh
+HOSTNAME=`uname -n`
+KERNEL=`uname -r`
+MACHINE=`uname -m`
+OS=`uname -s`
+USER=`whoami`
+VERSION=`cat .version`
+rm -f build.h
+cat > build.h << END
+/*
+ * build.h 
+ * Automatically generated
+ */
+#define BUILD_HOSTNAME "${HOSTNAME}"
+#define BUILD_KERNEL "${KERNEL}"
+#define BUILD_MACHINE "${MACHINE}"
+#define BUILD_OS "${OS}"
+#define BUILD_VERSION "${VERSION}"
+#define BUILD_USER "${USER}"
+END