[Pkg-voip-commits] r1024 - asterisk/trunk/debian/patches

Tzafrir Cohen tzafrir-guest at costa.debian.org
Wed Nov 23 04:45:52 UTC 2005


Author: tzafrir-guest
Date: 2005-11-23 04:45:46 +0000 (Wed, 23 Nov 2005)
New Revision: 1024

Added:
   asterisk/trunk/debian/patches/bristuff.dpatch
Log:
bristuff 0.3.0-PRE-1, asterisk.patch


Added: asterisk/trunk/debian/patches/bristuff.dpatch
===================================================================
--- asterisk/trunk/debian/patches/bristuff.dpatch	2005-11-23 02:39:00 UTC (rev 1023)
+++ asterisk/trunk/debian/patches/bristuff.dpatch	2005-11-23 04:45:46 UTC (rev 1024)
@@ -0,0 +1,6117 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## bristuff.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: bristuff support in asterisk: asterisk.patch from bristuff-0.3.0-PRE-1
+
+ at DPATCH@
+diff -urNad asterisk-1.2.0.dfsg/agi/Makefile /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/agi/Makefile
+--- asterisk-1.2.0.dfsg/agi/Makefile	2005-08-30 05:54:01.000000000 +0300
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/agi/Makefile	2005-11-23 05:50:44.272884361 +0200
+@@ -11,7 +11,7 @@
+ # the GNU General Public License
+ #
+ 
+-AGIS=agi-test.agi eagi-test eagi-sphinx-test
++AGIS=agi-test.agi eagi-test eagi-sphinx-test xagi-test
+ 
+ CFLAGS+=
+ 
+@@ -37,7 +37,7 @@
+ 	$(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o $(LIBS) 
+ 
+ clean:
+-	rm -f *.so *.o look .depend eagi-test eagi-sphinx-test
++	rm -f *.so *.o look .depend eagi-test eagi-sphinx-test xagi-test
+ 
+ %.so : %.o
+ 	$(CC) -shared -Xlinker -x -o $@ $<
+diff -urNad asterisk-1.2.0.dfsg/agi/xagi-test.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/agi/xagi-test.c
+--- asterisk-1.2.0.dfsg/agi/xagi-test.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/agi/xagi-test.c	2005-11-23 05:50:44.273884223 +0200
+@@ -0,0 +1,177 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * XAGI sample script 
++ * 
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * based on eagi-test.c
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/select.h>
++#ifdef SOLARIS
++#include <solaris-compat/compat.h>
++#endif
++
++#define AUDIO_FILENO_IN (STDERR_FILENO + 1)
++#define AUDIO_FILENO_OUT (STDERR_FILENO + 2)
++
++static int read_environment(void)
++{
++	char buf[256];
++	char *val;
++	/* Read environment */
++	for(;;) {
++		fgets(buf, sizeof(buf), stdin);
++		if (feof(stdin))
++			return -1;
++		buf[strlen(buf) - 1] = '\0';
++		/* Check for end of environment */
++		if (!strlen(buf))
++			return 0;
++		val = strchr(buf, ':');
++		if (!val) {
++			fprintf(stderr, "Invalid environment: '%s'\n", buf);
++			return -1;
++		}
++		*val = '\0';
++		val++;
++		val++;
++		/* Skip space */
++	//	fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
++
++		/* Load into normal environment */
++		setenv(buf, val, 1);
++		
++	}
++	/* Never reached */
++	return 0;
++}
++
++static void app_echo(void)
++{
++	fd_set fds;
++	int res;
++	int bytes = 0;
++	static char astresp[256];
++	char audiobuf[16000]; /* 1 second of audio */
++	for (;;) {
++		FD_ZERO(&fds);
++		FD_SET(STDIN_FILENO, &fds);
++		FD_SET(AUDIO_FILENO_IN, &fds);
++		/* Wait for *some* sort of I/O */
++		res = select(AUDIO_FILENO_IN + 1, &fds, NULL, NULL, NULL);
++		if (res < 0) {
++			fprintf(stderr, "Error in select: %s\n", strerror(errno));
++			return;
++		}
++		if (FD_ISSET(STDIN_FILENO, &fds)) {
++			fgets(astresp, sizeof(astresp), stdin);
++			if (feof(stdin)) {
++				return NULL;
++			}
++			astresp[strlen(astresp) - 1] = '\0';
++			fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
++			return astresp;
++		}
++		if (FD_ISSET(AUDIO_FILENO_IN, &fds)) {
++			/* what goes in.... */
++			res = read(AUDIO_FILENO_IN, audiobuf, sizeof(audiobuf));
++			if (res > 0) {
++			    bytes = res;
++			    /* must come out */
++			    write(AUDIO_FILENO_OUT, audiobuf, bytes);
++			}
++		}
++	}
++		
++}
++
++static char *wait_result(void)
++{
++	fd_set fds;
++	int res;
++	int bytes = 0;
++	static char astresp[256];
++	char audiobuf[4096];
++	for (;;) {
++		FD_ZERO(&fds);
++		FD_SET(STDIN_FILENO, &fds);
++		FD_SET(AUDIO_FILENO_IN, &fds);
++		/* Wait for *some* sort of I/O */
++		res = select(AUDIO_FILENO_IN + 1, &fds, NULL, NULL, NULL);
++		if (res < 0) {
++			fprintf(stderr, "Error in select: %s\n", strerror(errno));
++			return NULL;
++		}
++		if (FD_ISSET(STDIN_FILENO, &fds)) {
++			fgets(astresp, sizeof(astresp), stdin);
++			if (feof(stdin)) {
++				fprintf(stderr, "Got hungup on apparently\n");
++				return NULL;
++			}
++			astresp[strlen(astresp) - 1] = '\0';
++			fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
++			return astresp;
++		}
++		if (FD_ISSET(AUDIO_FILENO_IN, &fds)) {
++			res = read(AUDIO_FILENO_IN, audiobuf, sizeof(audiobuf));
++			/* drop it, like it's hot */
++		}
++	}
++		
++}
++
++static char *run_command(char *command)
++{
++	fprintf(stdout, "%s\n", command);
++	return wait_result();
++}
++
++
++static int run_script(void)
++{
++	char *res;
++		res = run_command("STREAM FILE demo-echotest \"\"");
++	if (!res) {
++		fprintf(stderr, "Failed to execute command\n");
++		return -1;
++	}
++	app_echo();
++	return 0;
++}
++
++int main(int argc, char *argv[])
++{
++	char *tmp;
++	int ver = 0;
++	int subver = 0;
++	/* Setup stdin/stdout for line buffering */
++	setlinebuf(stdin);
++	setlinebuf(stdout);
++	if (read_environment()) {
++		fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
++		exit(1);
++	}
++	tmp = getenv("agi_enhanced");
++	if (tmp) {
++		if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
++			ver = 0;
++	}
++	if (ver < 2) {
++		fprintf(stderr, "No XAGI services available.  Use XAGI, not AGI or EAGI\n");
++		exit(1);
++	}
++	if (run_script())
++		return -1;
++	exit(0);
++}
+diff -urNad asterisk-1.2.0.dfsg/apps/app_callingpres.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_callingpres.c
+--- asterisk-1.2.0.dfsg/apps/app_callingpres.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_callingpres.c	2005-11-23 05:50:44.275883945 +0200
+@@ -0,0 +1,70 @@
++/*
++ * An application to change the CallingPresentation for an Asterisk channel.
++ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License. 
++ *
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++
++static char *synopsis_callingpres = "Change the presentation for the callerid";
++static char *descrip_callingpres = "Callingpres(number): Changes the presentation for the callerid. Should be called before placing an outgoing call\n";
++static char *app_callingpres = "CallingPres";
++STANDARD_LOCAL_USER;
++LOCAL_USER_DECL;
++
++
++static int change_callingpres(struct ast_channel *chan, void *data)
++{
++    int mode = 0;
++    struct localuser *u;
++    LOCAL_USER_ADD(u);
++    if (data) {
++        mode = atoi((char *)data);
++        chan->cid.cid_pres = mode;
++    } else
++        ast_log(LOG_NOTICE, "Application %s requres an argument: %s(number)\n", app_callingpres,app_callingpres);
++    LOCAL_USER_REMOVE(u);
++    return 0;
++}    
++
++int unload_module(void)
++{
++    STANDARD_HANGUP_LOCALUSERS;
++    return ast_unregister_application(app_callingpres);
++}
++
++int load_module(void)
++{
++    return ast_register_application(app_callingpres, change_callingpres, synopsis_callingpres, descrip_callingpres);
++}
++
++char *description(void)
++{
++    return descrip_callingpres;
++}
++
++int usecount(void)
++{
++    int res;
++    STANDARD_USECOUNT(res);
++    return res;
++}
++
++char *key()
++{
++    return ASTERISK_GPL_KEY;
++}
+diff -urNad asterisk-1.2.0.dfsg/apps/app_chanisavail.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_chanisavail.c
+--- asterisk-1.2.0.dfsg/apps/app_chanisavail.c	2005-11-10 23:39:01.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_chanisavail.c	2005-11-23 05:50:44.280883253 +0200
+@@ -118,7 +118,7 @@
+ 				snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
+ 				status = inuse = ast_device_state(trychan);
+ 			}
+-			if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
++			if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status, NULL))) {
+ 					pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
+ 					/* Store the originally used channel too */
+ 					snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
+diff -urNad asterisk-1.2.0.dfsg/apps/app_devstate.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_devstate.c
+--- asterisk-1.2.0.dfsg/apps/app_devstate.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_devstate.c	2005-11-23 05:50:44.283882837 +0200
+@@ -0,0 +1,215 @@
++/*
++ * Devstate application
++ * 
++ * Since we like the snom leds so much, a little app to
++ * light the lights on the snom on demand ....
++ *
++ * Copyright (C) 2005, Druid Software
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/astdb.h>
++#include <asterisk/utils.h>
++#include <asterisk/cli.h>
++#include <asterisk/manager.h>
++#include <asterisk/devicestate.h>
++
++
++static char type[] = "DS";
++static char tdesc[] = "Application for sending device state messages";
++
++static char app[] = "Devstate";
++
++static char synopsis[] = "Generate a device state change event given the input parameters";
++
++static char descrip[] = " Devstate(device|state):  Generate a device state change event given the input parameters. Returns 0. State values match the asterisk device states. They are 0 = unknown, 1 = not inuse, 2 = inuse, 3 = busy, 4 = invalid, 5 = unavailable, 6 = ringing\n";
++
++static char devstate_cli_usage[] = 
++"Usage: devstate device state\n" 
++"       Generate a device state change event given the input parameters.\n Mainly used for lighting the LEDs on the snoms.\n";
++
++static int devstate_cli(int fd, int argc, char *argv[]);
++static struct ast_cli_entry  cli_dev_state =
++        { { "devstate", NULL }, devstate_cli, "Set the device state on one of the \"pseudo devices\".", devstate_cli_usage };
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++
++static int devstate_cli(int fd, int argc, char *argv[])
++{
++    char devName[128];
++    if (argc != 3)
++        return RESULT_SHOWUSAGE;
++
++    if (ast_db_put("DEVSTATES", argv[1], argv[2]))
++    {
++        ast_log(LOG_DEBUG, "ast_db_put failed\n");
++    }
++
++    snprintf(devName, sizeof(devName), "DS/%s", argv[1]);
++    ast_device_state_changed_literal(devName);
++    return RESULT_SUCCESS;
++}
++
++static int devstate_exec(struct ast_channel *chan, void *data)
++{
++    struct localuser *u;
++    char *device, *state, *info;
++    char devName[128];
++    if (!(info = ast_strdupa(data))) {
++            ast_log(LOG_WARNING, "Unable to dupe data :(\n");
++            return -1;
++    }
++    LOCAL_USER_ADD(u);
++    
++    device = info;
++    state = strchr(info, '|');
++    if (state) {
++        *state = '\0';
++        state++;
++    }
++    else
++    {
++        ast_log(LOG_DEBUG, "No state argument supplied\n");
++        return -1;
++    }
++
++    if (ast_db_put("DEVSTATES", device, state))
++    {
++        ast_log(LOG_DEBUG, "ast_db_put failed\n");
++    }
++
++    snprintf(devName, sizeof(devName), "DS/%s", device);
++    ast_device_state_changed_literal(devName);
++
++    LOCAL_USER_REMOVE(u);
++    return 0;
++}
++
++
++static int ds_devicestate(void *data)
++{
++    char *dest = data;
++    char stateStr[16];
++    if (ast_db_get("DEVSTATES", dest, stateStr, sizeof(stateStr)))
++    {
++        ast_log(LOG_DEBUG, "ds_devicestate couldnt get state in astdb\n");
++        return 0;
++    }
++    else
++    {
++        ast_log(LOG_DEBUG, "ds_devicestate dev=%s returning state %d\n",
++               dest, atoi(stateStr));
++        return (atoi(stateStr));
++    }
++}
++
++static struct ast_channel_tech devstate_tech = {
++	.type = type,
++	.description = tdesc,
++	.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
++	.devicestate = ds_devicestate,
++	.requester = NULL,
++	.send_digit = NULL,
++	.send_text = NULL,
++	.call = NULL,
++	.hangup = NULL,
++	.answer = NULL,
++	.read = NULL,
++	.write = NULL,
++	.bridge = NULL,
++	.exception = NULL,
++	.indicate = NULL,
++	.fixup = NULL,
++	.setoption = NULL,
++};
++
++static char mandescr_devstate[] = 
++"Description: Put a value into astdb\n"
++"Variables: \n"
++"	Family: ...\n"
++"	Key: ...\n"
++"	Value: ...\n";
++
++static int action_devstate(struct mansession *s, struct message *m)
++{
++        char *devstate = astman_get_header(m, "Devstate");
++        char *value = astman_get_header(m, "Value");
++	char *id = astman_get_header(m,"ActionID");
++	char devName[128];
++
++	if (!strlen(devstate)) {
++		astman_send_error(s, m, "No Devstate specified");
++		return 0;
++	}
++	if (!strlen(value)) {
++		astman_send_error(s, m, "No Value specified");
++		return 0;
++	}
++
++        if (!ast_db_put("DEVSTATES", devstate, value)) {
++	    snprintf(devName, sizeof(devName), "DS/%s", devstate);
++	    ast_device_state_changed(devName);
++	    ast_cli(s->fd, "Response: Success\r\n");
++	} else {
++	    ast_log(LOG_DEBUG, "ast_db_put failed\n");
++	    ast_cli(s->fd, "Response: Failed\r\n");
++	}
++	if (id && !ast_strlen_zero(id))
++		ast_cli(s->fd, "ActionID: %s\r\n",id);
++	ast_cli(s->fd, "\r\n");
++	return 0;
++}
++
++int load_module(void)
++{
++    if (ast_channel_register(&devstate_tech)) {
++        ast_log(LOG_DEBUG, "Unable to register channel class %s\n", type);
++        return -1;
++    }
++    ast_cli_register(&cli_dev_state);  
++    ast_manager_register2( "Devstate", EVENT_FLAG_CALL, action_devstate, "Change a device state", mandescr_devstate );
++    return ast_register_application(app, devstate_exec, synopsis, descrip);
++}
++
++int unload_module(void)
++{
++    int res = 0;
++    STANDARD_HANGUP_LOCALUSERS;
++    ast_manager_unregister( "Devstate");
++    ast_cli_unregister(&cli_dev_state);
++    res = ast_unregister_application(app);
++    ast_channel_unregister(&devstate_tech);    
++    return res;
++}
++
++char *description(void)
++{
++    return tdesc;
++}
++
++int usecount(void)
++{
++    int res;
++    STANDARD_USECOUNT(res);
++    return res;
++}
++
++char *key()
++{
++    return ASTERISK_GPL_KEY;
++}
+diff -urNad asterisk-1.2.0.dfsg/apps/app_dial.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_dial.c
+--- asterisk-1.2.0.dfsg/apps/app_dial.c	2005-11-14 12:24:59.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_dial.c	2005-11-23 05:50:44.286882421 +0200
+@@ -11,6 +11,10 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+  * This program is free software, distributed under the terms of
+  * the GNU General Public License Version 2. See the LICENSE file
+  * at the top of the source tree.
+@@ -113,7 +117,8 @@
+ "           context may be specified. Otherwise, the current extension is used.\n"
+ "    h    - Allow the called party to hang up by sending the '*' DTMF digit.\n"
+ "    H    - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
+-"    j    - Jump to priority n+101 if all of the requested channels were busy.\n"
++"    j    - Jump to priority n+101 if the called party was busy.\n"
++"           Jump to priority n+201 if all of the requested channels were busy.\n"
+ "    L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
+ "           left. Repeat the warning every 'z' ms. The following special\n"
+ "           variables can be used with this option:\n"
+@@ -158,8 +163,11 @@
+ "           family/key is not specified.\n"
+ "    r    - Indicate ringing to the calling party. Pass no audio to the calling\n"
+ "           party until the called channel has answered.\n"
++"    R	  - indicate ringing to the calling party when the called party indicates\n"
++"            ringing, pass no audio until answered.\n"
+ "    S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
+-"           answered the call.\n"  	
++"           answered the call.\n"
++"    c    - callback initiation, ring once and hangup.\n"
+ "    t    - Allow the called party to transfer the calling party by sending the\n"
+ "           DTMF sequence defiend in features.conf.\n"
+ "    T    - Allow the calling party to transfer the called party by sending the\n"
+@@ -210,6 +218,8 @@
+ 	OPT_CALLEE_MONITOR = (1 << 21),
+ 	OPT_CALLER_MONITOR = (1 << 22),
+ 	OPT_GOTO = (1 << 23),
++	OPT_NOINBAND = (1 << 24),
++	OPT_CALLBACK_INIT = (1 << 25),
+ } dial_exec_option_flags;
+ 
+ #define DIAL_STILLGOING			(1 << 30)
+@@ -248,6 +258,8 @@
+ 	AST_APP_OPTION('p', OPT_SCREENING),
+ 	AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+ 	AST_APP_OPTION('r', OPT_RINGBACK),
++	AST_APP_OPTION('R', OPT_NOINBAND),
++	AST_APP_OPTION('c', OPT_CALLBACK_INIT),
+ 	AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+ 	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+ 	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+@@ -383,7 +395,7 @@
+ 	char *context = NULL;
+ 	char cidname[AST_MAX_EXTENSION];
+ 
+-	single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK));
++	single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK | OPT_NOINBAND));
+ 	
+ 	if (single) {
+ 		/* Turn off hold music, etc */
+@@ -462,7 +474,7 @@
+ 						if (option_verbose > 2)
+ 							ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
+ 						/* Setup parameters */
+-						o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
++						o->chan = ast_request(tech, in->nativeformats, stuff, &cause, NULL);
+ 						if (!o->chan)
+ 							ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+ 					} else {
+@@ -1005,7 +1017,7 @@
+ 				ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
+ 		}
+ 		/* Request the peer */
+-		tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
++		tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause, NULL);
+ 		if (!tmp->chan) {
+ 			/* If we can't, just go on to the next call */
+ 			ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
+@@ -1036,7 +1048,7 @@
+ 					ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
+ 				ast_hangup(tmp->chan);
+ 				/* Setup parameters */
+-				tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
++				tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause, NULL);
+ 				if (!tmp->chan)
+ 					ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+ 			} else {
+@@ -1155,8 +1167,11 @@
+ 			ast_indicate(chan, AST_CONTROL_RINGING);
+ 			sentringing++;
+ 		}
+-	} else
++	} else {
+ 		strcpy(status, "CHANUNAVAIL");
++		/* See if there is a special message */
++		ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
++	}
+ 
+ 	time(&start_time);
+ 	peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result);
+diff -urNad asterisk-1.2.0.dfsg/apps/app_directed_pickup.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_directed_pickup.c
+--- asterisk-1.2.0.dfsg/apps/app_directed_pickup.c	2005-11-11 17:52:55.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_directed_pickup.c	2005-11-23 05:50:44.289882006 +0200
+@@ -41,7 +41,7 @@
+ #include "asterisk/app.h"
+ 
+ static const char *tdesc = "Directed Call Pickup Application";
+-static const char *app = "Pickup";
++static const char *app = "DPickup";
+ static const char *synopsis = "Directed Call Pickup";
+ static const char *descrip =
+ "  Pickup(extension[@context]): This application can pickup any ringing channel\n"
+diff -urNad asterisk-1.2.0.dfsg/apps/app_meetme.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_meetme.c
+--- asterisk-1.2.0.dfsg/apps/app_meetme.c	2005-11-11 02:45:02.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_meetme.c	2005-11-23 05:50:44.293881452 +0200
+@@ -451,7 +451,7 @@
+ 			ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
+ 			ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
+ 			cnf->markedusers = 0;
+-			cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL);
++			cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL, NULL);
+ 			if (cnf->chan) {
+ 				cnf->fd = cnf->chan->fds[0];	/* for use by conf_play() */
+ 			} else {
+diff -urNad asterisk-1.2.0.dfsg/apps/app_page.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_page.c
+--- asterisk-1.2.0.dfsg/apps/app_page.c	2005-11-08 00:01:22.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_page.c	2005-11-23 05:50:44.296881036 +0200
+@@ -83,7 +83,7 @@
+ {
+ 	struct calloutdata *cd = data;
+ 	ast_pbx_outgoing_app(cd->tech, AST_FORMAT_SLINEAR, cd->resource, 30000,
+-		"MeetMe", cd->meetmeopts, NULL, 0, cd->cidnum, cd->cidname, NULL, NULL);
++		"MeetMe", cd->meetmeopts, NULL, 0, 0, cd->cidnum, cd->cidname, NULL, NULL, NULL);
+ 	free(cd);
+ 	return NULL;
+ }
+diff -urNad asterisk-1.2.0.dfsg/apps/app_parkandannounce.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_parkandannounce.c
+--- asterisk-1.2.0.dfsg/apps/app_parkandannounce.c	2005-11-08 06:48:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_parkandannounce.c	2005-11-23 05:50:44.298880759 +0200
+@@ -183,7 +183,7 @@
+ 
+ 	memset(&oh, 0, sizeof(oh));
+ 	oh.parent_channel = chan;
+-	dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
++	dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, 0, chan->cid.cid_num, chan->cid.cid_name, &oh, NULL);
+ 
+ 	if(dchan) {
+ 		if(dchan->_state == AST_STATE_UP) {
+diff -urNad asterisk-1.2.0.dfsg/apps/app_pickup.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_pickup.c
+--- asterisk-1.2.0.dfsg/apps/app_pickup.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_pickup.c	2005-11-23 05:50:44.301880343 +0200
+@@ -0,0 +1,319 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Pickup, channel independent call pickup
++ * 
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * Copyright (C) 2004, Florian Overkamp <florian at obsimref.com>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <signal.h>
++#include <pthread.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/features.h>
++#include <asterisk/options.h>
++
++
++static char *tdesc = "PickUp/PickDown/Steal/PickupChan/StealChan";
++
++static char *app = "PickUp";
++
++static char *synopsis = "Channel independent call pickup.";
++
++static char *descrip = 
++"  PickDown([group]):  Tries to pickup the first ringing channel with callgroup == group.\n"
++"                    If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app2 = "Steal";
++
++static char *synopsis2 = "Channel independent call stealing. Just like pickup but for answered channels.";
++
++static char *descrip2 = 
++"  Steal([group]):  Tries to steal the first bridged channel with callgroup == group.\n"
++"                    If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app3 = "PickDown";
++
++static char *synopsis3 = "Channel independent call pickdown.";
++
++static char *descrip3 = 
++"  PickDown([group]):  Tries to hangup the first ringing channel with callgroup == group.\n"
++"                    If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app4 = "PickupChan";
++
++static char *synopsis4 = "Channel independent call pickup.";
++
++static char *descrip4 = 
++"  PickupChan(Technology/resource[&Technology2/resource2...]):  Tries to pickup the first ringing channel in the parameter list.\n";
++
++static char *app5 = "StealChan";
++
++static char *synopsis5 = "Channel independent call stealing. Just like pickup but for answered channels.";
++
++static char *descrip5 = 
++"  StealChan(Technology/resource[&Technology2/resource2...]):  Tries to steal the first ringing channel in the parameter list.\n";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int my_pickup_call(struct ast_channel *chan, unsigned int pickupgroup, int chanstate, int bridge) {
++	struct ast_channel *cur;
++	int res = -1;
++	cur = ast_channel_walk_locked(NULL);
++	while(cur) {
++		if ((cur != chan) &&
++			(pickupgroup & cur->callgroup) &&
++			 (cur->_state == chanstate)) {
++			 	break;
++		}
++		ast_mutex_unlock(&cur->lock);
++		cur = ast_channel_walk_locked(cur);
++	}
++	if (cur) {
++		if(option_verbose > 2) {
++		    if (chanstate == AST_STATE_RINGING) {
++			if (bridge == 1) {
++		    	    ast_verbose(VERBOSE_PREFIX_3 "Channel %s picked up ringing channel %s\n",chan->name,cur->name);
++			} else {
++		    	    ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n",chan->name,cur->name);
++			}
++		    } else {
++		        ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n",chan->name,cur->name);
++		    }
++		}
++		if (bridge == 1) {
++		    if (chan->_state != AST_STATE_UP) {
++			ast_answer(chan);
++		    }
++		    if (ast_channel_masquerade(cur, chan)) {
++			ast_log(LOG_ERROR, "unable to masquerade\n");
++		    }
++		    ast_mutex_unlock(&cur->lock);
++		    ast_mutex_unlock(&chan->lock);
++		} else {
++		    cur->_softhangup = AST_SOFTHANGUP_DEV;
++		    ast_mutex_unlock(&cur->lock);
++		}
++    	} else	{
++		if(option_verbose > 2) {
++		    ast_verbose(VERBOSE_PREFIX_3 "No channel found %d.\n",pickupgroup);
++		}
++	} 
++	return res;
++}
++
++static int my_pickup_channel(struct ast_channel *chan, void *data, int chanstate, int bridge) {
++       struct ast_channel *cur;
++       char channels[256];
++       char evalchan[256];
++       char *endptr;
++       int res = -1;
++       cur = ast_channel_walk_locked(NULL);
++       strncpy(channels, (char *)data, sizeof(channels) - 1);
++       while(cur) {
++               if ((cur != chan) &&
++                        (cur->_state == chanstate)) {
++                               /* This call is a candidate (correct ringstate and not ourselves), now check if the channel is in our list */
++                               strncpy(evalchan, (char *)cur->name, sizeof(evalchan) - 1);                             
++                               /* strip the subchannel tag */
++                               endptr = strrchr(evalchan, '-');
++                               if(endptr) {
++                                       *endptr = '\0';
++                               }
++                               endptr = strrchr(evalchan, '/');
++                               if(endptr) {
++                                       *endptr = '\0';
++                               }
++                               /* check for each of the members if they match (probably a stristr will do ?) */
++                               /* if we match the code, break */
++                               if(strstr(channels, evalchan) != NULL) {
++                                       ast_verbose(VERBOSE_PREFIX_1 "Nice channel, I'll take it: %s\n",evalchan);
++                                       break;
++                               }
++               }
++               ast_mutex_unlock(&cur->lock);
++               cur = ast_channel_walk_locked(cur);
++       }
++       if (cur) {
++               if(option_verbose > 2) {
++                   if (chanstate == AST_STATE_RINGING) {
++                       if (bridge == 1) {
++                           ast_verbose(VERBOSE_PREFIX_3 "Channel %s picked up ringing channel %s\n",chan->name,cur->name);
++                       } else {
++                           ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n",chan->name,cur->name);
++                       }
++                   } else {
++                       ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n",chan->name,cur->name);
++                   }
++               }
++               if (bridge == 1) {
++	    	   if (chan->_state != AST_STATE_UP) {
++		       ast_answer(chan);
++		   }
++                   if (ast_channel_masquerade(cur, chan)) {
++                       ast_log(LOG_ERROR, "unable to masquerade\n");
++                   }
++                   ast_mutex_unlock(&cur->lock);
++                   ast_mutex_unlock(&chan->lock);
++               } else {
++                   cur->_softhangup = AST_SOFTHANGUP_DEV;
++                   ast_mutex_unlock(&cur->lock);
++               }
++       } else  {
++               if(option_verbose > 2) {
++                   ast_verbose(VERBOSE_PREFIX_3 "No channel found %s.\n",channels);
++               }
++       } 
++       return res;
++}
++
++
++static int pickup_exec(struct ast_channel *chan, void *data)
++{
++	int res=0;
++	unsigned int pickupgroup=0;
++	struct localuser *u;
++	if (!data || !strlen(data)) {
++	    pickupgroup = chan->pickupgroup;
++	} else {
++	    pickupgroup = ast_get_group(data);
++	}
++	LOCAL_USER_ADD(u);
++	if (!res) {
++		res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 1);
++	}
++	if (res > 0)
++		res = 0;
++	LOCAL_USER_REMOVE(u);
++	return res;
++}
++
++static int steal_exec(struct ast_channel *chan, void *data)
++{
++	int res=0;
++	unsigned int pickupgroup=0;
++	struct localuser *u;
++	if (!data || !strlen(data)) {
++	    pickupgroup = chan->pickupgroup;
++	} else {
++	    pickupgroup = ast_get_group(data);
++	}
++	LOCAL_USER_ADD(u);
++	if (!res) {
++		res = my_pickup_call(chan, pickupgroup, AST_STATE_UP, 1);
++	}
++	if (res > 0)
++		res = 0;
++	LOCAL_USER_REMOVE(u);
++	return res;
++}
++
++static int pickdown_exec(struct ast_channel *chan, void *data)
++{
++	int res=0;
++	unsigned int pickupgroup=0;
++	struct localuser *u;
++	if (!data || !strlen(data)) {
++	    pickupgroup = chan->pickupgroup;
++	} else {
++	    pickupgroup = ast_get_group(data);
++	}
++	LOCAL_USER_ADD(u);
++	if (!res) {
++		res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 0);
++	}
++	if (res > 0)
++		res = 0;
++	LOCAL_USER_REMOVE(u);
++	return res;
++}
++
++static int pickupchan_exec(struct ast_channel *chan, void *data) {
++       int res=0;
++       struct localuser *u;
++        if (!data) {
++                ast_log(LOG_WARNING, "PickupChan requires an argument (technology1/number1&technology2/number2...)\n");
++                return -1;
++        }
++       LOCAL_USER_ADD(u);
++       if (!res) {
++               res = my_pickup_channel(chan, data, AST_STATE_RINGING, 1);
++       }
++       if (res > 0)
++               res = 0;
++       LOCAL_USER_REMOVE(u);
++       return res;
++}
++
++static int stealchan_exec(struct ast_channel *chan, void *data)
++{
++	int res=0;
++	struct localuser *u;
++        if (!data) {
++                ast_log(LOG_WARNING, "StealChan requires an argument (technology1/number1&technology2/number2...)\n");
++                return -1;
++        }
++
++	LOCAL_USER_ADD(u);
++	if (!res) {
++		res = my_pickup_channel(chan, data, AST_STATE_UP, 1);
++	}
++	if (res > 0)
++		res = 0;
++	LOCAL_USER_REMOVE(u);
++	return res;
++}
++
++
++int unload_module(void)
++{
++	STANDARD_HANGUP_LOCALUSERS;
++	ast_unregister_application(app5);
++	ast_unregister_application(app4);
++	ast_unregister_application(app3);
++	ast_unregister_application(app2);
++	return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++	ast_register_application(app5, stealchan_exec, synopsis5, descrip5);
++	ast_register_application(app4, pickupchan_exec, synopsis4, descrip4);
++	ast_register_application(app3, pickdown_exec, synopsis3, descrip3);
++	ast_register_application(app2, steal_exec, synopsis2, descrip2);
++	return ast_register_application(app, pickup_exec, synopsis, descrip);
++}
++
++char *description(void)
++{
++	return tdesc;
++}
++
++int usecount(void)
++{
++	int res;
++	STANDARD_USECOUNT(res);
++	return res;
++}
++
++char *key()
++{
++	return ASTERISK_GPL_KEY;
++}
+diff -urNad asterisk-1.2.0.dfsg/apps/app_queue.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_queue.c
+--- asterisk-1.2.0.dfsg/apps/app_queue.c	2005-11-11 01:22:37.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_queue.c	2005-11-23 05:50:44.306879650 +0200
+@@ -1363,7 +1363,7 @@
+ 		location = "";
+ 
+ 	/* Request the peer */
+-	tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
++	tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status, NULL);
+ 	if (!tmp->chan) {			/* If we can't, just go on to the next call */
+ #if 0
+ 		ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
+@@ -1669,7 +1669,7 @@
+ 					if (option_verbose > 2)
+ 						ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
+ 					/* Setup parameters */
+-					o->chan = ast_request(tech, in->nativeformats, stuff, &status);
++					o->chan = ast_request(tech, in->nativeformats, stuff, &status, NULL);
+ 					if (status != o->oldstatus) 
+ 						update_dial_status(qe->parent, o->member, status);						
+ 					if (!o->chan) {
+diff -urNad asterisk-1.2.0.dfsg/apps/app_readfile.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_readfile.c
+--- asterisk-1.2.0.dfsg/apps/app_readfile.c	2005-11-06 17:09:46.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_readfile.c	2005-11-23 05:50:44.309879235 +0200
+@@ -40,7 +40,7 @@
+ #include "asterisk/app.h"
+ #include "asterisk/module.h"
+ 
+-static char *tdesc = "Stores output of file into a variable";
++static char *tdesc = "Stores content of file into a variable";
+ 
+ static char *app_readfile = "ReadFile";
+ 
+diff -urNad asterisk-1.2.0.dfsg/apps/app_segfault.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_segfault.c
+--- asterisk-1.2.0.dfsg/apps/app_segfault.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_segfault.c	2005-11-23 05:50:44.312878819 +0200
+@@ -0,0 +1,75 @@
++/*
++ * Segfault application
++ * 
++ * An application to provoke a segmentation fault from the dialplan.
++ * (I know what you are thinking now...., but since Asterisk is too stable...
++ *  I needed something to test my failover switches.)
++ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License. THIS APPLICATION _WILL_ CRASH YOUR
++ * ASTERISK SERVER SO OF COURSE THERE IS NOT LIABILITY FOR NOTHING!
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++
++static char *tdesc = "Application for crashing Asterisk with a segmentation fault";
++
++static char *app = "Segfault";
++
++static char *synopsis = "This application will crash Asterisk with a segmentation fault.";
++
++static char *descrip = 
++"  Segfault():  Crash with a segfault. Never returns nufin.\n";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int segfault_exec(struct ast_channel *chan, void *data)
++{
++    struct localuser *u;
++    LOCAL_USER_ADD(u);
++    ((char *)0)[0] = 0;
++    LOCAL_USER_REMOVE(u);
++    return 0;
++}
++
++int unload_module(void)
++{
++    STANDARD_HANGUP_LOCALUSERS;
++    return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++    return ast_register_application(app, segfault_exec, synopsis, descrip);
++}
++
++char *description(void)
++{
++    return tdesc;
++}
++
++int usecount(void)
++{
++    int res;
++    STANDARD_USECOUNT(res);
++    return res;
++}
++
++char *key()
++{
++    return ASTERISK_GPL_KEY;
++}
+diff -urNad asterisk-1.2.0.dfsg/apps/app_zapras.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_zapras.c
+--- asterisk-1.2.0.dfsg/apps/app_zapras.c	2005-11-08 00:01:22.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/app_zapras.c	2005-11-23 05:50:44.314878542 +0200
+@@ -182,7 +182,7 @@
+ 				}
+ 			}
+ 			/* Throw back into audio mode */
+-			x = 1;
++			x = 0;
+ 			ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
+ 
+ 			/* Restore saved values */
+diff -urNad asterisk-1.2.0.dfsg/apps/Makefile /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/Makefile
+--- asterisk-1.2.0.dfsg/apps/Makefile	2005-11-11 02:32:45.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/apps/Makefile	2005-11-23 05:50:44.317878126 +0200
+@@ -28,6 +28,7 @@
+      app_test.so app_forkcdr.so app_math.so app_realtime.so \
+      app_dumpchan.so app_waitforsilence.so app_while.so app_setrdnis.so \
+      app_md5.so app_readfile.so app_chanspy.so app_settransfercapability.so \
++     app_pickup.so app_segfault.so app_callingpres.so app_devstate.so \
+      app_dictate.so app_externalivr.so app_directed_pickup.so \
+      app_mixmonitor.so app_stack.so
+ 
+diff -urNad asterisk-1.2.0.dfsg/asterisk.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/asterisk.c
+--- asterisk-1.2.0.dfsg/asterisk.c	2005-11-14 21:00:38.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/asterisk.c	2005-11-23 05:50:44.320877711 +0200
+@@ -215,6 +215,7 @@
+ char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
+ char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
+ char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
++char ast_config_AST_SYMBOLIC_NAME[20];
+ 
+ static char *_argv[256];
+ static int shuttingdown = 0;
+@@ -1795,6 +1796,7 @@
+ 	ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
+ 	ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
+ 	ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
++	ast_copy_string(ast_config_AST_SYMBOLIC_NAME, AST_SYMBOLIC_NAME, sizeof(ast_config_AST_SYMBOLIC_NAME));
+ 
+ 	/* no asterisk.conf? no problem, use buildtime config! */
+ 	if (!cfg) {
+@@ -1833,6 +1835,8 @@
+ 			ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
+ 		} else if (!strcasecmp(v->name, "astmoddir")) {
+ 			ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
++  		} else if (!strcasecmp(v->name, "uniquename")) {
++  			strncpy(ast_config_AST_SYMBOLIC_NAME,v->value,sizeof(ast_config_AST_SYMBOLIC_NAME));
+ 		}
+ 		v = v->next;
+ 	}
+diff -urNad asterisk-1.2.0.dfsg/build_tools/make_defaults_h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/build_tools/make_defaults_h
+--- asterisk-1.2.0.dfsg/build_tools/make_defaults_h	2005-06-20 20:26:07.000000000 +0300
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/build_tools/make_defaults_h	2005-11-23 05:50:44.323877295 +0200
+@@ -16,6 +16,7 @@
+ #define AST_KEY_DIR    "${INSTALL_PATH}${ASTVARLIBDIR}/keys"
+ #define AST_DB         "${INSTALL_PATH}${ASTVARLIBDIR}/astdb"
+ #define AST_TMP_DIR    "${INSTALL_PATH}${ASTSPOOLDIR}/tmp"
++#define AST_SYMBOLIC_NAME	"asterisk"
+ 
+ #define AST_CONFIG_FILE "${INSTALL_PATH}${ASTCONFPATH}"
+ 
+diff -urNad asterisk-1.2.0.dfsg/channel.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channel.c
+--- asterisk-1.2.0.dfsg/channel.c	2005-11-16 20:11:28.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channel.c	2005-11-23 05:50:44.328876602 +0200
+@@ -95,6 +95,7 @@
+ static int shutting_down = 0;
+ 
+ static int uniqueint = 0;
++AST_MUTEX_DEFINE_EXPORTED(uniquelock);
+ 
+ unsigned long global_fin = 0, global_fout = 0;
+ 
+@@ -511,6 +512,17 @@
+ 	.description = "Null channel (should not see this)",
+ };
+ 
++char *ast_alloc_uniqueid(void) {
++      char *uniqueid;
++      uniqueid = malloc(64);
++      if (!uniqueid) return NULL;
++      ast_mutex_lock(&uniquelock);
++      snprintf(uniqueid, 63, "%s-%d-%li.%d", ast_config_AST_SYMBOLIC_NAME, ast_mainpid, (long)time(NULL), uniqueint++);
++      ast_mutex_unlock(&uniquelock);
++      return uniqueid;
++}
++
++
+ /*--- ast_channel_alloc: Create a new channel structure */
+ struct ast_channel *ast_channel_alloc(int needqueue)
+ {
+@@ -518,6 +530,7 @@
+ 	int x;
+ 	int flags;
+ 	struct varshead *headp;        
++  	char *tmpuniqueid;
+ 	        
+ 
+ 	/* If shutting down, don't allocate any new channels */
+@@ -584,6 +597,12 @@
+ 	tmp->fin = global_fin;
+ 	tmp->fout = global_fout;
+ 	snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), "%li.%d", (long) time(NULL), uniqueint++);
++	tmpuniqueid = ast_alloc_uniqueid();
++	snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), tmpuniqueid);
++	if (tmpuniqueid) { 
++	    free(tmpuniqueid);
++	    tmpuniqueid = NULL;
++	}
+ 	headp = &tmp->varshead;
+ 	ast_mutex_init(&tmp->lock);
+ 	AST_LIST_HEAD_INIT_NOLOCK(headp);
+@@ -817,6 +836,20 @@
+ 	return channel_find_locked(NULL, NULL, 0, context, exten);
+ }
+ 
++struct ast_channel *ast_get_channel_by_uniqueid_locked(char *uniqueid)
++{
++	struct ast_channel *chan;
++	chan = ast_channel_walk_locked(NULL);
++	while(chan) {
++		if (!strcasecmp(chan->uniqueid, uniqueid))
++			return chan;
++		ast_mutex_unlock(&chan->lock);
++		chan = ast_channel_walk_locked(chan);
++	}
++	return NULL;
++}
++
++
+ /*--- ast_safe_sleep_conditional: Wait, look for hangups and condition arg */
+ int ast_safe_sleep_conditional(	struct ast_channel *chan, int ms,
+ 	int (*cond)(void*), void *data )
+@@ -950,6 +983,9 @@
+ 	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
+ 		ast_var_delete(vardata);
+ 
++	if (chan->sched)
++		sched_context_destroy(chan->sched);
++
+ 	free(chan);
+ 	ast_mutex_unlock(&chlock);
+ 
+@@ -1289,8 +1325,6 @@
+ 		ast_closestream(chan->stream);
+ 	if (chan->vstream)		/* Close video stream */
+ 		ast_closestream(chan->vstream);
+-	if (chan->sched)
+-		sched_context_destroy(chan->sched);
+ 	
+ 	if (chan->generatordata)	/* Clear any tone stuff remaining */ 
+ 		chan->generator->release(chan, chan->generatordata);
+@@ -2349,7 +2383,7 @@
+ 			  &chan->writetrans, 1);
+ }
+ 
+-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
++struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cid_num, const char *cid_name, struct outgoing_helper *oh, char* uniqueid)
+ {
+ 	int state = 0;
+ 	int cause = 0;
+@@ -2357,7 +2391,7 @@
+ 	struct ast_frame *f;
+ 	int res = 0;
+ 	
+-	chan = ast_request(type, format, data, &cause);
++	chan = ast_request(type, format, data, &cause, uniqueid);
+ 	if (chan) {
+ 		if (oh) {
+ 			if (oh->vars)	
+@@ -2369,6 +2403,7 @@
+ 		}
+ 		ast_set_callerid(chan, cid_num, cid_name, cid_num);
+ 
++		chan->cid.cid_pres = callingpres;
+ 		if (!ast_call(chan, data, 0)) {
+ 			while(timeout && (chan->_state != AST_STATE_UP)) {
+ 				res = ast_waitfor(chan, timeout);
+@@ -2391,6 +2426,7 @@
+ 					if (f->subclass == AST_CONTROL_RINGING)
+ 						state = AST_CONTROL_RINGING;
+ 					else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
++						res = 0;
+ 						state = f->subclass;
+ 						ast_frfree(f);
+ 						break;
+@@ -2460,12 +2496,12 @@
+ 	return chan;
+ }
+ 
+-struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
++struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cidnum, const char *cidname, char *uniqueid)
+ {
+-	return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL);
++	return __ast_request_and_dial(type, format, data, timeout, outstate, 0, cidnum, cidname, NULL, uniqueid);
+ }
+ 
+-struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
++struct ast_channel *ast_request(const char *type, int format, void *data, int *cause, char *uniqueid)
+ {
+ 	struct chanlist *chan;
+ 	struct ast_channel *c;
+@@ -2502,6 +2538,7 @@
+ 		if (!(c = chan->tech->requester(type, capabilities, data, cause)))
+ 			return NULL;
+ 
++		if (uniqueid) strncpy(c->uniqueid, uniqueid, sizeof(c->uniqueid));
+ 		if (c->_state == AST_STATE_DOWN) {
+ 			manager_event(EVENT_FLAG_CALL, "Newchannel",
+ 				      "Channel: %s\r\n"
+@@ -2749,6 +2786,29 @@
+ 	return res;
+ }
+ 
++int ast_channel_masquerade_locked(struct ast_channel *original, struct ast_channel *clone)
++{
++	struct ast_frame null = { AST_FRAME_NULL, };
++	int res = -1;
++	ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
++		clone->name, original->name);
++	if (original->masq) {
++		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
++			original->masq->name, original->name);
++	} else if (clone->masqr) {
++		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
++			clone->name, clone->masqr->name);
++	} else {
++		original->masq = clone;
++		clone->masqr = original;
++		ast_queue_frame(original, &null);
++		ast_queue_frame(clone, &null);
++		ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
++		res = 0;
++	}
++	return res;
++}
++
+ void ast_change_name(struct ast_channel *chan, char *newname)
+ {
+ 	char tmp[256];
+@@ -3310,6 +3370,7 @@
+ 	char callee_warning = 0;
+ 	int to;
+ 
++
+ 	if (c0->_bridge) {
+ 		ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", 
+ 			c0->name, c0->_bridge->name);
+@@ -3320,6 +3381,10 @@
+ 			c1->name, c1->_bridge->name);
+ 		return -1;
+ 	}
++
++	if (IS_DIGITAL(c0->transfercapability) || IS_DIGITAL(c1->transfercapability)) {
++	    config->flags = 0;
++	}
+ 	
+ 	/* Stop if we're a zombie or need a soft hangup */
+ 	if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) ||
+diff -urNad asterisk-1.2.0.dfsg/channels/chan_agent.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_agent.c
+--- asterisk-1.2.0.dfsg/channels/chan_agent.c	2005-11-08 06:02:35.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_agent.c	2005-11-23 05:50:44.332876048 +0200
+@@ -1327,7 +1327,7 @@
+ 						chan = agent_new(p, AST_STATE_DOWN);
+ 					} else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
+ 						/* Adjustable agent */
+-						p->chan = ast_request("Local", format, p->loginchan, cause);
++						p->chan = ast_request("Local", format, p->loginchan, cause, NULL);
+ 						if (p->chan)
+ 							chan = agent_new(p, AST_STATE_DOWN);
+ 					}
+diff -urNad asterisk-1.2.0.dfsg/channels/chan_features.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_features.c
+--- asterisk-1.2.0.dfsg/channels/chan_features.c	2005-11-06 17:09:46.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_features.c	2005-11-23 05:50:44.335875633 +0200
+@@ -438,7 +438,7 @@
+ 	}
+ 	ast_mutex_unlock(&featurelock);
+ 	if (!tmp) {
+-		chan = ast_request(tech, format, dest, &status);
++		chan = ast_request(tech, format, dest, &status, NULL);
+ 		if (!chan) {
+ 			ast_log(LOG_NOTICE, "Unable to allocate subchannel '%s/%s'\n", tech, dest);
+ 			return NULL;
+diff -urNad asterisk-1.2.0.dfsg/channels/chan_iax2.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_iax2.c
+--- asterisk-1.2.0.dfsg/channels/chan_iax2.c	2005-11-12 22:04:57.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_iax2.c	2005-11-23 05:50:44.343874524 +0200
+@@ -11,6 +11,9 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Hangup cause signalling implementation by
++ * Levent Guendogdu <levon at feature-it.com>
++ *
+  * This program is free software, distributed under the terms of
+  * the GNU General Public License Version 2. See the LICENSE file
+  * at the top of the source tree.
+@@ -3047,7 +3050,7 @@
+  	memset(&ied, 0, sizeof(ied));
+ 	ast_mutex_lock(&iaxsl[callno]);
+ 	if (callno && iaxs[callno]) {
+-		ast_log(LOG_DEBUG, "We're hanging up %s now...\n", c->name);
++ 		ast_log(LOG_DEBUG, "We're hanging up %s with cause %i now...\n", c->name, c->hangupcause);
+ 		alreadygone = ast_test_flag(iaxs[callno], IAX_ALREADYGONE);
+ 		/* Send the hangup unless we have had a transmission error or are already gone */
+  		iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, (unsigned char)c->hangupcause);
+diff -urNad asterisk-1.2.0.dfsg/channels/chan_sip.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_sip.c
+--- asterisk-1.2.0.dfsg/channels/chan_sip.c	2005-11-16 19:46:59.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_sip.c	2005-11-23 05:50:44.354873000 +0200
+@@ -4810,7 +4810,8 @@
+ 
+ 	/* If there is a VXML URL append it to the SIP URL */
+ 	if (p->options && p->options->vxml_url) {
+-		snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
++//		snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
++		snprintf(to, sizeof(to), "<%s;%s>", p->uri, p->options->vxml_url);
+ 	} else {
+ 		snprintf(to, sizeof(to), "<%s>", p->uri);
+ 	}
+diff -urNad asterisk-1.2.0.dfsg/channels/chan_zap.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_zap.c
+--- asterisk-1.2.0.dfsg/channels/chan_zap.c	2005-11-11 20:00:07.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/channels/chan_zap.c	2005-11-23 05:50:44.369870922 +0200
+@@ -11,6 +11,10 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2003, 2004, 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ *
+  * This program is free software, distributed under the terms of
+  * the GNU General Public License Version 2. See the LICENSE file
+  * at the top of the source tree.
+@@ -96,6 +100,7 @@
+ #include "asterisk/term.h"
+ #include "asterisk/utils.h"
+ #include "asterisk/transcap.h"
++#include "asterisk/devicestate.h"
+ 
+ #ifndef ZT_SIG_EM_E1
+ #error "Your zaptel is too old.  please cvs update"
+@@ -180,7 +185,7 @@
+ #define SIG_GR303FXOKS	(0x0100000 | ZT_SIG_FXOKS)
+ #define SIG_GR303FXSKS	(0x0100000 | ZT_SIG_FXSKS)
+ 
+-#define NUM_SPANS 		32
++#define NUM_SPANS 		128	/*!<"32 spans", muahahaha, us alaws like to have some more... */
+ #define NUM_DCHANS		4	/*!< No more than 4 d-channels */
+ #define MAX_CHANNELS	672		/*!< No more than a DS3 per trunk group */
+ 
+@@ -198,6 +203,9 @@
+ static char defaultcic[64] = "";
+ static char defaultozz[64] = "";
+ 
++static char nocid[256] = "No CID available";
++static char withheldcid[256] = "CID withheld";
++
+ static char language[MAX_LANGUAGE] = "";
+ static char musicclass[MAX_MUSICCLASS] = "";
+ static char progzone[10]= "";
+@@ -291,6 +299,7 @@
+ static char idleext[AST_MAX_EXTENSION];
+ static char idledial[AST_MAX_EXTENSION];
+ static int overlapdial = 0;
++static int usercid = 0;
+ static int facilityenable = 0;
+ static char internationalprefix[10] = "";
+ static char nationalprefix[10] = "";
+@@ -302,8 +311,6 @@
+ #ifdef PRI_GETSET_TIMERS
+ static int pritimers[PRI_MAX_TIMERS];
+ #endif
+-static int pridebugfd = -1;
+-static char pridebugfilename[1024]="";
+ #endif
+ 
+ /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
+@@ -324,10 +331,6 @@
+ 
+ static int ifcount = 0;
+ 
+-#ifdef ZAPATA_PRI
+-AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
+-#endif
+-
+ /*! \brief Whether we answer on a Polarity Switch event */
+ static int answeronpolarityswitch = 0;
+ 
+@@ -400,6 +403,27 @@
+ #define PRI_SPAN(p) (((p) >> 8) & 0xff)
+ #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
+ 
++struct zt_suspended_call {
++	ast_mutex_t lock;		/* Mutex */
++	char msn[AST_MAX_EXTENSION];	/* the MSN to which this parked call belongs */
++	char callid[10];			/* the callID provided by the user */
++	int parked_at;			/* extension in the call parking context */
++	struct zt_suspended_call *next;
++};
++
++struct zt_holded_call {
++	ast_mutex_t lock;		/* Mutex */
++	char msn[AST_MAX_EXTENSION];	/* the MSN to which this parked call belongs */
++	char uniqueid[AST_MAX_EXTENSION];	/* unique id of the onhold channel */
++	int tei;
++	int cref;
++	int alreadyhungup;
++	struct ast_channel *channel;
++	struct ast_channel *bridge;
++	q931_call *call;	/* this also covers tei mumbojumbo */
++	struct zt_holded_call *next;
++};
++
+ struct zt_pri {
+ 	pthread_t master;						/*!< Thread of master */
+ 	ast_mutex_t lock;						/*!< Mutex */
+@@ -413,6 +437,8 @@
+ 	int nsf;							/*!< Network-Specific Facilities */
+ 	int dialplan;							/*!< Dialing plan */
+ 	int localdialplan;						/*!< Local dialing plan */
++ 	char nocid[256];
++ 	char withheldcid[256];
+ 	char internationalprefix[10];					/*!< country access code ('00' for european dialplans) */
+ 	char nationalprefix[10];					/*!< area access code ('0' for european dialplans) */
+ 	char localprefix[20];						/*!< area access code + area code ('0'+area code for european dialplans) */
+@@ -432,6 +458,7 @@
+ 	int fds[NUM_DCHANS];						/*!< FD's for d-channels */
+ 	int offset;
+ 	int span;
++ 	int usercid;							/* trust user provided callerid (callerani) ?? */
+ 	int resetting;
+ 	int resetpos;
+ 	time_t lastreset;						/*!< time when unused channels were last reset */
+@@ -439,6 +466,9 @@
+ 	struct zt_pvt *pvts[MAX_CHANNELS];				/*!< Member channel pvt structs */
+ 	struct zt_pvt *crvs;						/*!< Member CRV structs */
+ 	struct zt_pvt *crvend;						/*!< Pointer to end of CRV structs */
++ 	struct zt_suspended_call *suspended_calls; /* Calls parked with SUSPEND messages */
++ 	struct zt_holded_call *holded_calls; /* Calls on hold */
++	int debugfd;
+ };
+ 
+ 
+@@ -558,6 +588,8 @@
+ 	unsigned int echocanbridged:1;
+ 	unsigned int echocanon:1;
+ 	unsigned int faxhandled:1;			/*!< Has a fax tone already been handled? */
++ 							/*!< KPJ: i will abuse this flag to implement a zapata option for dialing out
++ 							    on a zap channel with EC to be off no matter what happens. */
+ 	unsigned int firstradio:1;
+ 	unsigned int hanguponpolarityswitch:1;
+ 	unsigned int hardwaredtmf:1;
+@@ -570,7 +602,7 @@
+ 	unsigned int overlapdial:1;
+ 	unsigned int permcallwaiting:1;
+ 	unsigned int permhidecallerid:1;		/*!< Whether to hide our outgoing caller ID or not */
+-	unsigned int priindication_oob:1;
++	unsigned int priindication_oob:2;
+ 	unsigned int priexclusive:1;
+ 	unsigned int pulse:1;
+ 	unsigned int pulsedial:1;			/*!< whether a pulse dial phone is detected */
+@@ -609,6 +641,7 @@
+ #endif
+ 	char cid_num[AST_MAX_EXTENSION];
+ 	int cid_ton;					/*!< Type Of Number (TON) */
++	int cid_pres;					/*!< Calling Presentation */
+ 	char cid_name[AST_MAX_EXTENSION];
+ 	char lastcid_num[AST_MAX_EXTENSION];
+ 	char lastcid_name[AST_MAX_EXTENSION];
+@@ -673,6 +706,8 @@
+ 	struct zt_pri *pri;
+ 	struct zt_pvt *bearer;
+ 	struct zt_pvt *realcall;
++	int tei;					/* channel in use by this tei */
++	q931_call *holdedcall;
+ 	q931_call *call;
+ 	int prioffset;
+ 	int logicalspan;
+@@ -698,11 +733,12 @@
+ static int zt_indicate(struct ast_channel *chan, int condition);
+ static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+ static int zt_setoption(struct ast_channel *chan, int option, void *data, int datalen);
++static int zt_devicestate(void *data);
+ 
+ static const struct ast_channel_tech zap_tech = {
+ 	.type = type,
+ 	.description = tdesc,
+-	.capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
++	.capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
+ 	.requester = zt_request,
+ 	.send_digit = zt_digit,
+ 	.send_text = zt_sendtext,
+@@ -716,6 +752,7 @@
+ 	.indicate = zt_indicate,
+ 	.fixup = zt_fixup,
+ 	.setoption = zt_setoption,
++	.devicestate = zt_devicestate
+ };
+ 
+ #ifdef ZAPATA_PRI
+@@ -727,6 +764,13 @@
+ struct zt_pvt *round_robin[32];
+ 
+ #ifdef ZAPATA_PRI
++struct app_tmp {
++	char app[256];
++	char data[256];
++	struct ast_channel *chan;
++	pthread_t t;
++};
++
+ static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri)
+ {
+ 	int res;
+@@ -776,6 +820,112 @@
+ #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
+ #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
+ 
++static int zt_devicestate(void *data)
++{
++	int groupmatch = 0;
++	int channelmatch = 0;
++	struct zt_pvt *p;
++	char *dest=NULL;
++	int x,d;
++	char *s;
++	char opt=0;
++	int res, y=0;
++	struct zt_pvt *exit, *start, *end;
++	ast_mutex_t *lock;
++
++//	ast_log(LOG_NOTICE, "data = %s\n", (char *)data);
++	return AST_DEVICE_UNKNOWN;
++	
++	/* Assume we're locking the iflock */
++	lock = &iflock;
++	start = iflist;
++	end = ifend;
++
++	if (data) {
++		dest = ast_strdupa((char *)data);
++	} else {
++		ast_log(LOG_WARNING, "Channel requested with no data\n");
++		return AST_DEVICE_INVALID;
++	}
++	if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
++		/* Retrieve the group number */
++		char *stringp=NULL;
++		stringp=dest + 1;
++		s = strsep(&stringp, "/");
++		if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
++			ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
++			return AST_DEVICE_INVALID;
++		}
++		groupmatch = 1 << x;
++	} else {
++		char *stringp=NULL;
++		stringp=dest;
++		s = strsep(&stringp, "/");
++		p = iflist;
++		if (!strcasecmp(s, "pseudo")) {
++			/* Special case for pseudo */
++			x = CHAN_PSEUDO;
++			channelmatch = x;
++			/* bail out */
++			return AST_DEVICE_INVALID;
++		} 
++
++		else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
++			ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
++			return AST_DEVICE_INVALID;
++		} else {
++			channelmatch = x;
++			ast_log(LOG_NOTICE, "channelmatch = %d\n", channelmatch);
++		}
++	}
++	/* Search for an unowned channel */
++	if (ast_mutex_lock(lock)) {
++		ast_log(LOG_ERROR, "Unable to lock interface list???\n");
++		return AST_DEVICE_INVALID;
++	}
++	p = iflist;
++	exit = iflist;
++	res = AST_DEVICE_INVALID; /* start pessimistic */
++	while(p) {
++		if (p) {
++		    ast_mutex_lock(&p->lock);
++		    if ((groupmatch && ((p->group & groupmatch) != 0)) || (channelmatch && (p->channel == channelmatch))) {
++#ifdef ZAPATA_PRI
++			if (p->pri) {
++			    for(d=0;d<NUM_DCHANS;d++) {
++				if (p->pri->dchanavail[d] & DCHAN_UP) {
++			    	    res = AST_DEVICE_UNKNOWN;
++				}
++			    }
++			}
++#endif
++			if ((!ast_strlen_zero(p->cid_num) && (strncasecmp(p->cid_num, dest, strlen(p->cid_num)))) || (!ast_strlen_zero(p->dnid) && (strncasecmp(p->dnid, dest, strlen(p->dnid))))) {
++			    res = AST_DEVICE_UNKNOWN;
++			    if (p->owner) {
++				    if ((p->owner->_state == AST_STATE_RINGING) && (p->outgoing)) {
++			    		res = AST_DEVICE_RINGING;
++				    }
++				    if (((p->owner->_state == AST_STATE_RINGING) && (!p->outgoing)) || (p->owner->_state == AST_STATE_UP) || (p->owner->_state == AST_STATE_DIALING) || (p->owner->_state == AST_STATE_RESERVED) || (p->owner->_state == AST_STATE_RING)){
++			    		res = AST_DEVICE_INUSE;
++				    }
++			    }
++			    if ((res == AST_DEVICE_INUSE) || (res == AST_DEVICE_RINGING)) {
++				/* stop searching now, one non-idle channel is sufficient */
++				ast_mutex_unlock(&p->lock);
++				break;
++			    }
++			}
++		    }
++		    ast_mutex_unlock(&p->lock);
++		}		
++		p = p->next;
++	}
++	ast_mutex_unlock(lock);
++
++	return res;
++
++}
++
+ static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
+ {
+ 	int res;
+@@ -1378,12 +1528,16 @@
+ 	int res;
+ 	if (!p)
+ 		return;
++ 	if (p->faxhandled)  {
++ 		ast_log(LOG_DEBUG, "Not enabling echo cancellation on a fax/modem call\n");
++		return;
++ 	}
+ 	if (p->echocanon) {
+ 		ast_log(LOG_DEBUG, "Echo cancellation already on\n");
+ 		return;
+ 	}
+ 	if (p->digital) {
+-		ast_log(LOG_DEBUG, "Echo cancellation isn't required on digital connection\n");
++		ast_log(LOG_DEBUG, "Echo cancellation does not make any sense on digital connections!\n");
+ 		return;
+ 	}
+ 	if (p->echocancel) {
+@@ -1409,7 +1563,7 @@
+ {
+ 	int x;
+ 	int res;
+-	if (p && p->echocancel && p->echotraining) {
++	if (p && p->echocancel && p->echotraining && (!p->digital) && (!p->faxhandled)) {
+ 		x = p->echotraining;
+ 		res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOTRAIN, &x);
+ 		if (res) 
+@@ -1771,7 +1925,11 @@
+ 		ast_log(LOG_WARNING, "Unable to flush input on channel %d\n", p->channel);
+ 	p->outgoing = 1;
+ 
+-	set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
++	if (!IS_DIGITAL(ast->transfercapability)) {
++	    set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
++	} else {
++	    set_actual_gain(p->subs[SUB_REAL].zfd, 0, 0, 0, p->law);
++	}
+ 
+ 	switch(p->sig) {
+ 	case SIG_FXOLS:
+@@ -2011,6 +2169,12 @@
+ 		int ldp_strip;
+ 		int exclusive;
+ 
++ 		if ((p->pri->nodetype == BRI_NETWORK_PTMP) || (p->pri->nodetype == BRI_NETWORK)) {
++ 		    // pass NO audio when ringing an isdn phone
++ 		    p->dialing = 1;
++ 		    // maybe we could allow passing audio when calling a p2p PBX, but well... ;-)
++ 		}
++
+ 		c = strchr(dest, '/');
+ 		if (c)
+ 			c++;
+@@ -2028,6 +2192,7 @@
+ 			ast_mutex_unlock(&p->lock);
+ 			return -1;
+ 		}
++		strncpy(p->dnid, (c + p->stripmsd), sizeof(p->dnid)-1);
+ 		if (p->sig != SIG_FXSKS) {
+ 			p->dop.op = ZT_DIAL_OP_REPLACE;
+ 			s = strchr(c + p->stripmsd, 'w');
+@@ -2051,6 +2216,8 @@
+ 			pri_rel(p->pri);
+ 			ast_mutex_unlock(&p->lock);
+ 			return -1;
++		} else {
++		//	ast_log(LOG_NOTICE, "call %d\n", p->call);
+ 		}
+ 		if (!(sr = pri_sr_new())) {
+ 			ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
+@@ -2279,8 +2446,10 @@
+ 	}
+ 	if (newslot < 0) {
+ 		newslot = 0;
+-		ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
++		if (pri->nodetype != BRI_CPE_PTMP) {
++		    ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
+ 			pri->dchannels[newslot]);
++		}
+ 	}
+ 	if (old && (oldslot != newslot))
+ 		ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
+@@ -2486,6 +2655,13 @@
+ 								icause = atoi(cause);
+ 						}
+ 						pri_hangup(p->pri->pri, p->call, icause);
++						if (p->pri->nodetype == BRI_NETWORK_PTMP) {
++						    // fix for hangup in NT mode
++						    // XXX check me
++						    if ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING)) {
++							p->call = NULL;
++						    }
++						}
+ 					}
+ 					if (res < 0) 
+ 						ast_log(LOG_WARNING, "pri_disconnect failed\n");
+@@ -2682,10 +2858,14 @@
+ 			p->proceeding = 1;
+ 			res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
+ 			pri_rel(p->pri);
++			/* stop ignoring inband dtmf */
++			p->ignoredtmf = 0;
+ 		} else {
+ 			ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
+ 			res= -1;
+ 		}
++		/* the audio path is complete now, train the echo canceler */
++		zt_train_ec(p);
+ 		break;
+ #endif
+ #ifdef ZAPATA_R2
+@@ -3252,6 +3432,15 @@
+ {
+ 	struct zt_pvt *p = newchan->tech_pvt;
+ 	int x;
++ 	if (newchan && newchan->tech_pvt) {
++ 	    p = newchan->tech_pvt;
++ 	}
++ 	if (!p) {
++ 	    if (newchan) {
++ 		ast_log(LOG_ERROR, "channel %s has no tech_pvt structure\n", newchan->name);
++ 	    }
++ 	    return 0;
++ 	}
+ 	ast_mutex_lock(&p->lock);
+ 	ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name);
+ 	if (p->owner == oldchan) {
+@@ -4586,8 +4775,9 @@
+ 				}
+ 			} else if (f->frametype == AST_FRAME_DTMF) {
+ #ifdef ZAPATA_PRI
+-				if (!p->proceeding && p->sig==SIG_PRI && p->pri && p->pri->overlapdial) {
+-					/* Don't accept in-band DTMF when in overlap dial mode */
++				if (!p->proceeding && p->sig==SIG_PRI && p->pri && (p->pri->overlapdial || p->ignoredtmf)) {
++					/* Don't accept in-band DTMF when in overlap dial mode 
++					   or when in non-overlap overlapdialing mode ... */
+ 					f->frametype = AST_FRAME_NULL;
+ 					f->subclass = 0;
+ 				}
+@@ -4722,7 +4912,9 @@
+ #endif
+ 	/* Write a frame of (presumably voice) data */
+ 	if (frame->frametype != AST_FRAME_VOICE) {
+-		if (frame->frametype != AST_FRAME_IMAGE)
++		if (frame->frametype == AST_FRAME_TEXT) {
++			ast_log(LOG_NOTICE, "text\n");
++		} else if (frame->frametype != AST_FRAME_IMAGE)
+ 			ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
+ 		return 0;
+ 	}
+@@ -4793,7 +4985,7 @@
+ 		switch(condition) {
+ 		case AST_CONTROL_BUSY:
+ #ifdef ZAPATA_PRI
+-			if (p->priindication_oob && p->sig == SIG_PRI) {
++			if ((p->priindication_oob == 1) && p->sig == SIG_PRI) {
+ 				chan->hangupcause = AST_CAUSE_USER_BUSY;
+ 				chan->_softhangup |= AST_SOFTHANGUP_DEV;
+ 				res = 0;
+@@ -4875,7 +5067,7 @@
+ 		case AST_CONTROL_CONGESTION:
+ 			chan->hangupcause = AST_CAUSE_CONGESTION;
+ #ifdef ZAPATA_PRI
+-			if (p->priindication_oob && p->sig == SIG_PRI) {
++			if ((p->priindication_oob == 1) && p->sig == SIG_PRI) {
+ 				chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+ 				chan->_softhangup |= AST_SOFTHANGUP_DEV;
+ 				res = 0;
+@@ -5057,8 +5249,12 @@
+ 		if (state == AST_STATE_RING)
+ 			tmp->rings = 1;
+ 		tmp->tech_pvt = i;
+-		if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
+-			/* Only FXO signalled stuff can be picked up */
++#ifdef ZAPATA_PRI
++		if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS) || (i->sig == SIG_PRI)) {
++#else
++ 		if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
++#endif
++		/* Only FXO signalled stuff can be picked up */ /* i dont think so, mr. ulaw! we alaws like to pick up BRIs/PRIs */
+ 			tmp->callgroup = i->callgroup;
+ 			tmp->pickupgroup = i->pickupgroup;
+ 		}
+@@ -6688,6 +6884,8 @@
+ 		} else {
+ 			if (si->totalchans == 31) { /* if it's an E1 */
+ 				pris[*span].dchannels[0] = 16 + offset;
++			} else if (si->totalchans == 3) { /* if it's an S0 ZAPBRI */
++				pris[*span].dchannels[0] = 3 + offset;
+ 			} else {
+ 				pris[*span].dchannels[0] = 24 + offset;
+ 			}
+@@ -6933,6 +7131,11 @@
+ 							destroy_zt_pvt(&tmp);
+ 							return NULL;
+ 						}
++                                        	if ((pris[span].localdialplan) && (pris[span].localdialplan != localdialplan)) {
++							ast_log(LOG_ERROR, "Span %d is already a %s local dialing plan\n", span + 1, dialplan2str(pris[span].localdialplan));
++							destroy_zt_pvt(&tmp);
++                                                	return NULL;
++ 						}
+ 						if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, idledial)) {
+ 							ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, idledial);
+ 							destroy_zt_pvt(&tmp);
+@@ -6960,6 +7163,17 @@
+ 							return NULL;
+ 						}
+ 						pris[span].nodetype = pritype;
++// XXX
++						if (pritype == BRI_NETWORK_PTMP) {
++						    pris[span].dchanavail[0] =  DCHAN_AVAILABLE;
++						    pri_find_dchan(&pris[span]);
++						}
++// XXX tuev
++
++						if ((pritype == BRI_CPE) || (pritype == BRI_CPE_PTMP)) {
++						    pris[span].dchanavail[0] =  DCHAN_AVAILABLE;
++						    pri_find_dchan(&pris[span]);
++						}
+ 						pris[span].switchtype = myswitchtype;
+ 						pris[span].nsf = nsf;
+ 						pris[span].dialplan = dialplan;
+@@ -6968,9 +7182,14 @@
+ 						pris[span].minunused = minunused;
+ 						pris[span].minidle = minidle;
+ 						pris[span].overlapdial = overlapdial;
++  						pris[span].usercid = usercid;
++  						pris[span].suspended_calls = NULL;
++  						pris[span].holded_calls = NULL;
+ 						pris[span].facilityenable = facilityenable;
+ 						ast_copy_string(pris[span].idledial, idledial, sizeof(pris[span].idledial));
+ 						ast_copy_string(pris[span].idleext, idleext, sizeof(pris[span].idleext));
++  						ast_copy_string(pris[span].nocid, nocid, sizeof(pris[span].nocid) - 1);
++  						ast_copy_string(pris[span].withheldcid, withheldcid, sizeof(pris[span].withheldcid) - 1);
+ 						ast_copy_string(pris[span].internationalprefix, internationalprefix, sizeof(pris[span].internationalprefix));
+ 						ast_copy_string(pris[span].nationalprefix, nationalprefix, sizeof(pris[span].nationalprefix));
+ 						ast_copy_string(pris[span].localprefix, localprefix, sizeof(pris[span].localprefix));
+@@ -7397,7 +7616,7 @@
+ 			break;
+ 		if (!backwards && (x >= pri->numchans))
+ 			break;
+-		if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
++		if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner && !pri->pvts[x]->call) {
+ 			ast_log(LOG_DEBUG, "Found empty available channel %d/%d\n", 
+ 				pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
+ 			return x;
+@@ -7444,7 +7663,7 @@
+ 	end = ifend;
+ 	/* We do signed linear */
+ 	oldformat = format;
+-	format &= (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
++	format &= (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW);
+ 	if (!format) {
+ 		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
+ 		return NULL;
+@@ -7604,6 +7823,11 @@
+ 					p->digital = 1;
+ 					if (tmp)
+ 						tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
++				} else if (opt == 'm') {
++					/* If this is a modem/fax call, pretend to have the fax handled and dont do EC */
++					p->faxhandled = 1;
++					if (tmp)
++					    tmp->transfercapability = AST_TRANS_CAP_3_1K_AUDIO;
+ 				} else {
+ 					ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
+ 				}
+@@ -7657,6 +7881,57 @@
+ 	return NULL;
+ }
+ 
++static int pri_find_tei(struct zt_pri *pri, q931_call *c, int tei)
++{
++	int x=0;
++	for (x=0;x<pri->numchans;x++) {
++		if (!pri->pvts[x]) continue;
++		if ((pri->pvts[x]->tei == tei) && (pri->pvts[x]-> call != c)) {
++		    return x;
++		}
++	}
++	return -1;
++}
++
++static struct zt_holded_call *pri_get_callonhold(struct zt_pri *pri, int cref, int tei) {
++	struct zt_holded_call *zhc = pri->holded_calls;
++	struct zt_holded_call *zhctemp = NULL;
++
++	while (zhc) {
++	    if ((zhc->tei == tei) && ((zhc->cref == cref) || (cref == -1))) {
++		return zhc;
++	    }			
++	    zhctemp = zhc;
++	    if (zhc) zhc = zhc->next;
++	}
++	return NULL;	
++}
++
++static int pri_destroy_callonhold(struct zt_pri *pri, struct zt_holded_call *onhold) {
++	struct zt_holded_call *zhc = pri->holded_calls;
++	struct zt_holded_call *zhctemp = NULL;
++
++	while (zhc) {
++	    if (zhc == onhold) {
++		if (zhctemp) {
++		    zhctemp->next = zhc->next;
++		    zhc = zhctemp;
++		} else {
++		    pri->holded_calls = zhc->next;
++		    zhc = pri->holded_calls;
++		    zhctemp = NULL;
++		}
++	    }			
++	    zhctemp = zhc;
++	    if (zhc) zhc = zhc->next;
++	}
++	if (onhold) {
++	    free(onhold);
++	    onhold = NULL;
++	    return 1;	
++	}
++	return 0;	
++}
+ 
+ static int pri_find_principle(struct zt_pri *pri, int channel)
+ {
+@@ -7689,7 +7964,9 @@
+ static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
+ {
+ 	int x;
++	int res = 0;
+ 	struct zt_pvt *crv;
++	char tmpname[256];
+ 	if (!c) {
+ 		if (principle < 0)
+ 			return -1;
+@@ -7703,6 +7980,7 @@
+ 	/* First, check for other bearers */
+ 	for (x=0;x<pri->numchans;x++) {
+ 		if (!pri->pvts[x]) continue;
++// ast_log(LOG_NOTICE, "principle %d channel %d call %d channel[x]->call %d\n",principle, x, c, pri->pvts[x]->call);
+ 		if (pri->pvts[x]->call == c) {
+ 			/* Found our call */
+ 			if (principle != x) {
+@@ -7716,19 +7994,56 @@
+ 				}
+ 				/* Fix it all up now */
+ 				pri->pvts[principle]->owner = pri->pvts[x]->owner;
++ 				pri->pvts[principle]->outgoing = pri->pvts[x]->outgoing;
+ 				if (pri->pvts[principle]->owner) {
+ 					snprintf(pri->pvts[principle]->owner->name, sizeof(pri->pvts[principle]->owner->name), 
+ 						"Zap/%d:%d-%d", pri->trunkgroup, pri->pvts[principle]->channel, 1);
+ 					pri->pvts[principle]->owner->tech_pvt = pri->pvts[principle];
+ 					pri->pvts[principle]->owner->fds[0] = pri->pvts[principle]->subs[SUB_REAL].zfd;
+ 					pri->pvts[principle]->subs[SUB_REAL].owner = pri->pvts[x]->subs[SUB_REAL].owner;
+-				} else
++				} else {
+ 					ast_log(LOG_WARNING, "Whoa, there's no  owner, and we're having to fix up channel %d to channel %d\n", pri->pvts[x]->channel, pri->pvts[principle]->channel);
++				}
+ 				pri->pvts[principle]->call = pri->pvts[x]->call;
++  				pri->pvts[principle]->dsp = pri->pvts[x]->dsp;
++  				pri->pvts[principle]->alreadyhungup = pri->pvts[x]->alreadyhungup;
++				pri->pvts[principle]->digital = pri->pvts[x]->digital;
++  				pri->pvts[principle]->faxhandled = pri->pvts[x]->faxhandled;
++  
++  				if ((pri->nodetype == BRI_CPE_PTMP) || (pri->nodetype == BRI_CPE)) { 
++  				    /* this might also apply for other pri types! */
++  				    pri->pvts[principle]->law = pri->pvts[x]->law;
++  				    if (ioctl(pri->pvts[principle]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &pri->pvts[principle]->law) == -1)
++  					ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", pri->pvts[principle]->channel, pri->pvts[principle]->law);
++  				    res = zt_setlaw(pri->pvts[principle]->subs[SUB_REAL].zfd, pri->pvts[principle]->law);
++  				    if (res < 0) 
++  					ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[principle]->channel);
++				    if (!pri->pvts[principle]->digital) {
++  					res = set_actual_gain(pri->pvts[principle]->subs[SUB_REAL].zfd, 0, pri->pvts[principle]->rxgain, pri->pvts[principle]->txgain, pri->pvts[principle]->law);
++  				    } else {
++  					res = set_actual_gain(pri->pvts[principle]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[principle]->law);
++				    }
++				    if (res < 0) 
++  					ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[principle]->channel);
++  				    zt_confmute(pri->pvts[x], 0);
++  				    update_conf(pri->pvts[x]);
++  				    reset_conf(pri->pvts[x]);
++  				    restore_gains(pri->pvts[x]);
++  				    zt_disable_ec(pri->pvts[x]);
++  				    zt_setlinear(pri->pvts[x]->subs[SUB_REAL].zfd, 0);
++  				}
++  
++  				if (pri->pvts[principle]->owner) {
++  				    snprintf(tmpname, sizeof(tmpname), "Zap/%d-1", pri->pvts[principle]->channel);
++  				    ast_change_name(pri->pvts[principle]->owner, tmpname);
++  				}
++
++
+ 				/* Free up the old channel, now not in use */
+ 				pri->pvts[x]->subs[SUB_REAL].owner = NULL;
+ 				pri->pvts[x]->owner = NULL;
+ 				pri->pvts[x]->call = NULL;
++ 				pri->pvts[x]->dsp = NULL;
+ 			}
+ 			return principle;
+ 		}
+@@ -7757,7 +8072,9 @@
+ 		}
+ 		crv = crv->next;
+ 	}
+-	ast_log(LOG_WARNING, "Call specified, but not found?\n");
++	if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++	    ast_log(LOG_WARNING, "Call specified, but not found?\n");
++	}
+ 	return -1;
+ }
+ 
+@@ -7819,86 +8136,21 @@
+ #ifndef PRI_RESTART
+ #error "Upgrade your libpri"
+ #endif
+-static void zt_pri_message(struct pri *pri, char *s)
++static void zt_pri_message(char *s, int span)
+ {
+-	int x, y;
+-	int dchan = -1, span = -1;
+-	int dchancount = 0;
+-
+-	if (pri) {
+-		for (x = 0; x < NUM_SPANS; x++) {
+-			for (y = 0; y < NUM_DCHANS; y++) {
+-				if (pris[x].dchans[y])
+-					dchancount++;
+-
+-				if (pris[x].dchans[y] == pri)
+-					dchan = y;
+-			}
+-			if (dchan >= 0) {
+-				span = x;
+-				break;
+-			}
+-			dchancount = 0;
+-		}
+-		if ((dchan >= 0) && (span >= 0)) {
+-			if (dchancount > 1)
+-				ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
+-			else
+-				ast_verbose("%s", s);
+-		} else
+-			ast_verbose("PRI debug error: could not find pri associated it with debug message output\n");
+-	} else
+-		ast_verbose("%s", s);
+-
+-	ast_mutex_lock(&pridebugfdlock);
+-
+-	if (pridebugfd >= 0)
+-		write(pridebugfd, s, strlen(s));
+-
+-	ast_mutex_unlock(&pridebugfdlock);
++	ast_verbose("%d %s", span, s);
+ }
+ 
+-static void zt_pri_error(struct pri *pri, char *s)
++static void zt_pri_error(char *s, int span)
+ {
+-	int x, y;
+-	int dchan = -1, span = -1;
+-	int dchancount = 0;
+-
+-	if (pri) {
+-		for (x = 0; x < NUM_SPANS; x++) {
+-			for (y = 0; y < NUM_DCHANS; y++) {
+-				if (pris[x].dchans[y])
+-					dchancount++;
+-
+-				if (pris[x].dchans[y] == pri)
+-					dchan = y;
+-			}
+-			if (dchan >= 0) {
+-				span = x;
+-				break;
+-			}
+-			dchancount = 0;
+-		}
+-		if ((dchan >= 0) && (span >= 0)) {
+-			if (dchancount > 1)
+-				ast_log(LOG_WARNING, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
+-			else
+-				ast_verbose("%s", s);
+-		} else
+-			ast_verbose("PRI debug error: could not find pri associated it with debug message output\n");
+-	} else
+-		ast_log(LOG_WARNING, "%s", s);
+-
+-	ast_mutex_lock(&pridebugfdlock);
+-
+-	if (pridebugfd >= 0)
+-		write(pridebugfd, s, strlen(s));
+-
+-	ast_mutex_unlock(&pridebugfdlock);
++	ast_log(LOG_WARNING, "%d %s", span, s);
+ }
+ 
+ static int pri_check_restart(struct zt_pri *pri)
+ {
++	if ((pri->nodetype != PRI_NETWORK) || (pri->nodetype != PRI_CPE)) {
++	    return 0;
++	}
+ 	do {
+ 		pri->resetpos++;
+ 	} while((pri->resetpos < pri->numchans) &&
+@@ -7981,6 +8233,32 @@
+ 	}
+ }
+ 
++static void pri_make_callerid(struct zt_pri *pri, char *callerid, int callerid_len, char *callingnum, int callingnum_len, int callingplan, int callingpres, int stripmsd) {
++    if (callingnum && (callingnum_len > stripmsd)) {
++	callingnum += stripmsd;
++    }
++    switch (callingplan) {
++	case PRI_INTERNATIONAL_ISDN:
++	    snprintf(callerid, callerid_len, "%s%s", pri->internationalprefix, callingnum);
++	    break;
++	case PRI_NATIONAL_ISDN:
++	    snprintf(callerid, callerid_len, "%s%s", pri->nationalprefix, callingnum);
++	    break;
++	case PRI_LOCAL_ISDN:
++	    snprintf(callerid, callerid_len, "%s%s", pri->localprefix, callingnum);
++	    break;
++	case PRI_PRIVATE:
++	    snprintf(callerid, callerid_len, "%s%s", pri->privateprefix, callingnum);
++	    break;
++	case PRI_UNKNOWN:
++	    snprintf(callerid, callerid_len, "%s%s", pri->unknownprefix, callingnum);
++	    break;
++	default:
++	    snprintf(callerid, callerid_len, "%s", callingnum);
++	    break;
++    }
++}
++
+ static void *pri_dchannel(void *vpri)
+ {
+ 	struct zt_pri *pri = vpri;
+@@ -8072,6 +8350,8 @@
+ 				} else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
+ 					activeidles++;
+ 			}
++	//    ast_log(LOG_NOTICE, "name = %s condition = %d index = %d (%d) zfd = %d res = %d\n",chan->name, condition, index, SUB_REAL, p->subs[index].zfd, res);
++
+ #if 0
+ 			printf("nextidle: %d, haveidles: %d, minunsed: %d\n",
+ 				nextidle, haveidles, minunused);
+@@ -8173,9 +8453,36 @@
+ 					if (x == ZT_EVENT_ALARM) {
+ 						pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
+ 						pri_find_dchan(pri);
++						if ((pri->nodetype == BRI_CPE) || (pri->nodetype == BRI_CPE_PTMP)) {
++						    if (pri->pri) {
++							ast_log(LOG_NOTICE, "pri_shutdown\n");
++							for (i=0; i<pri->numchans; i++) {
++							    struct zt_pvt *p = pri->pvts[i];
++							    if (p) {
++								if (p->call) {
++								    if (p->pri && p->pri->pri) {
++								    	pri_destroycall(p->pri->pri, p->call);
++									p->call = NULL;
++									p->tei = -1;
++								    } else
++									ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
++								}
++								if (p->owner)
++								    p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++								p->inalarm = 1;
++							    }
++							}
++							pri_shutdown(pri->pri);
++						    }
++						}
+ 					} else if (x == ZT_EVENT_NOALARM) {
+-						pri->dchanavail[which] |= DCHAN_NOTINALARM;
+-						pri_restart(pri->dchans[which]);
++						if ((pri->nodetype == BRI_CPE) || (pri->nodetype == BRI_CPE_PTMP)) {
++						    pri->dchanavail[which] |= DCHAN_NOTINALARM;
++						    pri->dchanavail[which] |= DCHAN_UP;
++						} else {
++						    pri->dchanavail[which] |= DCHAN_NOTINALARM;
++						    pri_restart(pri->dchans[which]);
++						}
+ 					}
+ 				
+ 					if (option_debug)
+@@ -8187,8 +8494,7 @@
+ 					break;
+ 			}
+ 		} else if (errno != EINTR)
+-			ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
+-
++ 			ast_log(LOG_WARNING, "pri_event returned error %d (%s) on span %d\n", errno, strerror(errno), pri->span);
+ 		if (e) {
+ 			if (pri->debug)
+ 				pri_dump_event(pri->dchans[which], e);
+@@ -8196,32 +8502,101 @@
+ 				pri->dchanavail[which] |= DCHAN_UP;
+ 			switch(e->e) {
+ 			case PRI_EVENT_DCHAN_UP:
+-				if (option_verbose > 1) 
+-					ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
+-				pri->dchanavail[which] |= DCHAN_UP;
+-				if (!pri->pri) pri_find_dchan(pri);
+-
+-				/* Note presense of D-channel */
+-				time(&pri->lastreset);
+-
+-				/* Restart in 5 seconds */
+-				if (pri->resetinterval > -1) {
+-					pri->lastreset -= pri->resetinterval;
+-					pri->lastreset += 5;
+-				}
+-				pri->resetting = 0;
+-				/* Take the channels from inalarm condition */
+-				for (i=0; i<pri->numchans; i++)
+-					if (pri->pvts[i]) {
+-						pri->pvts[i]->inalarm = 0;
+-					}
++  				if (pri->nodetype == BRI_NETWORK_PTMP) {
++  				    if (option_verbose > 3) 
++  					ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up for TEI %d\n", pri_order(which), pri->span, e->gen.tei);
++  				    pri->dchanavail[which] |= (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP);
++  				    pri_find_dchan(pri);
++  
++  				    /* Note presense of D-channel */
++  				    time(&pri->lastreset);
++  
++  				    pri->resetting = 0;
++  				    /* Take the channels from inalarm condition */
++  				    for (i=0; i<pri->numchans; i++)
++  					if (pri->pvts[i]) {
++  						pri->pvts[i]->inalarm = 0;
++  					}
++  				} else {
++  				    if (pri->nodetype == BRI_CPE_PTMP) {
++  					if (option_verbose > 3) 
++  					    ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
++  				    } else {
++  					if (option_verbose > 1) 
++  					    ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
++  				    }
++  				    pri->dchanavail[which] |= (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP);
++  				    pri_find_dchan(pri);
++  
++  				    /* Note presense of D-channel */
++  				    time(&pri->lastreset);
++  
++  				    /* Restart in 5 seconds */
++  				    pri->lastreset -= pri->resetinterval;
++  				    pri->lastreset += 5;
++  				    pri->resetting = 0;
++  				    /* Take the channels from inalarm condition */
++  				    for (i=0; i<pri->numchans; i++) {
++ 					struct zt_pvt *p = pri->pvts[i];
++   					if (p) {
++   					    p->inalarm = 0;
++ 					    /* hang up calls that are not bridged yet, dont touch bridged calls */
++ 					    if (p->call) {
++ 						if (p->pri && p->pri->pri) {
++ 						    if (p->owner) {
++ 							if (p->owner->_state != AST_STATE_UP) {
++ 							    p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ 							    pri_destroycall(p->pri->pri, p->call);
++ 							}
++ 						    } else {
++ 							pri_destroycall(p->pri->pri, p->call);
++ 						    }
++ 						    p->call = NULL;
++ 						}
++ 					    }
++   					}
++ 				    }
++  				}
+ 				break;
+ 			case PRI_EVENT_DCHAN_DOWN:
+-				if (option_verbose > 1) 
+-					ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
+-				pri->dchanavail[which] &= ~DCHAN_UP;
+-				pri_find_dchan(pri);
+-				if (!pri_is_up(pri)) {
++  				if (pri->nodetype == BRI_NETWORK_PTMP) {
++  				    if (option_verbose > 3) 
++  					ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down for TEI %d\n", pri_order(which), pri->span, e->gen.tei);
++  				    // PTMP BRIs have N dchans, handled by libpri
++  				    if (e->gen.tei == 0) break;
++  				    /* Hangup active channels */
++  				    for (i=0; i<pri->numchans; i++) {
++  				    	struct zt_pvt *p = pri->pvts[i];
++ 					if (p) {
++  			//		ast_log(LOG_NOTICE, "chan %d tei %d\n",i,p->tei);
++  					    if (p->tei == e->gen.tei) {
++  						if (p->call) {
++  							if (p->pri && p->pri->pri) {
++  								pri_hangup(p->pri->pri, p->call, -1);
++  								pri_destroycall(p->pri->pri, p->call);
++  								p->tei = -1;
++  								p->call = NULL;
++  							} else
++  								ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
++  						}
++  						if (p->owner)
++  						    p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++  						p->inalarm = 1;
++  						p->tei = -1;
++  					    }
++  					}
++  				    } 
++  				} else {
++  				    if (pri->nodetype == BRI_CPE_PTMP) {
++  					if (option_verbose > 3) 
++  					    ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
++  				    } else {
++  					if (option_verbose > 1) 
++  					    ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
++  				    }
++  				    pri->dchanavail[which] &= ~DCHAN_UP;
++  				    pri_find_dchan(pri);
++  				    if (!pri_is_up(pri)) {
+ 					pri->resetting = 0;
+ 					/* Hangup active channels and put them in alarm mode */
+ 					for (i=0; i<pri->numchans; i++) {
+@@ -8229,7 +8604,7 @@
+ 						if (p) {
+ 							if (p->call) {
+ 								if (p->pri && p->pri->pri) {
+-									pri_hangup(p->pri->pri, p->call, -1);
++								//	pri_hangup(p->pri->pri, p->call, -1);
+ 									pri_destroycall(p->pri->pri, p->call);
+ 									p->call = NULL;
+ 								} else
+@@ -8242,6 +8617,7 @@
+ 							p->inalarm = 1;
+ 						}
+ 					}
++				    }
+ 				}
+ 				break;
+ 			case PRI_EVENT_RESTART:
+@@ -8276,8 +8652,8 @@
+ 								pri_destroycall(pri->pri, pri->pvts[x]->call);
+ 								pri->pvts[x]->call = NULL;
+ 							}
+-							if (pri->pvts[chanpos]->realcall) 
+-								pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
++							if (pri->pvts[x]->realcall) 
++								pri_hangup_all(pri->pvts[x]->realcall, pri);
+  							else if (pri->pvts[x]->owner)
+ 								pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+ 							ast_mutex_unlock(&pri->pvts[x]->lock);
+@@ -8311,7 +8687,6 @@
+ 					}
+ 				}
+ 				break;
+-				
+ 			case PRI_EVENT_INFO_RECEIVED:
+ 				chanpos = pri_find_principle(pri, e->ring.channel);
+ 				if (chanpos < 0) {
+@@ -8320,9 +8695,11 @@
+ 				} else {
+ 					chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
+ 					if (chanpos > -1) {
++//					ast_log(LOG_NOTICE, "INFO received on  channel %d/%d span %d\n", 
++//						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+ 						ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ 						/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
+-						if (pri->overlapdial && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
++						if (pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
+ 							/* how to do that */
+ 							int digitlen = strlen(e->ring.callednum);
+ 							char digit;
+@@ -8334,6 +8711,14 @@
+ 									zap_queue_frame(pri->pvts[chanpos], &f, pri);
+ 								}
+ 							}
++							if (!pri->overlapdial) {
++							    strncat(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
++							    if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten + 1)) {
++								tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++							    } else {
++								tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++							    }
++							} 
+ 						}
+ 						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ 					}
+@@ -8341,39 +8726,55 @@
+ 				break;
+ 			case PRI_EVENT_RING:
+ 				crv = NULL;
+-				if (e->ring.channel == -1)
++				if (e->ring.channel == -1) {
++					/* if no channel specified find one empty */
+ 					chanpos = pri_find_empty_chan(pri, 1);
+-				else
++				} else {
+ 					chanpos = pri_find_principle(pri, e->ring.channel);
+-				/* if no channel specified find one empty */
++				}
+ 				if (chanpos < 0) {
+-					ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n", 
+-						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
++					/* no channel specified and no free channel. this is a callwating SETUP */
++					if (e->ring.channel == -1) {
++					    if (option_verbose > 2)
++						ast_verbose(VERBOSE_PREFIX_3 "Ignoring callwaiting SETUP on channel %d/%d span %d %d\n", PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span, e->ring.channel);
++					    pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_USER_BUSY);
++					    break;
++					}
+ 				} else {
++					/* ok, we got a b channel for this call, lock it */
+ 					ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ 					if (pri->pvts[chanpos]->owner) {
+-						if (pri->pvts[chanpos]->call == e->ring.call) {
+-							ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
+-								PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+-							break;
+-						} else {
+-							ast_log(LOG_WARNING, "Ring requested on channel %d/%d already in use on span %d.  Hanging up owner.\n", 
++					    /* safety check, for messed up retransmissions? */
++					    if (pri->pvts[chanpos]->call == e->ring.call) {
++						ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
+ 							PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+-							if (pri->pvts[chanpos]->realcall) 
+-								pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
+-							else
+-								pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+-							ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+-							chanpos = -1;
+-						}
+-					}
+-					if (chanpos > -1)
+ 						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++						chanpos = -1;
++						break;
++					    } else {
++						ast_log(LOG_WARNING, "Ring requested on channel %d/%d already in use on span %d. Hanging up owner.\n", 
++						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
++						if (pri->pvts[chanpos]->realcall) 
++							pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
++						else
++							pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++						chanpos = -1;
++						break;
++					    }
++					}
++					if (chanpos > -1) {
++						/* everything is ok with the b channel */
++					    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++					}
+ 				}
+-				if ((chanpos < 0) && (e->ring.flexible))
+-					chanpos = pri_find_empty_chan(pri, 1);
++				/* actually, we already got a valid channel by now */
+ 				if (chanpos > -1) {
+ 					ast_mutex_lock(&pri->pvts[chanpos]->lock);
++					/* dont detect dtmfs before the signalling is done */
++					pri->pvts[chanpos]->ignoredtmf = 1;
++					/* this channel is owned by this TEI */
++					pri->pvts[chanpos]->tei = e->ring.tei;
+ 					if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+ 						/* Should be safe to lock CRV AFAIK while bearer is still locked */
+ 						crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
+@@ -8394,6 +8795,7 @@
+ 							break;
+ 						}
+ 					}
++  					/* assign call to b channel */
+ 					pri->pvts[chanpos]->call = e->ring.call;
+ 					apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+ 					if (pri->pvts[chanpos]->use_callerid) {
+@@ -8418,29 +8820,78 @@
+ 					}
+ 					apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
+ 							     e->ring.redirectingnum, e->ring.callingplanrdnis);
++  					/* get callingpres */
++  					pri->pvts[chanpos]->cid_pres = e->ring.callingpres;
++					switch (e->ring.callingpres) {
++					    case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++					    case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++					    case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++					    case PRES_PROHIB_NETWORK_NUMBER:
++						strncpy(pri->pvts[chanpos]->cid_name, pri->withheldcid, sizeof(pri->pvts[chanpos]->cid_name));
++						break;
++					    case PRES_NUMBER_NOT_AVAILABLE:
++						strncpy(pri->pvts[chanpos]->cid_name, pri->nocid, sizeof(pri->pvts[chanpos]->cid_name));
++						break;
++					}
+ 					/* If immediate=yes go to s|1 */
+ 					if (pri->pvts[chanpos]->immediate) {
+ 						if (option_verbose > 2)
+ 							ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of immediate=yes\n");
+ 						pri->pvts[chanpos]->exten[0] = 's';
+ 						pri->pvts[chanpos]->exten[1] = '\0';
+-					}
+-					/* Get called number */
+-					else if (!ast_strlen_zero(e->ring.callednum)) {
+-						ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+-						ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+-					} else
+-						pri->pvts[chanpos]->exten[0] = '\0';
+-					/* Set DNID on all incoming calls -- even immediate */
+-					if (!ast_strlen_zero(e->ring.callednum))
+-						ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+-					/* No number yet, but received "sending complete"? */
+-					if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
++  					} else if (ast_strlen_zero(e->ring.callednum)) {
++  					    /* called party number is empty */
++  					    if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
++  						if (!pri->overlapdial) {
++  						    // be able to set digittimeout for BRI phones
++  						    pri->pvts[chanpos]->exten[0] = 's';
++  						    pri->pvts[chanpos]->exten[1] = '\0';
++  						    tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++  						} else {
++  						    pri->pvts[chanpos]->exten[0] = '\0';
++  						}
++  					    } else {
++  						if (pri->nodetype == BRI_CPE) { 
++  						    /* fix for .at p2p bri lines */
++  						    pri->pvts[chanpos]->exten[0] = 's';
++  						    pri->pvts[chanpos]->exten[1] = '\0';
++  						} else {
++  						    pri->pvts[chanpos]->exten[0] = '\0';
++  						}
++  					    }
++  					    /* No number yet, but received "sending complete"? */
++   					    if (e->ring.complete) {
+ 						if (option_verbose > 2)
+ 							ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of Complete received\n");
+ 						pri->pvts[chanpos]->exten[0] = 's';
+ 						pri->pvts[chanpos]->exten[1] = '\0';
++ 					    }
++  					} else {
++  						/* Get called number */
++  						pri_make_callerid(pri, pri->pvts[chanpos]->dnid, sizeof(pri->pvts[chanpos]->dnid), e->ring.callednum, sizeof(e->ring.callednum),  e->ring.calledplan, 0, pri->pvts[chanpos]->stripmsd);
++  						pri_make_callerid(pri, pri->pvts[chanpos]->exten, sizeof(pri->pvts[chanpos]->exten), e->ring.callednum, sizeof(e->ring.callednum), e->ring.calledplan, 0, pri->pvts[chanpos]->stripmsd);
++  						if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
++  						    /* if we get the next digit we should stop the dialtone */
++  						    if (!pri->overlapdial) {
++  							// with overlapdial=no the exten is always prefixed by "s"
++  							if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten + 1)) {
++  							    tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++  							} else {
++  							    tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++  							}
++  						    } else {
++  							if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten)) {
++  							    tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++  							} else {
++  							    tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++  							}
++  						    }
++  						}
+ 					}
++  					/* Part 3: create channel, setup audio... */
++ 					/* Set DNID on all incoming calls -- even immediate */
++ 					if (!ast_strlen_zero(e->ring.callednum))
++ 						strncpy(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid) - 1);
+ 					/* Make sure extension exists (or in overlap dial mode, can exist) */
+ 					if ((pri->overlapdial && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+ 						ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+@@ -8459,22 +8910,38 @@
+ 						res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
+ 						if (res < 0) 
+ 							ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
+-						res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++ 						if (IS_DIGITAL(e->ring.ctype)) {
++   						    res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[chanpos]->law);
++   						} else {
++ 						    res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++ 						}
+ 						if (res < 0)
+ 							ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
+-						if (e->ring.complete || !pri->overlapdial)
++ 						if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++  						    if (e->ring.complete || !pri->overlapdial) {
+ 							/* Just announce proceeding */
+ 							pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
+-						else  {
++ 						//	pri->pvts[chanpos]->ignoredtmf = 0;
++ 						    } else  {
+ 							if (pri->switchtype != PRI_SWITCH_GR303_TMC) 
+ 								pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+ 							else
+ 								pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
++ 						    }
++ 						} else {
++ 							/* BRI_NETWORK | BRI_NETWORK_PTMP */
++ 							if (pri->overlapdial || (!strcasecmp(pri->pvts[chanpos]->exten, "s"))) {
++ 							    /* send a SETUP_ACKNOWLEDGE */
++ 							    pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
++ 							} else {
++ 							    /* send an ALERTING ??? wtf */
++ 							//    pri_acknowledge(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
++ 							    pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
++ 							}
+ 						}
+-						/* Get the use_callingpres state */
+-						pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+-					
+-						/* Start PBX */
++
++ 						/* overlapdial = yes  and the extension can be valid */
++
+ 						if (pri->overlapdial && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+ 							/* Release the PRI lock while we create the channel */
+ 							ast_mutex_unlock(&pri->lock);
+@@ -8486,10 +8953,21 @@
+ 								ast_log(LOG_DEBUG, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
+ 							} else {
+ 								c = zt_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
++ 								zt_enable_ec(pri->pvts[chanpos]);
+ 							}
+ 							if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+ 								pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+ 							}
++ 					    		if (!ast_strlen_zero(e->ring.callingnum)) {
++ 							    char tmpstr[256];
++ 							    pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingnum, sizeof(e->ring.callingnum), e->ring.callingplan, e->ring.callingpres, 0);
++ 							    pbx_builtin_setvar_helper(c, "PRI_NETWORK_CID", tmpstr);
++ 							}
++ 							if (!ast_strlen_zero(e->ring.callingani)) {
++ 							    char tmpstr[256];
++ 							    pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingani, sizeof(e->ring.callingani), e->ring.callingplanuser, e->ring.callingpresuser, 0);
++ 							    pbx_builtin_setvar_helper(c, "PRI_USER_CID", e->ring.callednum);
++ 							}
+ 							if(e->ring.ani2 >= 0) {
+ 								snprintf(ani2str, 5, "%.2d", e->ring.ani2);
+ 								pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+@@ -8505,8 +8983,8 @@
+ 							ast_mutex_lock(&pri->lock);
+ 							if (c && !ast_pthread_create(&threadid, &attr, ss_thread, c)) {
+ 								if (option_verbose > 2)
+-									ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+-										plancallingnum, !ast_strlen_zero(pri->pvts[chanpos]->exten) ? pri->pvts[chanpos]->exten : "<unspecified>", 
++									ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap %s call from '%s' to '%s' on channel %d/%d, span %d\n",
++										pri->pvts[chanpos]->digital ? "data" : "voice", plancallingnum, !ast_strlen_zero(pri->pvts[chanpos]->exten) ? pri->pvts[chanpos]->exten : "<unspecified>", 
+ 										pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+ 							} else {
+ 								ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", 
+@@ -8519,6 +8997,7 @@
+ 								}
+ 							}
+ 						} else  {
++						/* overlapdial = no */    
+ 							ast_mutex_unlock(&pri->lock);
+ 							/* Release PRI lock while we create the channel */
+ 							c = zt_new(pri->pvts[chanpos], AST_STATE_RING, 1, SUB_REAL, law, e->ring.ctype);
+@@ -8538,10 +9017,26 @@
+ 								snprintf(calledtonstr, sizeof(calledtonstr)-1, "%d", e->ring.calledplan);
+ 								pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+ 								if (option_verbose > 2)
+-									ast_verbose(VERBOSE_PREFIX_3 "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+-										plancallingnum, pri->pvts[chanpos]->exten, 
++ 									ast_verbose(VERBOSE_PREFIX_3 "Accepting %s call from '%s' to '%s' on channel %d/%d, span %d\n",
++ 										pri->pvts[chanpos]->digital ? "data" : "voice", e->ring.callingnum, pri->pvts[chanpos]->exten, 
+ 											pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+ 								zt_enable_ec(pri->pvts[chanpos]);
++ 							    if(!ast_strlen_zero(e->ring.callingsubaddr)) {
++ 								pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
++ 							    }
++ 					    		    if (!ast_strlen_zero(e->ring.callingnum)) {
++ 								char tmpstr[256];
++ 							        pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingnum, sizeof(e->ring.callingnum), e->ring.callingplan, e->ring.callingpres, 0);
++ 							        pbx_builtin_setvar_helper(c, "PRI_NETWORK_CID", tmpstr);
++ 							    }
++ 							    if (!ast_strlen_zero(e->ring.callingani)) {
++ 								char tmpstr[256];
++ 							        pri_make_callerid(pri, tmpstr,sizeof(tmpstr),  e->ring.callingani, sizeof(e->ring.callingani), e->ring.callingplanuser, e->ring.callingpresuser, 0);
++ 							        pbx_builtin_setvar_helper(c, "PRI_USER_CID", e->ring.callednum);
++ 							    }
++							    if (!ast_strlen_zero(e->ring.useruserinfo)) {
++							        pbx_builtin_setvar_helper(c, "UUI", e->ring.useruserinfo);
++							    }
+ 							} else {
+ 								ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", 
+ 									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+@@ -8550,6 +9045,7 @@
+ 							}
+ 						}
+ 					} else {
++					/* invalid extension */
+ 						if (option_verbose > 2)
+ 							ast_verbose(VERBOSE_PREFIX_3 "Extension '%s' in context '%s' from '%s' does not exist.  Rejecting call on channel %d/%d, span %d\n",
+ 								pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan, 
+@@ -8580,7 +9076,7 @@
+ 					} else {
+ 						ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ 						if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
+-							zt_enable_ec(pri->pvts[chanpos]);
++						// XXX	zt_enable_ec(pri->pvts[chanpos]);
+ 							pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
+ 							pri->pvts[chanpos]->alerting = 1;
+ 						} else
+@@ -8605,9 +9101,15 @@
+ 				}
+ 				break;
+ 			case PRI_EVENT_PROGRESS:
+-				/* Get chan value if e->e is not PRI_EVNT_RINGING */
++				/* Get chan value if e->e is not PRI_EVENT_RINGING */
+ 				chanpos = pri_find_principle(pri, e->proceeding.channel);
+ 				if (chanpos > -1) {
++				    if ((pri->pvts[chanpos]->priindication_oob == 2) && (e->proceeding.cause == PRI_CAUSE_USER_BUSY)) {
++					/* received PROGRESS with cause BUSY, no inband callprogress wanted => hang up! */
++					if (pri->pvts[chanpos]->owner) {
++					    pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++					}
++				    } else {
+ #ifdef PRI_PROGRESS_MASK
+ 					if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
+ #else
+@@ -8654,6 +9156,12 @@
+ 			case PRI_EVENT_PROCEEDING:
+ 				chanpos = pri_find_principle(pri, e->proceeding.channel);
+ 				if (chanpos > -1) {
++ 				    chanpos = pri_fixup_principle(pri, chanpos, e->proceeding.call);
++ 				    if (chanpos < 0) {
++ 					ast_log(LOG_WARNING, "Received PROCEEDING on channel %d/%d not in use on span %d\n", 
++						PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), pri->span);
++ 					chanpos = -1;
++ 				    } else {
+ 					if (!pri->pvts[chanpos]->proceeding) {
+ 						struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
+ 						
+@@ -8704,6 +9212,295 @@
+ 					}
+ 				}
+ 				break;				
++			case PRI_EVENT_SUSPEND_REQ:
++				if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++				    pri_suspend_reject(pri->pri, e->suspend_req.call, "");
++				    break;
++				}
++				chanpos = pri_find_principle(pri, e->suspend_req.channel);
++				if (chanpos < 0)  {
++					ast_log(LOG_WARNING, "Suspend requested on unconfigured channel %d span %d\n", chanpos, pri->span);
++					chanpos = -1;
++				}
++
++				if (chanpos > -1) {
++				    ast_mutex_lock(&pri->pvts[chanpos]->lock);
++				    if (pri->pvts[chanpos]->owner) {
++					if (ast_bridged_channel(pri->pvts[chanpos]->owner)) {
++					    struct zt_suspended_call *zpc;
++					    char tmpstr[256];
++					    zpc = malloc(sizeof(struct zt_suspended_call));
++					    if (!zpc) {
++						ast_log(LOG_ERROR, "unable to malloc zt_suspended_call\n");
++						break;
++					    }
++					    strncpy(zpc->msn,  pri->pvts[chanpos]->cid_num, sizeof(zpc->msn));
++					    strncpy(zpc->callid,  e->suspend_req.callid, sizeof(zpc->callid));
++					    ast_masq_park_call(ast_bridged_channel(pri->pvts[chanpos]->owner), NULL, 0, &zpc->parked_at);
++					    zpc->next = pri->suspended_calls;
++					    pri->suspended_calls = zpc;
++					    snprintf(tmpstr, sizeof(tmpstr), "Parked at %d", zpc->parked_at);
++					    pri_suspend_acknowledge(pri->pri, e->suspend_req.call,tmpstr);
++					    pri->pvts[chanpos]->call = NULL;
++					    pri->pvts[chanpos]->tei = -1;
++					    pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++					} else {
++					    pri_suspend_reject(pri->pri, e->suspend_req.call, "cant park a non-bridge");
++					    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++					    break;
++					}
++				    } else {
++					pri_suspend_reject(pri->pri, e->suspend_req.call, "");
++				    }
++				    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++				}
++				break;
++			case PRI_EVENT_RESUME_REQ:
++				if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++				    break;
++				}
++				chanpos = pri_find_empty_chan(pri, 1);
++				if (chanpos < 0) { 
++					pri_resume_reject(pri->pri, e->resume_req.call,"All channels busy");
++					ast_log(LOG_WARNING, "Resume requested on odd channel number %d span %d\n", chanpos, pri->span);
++					chanpos = -1;
++				} else if (!pri->pvts[chanpos]) {
++					pri_resume_reject(pri->pri, e->resume_req.call,"General protection fault in module 0x0BRI");
++					chanpos = -1;
++				}
++
++				if (chanpos > -1) {
++ 				    ast_mutex_lock(&pri->pvts[chanpos]->lock);
++				    if (!pri->pvts[chanpos]->owner) {
++					struct zt_suspended_call *zpc, *zpcl;
++					int unparked=0;
++					char extenstr[255], temp[255];
++					zpc = NULL;
++					zpcl = pri->suspended_calls;
++					while (zpcl) {
++					//    ast_log(LOG_NOTICE, "zpc->parked_at %d zpcl->callid %s\n",zpcl->parked_at, zpcl->callid);
++					    if (((strlen(zpcl->callid) == 0) && (strlen(e->resume_req.callid)==0)) || (!strcmp(zpcl->callid,e->resume_req.callid))) {
++						int law;
++						// found a parked call
++						snprintf(extenstr, sizeof(extenstr), "%d", zpcl->parked_at);
++						strncpy(pri->pvts[chanpos]->exten, extenstr, sizeof(pri->pvts[chanpos]->exten));
++					//	strncpy(pri->pvts[chanpos]->context, ast_parking_con(), sizeof(pri->pvts[chanpos]->context));
++					        pri->pvts[chanpos]->call = e->resume_req.call;
++ 					        law = 1;
++					        if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++					    	    ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law);
++					// uhh ohh...what shall we do without the bearer cap???
++						law = ZT_LAW_ALAW;
++						res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
++						if (res < 0) 
++						    ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++						if (!pri->pvts[chanpos]->digital) {
++						    res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++  						} else {
++  						    res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[chanpos]->law);
++						}
++						if (res < 0)
++						    ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++						/* Start PBX */
++						c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 1, SUB_REAL, law, PRI_TRANS_CAP_SPEECH);
++						if (c) {
++						    pri->pvts[chanpos]->owner = c;
++						    pri->pvts[chanpos]->call = e->resume_req.call;
++						    zt_enable_ec(pri->pvts[chanpos]);
++						    zt_train_ec(pri->pvts[chanpos]);
++						} else {
++						    ast_log(LOG_ERROR, "unable to start pbx\n");
++						}
++
++						if (zpc) {
++						    zpc->next = zpcl->next;
++						    free(zpcl);
++						    zpcl = zpc->next;
++						} else {
++						    // remove head
++						    pri->suspended_calls = zpcl->next;
++						    free(zpcl);
++						    zpcl = pri->suspended_calls;
++						    zpc = NULL;
++						}
++						unparked = 1;
++						snprintf(temp, sizeof(temp), "Unparked %s", extenstr);
++						pri_resume_acknowledge(pri->pri, e->resume_req.call, chanpos + 1, temp);
++					        break;
++					    }
++					    zpc = zpcl;
++					    if (zpcl) zpcl = zpcl->next;
++					}
++					if (!unparked)
++					    pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!");
++				    } else {
++					pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!");
++				    }
++				    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++				}
++				break;
++			case PRI_EVENT_HOLD_REQ:
++				if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++				    pri_hold_reject(pri->pri, e->hold_req.call);
++				    break;
++				}
++				chanpos = pri_find_principle(pri, e->hold_req.channel);
++				if (chanpos < 0)  {
++					ast_log(LOG_WARNING, "Hold requested on unconfigured channel %d span %d\n", chanpos, pri->span);
++					chanpos = -1;
++				}
++				if (chanpos > -1) {
++				//    ast_log(LOG_NOTICE, "Hold request for channel number %d span %d\n", chanpos, pri->span);
++				    ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ 				    if (pri->pvts[chanpos]->owner) {
++					struct zt_pvt *p = pri->pvts[chanpos];
++					struct zt_holded_call *zhc;
++					int holdacked=0;
++					
++//					ast_log(LOG_NOTICE,"HOLD request from channel %s tei %d\n",p->owner->name, e->hold_req.tei);
++				    	if (ast_bridged_channel(p->owner)) {
++					    zhc = malloc(sizeof(struct zt_holded_call));
++					    if (!zhc) {
++						ast_log(LOG_ERROR, "unable to malloc zt_holded_call\n");
++						break;
++					    }
++					    memset(zhc, 0, sizeof(zhc));
++					    strncpy(zhc->msn,  pri->pvts[chanpos]->cid_num, sizeof(zhc->msn));
++					    strncpy(zhc->uniqueid,  ast_bridged_channel(p->owner)->uniqueid, sizeof(zhc->uniqueid));
++					    zhc->tei = e->hold_req.tei;
++					    zhc->cref = e->hold_req.cref;
++					    zhc->call = e->hold_req.call;
++					    zhc->channel = p->owner;
++					    zhc->alreadyhungup = 0;
++					    zhc->bridge = ast_bridged_channel(p->owner);
++					    zhc->next = pri->holded_calls;
++					    pri->holded_calls = zhc;
++
++					    /* put channel on hold */
++					    ast_masq_hold_call(ast_bridged_channel(p->owner), p->owner);
++
++					    pri_hold_acknowledge(pri->pri, e->hold_req.call);
++					    holdacked = 1;
++					    p->call = NULL; // free the bchannel withouth destroying the call
++					    p->tei = -1;
++					} else {
++					    // cant hold a non-bridge,...yet
++					    
++					    // make a fake channel
++					    
++					    // masquerade
++					    
++					    // put on hold
++					    pri_hold_reject(pri->pri, e->hold_req.call);
++					}
++				    } else {
++					    pri_hold_reject(pri->pri, e->hold_req.call);
++				    }
++				    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++				} else {
++					pri_hold_reject(pri->pri, e->hold_req.call);
++				}
++				break; 
++			case PRI_EVENT_RETRIEVE_REQ:
++				if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++				    pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++				    break;
++				}
++				chanpos = pri_find_empty_chan(pri, 1);
++				if (chanpos < 0) { 
++					pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++					ast_log(LOG_WARNING, "Retrieve requested on odd channel number %d span %d\n", chanpos, pri->span);
++					chanpos = -1;
++					break;
++				} else if (!pri->pvts[chanpos]) {
++					ast_log(LOG_WARNING, "Retrieve requested on unconfigured channel number %d span %d\n", chanpos, pri->span);
++					pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++					chanpos = -1;
++					break;
++				}
++				if (chanpos > -1) {
++				    struct zt_holded_call *onhold = NULL;
++				    int retrieved = 0;
++				    int res = -1;
++				    struct app_tmp *tmp;
++				    pthread_attr_t attr;
++				    int law;
++
++				    onhold = pri_get_callonhold(pri, e->retrieve_req.cref, e->retrieve_req.tei);
++
++				    if (!onhold) {
++					pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++					break;
++				    }
++				    ast_mutex_lock(&pri->pvts[chanpos]->lock);
++					// found a parked call
++ 					law = 1;
++					if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++					    ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law);
++					// uhh ohh...what shall we do without the bearer cap???
++					law = ZT_LAW_ALAW;
++					res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
++					if (res < 0) 
++					    ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++					res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++					if (res < 0)
++					    ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++					/* Start PBX */
++					c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 0, SUB_REAL, law, PRI_TRANS_CAP_SPEECH);
++					if (c) {
++					    pri->pvts[chanpos]->owner = c;
++					    pri->pvts[chanpos]->outgoing = 1; /* for not sending proceedings... */
++					    pri->pvts[chanpos]->call = e->retrieve_req.call;
++					    pri->pvts[chanpos]->tei = e->retrieve_req.tei;
++				    	    zt_enable_ec(pri->pvts[chanpos]);
++				    	    zt_train_ec(pri->pvts[chanpos]);
++					} else {
++					    ast_log(LOG_ERROR, "unable to start pbx\n");
++					}
++
++					retrieved = 1;
++				//	ast_log(LOG_NOTICE, "sending RETRIEVE ACK on channel %d, span %d for tei %d cref %d\n",chanpos,pri->span, e->retrieve_req.tei,  e->retrieve_req.cref);
++					pri_retrieve_acknowledge(pri->pri, e->retrieve_req.call, chanpos + 1);
++
++					// the magic begins here: ....
++					tmp = malloc(sizeof(struct app_tmp));
++					if (tmp) {
++					    memset(tmp, 0, sizeof(struct app_tmp));
++					    strncpy(tmp->app, "holdedcall", sizeof(tmp->app) - 1);
++					    strncpy(tmp->data, onhold->uniqueid, sizeof(tmp->data) - 1);
++					    tmp->chan = c;
++					}
++					pri_destroy_callonhold(pri, onhold);
++					onhold = NULL;
++
++					ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++					pthread_attr_init(&attr);
++					pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++					if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
++ 					    ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", c->name, strerror(errno));
++					    free(tmp);
++					    ast_hangup(c);
++					    retrieved = 0;
++					}
++
++				    if (!retrieved) {
++					pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++				    }
++				}
++ 				break; 
++			case PRI_EVENT_DISPLAY_RECEIVED:
++				ast_log(LOG_NOTICE, "DISPLAY IE: [ %s ] received\n",e->display.text);
++				chanpos = pri_find_principle(pri, e->display.channel);
++				if (chanpos < 0) {
++				    ast_log(LOG_WARNING, "odd channel number %d span %d\n", chanpos, pri->span);
++				    chanpos = -1;
++				} 
++				if (chanpos > -1) {
++				    if (pri->pvts[chanpos]->owner) {
++			//		ast_sendtext(pri->pvt[chanpos]->owner, e->display.text);
++				    }
++				}				
++				break;
+ 			case PRI_EVENT_ANSWER:
+ 				chanpos = pri_find_principle(pri, e->answer.channel);
+ 				if (chanpos < 0) {
+@@ -8719,6 +9516,7 @@
+ 						chanpos = -1;
+ 					} else {
+ 						ast_mutex_lock(&pri->pvts[chanpos]->lock);
++  						pri->pvts[chanpos]->tei = e->answer.tei;
+ 						/* Now we can do call progress detection */
+ 
+ 						/* We changed this so it turns on the DSP no matter what... progress or no progress.
+@@ -8748,11 +9546,15 @@
+ 								ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
+ 							pri->pvts[chanpos]->dop.dialstr[0] = '\0';
+ 						} else if (pri->pvts[chanpos]->confirmanswer) {
+-							ast_log(LOG_DEBUG, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
++							ast_log(LOG_DEBUG, "Waiting for answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
+ 						} else {
++							pri->pvts[chanpos]->dialing = 0;
+ 							pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
+ 							/* Enable echo cancellation if it's not on already */
+ 							zt_enable_ec(pri->pvts[chanpos]);
++							zt_train_ec(pri->pvts[chanpos]);
++							/* stop ignoring inband dtmf */
++							pri->pvts[chanpos]->ignoredtmf = 0;
+ 						}
+ 						if (!ast_strlen_zero(e->answer.useruserinfo)) {
+ 							pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "USERUSERINFO", e->answer.useruserinfo);
+@@ -8797,18 +9599,21 @@
+ 								}
+ 							}
+ 							if (option_verbose > 2) 
+-								ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup\n", 
+-									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
++								ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup, cause %d\n", 
++									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
+ 						} else {
+ 							pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+ 							pri->pvts[chanpos]->call = NULL;
++							pri->pvts[chanpos]->tei = -1;
+ 						}
+ 						if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
+-							if (option_verbose > 2)
++ 							if ((pri->nodetype != BRI_CPE_PTMP) && (pri->nodetype != BRI_NETWORK_PTMP)) {
++							    if (option_verbose > 2)
+ 								ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d on span %d since channel reported in use\n", 
+ 									PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+-							pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+-							pri->pvts[chanpos]->resetting = 1;
++							    pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
++							    pri->pvts[chanpos]->resetting = 1;
++							}
+ 						}
+ 						if (e->hangup.aoc_units > -1)
+ 							if (option_verbose > 2)
+@@ -8819,8 +9624,20 @@
+ 						}
+ 						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ 					} else {
+-						ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
+-							PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++ 						struct zt_holded_call *onhold = NULL;
++						/* check calls on hold */
++ 						onhold = pri_get_callonhold(pri, e->hangup.cref, e->hangup.tei);
++ 						
++ 						if (onhold) {
++ 						    // ast_log(LOG_NOTICE, "hangup, found cref %d, tei %d\n",e->hangup.cref, e->hangup.tei);
++ 						    pri_hangup(pri->pri, onhold->call, e->hangup.cause);
++ 						    pri_destroy_callonhold(pri, onhold);
++ 						    onhold = NULL;
++ 						} else {
++ 						    ast_log(LOG_NOTICE, "Hangup, did not find cref %d, tei %d\n",e->hangup.cref, e->hangup.tei);
++ 						    ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
++  							PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++ 						}
+ 					}
+ 				} 
+ 				break;
+@@ -8830,17 +9647,25 @@
+ 			case PRI_EVENT_HANGUP_REQ:
+ 				chanpos = pri_find_principle(pri, e->hangup.channel);
+ 				if (chanpos < 0) {
+-					ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
+-						PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++					if (pri->nodetype == BRI_NETWORK_PTMP) {
++					    pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
++					} else {
++					    ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
++  						PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++					}
+ 					chanpos = -1;
+ 				}
+-				if (chanpos > -1) {
++				/* dont hang up if we want to hear inband call progress */
++				if ((chanpos > -1) && ((pri->pvts[chanpos]->priindication_oob != 2) || (!e->hangup.inband_progress) || (!pri->pvts[chanpos]->outgoing))){
+ 					chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
+ 					if (chanpos > -1) {
+ 						ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ 						if (pri->pvts[chanpos]->realcall) 
+ 							pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
+ 						else if (pri->pvts[chanpos]->owner) {
++							char tmpstr[256];
++							snprintf(tmpstr, sizeof(tmpstr), "%d", e->hangup.cause);
++							pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "PRI_CAUSE", tmpstr);
+ 							pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
+ 							switch(e->hangup.cause) {
+ 							case PRI_CAUSE_USER_BUSY:
+@@ -8863,25 +9688,90 @@
+ 								if (option_verbose > 2)
+ 									ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
+ 										pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
++ 							if (pri->nodetype == BRI_NETWORK_PTMP) {
++ 							    // check for bri transfers, not everybody uses ECT...
++ 							    if (pri->pvts[chanpos]->owner) {
++ 								// find on hold call
++ 								struct zt_holded_call *onhold = NULL;
++ 								struct ast_channel *transferee = NULL;
++ 
++ 								onhold = pri_get_callonhold(pri, -1, e->hangup.tei);
++ 
++ 								if (onhold) {
++ 									
++ 								    if (((pri->pvts[chanpos]->owner->_state != AST_STATE_RING) && (pri->pvts[chanpos]->owner->_state != AST_STATE_RESERVED)) || ((!ast_strlen_zero(pri->pvts[chanpos]->exten)) && (strncasecmp(pri->pvts[chanpos]->exten, "s", sizeof(pri->pvts[chanpos]->exten))))) {
++ 								        transferee = ast_get_holded_call(onhold->uniqueid);
++ 
++ 									if (transferee) {
++ 									    if (pri->pvts[chanpos]->owner->_state == AST_STATE_RINGING) {
++ 									    	ast_indicate(transferee, AST_CONTROL_RINGING);
++ 									    }
++ 
++ 									    pri->pvts[chanpos]->owner->_softhangup &= ~AST_SOFTHANGUP_DEV;
++  
++  									    ast_mutex_unlock(&transferee->lock);
++ 									    if (ast_channel_masquerade(pri->pvts[chanpos]->owner, transferee)) {
++ 										ast_log(LOG_WARNING, "unable to masquerade\n");
++ 									    } else { 
++ 										/* beware of zombies!!! */
++										ast_set_flag(transferee, AST_FLAG_ZOMBIE);
++ 								//		transferee->zombie = 1;
++ 										pri->pvts[chanpos]->owner = NULL;
++ 										pri->pvts[chanpos]->tei = -1;
++ 									    }
++ 									}
++ 								    } else { 
++ 									ast_retrieve_call_to_death(onhold->uniqueid);
++ 								    }
++ 								    onhold->alreadyhungup = 1;	
++ 								    pri_hangup(pri->pri, onhold->call, e->hangup.cause);
++ 								    onhold = NULL;
++ 								    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ 								    break;
++ 								}
++ 							    }
++ 							}
+ 						} else {
+ 							pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+ 							pri->pvts[chanpos]->call = NULL;
++ 							pri->pvts[chanpos]->tei = -1;
+ 						}
+ 						if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
+-							if (option_verbose > 2)
+-								ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d span %d since channel reported in use\n", 
+-									PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+-							pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+-							pri->pvts[chanpos]->resetting = 1;
++ 							if ((pri->nodetype != BRI_CPE_PTMP) && (pri->nodetype != BRI_NETWORK_PTMP)) {
++ 							    if (option_verbose > 2)
++  								ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d span %d since channel reported in use\n", 
++  									PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++							    pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
++							    pri->pvts[chanpos]->resetting = 1;
++							}
+ 						}
+ 						if (!ast_strlen_zero(e->hangup.useruserinfo)) {
+ 							pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "USERUSERINFO", e->hangup.useruserinfo);
+ 						}
+ 						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ 					} else {
+-						ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++ 						if (pri->nodetype != BRI_NETWORK_PTMP) {
++  						    ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++ 						} else {
++ 						    // check holded_calls!!!
++ 						    struct zt_holded_call *onhold = NULL;
++ 
++ 						    onhold = pri_get_callonhold(pri, e->hangup.cref, e->hangup.tei);
++ 
++ 						    if (onhold) {
++ 							    pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
++ 							    ast_retrieve_call_to_death(onhold->uniqueid);
++ 							    pri_destroy_callonhold(pri, onhold);
++ 							    onhold = NULL;
++ 						    } else {
++ 							ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++ 						    }
++ 						}
+ 					}
+ 				} 
++				if ((chanpos > -1) && (pri->pvts[chanpos]->owner) && (pri->pvts[chanpos]->priindication_oob == 2) && (e->hangup.inband_progress) && (pri->pvts[chanpos]->outgoing)) {
++				    ast_channel_setwhentohangup(pri->pvts[chanpos]->owner, 5);
++				}
+ 				break;
+ 			case PRI_EVENT_HANGUP_ACK:
+ 				chanpos = pri_find_principle(pri, e->hangup.channel);
+@@ -8895,6 +9785,7 @@
+ 					if (chanpos > -1) {
+ 						ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ 						pri->pvts[chanpos]->call = NULL;
++						pri->pvts[chanpos]->tei = -1;
+ 						pri->pvts[chanpos]->resetting = 0;
+ 						if (pri->pvts[chanpos]->owner) {
+ 							if (option_verbose > 2) 
+@@ -8904,7 +9795,9 @@
+ 							pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "USERUSERINFO", e->hangup.useruserinfo);
+ 						}
+ 						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++					    }
+ 					}
++				    }
+ 				}
+ 				break;
+ 			case PRI_EVENT_CONFIG_ERR:
+@@ -8971,15 +9864,25 @@
+ 					ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", 
+ 						PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
+ 				} else {
+-					ast_mutex_lock(&pri->pvts[chanpos]->lock);
+-					pri->pvts[chanpos]->setup_ack = 1;
+-					/* Send any queued digits */
+-					for (x=0;x<strlen(pri->pvts[chanpos]->dialdest);x++) {
++ 					chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
++ 					if (chanpos < 0) {
++ 						ast_log(LOG_WARNING, "Received SETUP_ACK on channel %d/%d not in use on span %d\n", 
++ 							PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
++ 						chanpos = -1;
++ 					} else {
++ 					    ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ 					    pri->pvts[chanpos]->setup_ack = 1;
++ 					    if (pri->pvts[chanpos]->owner) {
++ 					    //    ast_log(LOG_NOTICE, "SETUP_ACK for '%s'\n", pri->pvts[chanpos]->owner->name);
++ 					    }
++ 					    /* Send any queued digits */
++ 					    for (x=0;x<strlen(pri->pvts[chanpos]->dialdest);x++) {
+ 						ast_log(LOG_DEBUG, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
+ 						pri_information(pri->pri, pri->pvts[chanpos]->call, 
+ 							pri->pvts[chanpos]->dialdest[x]);
++					    }
++					    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ 					}
+-					ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ 				}
+ 				break;
+ 			case PRI_EVENT_NOTIFY:
+@@ -9003,6 +9906,78 @@
+ 					ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ 				}
+ 				break;
++ 			case PRI_EVENT_FACILITY:
++ 				    if (e->facility.operation == 0x06) {
++ 					struct ast_channel *chan = NULL;
++ 					struct zt_holded_call *onhold = NULL;
++ 					if (option_verbose > 2) {
++ 					    ast_verbose(VERBOSE_PREFIX_3 "ECT requested by TEI %d for cref %d\n", e->facility.tei, e->facility.cref);
++ 					}
++ 					/* search for cref/tei in held calls */
++ 					onhold = pri_get_callonhold(pri, e->facility.cref, e->facility.tei);
++ 					if (onhold) {
++ 					    chan = ast_get_holded_call(onhold->uniqueid);
++ 					    onhold->alreadyhungup = 1;
++ 					    onhold = NULL;
++ 					    if (!chan) {
++ 						/* hang up */
++ 					        pri_hangup(pri->pri, e->facility.call, 16);
++ 						break;
++ 					    }
++ 					} else {
++ 					    /* unknown cref/tei */
++ 					    ast_log(LOG_WARNING, "did not find call on hold for cref %d tei %d\n", e->facility.tei, e->facility.cref);
++ 					    /* hang up */
++ 					    pri_hangup(pri->pri, e->facility.call, 16);
++ 					    break;
++ 					}
++ 
++ 					/* find an active call for the same tei */
++ 					chanpos = pri_find_tei(pri, e->facility.call, e->facility.tei);
++ 					if (chanpos < 0) {
++ 					    /* did not find active call, hangup call on hold */
++ 					    if (chan) {
++ 						ast_hangup(chan);
++ 						chan = NULL;
++ 					    }
++ 					} else {
++ 					    ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ 					    /* transfer */
++ 					    if (pri->pvts[chanpos]->owner) {
++ 						if (option_verbose > 3) {
++ 						    ast_verbose(VERBOSE_PREFIX_3 "ECT: found %s on channel %d for tei %d\n", pri->pvts[chanpos]->owner->name ,chanpos, e->facility.tei);
++ 						}
++ 						/* pass callprogress if the channel is not up yet */
++ 						if (pri->pvts[chanpos]->owner->_state == AST_STATE_RINGING) {
++ 						    ast_indicate(chan, AST_CONTROL_RINGING);
++ 						}
++ 						/* unlock the channel we removed from hold */
++ 						ast_mutex_unlock(&chan->lock);
++ 						if (ast_channel_masquerade(pri->pvts[chanpos]->owner, chan)) {
++ 					    	    ast_log(LOG_WARNING, "unable to masquerade\n");
++ 						} else {
++ 						    /* beware of zombies !!! */
++						    ast_set_flag(chan, AST_FLAG_ZOMBIE);
++ 						//    chan->zombie = 1;
++ 						}
++ 					    }
++ 					    ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ 					}
++					/* disconnect */
++ 					pri_hangup(pri->pri, e->facility.call, 16);
++ 				    } else if (e->facility.operation == 0x0D) {
++ 					ast_log(LOG_NOTICE, "call deflection to %s requested.\n", e->facility.forwardnum);
++ 					/* mmmmmkay */
++ 					
++ 					/* lock the channel */
++ 					
++ 					/* async goto */
++ 					
++ 					/* disconnect isdn layer */
++ 				    } else {
++ 					ast_log(LOG_WARNING, "Unknown facility operation %#x requested.\n", e->facility.operation);
++ 				    }
++ 				break;
+ 			default:
+ 				ast_log(LOG_DEBUG, "Event: %d\n", e->e);
+ 			}
+@@ -9064,7 +10039,7 @@
+ 			pri->fds[i] = -1;
+ 			return -1;
+ 		}
+-		pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
++		pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype, pri->span);
+ 		/* Force overlap dial if we're doing GR-303! */
+ 		if (pri->switchtype == PRI_SWITCH_GR303_TMC)
+ 			pri->overlapdial = 1;
+@@ -9133,39 +10108,77 @@
+ 
+ static int handle_pri_set_debug_file(int fd, int argc, char **argv)
+ {
+-	int myfd;
++ 	int myfd, x, d;
++ 	int span;
++ 
++ 	if (argc < 6) 
++ 		return RESULT_SHOWUSAGE;
+ 
+ 	if (!strncasecmp(argv[1], "set", 3)) {
+-		if (argc < 5) 
++		if (argc < 7) 
+ 			return RESULT_SHOWUSAGE;
+ 
+-		if (ast_strlen_zero(argv[4]))
++		if (!argv[4] || ast_strlen_zero(argv[4]))
+ 			return RESULT_SHOWUSAGE;
+ 
++ 		if (!argv[5])
++ 			return RESULT_SHOWUSAGE;
++ 
++ 		if (!argv[6] || ast_strlen_zero(argv[6]))
++ 			return RESULT_SHOWUSAGE;
++ 
++ 		span = atoi(argv[6]);
++ 		if ((span < 1) && (span > NUM_SPANS)) {
++ 			return RESULT_SUCCESS;
++ 		}
++ 		
++
+ 		myfd = open(argv[4], O_CREAT|O_WRONLY);
+ 		if (myfd < 0) {
+-			ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
+-			return RESULT_SUCCESS;
++ 		    ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
++ 		    return RESULT_SUCCESS;
+ 		}
+-
+-		ast_mutex_lock(&pridebugfdlock);
+-
+-		if (pridebugfd >= 0)
+-			close(pridebugfd);
+-
+-		pridebugfd = myfd;
+-		ast_copy_string(pridebugfilename,argv[4],sizeof(pridebugfilename));
+-		
+-		ast_mutex_unlock(&pridebugfdlock);
+-
+-		ast_cli(fd, "PRI debug output will be sent to '%s'\n", argv[4]);
++ 		for (x=0; x < NUM_SPANS; x++) {
++ 	    	    ast_mutex_lock(&pris[x].lock);
++ 		    
++ 		    if (pris[x].span == span) {
++ 			if (pris[x].debugfd >= 0)
++ 			    close(pris[x].debugfd);
++ 			pris[x].debugfd = myfd;
++ 			for (d=0; d < NUM_DCHANS; d++) {
++ 			    if (pris[x].dchans[d])
++ 				pri_set_debug_fd(pris[x].dchans[d], myfd);
++ 			}
++ 		    }
++ 	    	    ast_mutex_unlock(&pris[x].lock);
++ 		}
++  
++ 		ast_cli(fd, "PRI debug output for span %d will be sent to '%s'\n", span, argv[4]);
+ 	} else {
++ 		if (!argv[5] || ast_strlen_zero(argv[5]))
++ 			return RESULT_SHOWUSAGE;
+ 		/* Assume it is unset */
+-		ast_mutex_lock(&pridebugfdlock);
+-		close(pridebugfd);
+-		pridebugfd = -1;
+-		ast_cli(fd, "PRI debug output to file disabled\n");
+-		ast_mutex_unlock(&pridebugfdlock);
++		span = atoi(argv[5]);
++ 		if ((span < 1) && (span > NUM_SPANS)) {
++ 			return RESULT_SUCCESS;
++ 		}
++ 
++ 		for (x=0; x < NUM_SPANS; x++) {
++ 	    	    ast_mutex_lock(&pris[x].lock);
++ 		    
++ 		    if (pris[x].span == span) {
++ 			if (pris[x].debugfd >= 0)
++ 			    close(pris[x].debugfd);
++ 			pris[x].debugfd = -1;
++ 			for (d=0; d < NUM_DCHANS; d++) {
++ 			    if (pris[x].dchans[d])
++ 				pri_set_debug_fd(pris[x].dchans[d], -1);
++ 			}
++ 		    }
++ 	    	    ast_mutex_unlock(&pris[x].lock);
++ 		}
++ 
++ 		ast_cli(fd, "PRI debug output to file for span %d disabled\n", span);
+ 	}
+ 
+ 	return RESULT_SUCCESS;
+@@ -9197,6 +10210,7 @@
+ 
+ 
+ 
++
+ static int handle_pri_no_debug(int fd, int argc, char *argv[])
+ {
+ 	int span;
+@@ -9303,36 +10317,6 @@
+ 	return RESULT_SUCCESS;
+ }
+ 
+-static int handle_pri_show_debug(int fd, int argc, char *argv[])
+-{
+-	int x;
+-	int span;
+-	int count=0;
+-	int debug=0;
+-
+-	for(span=0;span<NUM_SPANS;span++) {
+-	        if (pris[span].pri) {
+-			for(x=0;x<NUM_DCHANS;x++) {
+-				debug=0;
+-	        		if (pris[span].dchans[x]) {
+-	        			debug = pri_get_debug(pris[span].dchans[x]);
+-					ast_cli(fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" );
+-					count++;
+-				}
+-			}
+-		}
+-
+-	}
+-	ast_mutex_lock(&pridebugfdlock);
+-	if (pridebugfd >= 0) 
+-		ast_cli(fd, "Logging PRI debug to file %s\n", pridebugfilename);
+-	ast_mutex_unlock(&pridebugfdlock);
+-	    
+-	if (!count) 
+-		ast_cli(fd, "No debug set or no PRI running\n");
+-	return RESULT_SUCCESS;
+-}
+-
+ static char pri_debug_help[] = 
+ 	"Usage: pri debug span <span>\n"
+ 	"       Enables debugging on a given PRI span\n";
+@@ -9349,6 +10333,18 @@
+ 	"Usage: pri show span <span>\n"
+ 	"       Displays PRI Information\n";
+ 
++static char bri_debug_help[] = 
++	"Usage: bri debug span <span>\n"
++	"       Enables debugging on a given BRI span\n";
++	
++static char bri_no_debug_help[] = 
++	"Usage: bri no debug span <span>\n"
++	"       Disables debugging on a given BRI span\n";
++
++static char bri_really_debug_help[] = 
++	"Usage: bri intensive debug span <span>\n"
++	"       Enables debugging down to the Q.921 level\n";
++
+ static struct ast_cli_entry zap_pri_cli[] = {
+ 	{ { "pri", "debug", "span", NULL }, handle_pri_debug,
+ 	  "Enables PRI debugging on a span", pri_debug_help, complete_span_4 },
+@@ -9356,19 +10352,76 @@
+ 	  "Disables PRI debugging on a span", pri_no_debug_help, complete_span_5 },
+ 	{ { "pri", "intense", "debug", "span", NULL }, handle_pri_really_debug,
+ 	  "Enables REALLY INTENSE PRI debugging", pri_really_debug_help, complete_span_5 },
++	{ { "bri", "debug", "span", NULL }, handle_pri_debug,
++	  "Enables BRI debugging on a span", bri_debug_help, complete_span_4 },
++	{ { "bri", "no", "debug", "span", NULL }, handle_pri_no_debug,
++	  "Disables BRI debugging on a span", bri_no_debug_help, complete_span_5 },
++	{ { "bri", "intense", "debug", "span", NULL }, handle_pri_really_debug,
++	  "Enables REALLY INTENSE BRI debugging", bri_really_debug_help, complete_span_5 },
+ 	{ { "pri", "show", "span", NULL }, handle_pri_show_span,
+ 	  "Displays PRI Information", pri_show_span_help, complete_span_4 },
+-	{ { "pri", "show", "debug", NULL }, handle_pri_show_debug,
+-	  "Displays current PRI debug settings" },
+ 	{ { "pri", "set", "debug", "file", NULL }, handle_pri_set_debug_file,
+ 	  "Sends PRI debug output to the specified file" },
+-	{ { "pri", "unset", "debug", "file", NULL }, handle_pri_set_debug_file,
++	{ { "pri", "unset", "debug", "file", "span", NULL }, handle_pri_set_debug_file,
+ 	  "Ends PRI debug output to file" },
+ };
+ 
++static int app_zapCD(struct ast_channel *chan, void *data)
++{
++    int res=-1;
++    struct zt_pvt *p = chan->tech_pvt;
++
++    if(!data) {
++        ast_log(LOG_WARNING, "zapCD wants a number to deflect to\n");
++    }
++    return pri_deflect(p->pri->pri, p->call, data);
++}
++
++static char *zapCD_tdesc = "Call Deflection";
++static char *zapCD_app = "zapCD";
++static char *zapCD_synopsis = "Call Deflection";
+ #endif /* ZAPATA_PRI */
+ 
+ 
++static int app_zapEC(struct ast_channel *chan, void *data)
++{
++ int res=-1;
++ struct zt_pvt *p = NULL;
++
++ if (!data) {
++	ast_log(LOG_WARNING, "zapEC requires one argument (on | off)\n");
++ }
++ if (chan && !strcasecmp("ZAP",chan->type)) {
++	p = chan->tech_pvt;
++	if (!p) return res;
++	if (!strcasecmp("on",(char *)data)) {
++	    zt_enable_ec(p);
++	    res = 0;
++	    if (option_verbose > 3) {
++		ast_verbose(VERBOSE_PREFIX_3 "Enabled echo cancelation on channel %s.\n", chan->name);
++	    }
++	} else if (!strcasecmp("off",(char *)data)) {
++	    zt_disable_ec(p);
++	    res = 0;
++	    if (option_verbose > 3) {
++		ast_verbose(VERBOSE_PREFIX_3 "Disabled echo cancelation on channel %s.\n", chan->name);
++	    }
++	} else {
++ 	    ast_log(LOG_WARNING, "Unknown argument %s to zapEC\n", (char *)data);
++	}
++ } else {
++     ast_log(LOG_WARNING, "zapNoEC only works on ZAP channels, check your extensions.conf!\n");
++ }
++
++ return res;
++}
++
++static char *zapEC_tdesc = "Enable/disable Echo cancelation";
++static char *zapEC_app = "zapEC";
++static char *zapEC_synopsis = "Enable/Disable Echo Cancelation on a Zap channel";
++
++
++
+ #ifdef ZAPATA_R2
+ static int handle_r2_no_debug(int fd, int argc, char *argv[])
+ {
+@@ -9991,6 +11044,7 @@
+ 	ast_manager_unregister( "ZapDNDoff" );
+ 	ast_manager_unregister( "ZapDNDon" );
+ 	ast_manager_unregister("ZapShowChannels");
++	ast_unregister_application(zapEC_app);
+ 	ast_channel_unregister(&zap_tech);
+ 	if (!ast_mutex_lock(&iflock)) {
+ 		/* Hangup all interfaces if they have an owner */
+@@ -10349,8 +11403,8 @@
+ 			}
+ 		} else if (!strcasecmp(v->name, "echotraining")) {
+ 			if (sscanf(v->value, "%d", &y) == 1) {
+-				if ((y < 10) || (y > 4000)) {
+-					ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 2000 ms at line %d\n", v->lineno);					
++				if ((y < 10) || (y > 1000)) {
++					ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 1000 ms at line %d\n", v->lineno);					
+ 				} else {
+ 					echotraining = y;
+ 				}
+@@ -10536,6 +11590,22 @@
+ 					cur_signalling = SIG_GR303FXSKS;
+ 					cur_radio = 0;
+ 					pritype = PRI_CPE;
++ 			} else if (!strcasecmp(v->value, "bri_net_ptmp")) {
++ 				cur_radio = 0;
++ 				cur_signalling = SIG_PRI;
++ 				pritype = BRI_NETWORK_PTMP;
++ 			} else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
++ 				cur_signalling = SIG_PRI;
++ 				cur_radio = 0;
++ 				pritype = BRI_CPE_PTMP;
++ 			} else if (!strcasecmp(v->value, "bri_net")) {
++ 				cur_radio = 0;
++ 				cur_signalling = SIG_PRI;
++ 				pritype = BRI_NETWORK;
++ 			} else if (!strcasecmp(v->value, "bri_cpe")) {
++ 				cur_signalling = SIG_PRI;
++ 				cur_radio = 0;
++ 				pritype = BRI_CPE;
+ #endif
+ #ifdef ZAPATA_R2
+ 				} else if (!strcasecmp(v->value, "r2")) {
+@@ -10624,8 +11694,10 @@
+ 					priindication_oob = 1;
+ 				else if (!strcasecmp(v->value, "inband"))
+ 					priindication_oob = 0;
++				else if (!strcasecmp(v->value, "passthrough"))
++					priindication_oob = 2;
+ 				else
+-					ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d\n",
++					ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' , 'outofband' or 'passthrough' at line %d\n",
+ 						v->value, v->lineno);
+ 			} else if (!strcasecmp(v->name, "priexclusive")) {
+ 				cur_priexclusive = ast_true(v->value);
+@@ -10639,6 +11711,10 @@
+ 				ast_copy_string(privateprefix, v->value, sizeof(privateprefix));
+ 			} else if (!strcasecmp(v->name, "unknownprefix")) {
+ 				ast_copy_string(unknownprefix, v->value, sizeof(unknownprefix));
++ 			} else if (!strcasecmp(v->name, "nocid")) {
++  				ast_copy_string(nocid, v->value, sizeof(nocid) - 1);
++  			} else if (!strcasecmp(v->name, "withheldcid")) {
++  				ast_copy_string(withheldcid, v->value, sizeof(withheldcid) - 1);
+ 			} else if (!strcasecmp(v->name, "resetinterval")) {
+ 				if (!strcasecmp(v->value, "never"))
+ 					resetinterval = -1;
+@@ -10653,6 +11729,8 @@
+ 				ast_copy_string(idleext, v->value, sizeof(idleext));
+ 			} else if (!strcasecmp(v->name, "idledial")) {
+ 				ast_copy_string(idledial, v->value, sizeof(idledial));
++  			} else if (!strcasecmp(v->name, "pritrustusercid")) {
++  				usercid = ast_true(v->value);
+ 			} else if (!strcasecmp(v->name, "overlapdial")) {
+ 				overlapdial = ast_true(v->value);
+ 			} else if (!strcasecmp(v->name, "pritimer")) {
+@@ -10838,6 +11916,7 @@
+ #ifdef ZAPATA_PRI
+ 	if (!reload) {
+ 		for (x=0;x<NUM_SPANS;x++) {
++			pris[x].debugfd = -1;
+ 			if (pris[x].pvts[0]) {
+ 				if (start_pri(pris + x)) {
+ 					ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
+@@ -10895,11 +11974,46 @@
+ 	ast_manager_register( "ZapDNDon", 0, action_zapdndon, "Toggle Zap channel Do Not Disturb status ON" );
+ 	ast_manager_register( "ZapDNDoff", 0, action_zapdndoff, "Toggle Zap channel Do Not Disturb status OFF" );
+ 	ast_manager_register("ZapShowChannels", 0, action_zapshowchannels, "Show status zapata channels");
+-
++	ast_register_application(zapEC_app, app_zapEC, zapEC_synopsis, zapEC_tdesc);
++#ifdef ZAPATA_PRI
++        ast_register_application(zapCD_app, app_zapCD, zapCD_synopsis, zapCD_tdesc);
++#endif
+ 	return res;
+ }
+ 
++#ifdef ZAPATA_PRI
++static int zt_tdd_sendtext(struct ast_channel *c, const char *text);
++
++static int zt_pri_sendtext(struct ast_channel *c, const char *text) {
++    struct zt_pvt *p = c->tech_pvt;
++    if (!p) return -1;
++    if (!p->pri) return -1;
++	    if (strlen(text)) {
++		if (p->pri) {		
++		    if (!pri_grab(p, p->pri)) {
++		//	ast_log(LOG_NOTICE, "Sending Display IE  '%s'\n", text);
++			pri_information_display(p->pri->pri,p->call,(char *)text);
++			pri_rel(p->pri);
++	    	    } else ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
++		}
++	    }
++    return 0;
++}
++
++static int zt_sendtext(struct ast_channel *c, const char *text) {
++    struct zt_pvt *p = c->tech_pvt;
++    if (!p) return -1;
++    if (p->sig == SIG_PRI) {
++	return zt_pri_sendtext(c, text);
++    } else {
++	return zt_tdd_sendtext(c, text);
++    }
++}
++
++static int zt_tdd_sendtext(struct ast_channel *c, const char *text)
++#else
+ static int zt_sendtext(struct ast_channel *c, const char *text)
++#endif
+ {
+ #define	END_SILENCE_LEN 400
+ #define	HEADER_MS 50
+@@ -10918,6 +12032,7 @@
+ 	float scont = 0.0;
+ 	int index;
+ 
++
+ 	index = zt_get_index(c, p, 0);
+ 	if (index < 0) {
+ 		ast_log(LOG_WARNING, "Huh?  I don't exist?\n");
+diff -urNad asterisk-1.2.0.dfsg/codecs/codec_ilbc.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/codecs/codec_ilbc.c
+--- asterisk-1.2.0.dfsg/codecs/codec_ilbc.c	2005-11-06 17:09:46.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/codecs/codec_ilbc.c	2005-11-23 05:50:44.372870506 +0200
+@@ -49,7 +49,7 @@
+ #include "slin_ilbc_ex.h"
+ #include "ilbc_slin_ex.h"
+ 
+-#define USE_ILBC_ENHANCER	0
++#define USE_ILBC_ENHANCER	1
+ #define ILBC_MS 			30
+ /* #define ILBC_MS			20 */
+ 
+diff -urNad asterisk-1.2.0.dfsg/configs/watchdog.conf.sample /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/configs/watchdog.conf.sample
+--- asterisk-1.2.0.dfsg/configs/watchdog.conf.sample	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/configs/watchdog.conf.sample	2005-11-23 05:50:44.375870091 +0200
+@@ -0,0 +1,22 @@
++;
++; Configuration file for res_watchdog
++;
++; type     = isdnguard | watchdog
++; device   = /dev/...
++; interval = interval to trigger the watchdog in ms
++
++;[ISDNguard-direct]
++;type = isdnguard
++;device = /dev/ttyS0
++;interval = 200
++
++;[ISDNguard-with-daemon]
++;type = isdnguard
++;device = /var/run/guard.ctl
++;interval = 200
++
++;[kernel_watchdog]
++;type = watchdog
++;device = /dev/watchdog
++;interval = 100
++
+diff -urNad asterisk-1.2.0.dfsg/db.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/db.c
+--- asterisk-1.2.0.dfsg/db.c	2005-11-01 23:53:29.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/db.c	2005-11-23 05:50:44.377869813 +0200
+@@ -514,11 +514,18 @@
+ struct ast_cli_entry cli_database_deltree =
+ { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
+ 
++static char mandescr_dbput[] = 
++"Description: Put a value into astdb\n"
++"Variables: \n"
++"	Family: ...\n"
++"	Key: ...\n"
++"	Value: ...\n";
++
+ static int manager_dbput(struct mansession *s, struct message *m)
+ {
+ 	char *family = astman_get_header(m, "Family");
+ 	char *key = astman_get_header(m, "Key");
+-	char *val = astman_get_header(m, "Val");
++	char *val = astman_get_header(m, "Value");
+ 	int res;
+ 
+ 	if (!strlen(family)) {
+@@ -543,6 +550,12 @@
+ 	return 0;
+ }
+ 
++static char mandescr_dbget[] = 
++"Description: Get a value from astdb\n"
++"Variables: \n"
++"	Family: ...\n"
++"	Key: ...\n";
++
+ static int manager_dbget(struct mansession *s, struct message *m)
+ {
+ 	char *id = astman_get_header(m,"ActionID");
+@@ -572,7 +585,7 @@
+ 		ast_cli(s->fd, "Event: DBGetResponse\r\n"
+ 				"Family: %s\r\n"
+ 				"Key: %s\r\n"
+-				"Val: %s\r\n"
++				"Value: %s\r\n"
+ 				"%s"
+ 				"\r\n",
+ 				family, key, tmp, idText);
+@@ -580,6 +593,39 @@
+ 	return 0;
+ }
+ 
++static char mandescr_dbdel[] = 
++"Description: remove value from astdb\n"
++"Variables: \n"
++"	Family: ...\n"
++"	Key: ...\n";
++
++static int manager_dbdel(struct mansession *s, struct message *m)
++{
++        char *family = astman_get_header(m, "Family");
++        char *key = astman_get_header(m, "Key");
++	char *id = astman_get_header(m,"ActionID");
++
++	if (!strlen(family)) {
++		astman_send_error(s, m, "No family specified");
++		return 0;
++	}
++	if (!strlen(key)) {
++		astman_send_error(s, m, "No key specified");
++		return 0;
++	}
++
++	if (ast_db_del(family, key)) {
++	    ast_cli(s->fd, "Response: Failed\r\n");
++	} else {
++	    ast_cli(s->fd, "Response: Success\r\n");
++	}
++	if (id && !ast_strlen_zero(id))
++		ast_cli(s->fd, "ActionID: %s\r\n",id);
++	ast_cli(s->fd, "\r\n");
++
++	return 0;
++}
++
+ int astdb_init(void)
+ {
+ 	dbinit();
+@@ -589,7 +635,8 @@
+ 	ast_cli_register(&cli_database_put);
+ 	ast_cli_register(&cli_database_del);
+ 	ast_cli_register(&cli_database_deltree);
+-	ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
+-	ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
++	ast_manager_register("DBget", EVENT_FLAG_SYSTEM, manager_dbget, mandescr_dbget);
++	ast_manager_register("DBput", EVENT_FLAG_SYSTEM, manager_dbput, mandescr_dbput);
++	ast_manager_register("DBdel", EVENT_FLAG_SYSTEM, manager_dbdel, mandescr_dbdel);
+ 	return 0;
+ }
+diff -urNad asterisk-1.2.0.dfsg/editline/cygdef.h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/editline/cygdef.h
+--- asterisk-1.2.0.dfsg/editline/cygdef.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/editline/cygdef.h	2005-11-23 05:50:44.380869398 +0200
+@@ -0,0 +1,11 @@
++/* cygdef.h. Generated automatically by configure. */ 
++#ifndef _CYGDEF_H_
++#define _CYGDEF_H_ 1
++#include <sys/ioctl.h>
++#define __linux__ 1
++ 
++
++typedef void (*sig_t)(int);
++ 
++
++#endif /* _CYGDEF_H_ */
+diff -urNad asterisk-1.2.0.dfsg/HARDWARE /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/HARDWARE
+--- asterisk-1.2.0.dfsg/HARDWARE	2004-08-03 09:31:20.000000000 +0300
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/HARDWARE	2005-11-23 05:50:44.383868982 +0200
+@@ -37,6 +37,17 @@
+    * Wildcard TE410P - Quad T1/E1 switchable interface.  Supports PRI and 
+      RBS signalling, as well as PPP, FR, and HDLC data modes.
+ 
++-- Junghanns.NET
++	http://www.junghanns.net
++	
++    * quadBRI PCI ISDN - 4port BRI ISDN interface, supports NT and TE mode
++    
++    * octoBRI PCI ISDN - 8port BRI ISDN interface, supports NT and TE mode
++
++    * singleE1 PCI ISDN - Single E1 interface
++
++    * doubleE1 PCI ISDN - Double E1 interface
++
+ Non-zaptel compatible hardware
+ ==============================
+ 
+diff -urNad asterisk-1.2.0.dfsg/include/asterisk/agi.h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/agi.h
+--- asterisk-1.2.0.dfsg/include/asterisk/agi.h	2005-10-24 22:12:06.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/agi.h	2005-11-23 05:50:44.385868705 +0200
+@@ -29,7 +29,8 @@
+ 
+ typedef struct agi_state {
+ 	int fd;		/* FD for general output */
+-	int audio;	/* FD for audio output */
++	int audio_out;	/* FD for audio output */
++	int audio_in;	/* FD for audio output */
+ 	int ctrl;	/* FD for input control */
+ } AGI;
+ 
+diff -urNad asterisk-1.2.0.dfsg/include/asterisk/channel.h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/channel.h
+--- asterisk-1.2.0.dfsg/include/asterisk/channel.h	2005-11-11 05:48:28.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/channel.h	2005-11-23 05:50:44.390868012 +0200
+@@ -86,6 +86,9 @@
+ #ifndef _ASTERISK_CHANNEL_H
+ #define _ASTERISK_CHANNEL_H
+ 
++/* Max length of the uniqueid */
++#define AST_MAX_UNIQUEID 64
++
+ #include <unistd.h>
+ #include <setjmp.h>
+ #ifdef POLLCOMPAT 
+@@ -380,7 +383,7 @@
+ 	unsigned int fout;
+ 
+ 	/* Unique Channel Identifier */
+-	char uniqueid[32];
++	char uniqueid[AST_MAX_UNIQUEID];
+ 
+ 	/* Why is the channel hanged up */
+ 	int hangupcause;
+@@ -531,6 +534,8 @@
+ #define AST_STATE_MUTE		(1 << 16)	
+ /*! @} */
+ 
++extern ast_mutex_t uniquelock;			
++
+ /*! \brief Change the state of a channel */
+ int ast_setstate(struct ast_channel *chan, int state);
+ 
+@@ -567,7 +572,7 @@
+  * by the low level module
+  * \return Returns an ast_channel on success, NULL on failure.
+  */
+-struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
++struct ast_channel *ast_request(const char *type, int format, void *data, int *status, char *uniqueid);
+ 
+ /*!
+  * \brief Request a channel of a given type, with data as optional information used 
+@@ -582,9 +587,9 @@
+  * \return Returns an ast_channel on success or no answer, NULL on failure.  Check the value of chan->_state
+  * to know if the call was answered or not.
+  */
+-struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname);
++struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, char *uniqueid);
+ 
+-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
++struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, struct outgoing_helper *oh, char *uniqueid);
+ 
+ /*!\brief Register a channel technology (a new channel driver)
+  * Called by a channel module to register the kind of channels it supports.
+@@ -837,6 +842,10 @@
+ /*--- ast_get_channel_by_exten_locked: Get channel by exten (and optionally context) and lock it */
+ struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const char *context);
+ 
++/*! Get channel by uniqueid (locks channel) */
++struct ast_channel *ast_get_channel_by_uniqueid_locked(char *uniqueid);
++ 
++
+ /*! Waits for a digit */
+ /*! 
+  * \param c channel to wait for a digit on
+@@ -907,6 +916,9 @@
+    p->owner pointer) that is affected by the change.  The physical layer of the original
+    channel is hung up.  */
+ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
++int ast_channel_masquerade_locked(struct ast_channel *original, struct ast_channel *clone);
++ 
++char *ast_alloc_uniqueid(void);
+ 
+ /*! Gives the string form of a given cause code */
+ /*! 
+diff -urNad asterisk-1.2.0.dfsg/include/asterisk/features.h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/features.h
+--- asterisk-1.2.0.dfsg/include/asterisk/features.h	2005-10-24 22:12:06.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/features.h	2005-11-23 05:50:44.393867597 +0200
+@@ -45,6 +45,8 @@
+ };
+ 
+ 
++extern int ast_autoanswer_login(struct ast_channel *chan, void *data);
++extern int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data);
+ 
+ /*! \brief Park a call and read back parked location 
+  *  \param chan the channel to actually be parked
+@@ -68,11 +70,19 @@
+ */
+ extern int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
+ 
++extern int ast_hold_call(struct ast_channel *chan, struct ast_channel *host);
++extern int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *host);
++extern int ast_retrieve_call(struct ast_channel *chan, char *uniqueid);
++extern int ast_retrieve_call_to_death(char *uniqueid);
++extern struct ast_channel *ast_get_holded_call(char *uniqueid);
++
+ /*! \brief Determine system parking extension
+  *  Returns the call parking extension for drivers that provide special
+     call parking help */
+ extern char *ast_parking_ext(void);
+ 
++extern char *ast_parking_con(void);
++
+ /*! \brief Determine system call pickup extension */
+ extern char *ast_pickup_ext(void);
+ 
+diff -urNad asterisk-1.2.0.dfsg/include/asterisk/pbx.h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/pbx.h
+--- asterisk-1.2.0.dfsg/include/asterisk/pbx.h	2005-11-09 01:37:53.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk/pbx.h	2005-11-23 05:50:44.396867181 +0200
+@@ -57,7 +57,7 @@
+ 	AST_EXTENSION_BUSY = 1 << 1,
+ 	/*! All devices UNAVAILABLE/UNREGISTERED */
+ 	AST_EXTENSION_UNAVAILABLE = 1 << 2,
+-	/*! All devices RINGING */
++	/*! One or more devices RINGING */
+ 	AST_EXTENSION_RINGING = 1 << 3,
+ };
+ 
+@@ -156,6 +156,8 @@
+  */
+ extern struct ast_app *pbx_findapp(const char *app);
+ 
++void *ast_pbx_run_app(void *data);
++
+ /*! executes an application */
+ /*!
+  * \param c channel to execute on
+@@ -563,11 +565,11 @@
+ 
+ /* Synchronously or asynchronously make an outbound call and send it to a
+    particular extension */
+-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel);
++int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel, char *uniqueid);
+ 
+ /* Synchronously or asynchronously make an outbound call and send it to a
+    particular application with given extension */
+-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel);
++int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel, char *uniqueid);
+ 
+ /* Functions for returning values from structures */
+ const char *ast_get_context_name(struct ast_context *con);
+diff -urNad asterisk-1.2.0.dfsg/include/asterisk.h /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk.h
+--- asterisk-1.2.0.dfsg/include/asterisk.h	2005-11-08 03:29:14.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/include/asterisk.h	2005-11-23 05:50:44.399866765 +0200
+@@ -36,6 +36,7 @@
+ extern char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
++extern char ast_config_AST_SYMBOLIC_NAME[20];
+ extern char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH];
+diff -urNad asterisk-1.2.0.dfsg/LICENSE /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/LICENSE
+--- asterisk-1.2.0.dfsg/LICENSE	2005-10-15 07:29:13.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/LICENSE	2005-11-23 05:50:44.401866488 +0200
+@@ -1,7 +1,7 @@
+-Asterisk is distributed under the GNU General Public License version 2
+-and is also available under alternative licenses negotiated directly
+-with Digium, Inc. If you obtained Asterisk under the GPL, then the GPL
+-applies to all loadable Asterisk modules used on your system as well,
++BRIstuffed Asterisk is distributed under the GNU General Public License version 2
++and is not available under any alternative licenses.
++If you obtained BRIstuffed Asterisk under the GPL, then the GPL
++applies to all loadable BRIstuffed Asterisk modules used on your system as well,
+ except as defined below. The GPL (version 2) is included in this
+ source tree in the file COPYING.
+ 
+diff -urNad asterisk-1.2.0.dfsg/Makefile /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/Makefile
+--- asterisk-1.2.0.dfsg/Makefile	2005-11-16 22:23:53.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/Makefile	2005-11-23 05:50:44.404866073 +0200
+@@ -766,6 +766,8 @@
+ 		echo ";astctlowner = root" ; \
+ 		echo ";astctlgroup = apache" ; \
+ 		echo ";astctl = asterisk.ctl" ; \
++		echo "[options]" ; \
++		echo "uniquename = asterisk" ;\
+ 		) > $(DESTDIR)$(ASTCONFPATH) ; \
+ 	else \
+ 		echo "Skipping asterisk.conf creation"; \
+diff -urNad asterisk-1.2.0.dfsg/manager.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/manager.c
+--- asterisk-1.2.0.dfsg/manager.c	2005-11-15 20:35:30.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/manager.c	2005-11-23 05:50:44.408865518 +0200
+@@ -11,6 +11,9 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2003-2004, Junghanns.NET Gmbh
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+  * This program is free software, distributed under the terms of
+  * the GNU General Public License Version 2. See the LICENSE file
+  * at the top of the source tree.
+@@ -62,6 +65,7 @@
+ #include "asterisk/md5.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/utils.h"
++#include "asterisk/astdb.h"
+ 
+ struct fast_originate_helper {
+ 	char tech[256];
+@@ -75,6 +79,8 @@
+ 	char exten[256];
+ 	char idtext[256];
+ 	int priority;
++	int callingpres;
++	char uniqueid[64];
+ 	struct ast_variable *vars;
+ };
+ 
+@@ -656,11 +662,17 @@
+ {
+ 	struct ast_channel *c = NULL;
+ 	char *name = astman_get_header(m, "Channel");
+-	if (ast_strlen_zero(name)) {
+-		astman_send_error(s, m, "No channel specified");
++	char *uniqueid = astman_get_header(m, "Uniqueid");
++	if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
++		astman_send_error(s, m, "No channel or uniqueid specified");
+ 		return 0;
+ 	}
+-	c = ast_get_channel_by_name_locked(name);
++	if (!ast_strlen_zero(uniqueid)) {
++		c = ast_get_channel_by_uniqueid_locked(uniqueid);
++	} else {
++	    if (!ast_strlen_zero(name))
++		c = ast_get_channel_by_name_locked(name);
++	}	
+ 	if (!c) {
+ 		astman_send_error(s, m, "No such channel");
+ 		return 0;
+@@ -759,6 +771,7 @@
+ }
+ 
+ 
++
+ /*! \brief  action_status: Manager "status" command to show channels */
+ /* Needs documentation... */
+ static int action_status(struct mansession *s, struct message *m)
+@@ -865,32 +878,50 @@
+ 	char *exten = astman_get_header(m, "Exten");
+ 	char *context = astman_get_header(m, "Context");
+ 	char *priority = astman_get_header(m, "Priority");
++ 	char *uniqueid = astman_get_header(m, "Uniqueid");
++ 	char *uniqueid2 = astman_get_header(m, "ExtraUniqueid");
++	char *exten2 = astman_get_header(m, "ExtraExten");
++	char *context2 = astman_get_header(m, "ExtraContext");
++	char *priority2 = astman_get_header(m, "ExtraPriority");
+ 	struct ast_channel *chan, *chan2 = NULL;
+ 	int pi = 0;
++	int pi2 = 0;
+ 	int res;
+ 
+-	if (ast_strlen_zero(name)) {
+-		astman_send_error(s, m, "Channel not specified");
++ 	if ((!name || ast_strlen_zero(name)) && (!uniqueid || ast_strlen_zero(uniqueid))) {
++ 		astman_send_error(s, m, "Channel or Uniqueid not specified");
+ 		return 0;
+ 	}
+ 	if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
+ 		astman_send_error(s, m, "Invalid priority\n");
+ 		return 0;
+ 	}
+-	chan = ast_get_channel_by_name_locked(name);
++ 	if (uniqueid && (!ast_strlen_zero(uniqueid))) {
++ 	    chan = ast_get_channel_by_uniqueid_locked(uniqueid);
++ 	} else {
++ 	    chan = ast_get_channel_by_name_locked(name);
++ 	}
+ 	if (!chan) {
+ 		char buf[BUFSIZ];
+ 		snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
+ 		astman_send_error(s, m, buf);
+ 		return 0;
+ 	}
+-	if (!ast_strlen_zero(name2))
++ 	if (!ast_strlen_zero(uniqueid2)) {
++ 		chan2 = ast_get_channel_by_uniqueid_locked(uniqueid2);
++ 		if (!ast_strlen_zero(priority2) && (sscanf(priority, "%d", &pi2) != 1)) {
++ 		    astman_send_error(s, m, "Invalid priority2\n");
++ 		    return 0;
++ 		}
++ 	} else {
++	    if (!ast_strlen_zero(name2))
+ 		chan2 = ast_get_channel_by_name_locked(name2);
++	}
+ 	res = ast_async_goto(chan, context, exten, pi);
+ 	if (!res) {
+-		if (!ast_strlen_zero(name2)) {
++ 		if ((!ast_strlen_zero(name2)) || (!ast_strlen_zero(uniqueid2))){
+ 			if (chan2)
+-				res = ast_async_goto(chan2, context, exten, pi);
++ 				res = ast_async_goto(chan2, context2, exten2, pi2);
+ 			else
+ 				res = -1;
+ 			if (!res)
+@@ -936,15 +967,15 @@
+ 	struct ast_channel *chan = NULL;
+ 
+ 	if (!ast_strlen_zero(in->app)) {
+-		res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
++		res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, in->callingpres, 
+ 			!ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
+ 			!ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
+-			in->vars, &chan);
++			in->vars, &chan, in->uniqueid);
+ 	} else {
+-		res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
++		res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, in->callingpres, 
+ 			!ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
+ 			!ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
+-			in->vars, &chan);
++			in->vars, &chan, in->uniqueid);
+ 	}   
+ 	if (!res)
+ 		manager_event(EVENT_FLAG_CALL,
+@@ -955,7 +986,7 @@
+ 			"Exten: %s\r\n"
+ 			"Reason: %d\r\n"
+ 			"Uniqueid: %s\r\n",
+-			in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
++			in->idtext, in->tech, in->data, in->context, in->exten, reason, in->uniqueid ? in->uniqueid : (chan ? chan->uniqueid : "<null>"));
+ 	else
+ 		manager_event(EVENT_FLAG_CALL,
+ 			"OriginateFailure",
+@@ -965,7 +996,7 @@
+ 			"Exten: %s\r\n"
+ 			"Reason: %d\r\n"
+ 			"Uniqueid: %s\r\n",
+-			in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
++			in->idtext, in->tech, in->data, in->context, in->exten, reason, in->uniqueid ? in->uniqueid : (chan ? chan->uniqueid : "<null>"));
+ 
+ 	/* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
+ 	if (chan)
+@@ -998,6 +1029,7 @@
+ 	char *priority = astman_get_header(m, "Priority");
+ 	char *timeout = astman_get_header(m, "Timeout");
+ 	char *callerid = astman_get_header(m, "CallerID");
++ 	char *callingpres = astman_get_header(m, "CallingPres");
+ 	char *account = astman_get_header(m, "Account");
+ 	char *app = astman_get_header(m, "Application");
+ 	char *appdata = astman_get_header(m, "Data");
+@@ -1006,12 +1038,15 @@
+ 	struct ast_variable *vars = astman_get_variables(m);
+ 	char *tech, *data;
+ 	char *l=NULL, *n=NULL;
++ 	char *uniqueid;
+ 	int pi = 0;
++ 	int cpresi = 0;
+ 	int res;
+ 	int to = 30000;
+ 	int reason = 0;
+ 	char tmp[256];
+ 	char tmp2[256];
++ 	char idText[256] = "";
+ 	
+ 	pthread_t th;
+ 	pthread_attr_t attr;
+@@ -1027,6 +1062,10 @@
+ 		astman_send_error(s, m, "Invalid timeout\n");
+ 		return 0;
+ 	}
++	if (!ast_strlen_zero(callingpres) && (sscanf(callingpres, "%d", &cpresi) != 1)) {
++		astman_send_error(s, m, "Invalid CallingPres\n");
++		return 0;
++	}
+ 	ast_copy_string(tmp, name, sizeof(tmp));
+ 	tech = tmp;
+ 	data = strchr(tmp, '/');
+@@ -1053,6 +1092,7 @@
+ 		newvar->next = vars;
+ 		vars = newvar;
+ 	}
++ 	uniqueid = ast_alloc_uniqueid();
+ 	if (ast_true(async)) {
+ 		struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
+ 		if (!fast) {
+@@ -1072,8 +1112,10 @@
+ 			fast->vars = vars;	
+ 			ast_copy_string(fast->context, context, sizeof(fast->context));
+ 			ast_copy_string(fast->exten, exten, sizeof(fast->exten));
++			ast_copy_string(fast->uniqueid, uniqueid, sizeof(fast->uniqueid));
+ 			fast->timeout = to;
+ 			fast->priority = pi;
++			fast->callingpres = cpresi;
+ 			pthread_attr_init(&attr);
+ 			pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ 			if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
+@@ -1083,19 +1125,28 @@
+ 			}
+ 		}
+ 	} else if (!ast_strlen_zero(app)) {
+-        	res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
++        	res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, cpresi, l, n, vars, NULL, uniqueid);
+     	} else {
+ 		if (exten && context && pi)
+-	        	res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
++	        	res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, cpresi, l, n, vars, NULL, uniqueid);
+ 		else {
+ 			astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
+ 			return 0;
+ 		}
+ 	}   
+-	if (!res)
+-		astman_send_ack(s, m, "Originate successfully queued");
+-	else
++ 	if (!res) {
++ 	        if (id && !ast_strlen_zero(id)) {
++          	    snprintf(idText,256,"ActionID: %s\r\n",id);
++  		}
++ 		ast_cli(s->fd, "Response: Success\r\n"
++ 				    "%s"
++ 				   "Message: Originate successfully queued\r\n"
++ 				   "Uniqueid: %s\r\n"
++ 				   "\r\n",
++ 				    idText, uniqueid);
++ 	} else {
+ 		astman_send_error(s, m, "Originate failed");
++	}
+ 	return 0;
+ }
+ 
+diff -urNad asterisk-1.2.0.dfsg/pbx/pbx_spool.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/pbx/pbx_spool.c
+--- asterisk-1.2.0.dfsg/pbx/pbx_spool.c	2005-10-24 22:12:06.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/pbx/pbx_spool.c	2005-11-23 05:50:44.411865103 +0200
+@@ -256,11 +256,11 @@
+ 	if (!ast_strlen_zero(o->app)) {
+ 		if (option_verbose > 2)
+ 			ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
+-		res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, NULL);
++		res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, 0, o->cid_num, o->cid_name, o->vars, NULL, NULL);
+ 	} else {
+ 		if (option_verbose > 2)
+ 			ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
+-		res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, NULL);
++		res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, 0, o->cid_num, o->cid_name, o->vars, NULL, NULL);
+ 	}
+ 	if (res) {
+ 		ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason);
+diff -urNad asterisk-1.2.0.dfsg/pbx.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/pbx.c
+--- asterisk-1.2.0.dfsg/pbx.c	2005-11-14 21:00:38.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/pbx.c	2005-11-23 05:50:44.417864272 +0200
+@@ -350,7 +350,8 @@
+ 	
+ 	{ "Hangup", pbx_builtin_hangup,
+ 	"Hang up the calling channel",
+-	"  Hangup(): This application will hang up the calling channel.\n"
++	"  Hangup(Cause): Unconditionally hangs up a given channel by returning -1 always.\n" 
++	"                 If cause is given, it will set the hangup cause accordingly.\n" 
+ 	},
+ 
+ 	{ "NoOp", pbx_builtin_noop,
+@@ -4949,7 +4950,7 @@
+ 	return 0;  /* success */
+ }
+ 
+-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **channel)
++int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **channel, char *uniqueid)
+ {
+ 	struct ast_channel *chan;
+ 	struct async_stat *as;
+@@ -4959,7 +4960,7 @@
+ 
+ 	if (sync) {
+ 		LOAD_OH(oh);
+-		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++		chan = __ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
+ 		if (channel) {
+ 			*channel = chan;
+ 			if (chan)
+@@ -5055,7 +5056,7 @@
+ 			goto outgoing_exten_cleanup;
+ 		}	
+ 		memset(as, 0, sizeof(struct async_stat));
+-		chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
++		chan = ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
+ 		if (channel) {
+ 			*channel = chan;
+ 			if (chan)
+@@ -5097,7 +5098,7 @@
+ 	pthread_t t;
+ };
+ 
+-static void *ast_pbx_run_app(void *data)
++void *ast_pbx_run_app(void *data)
+ {
+ 	struct app_tmp *tmp = data;
+ 	struct ast_app *app;
+@@ -5113,7 +5114,7 @@
+ 	return NULL;
+ }
+ 
+-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel)
++int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel, char *uniqueid)
+ {
+ 	struct ast_channel *chan;
+ 	struct async_stat *as;
+@@ -5132,7 +5133,8 @@
+ 		goto outgoing_app_cleanup;	
+ 	}
+ 	if (sync) {
+-		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++		chan = __ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
++//		chan = ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
+ 		if (chan) {
+ 			if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
+ 				ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
+@@ -5217,7 +5219,7 @@
+ 			goto outgoing_app_cleanup;
+ 		}
+ 		memset(as, 0, sizeof(struct async_stat));
+-		chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
++		chan = ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
+ 		if (!chan) {
+ 			free(as);
+ 			res = -1;
+@@ -5502,6 +5504,9 @@
+  */
+ static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
+ {
++        /* Copy the hangup cause as specified */
++        if (data)
++	       chan->hangupcause = atoi(data);
+ 	/* Just return non-zero and it will hang up */
+ 	return -1;
+ }
+@@ -6141,6 +6146,9 @@
+ 			return -1;
+ 		}
+ 	}
++	if (chan->_state != AST_STATE_UP) {
++	    ast_answer(chan);
++	}
+ 	return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
+ }
+ 
+@@ -6148,8 +6156,12 @@
+ {
+ 	int res = 0;
+ 
+-	if (data)
++	if (data) {
++		if (chan->_state != AST_STATE_UP) {
++		    ast_answer(chan);
++		}
+ 		res = ast_say_digit_str(chan, (char *)data, "", chan->language);
++	}
+ 	return res;
+ }
+ 	
+@@ -6157,8 +6169,12 @@
+ {
+ 	int res = 0;
+ 
+-	if (data)
++	if (data) {
++		if (chan->_state != AST_STATE_UP) {
++		    ast_answer(chan);
++		}
+ 		res = ast_say_character_str(chan, (char *)data, "", chan->language);
++	}
+ 	return res;
+ }
+ 	
+@@ -6166,8 +6182,12 @@
+ {
+ 	int res = 0;
+ 
+-	if (data)
++	if (data) {
++		if (chan->_state != AST_STATE_UP) {
++		    ast_answer(chan);
++		}
+ 		res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
++	}
+ 	return res;
+ }
+ 	
+diff -urNad asterisk-1.2.0.dfsg/README /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/README
+--- asterisk-1.2.0.dfsg/README	2005-10-19 01:58:36.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/README	2005-11-23 05:50:44.420863856 +0200
+@@ -4,6 +4,8 @@
+ 
+ Copyright (C) 2001-2005 Digium, Inc.
+ and other copyright holders.
++Copyright (C) 2002-2005 Junghanns.NET GmbH 
++and other copyright holders.
+ ================================================================
+ 
+ * SECURITY
+diff -urNad asterisk-1.2.0.dfsg/res/Makefile /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/Makefile
+--- asterisk-1.2.0.dfsg/res/Makefile	2005-11-16 22:49:44.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/Makefile	2005-11-23 05:50:44.423863440 +0200
+@@ -11,7 +11,7 @@
+ # the GNU General Public License
+ #
+ 
+-MODS=res_indications.so res_monitor.so res_adsi.so res_agi.so res_features.so
++MODS=res_indications.so res_monitor.so res_adsi.so res_agi.so res_features.so res_watchdog.so
+ 
+ ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/odbcinst.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/odbcinst.h),)
+   ifneq (${OSARCH},FreeBSD)
+diff -urNad asterisk-1.2.0.dfsg/res/res_agi.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/res_agi.c
+--- asterisk-1.2.0.dfsg/res/res_agi.c	2005-11-08 03:55:30.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/res_agi.c	2005-11-23 05:50:44.427862886 +0200
+@@ -11,6 +11,9 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+  * This program is free software, distributed under the terms of
+  * the GNU General Public License Version 2. See the LICENSE file
+  * at the top of the source tree.
+@@ -74,16 +77,19 @@
+ 
+ static char *app = "AGI";
+ 
++static char *xapp = "XAGI";
++
+ static char *eapp = "EAGI";
+ 
+ static char *deadapp = "DeadAGI";
+ 
+ static char *synopsis = "Executes an AGI compliant application";
++static char *xsynopsis = "Executes an XAGI compliant application";
+ static char *esynopsis = "Executes an EAGI compliant application";
+ static char *deadsynopsis = "Executes AGI on a hungup channel";
+ 
+ static char *descrip =
+-"  [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
++"  [E|Dead|X]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
+ "program on a channel. AGI allows Asterisk to launch external programs\n"
+ "written in any language to control a telephony channel, play audio,\n"
+ "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
+@@ -91,7 +97,9 @@
+ "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
+ " hangup, or 0 on non-hangup exit. \n"
+ "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
+-"on file descriptor 3\n\n"
++" on file descriptor 3\n"
++"Using 'XAGI' provides enhanced AGI, with incoming audio available out of band"
++" on file descriptor 3 and outgoing audio available out of band on file descriptor 4\n\n"
+ "Use the CLI command 'show agi' to list available agi commands\n";
+ 
+ static int agidebug = 0;
+@@ -214,13 +222,14 @@
+ 	return 0;
+ }
+ 
+-static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
++static int launch_script(char *script, char *argv[], int *fds, int *efd, int *efd2, int *opid)
+ {
+ 	char tmp[256];
+ 	int pid;
+ 	int toast[2];
+ 	int fromast[2];
+ 	int audio[2];
++	int audio2[2];
+ 	int x;
+ 	int res;
+ 	sigset_t signal_set;
+@@ -265,6 +274,33 @@
+ 			return -1;
+ 		}
+ 	}
++	if (efd2) {
++		if (pipe(audio2)) {
++			ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
++			close(fromast[0]);
++			close(fromast[1]);
++			close(toast[0]);
++			close(toast[1]);
++			close(audio[0]);
++			close(audio[1]);
++			return -1;
++		}
++		res = fcntl(audio2[0], F_GETFL);
++		if (res > -1) 
++			res = fcntl(audio2[0], F_SETFL, res | O_NONBLOCK);
++		if (res < 0) {
++			ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
++			close(fromast[0]);
++			close(fromast[1]);
++			close(toast[0]);
++			close(toast[1]);
++			close(audio[0]);
++			close(audio[1]);
++			close(audio2[0]);
++			close(audio2[1]);
++			return -1;
++		}
++	}
+ 	pid = fork();
+ 	if (pid < 0) {
+ 		ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
+@@ -279,15 +315,19 @@
+ 		} else {
+ 			close(STDERR_FILENO + 1);
+ 		}
++		if (efd2) {
++			dup2(audio2[1], STDERR_FILENO + 2);
++		} else {
++			close(STDERR_FILENO + 2);
++		}
+ 		
+ 		/* unblock important signal handlers */
+ 		if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
+ 			ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
+ 			exit(1);
+ 		}
+-
+ 		/* Close everything but stdin/out/error */
+-		for (x=STDERR_FILENO + 2;x<1024;x++) 
++		for (x=STDERR_FILENO + 3;x<1024;x++) 
+ 			close(x);
+ 
+ 		/* Don't run AGI scripts with realtime priority -- it causes audio stutter */
+@@ -306,6 +346,9 @@
+ 	if (efd) {
+ 		*efd = audio[1];
+ 	}
++	if (efd2) {
++		*efd2 = audio2[0];
++	}
+ 	/* close what we're not using in the parent */
+ 	close(toast[1]);
+ 	close(fromast[0]);
+@@ -314,6 +357,9 @@
+ 		/* [PHM 12/18/03] */
+ 		close(audio[0]);
+ 	}
++	if (efd2) {
++		close(audio2[1]);
++	}
+ 
+ 	*opid = pid;
+ 	return 0;
+@@ -344,7 +390,7 @@
+ 	fdprintf(fd, "agi_context: %s\n", chan->context);
+ 	fdprintf(fd, "agi_extension: %s\n", chan->exten);
+ 	fdprintf(fd, "agi_priority: %d\n", chan->priority);
+-	fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
++	fdprintf(fd, "agi_enhanced: %d%s\n", enhanced, ".0");
+ 
+ 	/* User information */
+ 	fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
+@@ -376,7 +422,7 @@
+ 		return RESULT_SHOWUSAGE;
+ 	if (sscanf(argv[3], "%d", &to) != 1)
+ 		return RESULT_SHOWUSAGE;
+-	res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
++	res = ast_waitfordigit_full(chan, to, agi->audio_out, agi->ctrl);
+ 	fdprintf(agi->fd, "200 result=%d\n", res);
+ 	if (res >= 0)
+ 		return RESULT_SUCCESS;
+@@ -552,7 +598,7 @@
+ 		else
+ 			return RESULT_FAILURE;
+ 	}
+-	res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
++	res = ast_waitstream_full(chan, argv[3], agi->audio_out, agi->ctrl);
+ 	/* this is to check for if ast_waitstream closed the stream, we probably are at
+ 	 * the end of the stream, return that amount, else check for the amount */
+ 	sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
+@@ -612,7 +658,7 @@
+                 else
+                         return RESULT_FAILURE;
+         }
+-        res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
++        res = ast_waitstream_full(chan, argv[3], agi->audio_out, agi->ctrl);
+         /* this is to check for if ast_waitstream closed the stream, we probably are at
+          * the end of the stream, return that amount, else check for the amount */
+         sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
+@@ -624,7 +670,7 @@
+ 
+ 	/* If the user didnt press a key, wait for digitTimeout*/
+ 	if (res == 0 ) {
+-		res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
++		res = ast_waitfordigit_full(chan, timeout, agi->audio_out, agi->ctrl);
+ 		/* Make sure the new result is in the escape digits of the GET OPTION */
+ 		if ( !strchr(edigits,res) )
+                 	res=0;
+@@ -651,7 +697,7 @@
+ 		return RESULT_SHOWUSAGE;
+ 	if (sscanf(argv[2], "%d", &num) != 1)
+ 		return RESULT_SHOWUSAGE;
+-	res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
++	res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio_out, agi->ctrl);
+ 	if (res == 1)
+ 		return RESULT_SUCCESS;
+ 	fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -671,7 +717,7 @@
+ 	if (sscanf(argv[2], "%d", &num) != 1)
+ 		return RESULT_SHOWUSAGE;
+ 
+-	res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
++	res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl);
+ 	if (res == 1) /* New command */
+ 		return RESULT_SUCCESS;
+ 	fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -688,7 +734,7 @@
+ 	if (argc != 4)
+ 		return RESULT_SHOWUSAGE;
+ 
+-	res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
++	res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl);
+ 	if (res == 1) /* New command */
+ 		return RESULT_SUCCESS;
+ 	fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -778,7 +824,7 @@
+ 	if (argc != 4)
+ 		return RESULT_SHOWUSAGE;
+ 
+-	res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
++	res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl);
+ 	if (res == 1) /* New command */
+ 		return RESULT_SUCCESS;
+ 	fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -805,7 +851,7 @@
+ 		max = atoi(argv[4]); 
+ 	else
+ 		max = 1024;
+-	res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
++	res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio_out, agi->ctrl);
+ 	if (res == 2)			/* New command */
+ 		return RESULT_SUCCESS;
+ 	else if (res == 1)
+@@ -1843,7 +1889,12 @@
+ 	int ms;
+ 	int returnstatus = 0;
+ 	struct ast_frame *f;
++	struct ast_frame fr;
+ 	char buf[2048];
++	char audiobuf[2048];
++	int audiobytes;
++	int fds[2];
++	int enhanced = 0;
+ 	FILE *readf;
+ 	/* how many times we'll retry if ast_waitfor_nandfs will return without either 
+ 	  channel or file descriptor in case select is interrupted by a system call (EINTR) */
+@@ -1857,10 +1908,22 @@
+ 		return -1;
+ 	}
+ 	setlinebuf(readf);
+-	setup_env(chan, request, agi->fd, (agi->audio > -1));
++	if (agi->audio_out > -1) {
++	    enhanced = 1;
++	}
++	if (agi->audio_in > -1) {
++	    enhanced++;
++	}
++	setup_env(chan, request, agi->fd, enhanced);
++	fds[0] = agi->ctrl;
++	fds[1] = agi->audio_in;
+ 	for (;;) {
+ 		ms = -1;
+-		c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
++		if (agi->audio_in > -1) {
++		    c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, fds, 2, NULL, &outfd, &ms);
++		} else {
++		    c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
++		}
+ 		if (c) {
+ 			retry = RETRY;
+ 			/* Idle the channel until we get a command */
+@@ -1871,13 +1934,24 @@
+ 				break;
+ 			} else {
+ 				/* If it's voice, write it to the audio pipe */
+-				if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
++				if ((agi->audio_out > -1) && (f->frametype == AST_FRAME_VOICE)) {
+ 					/* Write, ignoring errors */
+-					write(agi->audio, f->data, f->datalen);
++					write(agi->audio_out, f->data, f->datalen);
+ 				}
+ 				ast_frfree(f);
+ 			}
+ 		} else if (outfd > -1) {
++		    if ((agi->audio_in > -1) && (outfd == agi->audio_in)) {
++			audiobytes = read(agi->audio_in, audiobuf, sizeof(audiobuf));
++			if (audiobytes > 0) {
++			//    ast_log(LOG_NOTICE, "read %d bytes of audio\n", audiobytes);
++			    fr.frametype = AST_FRAME_VOICE;
++			    fr.subclass = AST_FORMAT_SLINEAR;
++			    fr.datalen = audiobytes;
++			    fr.data = audiobuf;
++			    ast_write(chan, &fr);
++			}
++		    } else {
+ 			retry = RETRY;
+ 			if (!fgets(buf, sizeof(buf), readf)) {
+ 				/* Program terminated */
+@@ -1899,6 +1973,7 @@
+ 			if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
+ 				break;
+ 			}
++		    }
+ 		} else {
+ 			if (--retry <= 0) {
+ 				ast_log(LOG_WARNING, "No channel, no fd?\n");
+@@ -2005,6 +2080,7 @@
+ 	int argc = 0;
+ 	int fds[2];
+ 	int efd = -1;
++	int efd2 = -1;
+ 	int pid;
+         char *stringp;
+ 	AGI agi;
+@@ -2031,15 +2107,18 @@
+ 		}
+ 	}
+ #endif
+-	res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
++	res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, (enhanced == 2) ? &efd2 : NULL, &pid);
+ 	if (!res) {
+ 		agi.fd = fds[1];
+ 		agi.ctrl = fds[0];
+-		agi.audio = efd;
++		agi.audio_out = efd;
++		agi.audio_in = efd2;
+ 		res = run_agi(chan, argv[0], &agi, pid, dead);
+ 		close(fds[1]);
+ 		if (efd > -1)
+ 			close(efd);
++		if (efd2 > -1)
++			close(efd2);
+ 	}
+ 	LOCAL_USER_REMOVE(u);
+ 	return res;
+@@ -2073,6 +2152,35 @@
+ 	return res;
+ }
+ 
++static int xagi_exec(struct ast_channel *chan, void *data)
++{
++	int readformat, writeformat;
++	int res;
++
++	if (chan->_softhangup)
++		ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
++	readformat = chan->readformat;
++	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
++		ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
++		return -1;
++	}
++	writeformat = chan->writeformat;
++	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
++		ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
++		return -1;
++	}
++	res = agi_exec_full(chan, data, 2, 0);
++	if (!res) {
++		if (ast_set_read_format(chan, readformat)) {
++			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
++		}
++		if (ast_set_write_format(chan, writeformat)) {
++			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(writeformat));
++		}
++	}
++	return res;
++}
++
+ static int deadagi_exec(struct ast_channel *chan, void *data)
+ {
+ 	return agi_exec_full(chan, data, 0, 1);
+@@ -2102,6 +2210,7 @@
+ 	ast_cli_unregister(&dumpagihtml);
+ 	ast_cli_unregister(&cli_debug);
+ 	ast_cli_unregister(&cli_no_debug);
++	ast_unregister_application(xapp);
+ 	ast_unregister_application(eapp);
+ 	ast_unregister_application(deadapp);
+ 	return ast_unregister_application(app);
+@@ -2115,6 +2224,7 @@
+ 	ast_cli_register(&cli_no_debug);
+ 	ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
+ 	ast_register_application(eapp, eagi_exec, esynopsis, descrip);
++	ast_register_application(xapp, xagi_exec, xsynopsis, descrip);
+ 	return ast_register_application(app, agi_exec, synopsis, descrip);
+ }
+ 
+diff -urNad asterisk-1.2.0.dfsg/res/res_features.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/res_features.c
+--- asterisk-1.2.0.dfsg/res/res_features.c	2005-11-11 01:26:40.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/res_features.c	2005-11-23 05:50:44.433862055 +0200
+@@ -11,6 +11,10 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+  * This program is free software, distributed under the terms of
+  * the GNU General Public License Version 2. See the LICENSE file
+  * at the top of the source tree.
+@@ -56,6 +60,7 @@
+ #include "asterisk/utils.h"
+ #include "asterisk/adsi.h"
+ #include "asterisk/monitor.h"
++#include "asterisk/indications.h"
+ 
+ #ifdef __AST_DEBUG_MALLOC
+ static void FREE(void *ptr)
+@@ -73,6 +78,7 @@
+ #define AST_MAX_WATCHERS 256
+ 
+ static char *parkedcall = "ParkedCall";
++static char *holdedcall = "HoldedCall";
+ 
+ /* No more than 45 seconds parked before you do something with them */
+ static int parkingtime = DEFAULT_PARK_TIME;
+@@ -132,6 +138,20 @@
+ "into the dialplan, although you should include the 'parkedcalls'\n"
+ "context.\n";
+ 
++static char *autoanswerlogin = "AutoanswerLogin";
++
++static char *synopsis3 = "Log in for autoanswer";
++
++static char *descrip3 = "AutoanswerLogin(exten):"
++"Used to login to the autoanswer application for an extension.\n";
++
++static char *autoanswer = "Autoanswer";
++
++static char *synopsis4 = "Autoanswer a call";
++
++static char *descrip4 = "Autoanswer(exten):"
++"Used to autoanswer a call for an extension.\n";
++
+ static struct ast_app *monitor_app=NULL;
+ static int monitor_ok=1;
+ 
+@@ -150,12 +170,51 @@
+ 	struct parkeduser *next;
+ };
+ 
++struct holdeduser {
++	struct ast_channel *chan;
++	struct timeval start;
++	int parkingnum;
++	int cref;
++	int tei;
++	/* Where to go if our parking time expires */
++	char context[AST_MAX_EXTENSION];
++	char exten[AST_MAX_EXTENSION];
++	int priority;
++	int parkingtime;
++	char uniqueid[AST_MAX_UNIQUEID];
++	char uniqueidpeer[AST_MAX_UNIQUEID];
++	struct holdeduser *next;
++};
++
++/* auto answer user */
++struct aauser {
++	struct ast_channel *chan;
++	struct timeval start;
++	/* waiting on this extension/context */
++	char exten[AST_MAX_EXTENSION];
++	char context[AST_MAX_EXTENSION];
++	int priority;
++	int notquiteyet;
++	struct aauser *next;
++};
++
++ 
++static struct aauser *aalot;
++AST_MUTEX_DEFINE_STATIC(autoanswer_lock);
++static pthread_t autoanswer_thread;
++
+ static struct parkeduser *parkinglot;
+ 
++static struct holdeduser *holdlist;
++
+ AST_MUTEX_DEFINE_STATIC(parking_lock);
+ 
++AST_MUTEX_DEFINE_STATIC(holding_lock);
++
+ static pthread_t parking_thread;
+ 
++static pthread_t holding_thread;
++
+ STANDARD_LOCAL_USER;
+ 
+ LOCAL_USER_DECL;
+@@ -165,6 +224,12 @@
+ 	return parking_ext;
+ }
+ 
++char *ast_parking_con(void)
++{
++	return parking_con;
++}
++
++
+ char *ast_pickup_ext(void)
+ {
+ 	return pickup_ext;
+@@ -361,11 +426,12 @@
+ 		"From: %s\r\n"
+ 		"Timeout: %ld\r\n"
+ 		"CallerID: %s\r\n"
+-		"CallerIDName: %s\r\n\r\n"
++		"CallerIDName: %s\r\n"
++		"Unqiueid: %s\r\n\r\n"
+ 		,pu->parkingnum, pu->chan->name, peer->name
+ 		,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
+ 		,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-		,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++		,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+ 		);
+ 
+ 	if (peer) {
+@@ -418,7 +484,8 @@
+ 		ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
+ 		ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
+ 		chan->priority = rchan->priority;
+-
++		/* might be dirty but we want trackable channels */
++		strncpy(chan->uniqueid, rchan->uniqueid, sizeof(chan->uniqueid) - 1);
+ 		/* Make the masq execute */
+ 		f = ast_read(chan);
+ 		if (f)
+@@ -1087,7 +1154,7 @@
+ 	struct ast_frame *f = NULL;
+ 	int res = 0, ready = 0;
+ 	
+-	if ((chan = ast_request(type, format, data, &cause))) {
++	if ((chan = ast_request(type, format, data, &cause, NULL))) {
+ 		ast_set_callerid(chan, cid_num, cid_name, cid_num);
+ 		ast_channel_inherit_variables(caller, chan);	
+ 		if (!ast_call(chan, data, timeout)) {
+@@ -1533,10 +1600,11 @@
+ 					"Exten: %d\r\n"
+ 					"Channel: %s\r\n"
+ 					"CallerID: %s\r\n"
+-					"CallerIDName: %s\r\n\r\n"
++					"CallerIDName: %s\r\n"
++					"Uniqueid: %s\r\n\r\n"
+ 					,pu->parkingnum, pu->chan->name
+ 					,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-					,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++					,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+ 					);
+ 
+ 				if (option_verbose > 1) 
+@@ -1577,10 +1645,11 @@
+ 								"Exten: %d\r\n"
+ 								"Channel: %s\r\n"
+ 								"CallerID: %s\r\n"
+-								"CallerIDName: %s\r\n\r\n"
++								"CallerIDName: %s\r\n"
++								"Uniqueid: %s\r\n\r\n"
+ 								,pu->parkingnum, pu->chan->name
+ 								,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-								,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++								,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+ 								);
+ 
+ 							/* There's a problem, hang them up*/
+@@ -1667,6 +1736,280 @@
+ 	return res;
+ }
+ 
++int ast_hold_call(struct ast_channel *chan, struct ast_channel *peer)
++{
++	/* We put the user in the parking list, then wake up the parking thread to be sure it looks
++	   after these channels too */
++	struct holdeduser *pu;
++	pu = malloc(sizeof(struct holdeduser));
++	if (pu) {
++		memset(pu, 0, sizeof(pu));
++		ast_mutex_lock(&holding_lock);
++		chan->appl = "Holded Call";
++		chan->data = NULL; 
++
++		pu->chan = chan;
++		strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
++		strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
++		/* Start music on hold */
++		ast_moh_start(pu->chan, NULL);
++		gettimeofday(&pu->start, NULL);
++		pu->next = holdlist;
++		holdlist = pu;
++		ast_mutex_unlock(&holding_lock);
++		/* Wake up the (presumably select()ing) thread */
++		pthread_kill(holding_thread, SIGURG);
++
++		manager_event(EVENT_FLAG_CALL, "HoldedCall",
++                            "Channel1: %s\r\n"
++                            "Channel2: %s\r\n"
++                    	    "Uniqueid1: %s\r\n"
++                    	    "Uniqueid2: %s\r\n"
++                            ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
++
++	} else {
++		ast_log(LOG_WARNING, "Out of memory\n");
++		return -1;
++	}
++	return 0;
++}
++
++int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer)
++{
++	struct ast_channel *chan;
++	struct ast_frame *f;
++	/* Make a new, fake channel that we'll use to masquerade in the real one */
++	chan = ast_channel_alloc(0);
++	if (chan) {
++		/* Let us keep track of the channel name */
++		snprintf(chan->name, sizeof (chan->name), "Onhold/%s",rchan->name);
++		/* Make formats okay */
++		chan->readformat = rchan->readformat;
++		chan->writeformat = rchan->writeformat;
++		ast_channel_masquerade(chan, rchan);
++		/* Setup the extensions and such */
++		strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
++		strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
++		chan->priority = rchan->priority;
++		/* this might be dirty, but we need to preserve the uniqueid */
++		strncpy(chan->uniqueid, rchan->uniqueid, sizeof(chan->uniqueid) - 1);
++		/* Make the masq execute */
++		f = ast_read(chan);
++		if (f)
++			ast_frfree(f);
++		ast_hold_call(chan, peer);
++		return -1;
++    	} else {
++		ast_log(LOG_WARNING, "Unable to create holded channel\n");
++		return -1;
++	}
++	return 0;
++}
++
++int ast_retrieve_call(struct ast_channel *chan, char *uniqueid)
++{
++	int res=-1, dres=-1;
++	struct ast_channel *peer=NULL;
++	struct ast_bridge_config config;
++
++	peer = ast_get_holded_call(uniqueid);
++
++	/* JK02: it helps to answer the channel if not already up */
++	if (chan->_state != AST_STATE_UP) {
++		ast_answer(chan);
++	}
++
++	if (peer) {
++		ast_mutex_unlock(&peer->lock);
++		ast_moh_stop(peer);
++		res = ast_channel_make_compatible(chan, peer);
++		if (res < 0) {
++			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
++			ast_hangup(peer);
++			return -1;
++		}
++		/* This runs sorta backwards, since we give the incoming channel control, as if it
++		   were the person called. */
++		if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
++
++		memset(&config,0,sizeof(struct ast_bridge_config));
++		ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
++		ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
++		config.timelimit = 0;
++		config.play_warning = 0;
++		config.warning_freq = 0;
++		config.warning_sound=NULL;
++		res = ast_bridge_call(chan,peer,&config);
++
++		/* Simulate the PBX hanging up */
++		if (res != AST_PBX_NO_HANGUP_PEER)
++			ast_hangup(peer);
++		return res;
++	} else {
++		/* XXX Play a message XXX */
++	  dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
++	  if (!dres)
++	    dres = ast_waitstream(chan, "");
++	  else {
++	    ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
++	    dres = 0;
++	  }
++	}
++	return res;
++}
++
++int ast_retrieve_call_to_death(char *uniqueid)
++{
++	int res=-1;
++	struct ast_channel *peer=NULL;
++
++	peer = ast_get_holded_call(uniqueid);
++
++	if (peer) {
++		res=0;
++		if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
++		ast_mutex_unlock(&peer->lock);
++		ast_hangup(peer);
++	} else {
++		ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
++	}
++	return res;
++}
++
++struct ast_channel *ast_get_holded_call(char *uniqueid)
++{
++	int res=-1;
++	struct ast_channel *peer=NULL;
++	struct holdeduser *pu, *pl=NULL;
++
++	ast_mutex_lock(&holding_lock);
++	pu = holdlist;
++	while(pu) {
++		if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
++			if (pl)
++				pl->next = pu->next;
++			else
++				holdlist = pu->next; 
++			break;
++		}
++		pl = pu;
++		pu = pu->next;
++	}
++	ast_mutex_unlock(&holding_lock);
++	if (pu) {
++		peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
++		free(pu);
++		if (peer) {
++		    res=0;
++		    if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
++		    ast_moh_stop(peer);
++		    return peer;
++		} else {
++		    if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
++		    return NULL;
++		}
++	} else {
++		ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
++	}
++	return NULL;
++}
++
++/* this is our autmagically service thread that keeps channels onhold happy */
++static void *do_holding_thread(void *ignore)
++{
++	int ms, tms, max;
++	struct holdeduser *pu, *pl, *pt = NULL;
++	struct timeval tv;
++	struct ast_frame *f;
++	int x;
++	fd_set rfds, efds;
++	fd_set nrfds, nefds;
++	FD_ZERO(&rfds);
++	FD_ZERO(&efds);
++	for (;;) {
++		ms = -1;
++		max = -1;
++		ast_mutex_lock(&holding_lock);
++		pl = NULL;
++		pu = holdlist;
++		gettimeofday(&tv, NULL);
++		FD_ZERO(&nrfds);
++		FD_ZERO(&nefds);
++		while(pu) {
++			tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
++				for (x=0;x<AST_MAX_FDS;x++) {
++					if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
++				/*		if (FD_ISSET(pu->chan->fds[x], &efds))
++							pu->chan->exception = 1; */
++						pu->chan->fdno = x;
++						/* See if they need servicing */
++						f = ast_read(pu->chan);
++						if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
++							/* There's a problem, hang them up*/
++							if (option_verbose > 1) 
++								ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
++							ast_hangup(pu->chan);
++							/* find the corresponding channel and hang them up too! */
++							/* but only if it is not bridged yet! */
++							/* And take them out of the parking lot */
++							if (pl) 
++								pl->next = pu->next;
++							else
++								holdlist = pu->next;
++							pt = pu;
++							pu = pu->next;
++							free(pt);
++							break;
++						} else {
++							/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
++							ast_frfree(f);
++							goto std;	/* XXX Ick: jumping into an else statement??? XXX */
++						}
++					}
++				}
++				if (x >= AST_MAX_FDS) {
++std:					for (x=0;x<AST_MAX_FDS;x++) {
++						/* Keep this one for next one */
++						if (pu->chan->fds[x] > -1) {
++							FD_SET(pu->chan->fds[x], &nrfds);
++							FD_SET(pu->chan->fds[x], &nefds);
++							if (pu->chan->fds[x] > max)
++								max = pu->chan->fds[x];
++						}
++					}
++					/* Keep track of our longest wait */
++					if ((tms < ms) || (ms < 0))
++						ms = tms;
++					pl = pu;
++					pu = pu->next;
++				}
++		}
++		ast_mutex_unlock(&holding_lock);
++		rfds = nrfds;
++		efds = nefds;
++		tv.tv_sec = ms / 1000;
++		tv.tv_usec = (ms % 1000) * 1000;
++		/* Wait for something to happen */
++		ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
++		pthread_testcancel();
++	}
++	return NULL;	/* Never reached */
++}
++
++static int retrieve_call_exec(struct ast_channel *chan, void *data) {
++	int res=0;
++	struct localuser *u;
++	char *uniqueid = (char *)data;
++	LOCAL_USER_ADD(u);
++	    res = ast_retrieve_call(chan, uniqueid);
++	LOCAL_USER_REMOVE(u);
++	return res;
++}
++
+ static int park_exec(struct ast_channel *chan, void *data)
+ {
+ 	int res=0;
+@@ -1714,10 +2057,11 @@
+ 			"Channel: %s\r\n"
+ 			"From: %s\r\n"
+ 			"CallerID: %s\r\n"
+-			"CallerIDName: %s\r\n\r\n"
++			"CallerIDName: %s\r\n"
++			"Uniqueid: %s\r\n\r\n"
+ 			,pu->parkingnum, pu->chan->name, chan->name
+ 			,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-			,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++			,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+ 			);
+ 
+ 		free(pu);
+@@ -1885,12 +2229,13 @@
+ 			"Timeout: %ld\r\n"
+ 			"CallerID: %s\r\n"
+ 			"CallerIDName: %s\r\n"
++			"Uniqueid: %s\r\n"
+ 			"%s"
+ 			"\r\n"
+                         ,cur->parkingnum, cur->chan->name
+                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
+ 			,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
+-			,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
++			,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : ""), cur->chan->uniqueid
+ 			,idText);
+ 
+             cur = cur->next;
+@@ -1906,6 +2251,386 @@
+         return RESULT_SUCCESS;
+ }
+ 
++static int handle_autoanswer(int fd, int argc, char *argv[])
++{
++	struct aauser *cur;
++
++	ast_cli(fd, "%25s %10s %15s \n", "Channel"
++		, "Extension", "Context");
++
++	ast_mutex_lock(&autoanswer_lock);
++
++	cur=aalot;
++	while(cur) {
++		ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
++
++		cur = cur->next;
++	}
++
++	ast_mutex_unlock(&autoanswer_lock);
++
++	return RESULT_SUCCESS;
++}
++static char showautoanswer_help[] =
++"Usage: show autoanswer\n"
++"       Lists currently logged in autoanswr channels.\n";
++
++static struct ast_cli_entry showautoanswer =
++{ { "show", "autoanswer", NULL }, handle_autoanswer, "Lists autoanswer channels", showautoanswer_help };
++
++int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data)
++{
++	struct ast_channel *chan;
++	struct ast_frame *f;
++	/* Make a new, fake channel that we'll use to masquerade in the real one */
++	chan = ast_channel_alloc(0);
++	if (chan) {
++		/* Let us keep track of the channel name */
++		snprintf(chan->name, sizeof (chan->name), "Autoanswer/%s",rchan->name);
++		/* Make formats okay */
++		chan->readformat = rchan->readformat;
++		chan->writeformat = rchan->writeformat;
++		ast_channel_masquerade(chan, rchan);
++		/* Setup the extensions and such */
++		strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
++		strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
++		chan->priority = rchan->priority;
++		/* Make the masq execute */
++		f = ast_read(chan);
++		if (f)
++			ast_frfree(f);
++		ast_autoanswer_login(chan, data);
++	} else {
++		ast_log(LOG_WARNING, "Unable to create aa channel\n");
++		return -1;
++	}
++	return 0;
++}
++
++static int autoanswer_login_exec(struct ast_channel *chan, void *data)
++{
++	int res=0;
++	struct localuser *u;
++	LOCAL_USER_ADD(u);
++	if (!data) {
++		ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
++		return -1;
++	}
++	res = ast_masq_autoanswer_login(chan, data);
++	LOCAL_USER_REMOVE(u);
++	return res; 
++}
++
++int ast_autoanswer_login(struct ast_channel *chan, void *data)
++{
++	/* We put the user in the parking list, then wake up the parking thread to be sure it looks
++	   after these channels too */
++	struct ast_context *con;
++	char exten[AST_MAX_EXTENSION];
++	struct aauser *pu,*pl = NULL;
++	char *s, *stringp, *aacontext, *aaexten = NULL;
++
++	s = ast_strdupa((void *) data);
++	stringp=s;
++	aacontext = strsep(&stringp, "|");
++	aaexten = strsep(&stringp, "|");
++	if (!aaexten) {
++	    aaexten = aacontext;
++	    aacontext = NULL;
++	}
++	if (!aaexten) {
++		ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
++		return -1;
++	} else {
++		if (!aacontext) {
++			aacontext = "default";
++		}
++	}
++
++	ast_mutex_lock(&autoanswer_lock);
++	pu = aalot;
++	while(pu) {
++		if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
++			if (pl)
++				pl->next = pu->next;
++			else
++				aalot = pu->next;
++			break;
++		}
++		pl = pu;
++		pu = pu->next;
++	}
++	ast_mutex_unlock(&autoanswer_lock);
++	if (pu) {
++	    ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
++	    manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
++                    			    "Channel: %s\r\n"
++                    			    "Uniqueid: %s\r\n"
++                    			    "Context: %s\r\n"
++                    			    "Exten: %s\r\n"
++                    			,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++	    ast_hangup(pu->chan);
++	    free(pu);
++	}
++	pu = malloc(sizeof(struct aauser));
++	if (pu) {
++		memset(pu, 0, sizeof(pu));
++		ast_mutex_lock(&autoanswer_lock);
++		chan->appl = "Autoanswer";
++		chan->data = NULL; 
++
++		pu->chan = chan;
++		if (chan->_state != AST_STATE_UP) {
++		    ast_answer(chan);
++		}
++
++		/* Start music on hold */
++		ast_moh_start(pu->chan, NULL);
++		gettimeofday(&pu->start, NULL);
++		strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
++		strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
++		pu->next = aalot;
++		aalot = pu;
++		con = ast_context_find(aacontext);
++		if (!con) {
++			con = ast_context_create(NULL,aacontext, registrar);
++			if (!con) {
++				ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
++			}
++		}
++		if (con) {
++			snprintf(exten, sizeof(exten), "%s", aaexten);
++			ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
++		}
++
++		ast_mutex_unlock(&autoanswer_lock);
++		/* Wake up the (presumably select()ing) thread */
++		pthread_kill(autoanswer_thread, SIGURG);
++		if (option_verbose > 1) 
++			ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
++			manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
++                                "Channel: %s\r\n"
++                                "Uniqueid: %s\r\n"
++        			"Context: %s\r\n"
++                    		"Exten: %s\r\n"
++                    		,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++
++			return 0;
++	} else {
++		ast_log(LOG_WARNING, "Out of memory\n");
++		return -1;
++	}
++	return 0;
++}
++
++static void *do_autoanswer_thread(void *ignore)
++{
++	int ms, tms, max;
++	struct ast_context *con;
++	char exten[AST_MAX_EXTENSION];
++	struct aauser *pu, *pl, *pt = NULL;
++	struct timeval tv;
++	struct ast_frame *f;
++	int x;
++	fd_set rfds, efds;
++	fd_set nrfds, nefds;
++	FD_ZERO(&rfds);
++	FD_ZERO(&efds);
++	for (;;) {
++		ms = -1;
++		max = -1;
++		ast_mutex_lock(&autoanswer_lock);
++		pl = NULL;
++		pu = aalot;
++		gettimeofday(&tv, NULL);
++		FD_ZERO(&nrfds);
++		FD_ZERO(&nefds);
++		while(pu) {
++			tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
++			for (x=0;x<AST_MAX_FDS;x++) {
++				if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
++/*					if (FD_ISSET(pu->chan->fds[x], &efds))
++						pu->chan->exception = 1; */
++					pu->chan->fdno = x;
++					/* See if they need servicing */
++					f = ast_read(pu->chan);
++					if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
++						/* There's a problem, hang them up*/
++						if (option_verbose > 1) 
++							ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
++						manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
++                            			    "Channel: %s\r\n"
++                            			    "Uniqueid: %s\r\n"
++                    				    "Context: %s\r\n"
++                    				    "Exten: %s\r\n"
++                    				,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++						ast_hangup(pu->chan);
++						con = ast_context_find(pu->context);
++						if (con) {
++						    snprintf(exten, sizeof(exten), "%s", pu->exten);
++						    if (ast_context_remove_extension2(con, exten, 1, registrar))
++							ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
++						} else {
++							ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
++						}
++						/* And take them out of the parking lot */
++						if (pl) 
++							pl->next = pu->next;
++						else
++							aalot = pu->next;
++						pt = pu;
++						pu = pu->next;
++						free(pt);
++						break;
++					} else {
++						/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
++						ast_frfree(f);
++						goto std;	/* XXX Ick: jumping into an else statement??? XXX */
++					}
++				}
++			}
++			if (x >= AST_MAX_FDS) {
++std:				for (x=0;x<AST_MAX_FDS;x++) {
++					/* Keep this one for next one */
++					if (pu->chan->fds[x] > -1) {
++						FD_SET(pu->chan->fds[x], &nrfds);
++						FD_SET(pu->chan->fds[x], &nefds);
++						if (pu->chan->fds[x] > max)
++							max = pu->chan->fds[x];
++					}
++				}
++				/* Keep track of our longest wait */
++				if ((tms < ms) || (ms < 0))
++					ms = tms;
++				pl = pu;
++				pu = pu->next;
++			}
++		}
++		ast_mutex_unlock(&autoanswer_lock);
++		rfds = nrfds;
++		efds = nefds;
++		tv.tv_sec = ms / 1000;
++		tv.tv_usec = (ms % 1000) * 1000;
++		/* Wait for something to happen */
++		ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
++		pthread_testcancel();
++	}
++	return NULL;	/* Never reached */
++}
++
++static int autoanswer_exec(struct ast_channel *chan, void *data)
++{
++	int res=0;
++	struct localuser *u;
++	struct ast_channel *peer=NULL;
++	struct aauser *pu, *pl=NULL;
++	struct ast_bridge_config config;
++	char *s, *stringp, *aacontext, *aaexten = NULL;
++	char datastring[80];
++
++	if (!data) {
++		ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
++		return -1;
++	}
++	s = ast_strdupa((void *) data);
++	stringp=s;
++	aacontext = strsep(&stringp, "|");
++	aaexten = strsep(&stringp, "|");
++	if (!aaexten) {
++	    aaexten = aacontext;
++	    aacontext = NULL;
++	}
++	if (!aaexten) {
++		ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
++		return -1;
++	} else {
++		if (!aacontext) {
++			aacontext = "default";
++		}
++	}
++
++	LOCAL_USER_ADD(u);
++	ast_mutex_lock(&autoanswer_lock);
++	pu = aalot;
++	while(pu) {
++		if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
++			if (pl)
++				pl->next = pu->next;
++			else
++				aalot = pu->next;
++			break;
++		}
++		pl = pu;
++		pu = pu->next;
++	}
++	ast_mutex_unlock(&autoanswer_lock);
++	if (pu) {
++		peer = pu->chan;
++		free(pu);
++		pu = NULL;
++	}
++	/* JK02: it helps to answer the channel if not already up */
++	if (chan->_state != AST_STATE_UP) {
++		ast_answer(chan);
++	}
++
++	if (peer) {
++		ast_moh_stop(peer);
++		/* Play a courtesy beep in the callED channel to prefix the bridge connecting */	
++		if (!ast_strlen_zero(courtesytone)) {
++			if (!ast_streamfile(peer, courtesytone, peer->language)) {
++				if (ast_waitstream(peer, "") < 0) {
++					ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
++					ast_hangup(peer);
++					return -1;
++				}
++			}
++		}
++ 
++		res = ast_channel_make_compatible(chan, peer);
++		if (res < 0) {
++			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
++			ast_hangup(peer);
++			return -1;
++		}
++		/* This runs sorta backwards, since we give the incoming channel control, as if it
++		   were the person called. */
++		if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered  %s\n", peer->name, chan->name);
++		manager_event(EVENT_FLAG_CALL, "Autoanswer",
++                    "Channel: %s\r\n"
++                    "Uniqueid: %s\r\n"
++                    "Channel2: %s\r\n"
++                    "Uniqueid2: %s\r\n"
++                    "Context: %s\r\n"
++                    "Exten: %s\r\n"
++                ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
++
++
++		memset(&config,0,sizeof(struct ast_bridge_config));
++		ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
++		ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
++		config.timelimit = 0;
++		config.play_warning = 0;
++		config.warning_freq = 0;
++		config.warning_sound=NULL;
++		res = ast_bridge_call(chan,peer,&config);
++
++		if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
++			/* relogin */
++		snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
++		ast_autoanswer_login(peer, datastring);
++		return res;
++	} else {
++		if (option_verbose > 2) 
++			ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
++		res = -1;
++	}
++	LOCAL_USER_REMOVE(u);
++	return res;
++}
++
+ 
+ int ast_pickup_call(struct ast_channel *chan)
+ {
+@@ -2135,14 +2860,22 @@
+ 	if ((res = load_config()))
+ 		return res;
+ 	ast_cli_register(&showparked);
++	ast_cli_register(&showautoanswer);
+ 	ast_cli_register(&showfeatures);
+ 	ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
++	ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL);
+ 	res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
+ 	if (!res)
+ 		res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
+ 	if (!res) {
+ 		ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
+ 	}
++	res = ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
++	ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
++	if (!res)
++		res = ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
++	if (!res)
++		res = ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4);
+ 	return res;
+ }
+ 
+@@ -2153,7 +2886,11 @@
+ 
+ 	ast_manager_unregister("ParkedCalls");
+ 	ast_cli_unregister(&showfeatures);
++ 	ast_cli_unregister(&showautoanswer);
+ 	ast_cli_unregister(&showparked);
++ 	ast_unregister_application(autoanswer);
++ 	ast_unregister_application(autoanswerlogin);
++ 	ast_unregister_application(holdedcall);
+ 	ast_unregister_application(parkcall);
+ 	return ast_unregister_application(parkedcall);
+ }
+diff -urNad asterisk-1.2.0.dfsg/res/res_watchdog.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/res_watchdog.c
+--- asterisk-1.2.0.dfsg/res/res_watchdog.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/res/res_watchdog.c	2005-11-23 05:50:44.436861639 +0200
+@@ -0,0 +1,148 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Resource to make watchdogs happy
++ *
++ * Copyright (C) 2005, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/time.h>
++#include <sys/signal.h>
++#include <netinet/in.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/options.h>
++#include <asterisk/module.h>
++#include <asterisk/translate.h>
++#include <asterisk/say.h>
++#include <asterisk/features.h>
++#include <asterisk/musiconhold.h>
++#include <asterisk/config.h>
++#include <asterisk/cli.h>
++#include <asterisk/manager.h>
++#include <asterisk/utils.h>
++#include <asterisk/adsi.h>
++
++static struct watchdog_pvt *watchdogs = NULL;
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++typedef struct watchdog_pvt {
++    char device[80];
++    int fd;
++    int type;
++    int interval;
++    pthread_t watchdog_thread;
++    struct watchdog_pvt *next;
++} watchdog_pvt;
++
++static void *do_watchdog_thread(void *data) {
++    struct watchdog_pvt *woof = (struct watchdog_pvt *)data;
++    for (;;) {
++	if (woof->fd) {
++	    write(woof->fd, "PING\n", 1);
++	}
++	usleep(woof->interval * 1000);
++    }
++    return NULL;
++}
++
++
++int load_module(void)
++{
++	int res = 0;
++	char *cat, *utype, *udevice, *uinterval;
++	struct ast_config *cfg;
++	struct watchdog_pvt *woof = NULL;
++
++	cfg = ast_config_load("watchdog.conf");
++	if (cfg) {
++	    cat = ast_category_browse(cfg, NULL);
++	    while(cat) {
++		cat = ast_category_browse(cfg, cat);
++		utype = ast_variable_retrieve(cfg, cat, "type");
++		if (utype) {
++		    ast_log(LOG_NOTICE, "type = %s\n", utype);
++		}
++		udevice = ast_variable_retrieve(cfg, cat, "device");
++		if (udevice) {
++		    ast_log(LOG_NOTICE, "device = %s\n", udevice);
++		}
++		uinterval = ast_variable_retrieve(cfg, cat, "interval");
++		if (uinterval) {
++		    ast_log(LOG_NOTICE, "interval = %s\n", uinterval);
++		}
++		if (uinterval && udevice && utype) {
++		    woof = malloc(sizeof(struct watchdog_pvt));
++		    if (!woof) {
++			ast_log(LOG_ERROR, "unable to malloc!\n");
++			return -1;
++		    }
++		    memset(woof, 0x0, sizeof(struct watchdog_pvt));
++		    strncpy(woof->device, udevice, sizeof(woof->device) - 1);
++		    
++		    woof->interval = atoi(uinterval);;
++		    woof->next = watchdogs;
++		    watchdogs = woof;
++		    woof->fd = open(woof->device, O_WRONLY | O_SYNC);
++		    if (woof->fd) {
++			if (!strncmp(utype, "isdnguard", sizeof(utype))) {
++			    woof->type = 1;
++			    write(woof->fd, "START\n", 6);
++			}
++			ast_pthread_create(&woof->watchdog_thread, NULL, do_watchdog_thread, woof);
++		    } else {
++			ast_log(LOG_WARNING, "error opening watchdog device %s !\n", woof->device);
++		    }
++		}
++	    }
++    	    ast_config_destroy(cfg);
++	}
++	return res;
++}
++
++
++int unload_module(void)
++{
++	struct watchdog_pvt *dogs, *woof;
++	STANDARD_HANGUP_LOCALUSERS;
++	dogs = watchdogs;
++	while (dogs) {
++	    pthread_cancel(dogs->watchdog_thread);
++	    woof = dogs->next;
++	    free(dogs);
++	    dogs = woof;
++	}
++	return 0;
++}
++
++char *description(void)
++{
++	return "Watchdog Resource";
++}
++
++int usecount(void)
++{
++	return 1;
++}
++
++char *key()
++{
++	return ASTERISK_GPL_KEY;
++}
+diff -urNad asterisk-1.2.0.dfsg/rtp.c /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/rtp.c
+--- asterisk-1.2.0.dfsg/rtp.c	2005-11-11 06:07:03.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/rtp.c	2005-11-23 05:50:44.439861223 +0200
+@@ -442,6 +442,11 @@
+ 	struct rtpPayloadType rtpPT;
+ 	
+ 	len = sizeof(sin);
++
++	/* XXX SYMPTON CURE, DIRTY FIX, CHECK, BEGIN */
++	if (!rtp)
++	    return &null_frame;
++	/* XXX SYMPTON CURE, DIRTY FIX, CHECK, END */
+ 	
+ 	/* Cache where the header will go */
+ 	res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
+diff -urNad asterisk-1.2.0.dfsg/.version /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/.version
+--- asterisk-1.2.0.dfsg/.version	2005-11-17 07:37:05.000000000 +0200
++++ /tmp/dpep.xhUJBp/asterisk-1.2.0.dfsg/.version	2005-11-23 05:50:44.442860808 +0200
+@@ -1 +1 @@
+-1.2.0
++1.2.0-BRIstuffed-0.3.0-PRE-1


Property changes on: asterisk/trunk/debian/patches/bristuff.dpatch
___________________________________________________________________
Name: svn:executable
   + *




More information about the Pkg-voip-commits mailing list