+++ /dev/null
---- a/README
-+++ b/README
-@@ -4,6 +4,8 @@ and the Asterisk.org developer community
-
- Copyright (C) 2001-2006 Digium, Inc.
- and other copyright holders.
-+Copyright (C) 2002-2005 Junghanns.NET GmbH
-+and other copyright holders.
- ================================================================
-
- * SECURITY
---- a/LICENSE
-+++ b/LICENSE
-@@ -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.
-
---- a/doc/hardware.txt
-+++ b/doc/hardware.txt
-@@ -31,6 +31,19 @@ Zaptel compatible hardware
- * Wildcard TE410P - Quad T1/E1 switchable interface. Supports PRI and
- RBS signalling, as well as PPP, FR, and HDLC data modes.
-
-+-- Junghanns.NET (Primary author of BRIstuff)
-+ 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
-+
-+ * uno/duo/quad GSM PCI - 1/2/4 channel GSM interface cards
-+
- Non-zaptel compatible hardware
- ==============================
-
---- a/build_tools/make_defaults_h
-+++ b/build_tools/make_defaults_h
-@@ -17,6 +17,7 @@ cat << END
- #define AST_KEY_DIR "${INSTALL_PATH}${ASTDATADIR}/keys"
- #define AST_DB "${INSTALL_PATH}${ASTVARLIBDIR}/astdb"
- #define AST_TMP_DIR "${INSTALL_PATH}${ASTSPOOLDIR}/tmp"
-+#define AST_SYSTEM_NAME "asterisk"
-
- #define AST_CONFIG_FILE "${INSTALL_PATH}${ASTCONFPATH}"
-
---- a/main/asterisk.c
-+++ b/main/asterisk.c
-@@ -2427,6 +2427,7 @@ static void ast_readconfig(void)
- 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_SYSTEM_NAME, AST_SYSTEM_NAME, sizeof(ast_config_AST_SYSTEM_NAME));
-
- /* no asterisk.conf? no problem, use buildtime config! */
- if (!cfg) {
-@@ -2551,6 +2552,8 @@ static void ast_readconfig(void)
- ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
- } else if (!strcasecmp(v->name, "systemname")) {
- ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
-+ } else if (!strcasecmp(v->name, "uniquename")) {
-+ ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
- } else if (!strcasecmp(v->name, "languageprefix")) {
- ast_language_is_prefix = ast_true(v->value);
- }
---- a/include/asterisk/agi.h
-+++ b/include/asterisk/agi.h
-@@ -30,6 +30,7 @@ extern "C" {
- typedef struct agi_state {
- int fd; /* FD for general output */
- int audio; /* FD for audio output */
-+ int audio_in; /* FD for audio output */
- int ctrl; /* FD for input control */
- unsigned int fast:1; /* flag for fast agi or not */
- } AGI;
---- a/res/res_agi.c
-+++ b/res/res_agi.c
-@@ -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@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.
-@@ -75,16 +78,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
-
- 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"
-@@ -97,6 +103,8 @@ static char *descrip =
- "variable to \"no\" before executing the AGI application.\n"
- " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
- "on file descriptor 3\n\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 'agi show' to list available agi commands\n"
- " This application sets the following channel variable upon completion:\n"
- " AGISTATUS The status of the attempt to the run the AGI script\n"
-@@ -236,13 +244,14 @@ static enum agi_result launch_netscript(
- return AGI_RESULT_SUCCESS_FAST;
- }
-
--static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
-+static enum agi_result 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, old_set;
-@@ -287,6 +296,33 @@ static enum agi_result launch_script(cha
- return AGI_RESULT_FAILURE;
- }
- }
-+ 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 AGI_RESULT_FAILURE;
-+ }
-+ 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 AGI_RESULT_FAILURE;
-+ }
-+ }
-
- /* Block SIGHUP during the fork - prevents a race */
- sigfillset(&signal_set);
-@@ -322,6 +358,11 @@ static enum agi_result launch_script(cha
- } else {
- close(STDERR_FILENO + 1);
- }
-+ if (efd2) {
-+ dup2(audio2[1], STDERR_FILENO + 2);
-+ } else {
-+ close(STDERR_FILENO + 2);
-+ }
-
- /* Before we unblock our signals, return our trapped signals back to the defaults */
- signal(SIGHUP, SIG_DFL);
-@@ -339,7 +380,7 @@ static enum agi_result launch_script(cha
- }
-
- /* Close everything but stdin/out/error */
-- for (x=STDERR_FILENO + 2;x<1024;x++)
-+ for (x=STDERR_FILENO + 3;x<1024;x++)
- close(x);
-
- /* Execute script */
-@@ -359,12 +400,19 @@ static enum agi_result launch_script(cha
- 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]);
-
-- if (efd)
-+ if (efd) {
- close(audio[0]);
-+ }
-+ if (efd2) {
-+ close(audio2[1]);
-+ }
-
- *opid = pid;
- return AGI_RESULT_SUCCESS;
-@@ -394,7 +442,7 @@ static void setup_env(struct ast_channel
- 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 : "");
-@@ -1835,8 +1883,13 @@ static enum agi_result run_agi(struct as
- int ms;
- enum agi_result returnstatus = AGI_RESULT_SUCCESS;
- struct ast_frame *f;
-+ struct ast_frame fr;
- char buf[AGI_BUF_LEN];
-+ char audiobuf[AGI_BUF_LEN];
- char *res = NULL;
-+ 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) */
-@@ -1850,10 +1903,22 @@ static enum agi_result run_agi(struct as
- return AGI_RESULT_FAILURE;
- }
- setlinebuf(readf);
-- setup_env(chan, request, agi->fd, (agi->audio > -1));
-+ if (agi->audio > -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 = AGI_NANDFS_RETRY;
- /* Idle the channel until we get a command */
-@@ -1871,6 +1936,16 @@ static enum agi_result run_agi(struct as
- 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) {
-+ fr.frametype = AST_FRAME_VOICE;
-+ fr.subclass = AST_FORMAT_SLINEAR;
-+ fr.datalen = audiobytes;
-+ fr.data = audiobuf;
-+ ast_write(chan, &fr);
-+ }
-+ } else {
- size_t len = sizeof(buf);
- size_t buflen = 0;
-
-@@ -1922,6 +1997,7 @@ static enum agi_result run_agi(struct as
- if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
- break;
- }
-+ }
- } else {
- if (--retry <= 0) {
- ast_log(LOG_WARNING, "No channel, no fd?\n");
-@@ -2030,6 +2106,7 @@ static int agi_exec_full(struct ast_chan
- int argc = 0;
- int fds[2];
- int efd = -1;
-+ int efd2 = -1;
- int pid;
- char *stringp;
- AGI agi;
-@@ -2056,12 +2133,13 @@ static int agi_exec_full(struct ast_chan
- }
- #endif
- ast_replace_sigchld();
-- 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_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
- int status = 0;
- agi.fd = fds[1];
- agi.ctrl = fds[0];
- agi.audio = efd;
-+ agi.audio_in = efd2;
- agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
- res = run_agi(chan, argv[0], &agi, pid, &status, dead);
- /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
-@@ -2071,6 +2149,8 @@ static int agi_exec_full(struct ast_chan
- close(fds[1]);
- if (efd > -1)
- close(efd);
-+ if (efd2 > -1)
-+ close(efd2);
- }
- ast_unreplace_sigchld();
- ast_module_user_remove(u);
-@@ -2119,6 +2199,35 @@ static int eagi_exec(struct ast_channel
- 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)
- {
- if (!ast_check_hangup(chan))
-@@ -2174,6 +2283,7 @@ static int unload_module(void)
- {
- ast_module_user_hangup_all();
- ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
-+ ast_unregister_application(xapp);
- ast_unregister_application(eapp);
- ast_unregister_application(deadapp);
- return ast_unregister_application(app);
-@@ -2184,6 +2294,7 @@ static int load_module(void)
- ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
- 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);
- }
-
---- /dev/null
-+++ b/agi/xagi-test.c
-@@ -0,0 +1,175 @@
-+/*
-+ * Asterisk -- A telephony toolkit for Linux.
-+ *
-+ * XAGI sample script
-+ *
-+ * Copyright (C) 2005 Junghanns.NET GmbH
-+ * Klaus-Peter Junghanns <kpj@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;
-+ }
-+ astresp[strlen(astresp) - 1] = '\0';
-+ fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
-+ return;
-+ }
-+ 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;
-+ 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);
-+}
---- a/agi/Makefile
-+++ b/agi/Makefile
-@@ -13,7 +13,7 @@
-
- .PHONY: clean all uninstall
-
--AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi
-+AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi xagi-test
-
- ifeq ($(OSARCH),SunOS)
- LIBS+=-lsocket -lnsl
-@@ -38,7 +38,7 @@ uninstall:
- for x in $(AGIS); do rm -f $(DESTDIR)$(AGI_DIR)/$$x ; done
-
- clean:
-- rm -f *.so *.o look eagi-test eagi-sphinx-test
-+ rm -f *.so *.o look eagi-test eagi-sphinx-test xagi-test
- rm -f .*.o.d .*.oo.d *.s *.i
- rm -f strcompat.c
-
---- /dev/null
-+++ b/apps/app_segfault.c
-@@ -0,0 +1,55 @@
-+/*
-+ * 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@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 "asterisk.h"
-+
-+#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 *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";
-+
-+static int segfault_exec(struct ast_channel *chan, void *data)
-+{
-+ ((char *)0)[0] = 0;
-+ return 0;
-+}
-+
-+static int unload_module(void)
-+{
-+ return ast_unregister_application(app);
-+}
-+
-+static int load_module(void)
-+{
-+ return ast_register_application(app, segfault_exec, synopsis, descrip);
-+}
-+
-+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Application for crashing Asterisk with a segmentation fault",
-+ .load = load_module,
-+ .unload = unload_module,
-+);
---- a/apps/app_directed_pickup.c
-+++ b/apps/app_directed_pickup.c
-@@ -45,7 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
-
- #define PICKUPMARK "PICKUPMARK"
-
--static const char *app = "Pickup";
-+static const char *app = "DPickup";
- static const char *synopsis = "Directed Call Pickup";
- static const char *descrip =
- " Pickup(extension[@context][&extension2@context...]): This application can pickup any ringing channel\n"
---- /dev/null
-+++ b/apps/app_pickup.c
-@@ -0,0 +1,300 @@
-+/*
-+ * Asterisk -- A telephony toolkit for Linux.
-+ *
-+ * Pickup, channel independent call pickup
-+ *
-+ * Copyright (C) 2004, Junghanns.NET GmbH
-+ *
-+ * Klaus-Peter Junghanns <kpj@junghanns.net>
-+ *
-+ * Copyright (C) 2004, Florian Overkamp <florian@obsimref.com>
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License
-+ */
-+
-+#include "asterisk.h"
-+
-+#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 *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";
-+
-+
-+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';
-+ }
-+ /* 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 ast_module_user *u;
-+ if (!data || !strlen(data)) {
-+ pickupgroup = chan->pickupgroup;
-+ } else {
-+ pickupgroup = ast_get_group(data);
-+ }
-+ u = ast_module_user_add(chan);
-+ if (!res) {
-+ res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 1);
-+ }
-+ if (res > 0)
-+ res = 0;
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
-+static int steal_exec(struct ast_channel *chan, void *data)
-+{
-+ int res=0;
-+ unsigned int pickupgroup=0;
-+ struct ast_module_user *u;
-+ if (!data || !strlen(data)) {
-+ pickupgroup = chan->pickupgroup;
-+ } else {
-+ pickupgroup = ast_get_group(data);
-+ }
-+ u = ast_module_user_add(chan);
-+ if (!res) {
-+ res = my_pickup_call(chan, pickupgroup, AST_STATE_UP, 1);
-+ }
-+ if (res > 0)
-+ res = 0;
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
-+static int pickdown_exec(struct ast_channel *chan, void *data)
-+{
-+ int res=0;
-+ unsigned int pickupgroup=0;
-+ struct ast_module_user *u;
-+ if (!data || !strlen(data)) {
-+ pickupgroup = chan->pickupgroup;
-+ } else {
-+ pickupgroup = ast_get_group(data);
-+ }
-+ u = ast_module_user_add(chan);
-+ if (!res) {
-+ res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 0);
-+ }
-+ if (res > 0)
-+ res = 0;
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
-+static int pickupchan_exec(struct ast_channel *chan, void *data) {
-+ int res=0;
-+ struct ast_module_user *u;
-+ if (!data) {
-+ ast_log(LOG_WARNING, "PickupChan requires an argument (technology1/number1&technology2/number2...)\n");
-+ return -1;
-+ }
-+ u = ast_module_user_add(chan);
-+ if (!res) {
-+ res = my_pickup_channel(chan, data, AST_STATE_RINGING, 1);
-+ }
-+ if (res > 0)
-+ res = 0;
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
-+static int stealchan_exec(struct ast_channel *chan, void *data)
-+{
-+ int res=0;
-+ struct ast_module_user *u;
-+ if (!data) {
-+ ast_log(LOG_WARNING, "StealChan requires an argument (technology1/number1&technology2/number2...)\n");
-+ return -1;
-+ }
-+
-+ u = ast_module_user_add(chan);
-+ if (!res) {
-+ res = my_pickup_channel(chan, data, AST_STATE_UP, 1);
-+ }
-+ if (res > 0)
-+ res = 0;
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
-+
-+static int unload_module(void)
-+{
-+ ast_module_user_hangup_all();
-+ ast_unregister_application(app5);
-+ ast_unregister_application(app4);
-+ ast_unregister_application(app3);
-+ ast_unregister_application(app2);
-+ return ast_unregister_application(app);
-+}
-+
-+static 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);
-+}
-+
-+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PickUp/PickDown/Steal/PickupChan/StealChan",
-+ .load = load_module,
-+ .unload = unload_module,
-+);
---- /dev/null
-+++ b/apps/app_devstate.c
-@@ -0,0 +1,202 @@
-+/*
-+ * 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 "asterisk.h"
-+
-+#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/astdb.h"
-+#include "asterisk/cli.h"
-+#include "asterisk/manager.h"
-+#include "asterisk/devicestate.h"
-+#include "asterisk/module.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 };
-+
-+
-+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)
-+{
-+ char *device, *state, *info;
-+ char devName[128];
-+ struct ast_module_user *u;
-+
-+
-+ if (!(info = ast_strdupa(data))) {
-+ ast_log(LOG_WARNING, "Unable to dupe data :(\n");
-+ return -1;
-+ }
-+
-+ u = ast_module_user_add(chan);
-+ 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);
-+
-+ ast_module_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_begin = NULL,
-+ .send_digit_end = 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, const struct message *m)
-+{
-+ const char *devstate = astman_get_header(m, "Devstate");
-+ const char *value = astman_get_header(m, "Value");
-+ const char *id = astman_get_header(m,"ActionID");
-+ char devName[128];
-+ char idText[256] = "";
-+
-+ 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_strlen_zero(id))
-+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
-+
-+ if (!ast_db_put("DEVSTATES", devstate, (char *)value)) {
-+ snprintf(devName, sizeof(devName), "DS/%s", devstate);
-+ ast_device_state_changed_literal(devName);
-+ astman_append(s, "Response: Success\r\n%s\r\n", idText);
-+ } else {
-+ ast_log(LOG_DEBUG, "ast_db_put failed\n");
-+ astman_append(s, "Response: Failed\r\n%s\r\n", idText);
-+ }
-+ return 0;
-+}
-+
-+static 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);
-+}
-+
-+static int unload_module(void)
-+{
-+ int res = 0;
-+
-+ ast_module_user_hangup_all();
-+ ast_manager_unregister( "Devstate");
-+ ast_cli_unregister(&cli_dev_state);
-+ res = ast_unregister_application(app);
-+ ast_channel_unregister(&devstate_tech);
-+ return res;
-+}
-+
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Devstate Application");
-+
---- /dev/null
-+++ b/configs/watchdog.conf.sample
-@@ -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
-+
---- /dev/null
-+++ b/res/res_watchdog.c
-@@ -0,0 +1,137 @@
-+/*
-+ * Asterisk -- A telephony toolkit for Linux.
-+ *
-+ * Resource to make watchdogs happy
-+ *
-+ * Copyright (C) 2005, Junghanns.NET GmbH
-+ *
-+ * Klaus-Peter Junghanns <kpj@junghanns.net>
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License
-+ */
-+
-+#include "asterisk.h"
-+#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/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/lock.h>
-+#include <asterisk/adsi.h>
-+
-+static struct watchdog_pvt *watchdogs = NULL;
-+
-+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", 5);
-+ }
-+ usleep(woof->interval * 1000);
-+ }
-+ return NULL;
-+}
-+
-+
-+static int load_module(void)
-+{
-+ int res = 0;
-+ const 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;
-+}
-+
-+
-+static int unload_module(void)
-+{
-+ struct watchdog_pvt *dogs, *woof;
-+ dogs = watchdogs;
-+ while (dogs) {
-+ pthread_cancel(dogs->watchdog_thread);
-+ pthread_join(dogs->watchdog_thread, NULL);
-+ close(dogs->fd);
-+ woof = dogs->next;
-+ free(dogs);
-+ dogs = woof;
-+ }
-+ return 0;
-+}
-+
-+
-+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Watchdog Resource",
-+ .load = load_module,
-+ .unload = unload_module,
-+);
---- a/main/db.c
-+++ b/main/db.c
-@@ -574,7 +574,7 @@ static int manager_dbget(struct mansessi
- astman_append(s, "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);
-@@ -582,11 +582,35 @@ static int manager_dbget(struct mansessi
- return 0;
- }
-
-+static int manager_dbdel(struct mansession *s, const struct message *m)
-+{
-+ const char *family = astman_get_header(m, "Family");
-+ const char *key = astman_get_header(m, "Key");
-+
-+ 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)) {
-+ astman_send_error(s, m, "Failed to delete entry");
-+ } else {
-+ astman_send_ack(s, m, "Deleted entry successfully");
-+ }
-+
-+ return 0;
-+}
-+
- int astdb_init(void)
- {
- dbinit();
- ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
-- 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, "Get DB Entry");
-+ ast_manager_register("DBput", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
-+ ast_manager_register("DBdel", EVENT_FLAG_SYSTEM, manager_dbdel, "Delete DB Entry");
- return 0;
- }
---- /dev/null
-+++ b/configs/esel.conf.sample
-@@ -0,0 +1,12 @@
-+;
-+; Configuration file for res_esel
-+;
-+
-+;[asterisk-2]
-+;host = 192.168.0.1
-+;port = 5038
-+;username = manager
-+;secret = donkey
-+
-+; export the extension snom in context phones to DS/100
-+;export => snom@phones,100
---- /dev/null
-+++ b/res/res_esel.c
-@@ -0,0 +1,384 @@
-+/*
-+ * Asterisk -- A telephony toolkit for Linux.
-+ *
-+ * Extension State Export Logic (E.S.E.L) (Sorry, i couldnt resist...)
-+ *
-+ * Resource to export extension states to other Asterisk servers
-+ *
-+ * Copyright (C) 2006, Junghanns.NET GmbH
-+ *
-+ * Klaus-Peter Junghanns <kpj@junghanns.net>
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License
-+ */
-+
-+#include "asterisk.h"
-+
-+#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 <sys/types.h>
-+#include <sys/socket.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/lock.h"
-+#include "asterisk/adsi.h"
-+
-+
-+AST_MUTEX_DEFINE_STATIC(listlock);
-+
-+typedef struct esel_extension_state {
-+ char context[AST_MAX_EXTENSION];
-+ char exten[AST_MAX_EXTENSION];
-+ int state;
-+ char devstate[AST_MAX_EXTENSION];
-+ struct esel_extension_state *next;
-+ struct esel_extension_state *prev;
-+} esel_extension_state;
-+
-+typedef struct esel_export {
-+ char context[AST_MAX_EXTENSION];
-+ char exten[AST_MAX_EXTENSION];
-+ char devstate[AST_MAX_EXTENSION];
-+ struct esel_export *next;
-+} esel_export;
-+
-+typedef struct esel_queue {
-+ struct esel_extension_state *head;
-+ struct esel_extension_state *tail;
-+ int count;
-+ ast_cond_t cond;
-+ ast_mutex_t lock;
-+} esel_queue;
-+
-+typedef struct esel_pvt {
-+ char name[80];
-+ char username[80];
-+ char secret[80];
-+ char host[80];
-+ int port;
-+ struct sockaddr_in raddr;
-+ int sockfd;
-+ int connected;
-+ pthread_t esel_thread;
-+
-+ /* list of extensions to export */
-+ struct esel_export *extensions;
-+
-+ /* queue */
-+ struct esel_queue queue;
-+
-+ struct esel_pvt *next;
-+} esel_pvt;
-+
-+static struct esel_pvt *donkeys = NULL;
-+
-+static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data) {
-+ struct esel_extension_state *exstate = NULL;
-+
-+ exstate = malloc(sizeof(struct esel_extension_state));
-+ if (!exstate) {
-+ ast_log(LOG_ERROR, "Unable to malloc!\n");
-+ return 1;
-+ }
-+ memset(exstate,0,sizeof(struct esel_extension_state));
-+ exstate->next = NULL;
-+ exstate->prev = NULL;
-+
-+ ast_mutex_lock(&queue->lock);
-+ if (queue->count > 100) {
-+ ast_mutex_unlock(&queue->lock);
-+ free(exstate);
-+ if (option_verbose > 5)
-+ ast_log(LOG_WARNING, "E.S.E.L Queue too long.\n");
-+ return -1;
-+ }
-+ ast_copy_string(exstate->exten, exten, sizeof(exstate->exten));
-+ ast_copy_string(exstate->context, context, sizeof(exstate->context));
-+ exstate->state = state;
-+ if (!queue->head) {
-+ /* Empty queue */
-+ queue->head = exstate;
-+ queue->tail = exstate;
-+ } else {
-+ /* Double link */
-+ queue->tail->next = exstate;
-+ exstate->prev = queue->tail;
-+ queue->tail = exstate;
-+ }
-+ queue->count++;
-+ ast_cond_signal(&queue->cond);
-+ ast_mutex_unlock(&queue->lock);
-+ return 0;
-+}
-+
-+static int esel_is_exported(struct esel_export *extensions, struct esel_extension_state *exstate) {
-+ struct esel_export *export = NULL;
-+ export = extensions;
-+ while (export) {
-+ if ((!strcasecmp(export->exten, exstate->exten)) && (!strcasecmp(export->context, exstate->context))) {
-+ /* copy mapping */
-+ ast_copy_string(exstate->devstate, export->devstate, sizeof(exstate->devstate));
-+ return 1;
-+ }
-+ export = export->next;
-+ }
-+ return 0;
-+}
-+
-+static int esel_state2devstate(int state) {
-+ switch(state) {
-+ case 1:
-+ return 2;
-+ case 8:
-+ return 6;
-+ default:
-+ return state;
-+ }
-+}
-+
-+static void esel_export_to_remote(struct esel_extension_state *exstate, struct esel_pvt *esel) {
-+ char msg[1024];
-+ int sent = 0;
-+ memset(msg, 0x0, sizeof(msg));
-+ snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state));
-+ sent = send(esel->sockfd, msg, strlen(msg), 0);
-+ if (sent == -1) {
-+ esel->connected = 0;
-+ }
-+// ast_log(LOG_NOTICE, "%s", msg);
-+}
-+
-+static void *do_esel_thread(void *data) {
-+ struct esel_pvt *esel = (struct esel_pvt *)data;
-+ struct esel_queue *queue = &esel->queue;
-+ struct esel_extension_state *exstate = NULL;
-+ char msg[1024];
-+ char buf[1024];
-+ int numbytes = 0;
-+ int sent = 0;
-+ int res = 0;
-+ for (;;) {
-+ if (esel->connected) {
-+ ast_mutex_lock(&queue->lock);
-+ if (queue->count == 0)
-+ ast_cond_wait(&queue->cond, &queue->lock);
-+ exstate = queue->head;
-+ if (exstate) {
-+ if (exstate->next) {
-+ queue->head = exstate->next;
-+ } else {
-+ queue->head = NULL;
-+ queue->tail = NULL;
-+ }
-+ queue->count--;
-+ } else {
-+ ast_log(LOG_ERROR, "I SHOULD NEVER HAPPEN! EXPECT SOME MAJOR KABOOM! DUCK AND COVER!\n");
-+ }
-+ ast_mutex_unlock(&queue->lock);
-+
-+ if (exstate) {
-+ if (esel_is_exported(esel->extensions, exstate)) {
-+ esel_export_to_remote(exstate, esel);
-+ }
-+ free(exstate);
-+ exstate = NULL;
-+ }
-+ } else {
-+ if (esel->sockfd > 0)
-+ close(esel->sockfd);
-+ if ((esel->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
-+ ast_log(LOG_ERROR, "unable to request socket!\n");
-+ return NULL;
-+ }
-+ /* try to connect */
-+ res = connect(esel->sockfd, (struct sockaddr *)&esel->raddr, sizeof(struct sockaddr));
-+ if (res) {
-+ ast_log(LOG_NOTICE, "error connecting to %s:%d\n", esel->host, esel->port);
-+ } else {
-+ while (strncasecmp(buf, "Asterisk Call Manager:", 21)) {
-+ if ((numbytes=recv(esel->sockfd, buf, sizeof(buf), 0)) == -1) {
-+ esel->connected = 0;
-+ continue;
-+ }
-+ buf[numbytes] = '\0';
-+ // ast_log(LOG_NOTICE, "read: %s", buf);
-+ }
-+ /* log into remote manager */
-+ memset(msg, 0x0, sizeof(msg));
-+ snprintf(msg, sizeof(msg) - 1, "Action: Login\r\nUsername: %s\r\nSecret: %s\r\n\r\n", esel->username, esel->secret);
-+ sent = send(esel->sockfd, msg, strlen(msg), 0);
-+
-+ while (strncasecmp(buf, "Response:", 9)) {
-+ if ((numbytes=recv(esel->sockfd, buf, sizeof(buf), 0)) == -1) {
-+ continue;
-+ }
-+ buf[numbytes] = '\0';
-+ // ast_log(LOG_NOTICE, "read: %s", buf);
-+ }
-+
-+ if (!strncasecmp(buf, "Response: Success", 17)) {
-+ esel->connected = 1;
-+ } else {
-+ ast_log(LOG_ERROR, "error login into remote asterisk %s\n", esel->name);
-+ }
-+ }
-+ /* time heals everything... */
-+ sleep(10);
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static int esel_state_cb(char *context, char *exten, int state, void *data) {
-+ struct esel_pvt *esel;
-+
-+ esel = donkeys;
-+ ast_mutex_lock(&listlock);
-+ while (esel) {
-+ esel_queue_extension_state(&esel->queue, context, exten, state, data);
-+ esel = esel->next;
-+ }
-+ ast_mutex_unlock(&listlock);
-+ return 0;
-+}
-+
-+
-+static int load_module(void)
-+{
-+ int res = 0;
-+ const char *cat, *host, *port, *username, *secret, *name;
-+ struct ast_config *cfg;
-+ struct ast_variable *var;
-+ struct esel_pvt *esel = NULL;
-+ struct esel_export *export = NULL;
-+ struct hostent *he;
-+ struct ast_hostent h;
-+
-+ cfg = ast_config_load("esel.conf");
-+ if (cfg) {
-+ cat = ast_category_browse(cfg, NULL);
-+ while(cat) {
-+ name = cat;
-+ host = ast_variable_retrieve(cfg, cat, "host");
-+ username = ast_variable_retrieve(cfg, cat, "username");
-+ secret = ast_variable_retrieve(cfg, cat, "secret");
-+ port = ast_variable_retrieve(cfg, cat, "port");
-+
-+ if (name && host && username && secret && port) {
-+ esel = malloc(sizeof(struct esel_pvt));
-+ if (!esel) {
-+ ast_log(LOG_ERROR, "unable to malloc!\n");
-+ return -1;
-+ }
-+ memset(esel, 0x0, sizeof(struct esel_pvt));
-+ ast_copy_string(esel->name, name, sizeof(esel->name));
-+ ast_copy_string(esel->host, host, sizeof(esel->host));
-+ ast_copy_string(esel->username, username, sizeof(esel->username));
-+ ast_copy_string(esel->secret, secret, sizeof(esel->secret));
-+
-+ esel->port = atoi(port);
-+ if ((he=ast_gethostbyname(host, &h)) == NULL) {
-+ ast_log(LOG_ERROR, "unknown host!\n");
-+ return -1;
-+ }
-+
-+ esel->raddr.sin_family = AF_INET;
-+ esel->raddr.sin_port = htons(esel->port);
-+ esel->raddr.sin_addr = *((struct in_addr *)he->h_addr);
-+ bzero(&(esel->raddr.sin_zero), 8);
-+
-+ esel->connected = 0;
-+
-+ ast_mutex_init(&esel->queue.lock);
-+ ast_cond_init(&esel->queue.cond, NULL);
-+
-+
-+ /* read exports */
-+ var = ast_variable_browse(cfg, cat);
-+ while (var) {
-+ if (!strcasecmp(var->name, "export")) {
-+ char *extenp = NULL, *contextp = NULL, *devstatep = NULL;
-+ extenp = var->value;
-+ devstatep = strchr(var->value, ',') + 1;
-+ contextp = strchr(var->value, '@') + 1;
-+ if (devstatep && contextp) {
-+ export = malloc(sizeof(struct esel_export));
-+ if (!export) {
-+ ast_log(LOG_ERROR, "unable to malloc!\n");
-+ return -1;
-+ }
-+ memset(export, 0x0, sizeof(struct esel_export));
-+ ast_copy_string(export->exten, extenp, contextp - extenp);
-+ ast_copy_string(export->context, contextp, devstatep - contextp);
-+ ast_copy_string(export->devstate, devstatep, sizeof(export->devstate));
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_3 "exporting %s @ %s as %s to %s\n", export->exten, export->context , export->devstate , esel->name);
-+ export->next = esel->extensions;
-+ esel->extensions = export;
-+ export = NULL;
-+ }
-+ }
-+ var = var->next;
-+ }
-+
-+
-+
-+ esel->next = donkeys;
-+ donkeys = esel;
-+
-+ ast_pthread_create(&esel->esel_thread, NULL, do_esel_thread, esel);
-+
-+ }
-+ cat = ast_category_browse(cfg, cat);
-+ }
-+ ast_config_destroy(cfg);
-+ }
-+ ast_extension_state_add(NULL, NULL, esel_state_cb, NULL);
-+ return res;
-+}
-+
-+
-+static int unload_module(void)
-+{
-+ struct esel_pvt *esel, *eseln;
-+ ast_module_user_hangup_all();
-+ esel = donkeys;
-+ ast_mutex_lock(&listlock);
-+ while (esel) {
-+ pthread_cancel(esel->esel_thread);
-+ pthread_join(esel->esel_thread, NULL);
-+ ast_mutex_destroy(&esel->queue.lock);
-+ close(esel->sockfd);
-+ eseln = esel->next;
-+ free(esel);
-+ esel = eseln;
-+ }
-+ ast_mutex_unlock(&listlock);
-+ return 0;
-+}
-+
-+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Extension State Export Logic (E.S.E.L.) Resource",
-+ .load = load_module,
-+ .unload = unload_module,
-+);
---- a/channels/chan_iax2.c
-+++ b/channels/chan_iax2.c
-@@ -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@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.
-@@ -3362,7 +3365,7 @@ static int iax2_hangup(struct ast_channe
- ast_mutex_lock(&iaxsl[callno]);
- if (callno && iaxs[callno]) {
- if (option_debug)
-- 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);
-@@ -3416,7 +3419,8 @@ static int iax2_setoption(struct ast_cha
-
- static struct ast_frame *iax2_read(struct ast_channel *c)
- {
-- ast_log(LOG_NOTICE, "I should never be called!\n");
-+ if (option_verbose > 3)
-+ ast_log(LOG_NOTICE, "I should never be called!\n");
- return &ast_null_frame;
- }
-
---- a/apps/app_zapras.c
-+++ b/apps/app_zapras.c
-@@ -183,7 +183,7 @@ static void run_ras(struct ast_channel *
- }
- }
- /* Throw back into audio mode */
-- x = 1;
-+ x = 0;
- ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
-
- /* Restore saved values */
---- a/main/channel.c
-+++ b/main/channel.c
-@@ -3898,6 +3898,10 @@ enum ast_bridge_result ast_channel_bridg
- 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) ||
---- a/apps/app_meetme.c
-+++ b/apps/app_meetme.c
-@@ -1405,8 +1405,9 @@ static int conf_run(struct ast_channel *
- char members[10] = "";
- int dtmf, opt_waitmarked_timeout = 0;
- time_t timeout = 0;
-+ int dyna_buff = CONF_SIZE;
- ZT_BUFFERINFO bi;
-- char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
-+ char __buf[ZT_MAX_BUF_SPACE / ZT_DEFAULT_NUM_BUFS + AST_FRIENDLY_OFFSET];
- char *buf = __buf + AST_FRIENDLY_OFFSET;
- int setusercount = 0;
-
-@@ -1615,7 +1616,7 @@ static int conf_run(struct ast_channel *
- }
- /* Setup buffering information */
- memset(&bi, 0, sizeof(bi));
-- bi.bufsize = CONF_SIZE/2;
-+ bi.bufsize = dyna_buff / 2;
- bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.numbufs = audio_buffers;
-@@ -1926,6 +1927,14 @@ static int conf_run(struct ast_channel *
- f = ast_read(c);
- if (!f)
- break;
-+ if (f->datalen && f->datalen != dyna_buff) {
-+ ast_log(LOG_NOTICE, "Audio bytes: %d Buffer size: %d\n", f->datalen, dyna_buff);
-+ if (f->datalen < ZT_MAX_BUF_SPACE/audio_buffers) { /* skip too large frame to avoid overflow */
-+ dyna_buff = f->datalen;
-+ close(fd);
-+ goto zapretry;
-+ }
-+ }
- if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
- if (user->talk.actual)
- ast_frame_adjust_volume(f, user->talk.actual);
-Answer the channel before saying things (SayNumber, SayDigits,
-SayCharacters, SayPhonetic).
-
---- a/main/pbx.c
-+++ b/main/pbx.c
-@@ -6076,6 +6076,9 @@ static int pbx_builtin_saynumber(struct
- return -1;
- }
- }
-+ if (chan->_state != AST_STATE_UP) {
-+ ast_answer(chan);
-+ }
-
- if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
- ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
-@@ -6088,8 +6091,12 @@ static int pbx_builtin_saydigits(struct
- {
- int res = 0;
-
-- if (data)
-+ if (data) {
-+ if (chan->_state != AST_STATE_UP) {
-+ ast_answer(chan);
-+ }
- res = ast_say_digit_str(chan, data, "", chan->language);
-+ }
- return res;
- }
-
-@@ -6097,8 +6104,12 @@ static int pbx_builtin_saycharacters(str
- {
- int res = 0;
-
-- if (data)
-+ if (data) {
-+ if (chan->_state != AST_STATE_UP) {
-+ ast_answer(chan);
-+ }
- res = ast_say_character_str(chan, data, "", chan->language);
-+ }
- return res;
- }
-
-@@ -6106,8 +6117,12 @@ static int pbx_builtin_sayphonetic(struc
- {
- int res = 0;
-
-- if (data)
-+ if (data) {
-+ if (chan->_state != AST_STATE_UP) {
-+ ast_answer(chan);
-+ }
- res = ast_say_phonetic_str(chan, data, "", chan->language);
-+ }
- return res;
- }
-
---- a/apps/app_dial.c
-+++ b/apps/app_dial.c
-@@ -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@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.
-@@ -130,7 +134,8 @@ static char *descrip =
- " H - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
- " i - Asterisk will ignore any forwarding requests it may receive on this\n"
- " dial attempt.\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"
- " k - Allow the called party to enable parking of the call by sending\n"
- " the DTMF sequence defined for call parking in features.conf.\n"
- " K - Allow the calling party to enable parking of the call by sending\n"
-@@ -1292,14 +1297,16 @@ static int dial_exec_full(struct ast_cha
- }
-
- if (!outgoing) {
-- strcpy(status, "CHANUNAVAIL");
-+ ast_copy_string(status, "CHANUNAVAIL", sizeof(status));
- if(fulldial == num_dialed) {
- res = -1;
- goto out;
- }
-+ /* See if there is a special message */
-+ ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
- } else {
- /* Our status will at least be NOANSWER */
-- strcpy(status, "NOANSWER");
-+ ast_copy_string(status, "NOANSWER", sizeof(status));
- if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
- moh = 1;
- if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
---- a/apps/app_dial.c
-+++ b/apps/app_dial.c
-@@ -71,6 +71,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
- #include "asterisk/privacy.h"
- #include "asterisk/stringfields.h"
- #include "asterisk/global_datastores.h"
-+#include "asterisk/transcap.h"
-
- static char *app = "Dial";
-
-@@ -1652,23 +1653,25 @@ static int dial_exec_full(struct ast_cha
- ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
- if (play_to_callee)
- ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
-- if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
-+ if ((chan->transfercapability != AST_TRANS_CAP_DIGITAL) && (chan->transfercapability != AST_TRANS_CAP_RESTRICTED_DIGITAL)) {
-+ /* only non-digital calls are allowed to go through userspace */
-+ if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
- ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
-- if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
-+ if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
- ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
-- if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
-+ if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
- ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
-- if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
-+ if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
- ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
-- if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
-+ if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
- ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
-- if (ast_test_flag(peerflags, OPT_CALLER_MONITOR))
-+ if (ast_test_flag(peerflags, OPT_CALLER_MONITOR))
- ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
-- if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
-+ if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
- ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
-- if (ast_test_flag(peerflags, OPT_CALLER_PARK))
-+ if (ast_test_flag(peerflags, OPT_CALLER_PARK))
- ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
--
-+ }
- config.timelimit = timelimit;
- config.play_warning = play_warning;
- config.warning_freq = warning_freq;
---- a/apps/app_dial.c
-+++ b/apps/app_dial.c
-@@ -198,6 +198,8 @@ static char *descrip =
- " 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"
- " t - Allow the called party to transfer the calling party by sending the\n"
-@@ -254,6 +256,7 @@ enum {
- OPT_CALLEE_PARK = (1 << 25),
- OPT_CALLER_PARK = (1 << 26),
- OPT_IGNORE_FORWARDING = (1 << 27),
-+ OPT_NOINBAND = (1 << 28),
- } dial_exec_option_flags;
-
- #define DIAL_STILLGOING (1 << 30)
-@@ -297,6 +300,7 @@ AST_APP_OPTIONS(dial_exec_options, {
- 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_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
- AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
- AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
-@@ -412,7 +416,7 @@ static struct ast_channel *wait_for_answ
- int orig = *to;
- struct ast_channel *peer = NULL;
- /* single is set if only one destination is enabled */
-- int single = outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
-+ int single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK | OPT_NOINBAND));
-
- if (single) {
- /* Turn off hold music, etc */
-@@ -633,7 +637,7 @@ static struct ast_channel *wait_for_answ
- /* Setup early media if appropriate */
- if (single && CAN_EARLY_BRIDGE(peerflags))
- ast_rtp_early_bridge(in, c);
-- if (!ast_test_flag(outgoing, OPT_RINGBACK))
-+ if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND))
- ast_indicate(in, AST_CONTROL_PROGRESS);
- break;
- case AST_CONTROL_VIDUPDATE:
-@@ -651,7 +655,7 @@ static struct ast_channel *wait_for_answ
- ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", c->name, in->name);
- if (single && CAN_EARLY_BRIDGE(peerflags))
- ast_rtp_early_bridge(in, c);
-- if (!ast_test_flag(outgoing, OPT_RINGBACK))
-+ if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND))
- ast_indicate(in, AST_CONTROL_PROCEEDING);
- break;
- case AST_CONTROL_HOLD:
-@@ -669,7 +673,7 @@ static struct ast_channel *wait_for_answ
- /* Ignore going off hook and flash */
- break;
- case -1:
-- if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
-+ if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK | OPT_NOINBAND)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "%s stopped sounds\n", c->name);
- ast_indicate(in, -1);
-@@ -1091,7 +1095,7 @@ static int dial_exec_full(struct ast_cha
- outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
- }
-
-- ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING);
-+ ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_NOINBAND);
- /* loop through the list of dial destinations */
- rest = args.peers;
- while ((cur = strsep(&rest, "&")) ) {
-@@ -1116,7 +1120,7 @@ static int dial_exec_full(struct ast_cha
- OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
- OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
- OPT_CALLEE_PARK | OPT_CALLER_PARK |
-- OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
-+ OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_NOINBAND);
- ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);
- }
- ast_copy_string(numsubst, number, sizeof(numsubst));
-@@ -1319,7 +1323,7 @@ static int dial_exec_full(struct ast_cha
- ast_moh_start(chan, NULL, NULL);
- }
- ast_indicate(chan, AST_CONTROL_PROGRESS);
-- } else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
-+ } else if (ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND)) {
- ast_indicate(chan, AST_CONTROL_RINGING);
- sentringing++;
- }
-@@ -1442,7 +1446,7 @@ static int dial_exec_full(struct ast_cha
-
- if (ast_test_flag(&opts, OPT_MUSICBACK)) {
- ast_moh_stop(chan);
-- } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
-+ } else if (ast_test_flag(&opts, OPT_RINGBACK | OPT_NOINBAND)) {
- ast_indicate(chan, -1);
- sentringing=0;
- }
---- a/apps/app_dial.c
-+++ b/apps/app_dial.c
-@@ -201,7 +201,8 @@ static char *descrip =
- " 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 defined in features.conf.\n"
- " T - Allow the calling party to transfer the called party by sending the\n"
-@@ -257,6 +258,7 @@ enum {
- OPT_CALLER_PARK = (1 << 26),
- OPT_IGNORE_FORWARDING = (1 << 27),
- OPT_NOINBAND = (1 << 28),
-+ OPT_CALLBACK_INIT = (1 << 29),
- } dial_exec_option_flags;
-
- #define DIAL_STILLGOING (1 << 30)
-@@ -301,6 +303,7 @@ AST_APP_OPTIONS(dial_exec_options, {
- 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),
-@@ -621,14 +624,20 @@ static struct ast_channel *wait_for_answ
- HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
- break;
- case AST_CONTROL_RINGING:
-- if (option_verbose > 2)
-+ if (ast_test_flag(peerflags, OPT_CALLBACK_INIT)) {
-+ if (option_verbose > 2)
-+ ast_verbose( VERBOSE_PREFIX_3 "%s is ringing, hanging up.\n", o->chan->name);
-+ return NULL;
-+ } else {
-+ if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", c->name);
-- /* Setup early media if appropriate */
-- if (single && CAN_EARLY_BRIDGE(peerflags))
-+ /* Setup early media if appropriate */
-+ if (single && CAN_EARLY_BRIDGE(peerflags))
- ast_rtp_early_bridge(in, c);
-- if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
-+ if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
- ast_indicate(in, AST_CONTROL_RINGING);
- (*sentringing)++;
-+ }
- }
- break;
- case AST_CONTROL_PROGRESS:
-@@ -1095,7 +1104,7 @@ static int dial_exec_full(struct ast_cha
- outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
- }
-
-- ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_NOINBAND);
-+ ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_CALLBACK_INIT | OPT_NOINBAND);
- /* loop through the list of dial destinations */
- rest = args.peers;
- while ((cur = strsep(&rest, "&")) ) {
-# Allow as many spans as Zaptel can take (defualt: 128).
-# There is a static array of zt_pris allocated at this size.
-# For that reason upstream only sort-of merged it: made it a
-# compile-time option in 1.6 .
-
---- a/channels/chan_zap.c
-+++ b/channels/chan_zap.c
-@@ -190,7 +190,7 @@ static const char config[] = "zapata.con
- #define SIG_GR303FXOKS (0x0100000 | ZT_SIG_FXOKS)
- #define SIG_GR303FXSKS (0x0100000 | ZT_SIG_FXSKS)
-
--#define NUM_SPANS 32
-+#define NUM_SPANS ZT_MAX_SPANS
- #define NUM_DCHANS 4 /*!< No more than 4 d-channels */
- #define MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
-
---- a/include/asterisk/channel.h
-+++ b/include/asterisk/channel.h
-@@ -435,6 +435,7 @@ struct ast_channel {
- unsigned int flags; /*!< channel flags of AST_FLAG_ type */
- unsigned short transfercapability; /*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
- AST_LIST_HEAD_NOLOCK(, ast_frame) readq;
-+ char lowlayercompat[16]; /*!< ISDN Low Layer Compatibility */
- int alertpipe[2];
-
- int nativeformats; /*!< Kinds of data this channel can natively handle */
---- a/channels/chan_zap.c
-+++ b/channels/chan_zap.c
-@@ -11,6 +11,10 @@
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
-+ * Copyright (C) 2003-2006 Junghanns.NET GmbH
-+ * Klaus-Peter Junghanns <kpj@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.
-@@ -216,8 +220,6 @@ static struct ast_channel inuse;
- #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) */
-@@ -235,10 +237,6 @@ AST_MUTEX_DEFINE_STATIC(iflock);
-
- static int ifcount = 0;
-
--#ifdef HAVE_PRI
--AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
--#endif
--
- /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
- AST_MUTEX_DEFINE_STATIC(monlock);
-@@ -253,6 +251,7 @@ static enum ast_bridge_result zt_bridge(
-
- static int zt_sendtext(struct ast_channel *c, const char *text);
-
-+
- /*! \brief Avoid the silly zt_getevent which ignores a bunch of events */
- static inline int zt_get_event(int fd)
- {
-@@ -297,6 +296,14 @@ static int ringt_base = DEFAULT_RINGT;
- #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_pri {
- pthread_t master; /*!< Thread of master */
- ast_mutex_t lock; /*!< Mutex */
-@@ -310,6 +317,8 @@ struct zt_pri {
- int nsf; /*!< Network-Specific Facilities */
- int dialplan; /*!< Dialing plan */
- int localdialplan; /*!< Local dialing plan */
-+ char nocid[AST_MAX_EXTENSION]; /*!< CallerID string to use if none provided */
-+ char withheldcid[AST_MAX_EXTENSION]; /*!< CallerID string to use if CallerID is withheld */
- 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) */
-@@ -321,6 +330,7 @@ struct zt_pri {
- int prilogicalspan; /*!< Logical span number within trunk group */
- int numchans; /*!< Num of channels we represent */
- int overlapdial; /*!< In overlap dialing mode */
-+ int usercid;
- int facilityenable; /*!< Enable facility IEs */
- struct pri *dchans[NUM_DCHANS]; /*!< Actual d-channels */
- int dchanavail[NUM_DCHANS]; /*!< Whether each channel is available */
-@@ -336,6 +346,8 @@ struct zt_pri {
- 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 */
-+ int debugfd;
- };
-
-
-@@ -453,6 +465,8 @@ static struct zt_pvt {
- 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;
-@@ -467,7 +481,8 @@ static struct zt_pvt {
- 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 pritransfer:2;
- unsigned int priexclusive:1;
- unsigned int pulse:1;
- unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */
-@@ -504,6 +519,7 @@ static struct zt_pvt {
- #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];
-@@ -569,6 +585,8 @@ static struct zt_pvt {
- struct zt_pvt *bearer;
- struct zt_pvt *realcall;
- q931_call *call;
-+ int tei; /* channel in use by this tei */
-+ q931_call *holdedcall;
- int prioffset;
- int logicalspan;
- #endif
-@@ -614,11 +632,14 @@ static struct zt_chan_conf zt_chan_conf_
- .minunused = 2,
- .idleext = "",
- .idledial = "",
-+ .nocid = "No CID available",
-+ .withheldcid = "CID withheld",
- .internationalprefix = "",
- .nationalprefix = "",
- .localprefix = "",
- .privateprefix = "",
- .unknownprefix = "",
-+ .usercid = 0,
-
- .resetinterval = 3600
- },
-@@ -630,6 +651,8 @@ static struct zt_chan_conf zt_chan_conf_
- .mohinterpret = "default",
- .mohsuggest = "",
- .transfertobusy = 1,
-+ .priindication_oob = 0,
-+ .pritransfer = 0,
-
- .cid_signalling = CID_SIG_BELL,
- .cid_start = CID_START_RING,
-@@ -684,6 +707,8 @@ static int zt_indicate(struct ast_channe
- 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_func_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len);
-+static void enable_dtmf_detect(struct zt_pvt *p);
-+static void disable_dtmf_detect(struct zt_pvt *p);
-
- static const struct ast_channel_tech zap_tech = {
- .type = "Zap",
-@@ -715,6 +740,13 @@ static const struct ast_channel_tech zap
- struct zt_pvt *round_robin[32];
-
- #ifdef HAVE_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;
-@@ -1417,12 +1449,16 @@ static void zt_enable_ec(struct zt_pvt *
- 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) {
-@@ -1449,7 +1485,7 @@ static void zt_train_ec(struct zt_pvt *p
- {
- 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)
-@@ -1810,7 +1846,12 @@ static int zt_call(struct ast_channel *a
- 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, 0, 0, p->law);
-+ } else {
-+ set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
-+ }
-+
-
- mysig = p->sig;
- if (p->outsigmod > -1)
-@@ -2041,6 +2082,7 @@ static int zt_call(struct ast_channel *a
- case SIG_PRI:
- /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
- p->dialdest[0] = '\0';
-+ disable_dtmf_detect(p);
- break;
- default:
- ast_log(LOG_DEBUG, "not yet implemented\n");
-@@ -2061,6 +2103,12 @@ static int zt_call(struct ast_channel *a
- const char *rr_str;
- int redirect_reason;
-
-+ 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++;
-@@ -2083,6 +2131,7 @@ static int zt_call(struct ast_channel *a
- ast_mutex_unlock(&p->lock);
- return -1;
- }
-+ strncpy(p->dnid, (c + p->stripmsd), sizeof(p->dnid)-1);
- if (mysig != SIG_FXSKS) {
- p->dop.op = ZT_DIAL_OP_REPLACE;
- s = strchr(c + p->stripmsd, 'w');
-@@ -2106,6 +2155,8 @@ static int zt_call(struct ast_channel *a
- 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);
-@@ -2135,7 +2186,7 @@ static int zt_call(struct ast_channel *a
- pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1);
- pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability,
- (p->digital ? -1 :
-- ((p->law == ZT_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)));
-+ ((p->law == ZT_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)), ast->lowlayercompat);
- if (p->pri->facilityenable)
- pri_facility_enable(p->pri->pri);
-
-@@ -2399,8 +2450,10 @@ static int pri_find_dchan(struct zt_pri
- }
- 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",
-@@ -2410,6 +2463,16 @@ static int pri_find_dchan(struct zt_pri
- }
- #endif
-
-+static int zt_setlaw(int zfd, int law)
-+{
-+ int res;
-+ res = ioctl(zfd, ZT_SETLAW, &law);
-+ if (res)
-+ return res;
-+ return 0;
-+}
-+
-+
- static int zt_hangup(struct ast_channel *ast)
- {
- int res;
-@@ -2457,8 +2520,7 @@ static int zt_hangup(struct ast_channel
- if (option_debug)
- ast_log(LOG_DEBUG, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
- p->channel, index, p->subs[SUB_REAL].zfd, p->subs[SUB_CALLWAIT].zfd, p->subs[SUB_THREEWAY].zfd);
-- p->ignoredtmf = 0;
--
-+
- if (index > -1) {
- /* Real channel, do some fixup */
- p->subs[index].owner = NULL;
-@@ -2560,6 +2622,7 @@ static int zt_hangup(struct ast_channel
- }
-
- if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
-+ int outgoing = p->outgoing;
- p->owner = NULL;
- p->ringt = 0;
- p->distinctivering = 0;
-@@ -2602,7 +2665,7 @@ static int zt_hangup(struct ast_channel
- pri_call_set_useruser(p->call, useruser);
- #endif
-
-- pri_hangup(p->pri->pri, p->call, -1);
-+ pri_hangup(p->pri->pri, p->call, -1, -1);
- p->call = NULL;
- if (p->bearer)
- p->bearer->call = NULL;
-@@ -2622,7 +2685,28 @@ static int zt_hangup(struct ast_channel
- if (atoi(cause))
- icause = atoi(cause);
- }
-- pri_hangup(p->pri->pri, p->call, icause);
-+
-+ pri_hangup(p->pri->pri, p->call, icause, -1);
-+
-+ /* if we send a rel9999ease complete we wont ge no hangup event, so clear the call here */
-+ if (icause == 34 || icause == 44 || icause == 82 || icause == 1 || icause == 81 || icause == 17) {
-+ if ((ast->_state == AST_STATE_RING) || (ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING) || (ast->_state == AST_STATE_RESERVED)) {
-+ p->call = NULL;
-+ } else {
-+ ast_log(LOG_ERROR, "What is wrong with you? You cannot use cause %d number when in state %d!\n", icause, ast->_state);
-+ icause = 16; /* Note, in pri_hangup() libpri will already override the cause */
-+ }
-+ }
-+
-+ if (p->pri->nodetype == BRI_NETWORK_PTMP) {
-+ if ((icause == 16 || icause == -1) && (ast->_state != AST_STATE_UP)) {
-+ if (outgoing) {
-+ p->call = NULL;
-+ }
-+ }
-+ }
-+
-+
- }
- if (res < 0)
- ast_log(LOG_WARNING, "pri_disconnect failed\n");
-@@ -2806,10 +2890,14 @@ static int zt_answer(struct ast_channel
- p->proceeding = 1;
- res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
- pri_rel(p->pri);
-+ /* stop ignoring inband dtmf */
-+ enable_dtmf_detect(p);
- } 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
- case 0:
-@@ -3446,6 +3534,15 @@ static int zt_fixup(struct ast_channel *
- {
- 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) {
-@@ -3655,8 +3752,10 @@ static void zt_handle_dtmfup(struct ast_
- pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
- if (ast_async_goto(ast, target_context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
-- } else
-+ } else {
-+ if (option_verbose > 2)
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
-+ }
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
- } else if (option_debug)
-@@ -3815,7 +3914,7 @@ static struct ast_frame *zt_handle_event
- if (p->call) {
- if (p->pri && p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
-- pri_hangup(p->pri->pri, p->call, -1);
-+ pri_hangup(p->pri->pri, p->call, -1, -1);
- pri_destroycall(p->pri->pri, p->call);
- p->call = NULL;
- pri_rel(p->pri);
-@@ -4886,7 +4985,7 @@ static struct ast_frame *zt_read(struct
- p->subs[index].f.data = NULL;
- p->subs[index].f.datalen= 0;
- }
-- if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !index) {
-+ if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !index) {
- /* Perform busy detection. etc on the zap line */
- f = ast_dsp_process(ast, p->dsp, &p->subs[index].f);
- if (f) {
-@@ -4898,8 +4997,9 @@ static struct ast_frame *zt_read(struct
- }
- } else if (f->frametype == AST_FRAME_DTMF) {
- #ifdef HAVE_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->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;
- }
-@@ -4974,7 +5074,9 @@ static int zt_write(struct ast_channel *
- #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;
- }
-@@ -5042,7 +5144,7 @@ static int zt_indicate(struct ast_channe
- switch (condition) {
- case AST_CONTROL_BUSY:
- #ifdef HAVE_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;
-@@ -5124,7 +5226,7 @@ static int zt_indicate(struct ast_channe
- case AST_CONTROL_CONGESTION:
- chan->hangupcause = AST_CAUSE_CONGESTION;
- #ifdef HAVE_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;
-@@ -5321,8 +5423,12 @@ static struct ast_channel *zt_new(struct
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->tech_pvt = i;
-+#ifdef HAVE_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)) {
-- /* Only FXO signalled stuff can be picked up */
-+#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;
- }
-@@ -5452,6 +5558,7 @@ static void *ss_thread(void *data)
- int len = 0;
- int res;
- int index;
-+ int network;
-
- /* in the bizarre case where the channel has become a zombie before we
- even get started here, abort safely
-@@ -5480,10 +5587,17 @@ static void *ss_thread(void *data)
- len = strlen(exten);
- res = 0;
- while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
-- if (len && !ast_ignore_pattern(chan->context, exten))
-+ if (len && !ast_ignore_pattern(chan->context, exten)) {
- tone_zone_play_tone(p->subs[index].zfd, -1);
-- else
-- tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);
-+ } else {
-+ network = p->pri->nodetype == PRI_NETWORK || p->pri->nodetype == BRI_NETWORK || p->pri->nodetype == BRI_NETWORK_PTMP;
-+ if (network) {
-+ tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);
-+ } else {
-+ /* cpe be quiet */
-+ tone_zone_play_tone(p->subs[index].zfd, -1);
-+ }
-+ }
- if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
- timeout = matchdigittimeout;
- else
-@@ -6697,9 +6811,20 @@ static int handle_init_event(struct zt_p
- case ZT_EVENT_NOALARM:
- i->inalarm = 0;
- if (!i->unknown_alarm) {
-+#ifdef HAVE_PRI
-+ if (i->pri) {
-+ if ((i->pri->nodetype == BRI_CPE_PTMP) || (i->pri->nodetype == BRI_CPE)) {
-+ /* dont annoy BRI TE mode users with layer2layer alarms */
-+ } else {
-+#endif
- ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
- manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
- "Channel: %d\r\n", i->channel);
-+#ifdef HAVE_PRI
-+ }
-+ }
-+#endif
-+
- } else {
- i->unknown_alarm = 0;
- }
-@@ -6708,7 +6833,13 @@ static int handle_init_event(struct zt_p
- i->inalarm = 1;
- res = get_alarms(i);
- do {
-- const char *alarm_str = alarm2str(res);
-+#ifdef HAVE_PRI
-+ if (i->pri) {
-+ if ((i->pri->nodetype == BRI_CPE_PTMP) || (i->pri->nodetype == BRI_CPE)) {
-+ /* dont annoy BRI TE mode users with layer2layer alarms */
-+ } else {
-+#endif
-+ const char *alarm_str = alarm2str(res);
-
- /* hack alert! Zaptel 1.4 now exposes FXO battery as an alarm, but asterisk 1.4
- * doesn't know what to do with it. Don't confuse users with log messages. */
-@@ -6724,6 +6855,10 @@ static int handle_init_event(struct zt_p
- "Alarm: %s\r\n"
- "Channel: %d\r\n",
- alarm_str, i->channel);
-+#ifdef HAVE_PRI
-+ }
-+ }
-+#endif
- } while (0);
- /* fall thru intentionally */
- case ZT_EVENT_ONHOOK:
-@@ -6768,8 +6903,10 @@ static int handle_init_event(struct zt_p
- zt_set_hook(i->subs[SUB_REAL].zfd, ZT_ONHOOK);
- break;
- case SIG_PRI:
-- zt_disable_ec(i);
-- res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, -1);
-+ if (event != ZT_EVENT_ALARM) {
-+ zt_disable_ec(i);
-+ res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, -1);
-+ }
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
-@@ -7062,6 +7199,8 @@ static int pri_resolve_span(int *span, i
- } 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;
- }
-@@ -7314,6 +7453,11 @@ static struct zt_pvt *mkintf(int channel
- destroy_zt_pvt(&tmp);
- return NULL;
- }
-+ if ((pris[span].localdialplan) && (pris[span].localdialplan != conf->pri.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 (pris[span].minunused && (pris[span].minunused != conf->pri.minunused)) {
- ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.minunused);
- destroy_zt_pvt(&tmp);
-@@ -7331,6 +7475,11 @@ static struct zt_pvt *mkintf(int channel
- return NULL;
- }
- pris[span].nodetype = conf->pri.nodetype;
-+
-+ if (conf->pri.nodetype == BRI_NETWORK_PTMP) {
-+ pris[span].dchanavail[0] = DCHAN_AVAILABLE;
-+ pri_find_dchan(&pris[span]);
-+ }
- pris[span].switchtype = myswitchtype;
- pris[span].nsf = conf->pri.nsf;
- pris[span].dialplan = conf->pri.dialplan;
-@@ -7339,9 +7488,13 @@ static struct zt_pvt *mkintf(int channel
- pris[span].minunused = conf->pri.minunused;
- pris[span].minidle = conf->pri.minidle;
- pris[span].overlapdial = conf->pri.overlapdial;
-+ pris[span].usercid = conf->pri.usercid;
-+ pris[span].suspended_calls = NULL;
- pris[span].facilityenable = conf->pri.facilityenable;
- ast_copy_string(pris[span].idledial, conf->pri.idledial, sizeof(pris[span].idledial));
- ast_copy_string(pris[span].idleext, conf->pri.idleext, sizeof(pris[span].idleext));
-+ ast_copy_string(pris[span].nocid, conf->pri.nocid, sizeof(pris[span].nocid));
-+ ast_copy_string(pris[span].withheldcid, conf->pri.withheldcid, sizeof(pris[span].withheldcid));
- ast_copy_string(pris[span].internationalprefix, conf->pri.internationalprefix, sizeof(pris[span].internationalprefix));
- ast_copy_string(pris[span].nationalprefix, conf->pri.nationalprefix, sizeof(pris[span].nationalprefix));
- ast_copy_string(pris[span].localprefix, conf->pri.localprefix, sizeof(pris[span].localprefix));
-@@ -7483,6 +7636,7 @@ static struct zt_pvt *mkintf(int channel
- tmp->restrictcid = conf->chan.restrictcid;
- tmp->use_callingpres = conf->chan.use_callingpres;
- tmp->priindication_oob = conf->chan.priindication_oob;
-+ tmp->pritransfer = conf->chan.pritransfer;
- tmp->priexclusive = conf->chan.priexclusive;
- if (tmp->usedistinctiveringdetection) {
- if (!tmp->use_callerid) {
-@@ -7765,7 +7919,7 @@ static int pri_find_empty_chan(struct zt
- 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;
-@@ -7961,6 +8115,11 @@ static struct ast_channel *zt_request(co
- 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);
- }
-@@ -7994,13 +8153,14 @@ next:
- *cause = AST_CAUSE_BUSY;
- } else if (groupmatched) {
- *cause = AST_CAUSE_CONGESTION;
-+ } else {
-+ *cause = AST_CAUSE_CONGESTION;
- }
- }
-
- return tmp;
- }
-
--
- #ifdef HAVE_PRI
- static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv)
- {
-@@ -8045,6 +8205,7 @@ static int pri_find_principle(struct zt_
- static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
- {
- int x;
-+ int res = 0;
- struct zt_pvt *crv;
- if (!c) {
- if (principle < 0)
-@@ -8075,6 +8236,7 @@ static int pri_fixup_principle(struct zt
- }
- /* Fix it all up now */
- new->owner = old->owner;
-+ new->outgoing = old->outgoing;
- old->owner = NULL;
- if (new->owner) {
- ast_string_field_build(new->owner, name,
-@@ -8094,6 +8256,34 @@ static int pri_fixup_principle(struct zt
- new->dsp_features = old->dsp_features;
- old->dsp = NULL;
- old->dsp_features = 0;
-+
-+ /* Copy faxhandled/digial, alreadyhungup */
-+ new->faxhandled = old->faxhandled;
-+ new->digital = old->digital;
-+ new->alreadyhungup = old->alreadyhungup;
-+
-+ /* Copy law, gains, etc */
-+ new->law = old->law;
-+ if (ioctl(new->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &new->law) == -1)
-+ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", new->channel, new->law);
-+ res = zt_setlaw(new->subs[SUB_REAL].zfd, new->law);
-+ if (res < 0)
-+ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", new->channel);
-+ if (!new->digital) {
-+ res = set_actual_gain(new->subs[SUB_REAL].zfd, 0, new->rxgain, new->txgain, new->law);
-+ } else {
-+ res = set_actual_gain(new->subs[SUB_REAL].zfd, 0, 0, 0, new->law);
-+ }
-+ if (res < 0)
-+ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", new->channel);
-+
-+ /* Shutdown old channel */
-+ zt_confmute(old, 0);
-+ update_conf(old);
-+ reset_conf(old);
-+ restore_gains(old);
-+ zt_disable_ec(old);
-+ zt_setlinear(old->subs[SUB_REAL].zfd, 0);
- }
- return principle;
- }
-@@ -8122,7 +8312,9 @@ static int pri_fixup_principle(struct zt
- }
- 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;
- }
-
-@@ -8181,86 +8373,21 @@ static void *do_idle_thread(void *vchan)
- #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_log(LOG_ERROR, "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_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
-- else
-- ast_log(LOG_ERROR, "%s", s);
-- } else
-- ast_log(LOG_ERROR, "PRI debug error: could not find pri associated it with debug message output\n");
-- } else
-- ast_log(LOG_ERROR, "%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) &&
-@@ -8344,13 +8471,30 @@ static void apply_plan_to_number(char *b
- }
- }
-
--static int zt_setlaw(int zfd, int law)
--{
-- int res;
-- res = ioctl(zfd, ZT_SETLAW, &law);
-- if (res)
-- return res;
-- return 0;
-+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)
-@@ -8530,15 +8674,44 @@ static void *pri_dchannel(void *vpri)
- /* Check for an event */
- x = 0;
- res = ioctl(pri->fds[which], ZT_GETEVENT, &x);
-- if (x)
-+ if ((pri->nodetype != BRI_CPE) && (pri->nodetype != BRI_CPE_PTMP)) {
-+ /* dont annoy BRI TE mode users with layer2layer alarms */
-+ if (x)
- ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span);
-+ }
- /* Keep track of alarm state */
- 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) {
-+ 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)
-@@ -8550,8 +8723,7 @@ static void *pri_dchannel(void *vpri)
- 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);
-@@ -8576,6 +8748,17 @@ static void *pri_dchannel(void *vpri)
-
- switch (e->e) {
- case PRI_EVENT_DCHAN_UP:
-+ 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);
-+ } 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);
-+ }
-+
- if (!pri->pri) pri_find_dchan(pri);
-
- /* Note presense of D-channel */
-@@ -8594,6 +8777,12 @@ static void *pri_dchannel(void *vpri)
- }
- break;
- case PRI_EVENT_DCHAN_DOWN:
-+ 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;
-+ }
- pri_find_dchan(pri);
- if (!pri_is_up(pri)) {
- pri->resetting = 0;
-@@ -8601,16 +8790,18 @@ static void *pri_dchannel(void *vpri)
- for (i = 0; i < pri->numchans; i++) {
- struct zt_pvt *p = pri->pvts[i];
- if (p) {
-+ if ((p->tei == e->gen.tei) || (pri->nodetype != BRI_NETWORK_PTMP)) {
- if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
- /* T309 is not enabled : hangup calls when alarm occurs */
- 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, -1);
- pri_destroycall(p->pri->pri, p->call);
- p->call = NULL;
- } else
- ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
- }
-+ p->tei = -1;
- if (p->realcall) {
- pri_hangup_all(p->realcall, pri);
- } else if (p->owner)
-@@ -8619,6 +8810,7 @@ static void *pri_dchannel(void *vpri)
- p->inalarm = 1;
- }
- }
-+ }
- }
- break;
- case PRI_EVENT_RESTART:
-@@ -8653,8 +8845,8 @@ static void *pri_dchannel(void *vpri)
- 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);
-@@ -8688,7 +8880,6 @@ static void *pri_dchannel(void *vpri)
- }
- }
- break;
--
- case PRI_EVENT_INFO_RECEIVED:
- chanpos = pri_find_principle(pri, e->ring.channel);
- if (chanpos < 0) {
-@@ -8697,9 +8888,11 @@ static void *pri_dchannel(void *vpri)
- } 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;
-@@ -8711,6 +8904,14 @@ static void *pri_dchannel(void *vpri)
- 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);
- }
-@@ -8718,36 +8919,59 @@ static void *pri_dchannel(void *vpri)
- 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 <= 0) {
-+ 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, -1);
-+ 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",
-+ /* 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);
-- break;
-+ 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 {
-- /* This is where we handle initial glare */
-- ast_log(LOG_DEBUG, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiating channel.\n",
-- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-- chanpos = -1;
-+ pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-+ /* XXX destroy the call here, so we can accept the retransmission as a new call */
-+ pri_destroycall(pri->pri, e->ring.call);
- }
-- }
-- if (chanpos > -1)
- 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 */
-+ disable_dtmf_detect(pri->pvts[chanpos]);
-+ /* 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));
-@@ -8761,13 +8985,14 @@ static void *pri_dchannel(void *vpri)
- ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
- } else
- ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
-- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
-+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE, -1);
- if (crv)
- ast_mutex_unlock(&crv->lock);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- 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) {
-@@ -8792,34 +9017,82 @@ static void *pri_dchannel(void *vpri)
- }
- 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:
-+ ast_copy_string(pri->pvts[chanpos]->cid_name, pri->withheldcid, sizeof(pri->pvts[chanpos]->cid_name));
-+ break;
-+ case PRES_NUMBER_NOT_AVAILABLE:
-+ ast_copy_string(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 if (pri->overlapdial)
-- pri->pvts[chanpos]->exten[0] = '\0';
-- else {
-- /* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
-- pri->pvts[chanpos]->exten[0] = 's';
-- pri->pvts[chanpos]->exten[1] = '\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 if (pri->overlapdial) {
-+ pri->pvts[chanpos]->exten[0] = '\0';
-+ } else {
-+ /* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
-+ pri->pvts[chanpos]->exten[0] = 's';
-+ pri->pvts[chanpos]->exten[1] = '\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)) {
-@@ -8838,19 +9111,36 @@ static void *pri_dchannel(void *vpri)
- 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->pvts[chanpos]->proceeding = 1;
- pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
-- } else {
-+ } 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);
-+ }
- }
-+ /* overlapdial = yes and the extension can be valid */
- /* Get the use_callingpres state */
- pri->pvts[chanpos]->callingpres = e->ring.callingpres;
-
-@@ -8862,10 +9152,17 @@ static void *pri_dchannel(void *vpri)
- /* Set bearer and such */
- pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
- c = zt_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
-+ if (c && (e->ring.lowlayercompat[0] > 0)) {
-+ memcpy(c->lowlayercompat, e->ring.lowlayercompat, sizeof(c->lowlayercompat));
-+ }
- pri->pvts[chanpos]->owner = &inuse;
- 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);
-+ if (c && (e->ring.lowlayercompat[0] > 0)) {
-+ memcpy(c->lowlayercompat, e->ring.lowlayercompat, sizeof(c->lowlayercompat));
-+ }
-+ zt_enable_ec(pri->pvts[chanpos]); /* XXX rethink */
- }
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-@@ -8873,6 +9170,16 @@ static void *pri_dchannel(void *vpri)
- 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", tmpstr);
-+ }
- if (e->ring.ani2 >= 0) {
- snprintf(ani2str, 5, "%.2d", e->ring.ani2);
- pbx_builtin_setvar_helper(c, "ANI2", ani2str);
-@@ -8896,8 +9203,8 @@ static void *pri_dchannel(void *vpri)
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- 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, S_OR(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, S_OR(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",
-@@ -8905,15 +9212,19 @@ static void *pri_dchannel(void *vpri)
- if (c)
- ast_hangup(c);
- else {
-- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
-+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION, -1);
- pri->pvts[chanpos]->call = NULL;
- }
- }
- pthread_attr_destroy(&attr);
- } 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);
-+ if (c && (e->ring.lowlayercompat[0] > 0)) {
-+ memcpy(c->lowlayercompat, e->ring.lowlayercompat, sizeof(c->lowlayercompat));
-+ }
- if (c) {
- char calledtonstr[10];
-
-@@ -8940,26 +9251,43 @@ static void *pri_dchannel(void *vpri)
- ast_mutex_lock(&pri->lock);
-
- 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_mutex_lock(&pri->lock);
-
- 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);
-- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
-+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION, -1);
- pri->pvts[chanpos]->call = NULL;
- }
- }
- } 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,
- pri->pvts[chanpos]->prioffset, pri->span);
-- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
-+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED, -1);
- pri->pvts[chanpos]->call = NULL;
- pri->pvts[chanpos]->exten[0] = '\0';
- }
-@@ -8968,9 +9296,9 @@ static void *pri_dchannel(void *vpri)
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- } else {
- if (e->ring.flexible)
-- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
-+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION, -1);
- else
-- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
-+ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL, -1);
- }
- break;
- case PRI_EVENT_RINGING:
-@@ -8986,7 +9314,7 @@ static void *pri_dchannel(void *vpri)
- } 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
-@@ -9018,9 +9346,16 @@ static void *pri_dchannel(void *vpri)
- }
- 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->hangupcause = AST_CAUSE_USER_BUSY;
-+ 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
-@@ -9062,11 +9397,18 @@ static void *pri_dchannel(void *vpri)
- pri->pvts[chanpos]->progress = 1;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
-+ }
- }
- break;
- 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, };
-
-@@ -9091,6 +9433,7 @@ static void *pri_dchannel(void *vpri)
- pri->pvts[chanpos]->proceeding = 1;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
-+ }
- }
- break;
- case PRI_EVENT_FACNAME:
-@@ -9114,6 +9457,163 @@ static void *pri_dchannel(void *vpri)
- }
- }
- 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;
-+ }
-+ /* holded calls are not implemented yet */
-+ 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;
-+ }
-+ /* Holded calls are currently not supported */
-+ pri_retrieve_reject(pri->pri, e->retrieve_req.call);
-+ chanpos = -1;
-+ 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) {
-@@ -9126,6 +9626,7 @@ static void *pri_dchannel(void *vpri)
- PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
- } 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.
-@@ -9155,11 +9656,16 @@ static void *pri_dchannel(void *vpri)
- 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);
-+ enable_dtmf_detect(pri->pvts[chanpos]);
- } 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 */
-+ enable_dtmf_detect(pri->pvts[chanpos]);
- }
-
- #ifdef SUPPORT_USERUSER
-@@ -9216,20 +9722,29 @@ static void *pri_dchannel(void *vpri)
- 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_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause, -1);
- 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;
-- }
-- if (e->hangup.aoc_units > -1)
-+ 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 (e->hangup.aoc_units > -1) {
-+ if (pri->pvts[chanpos]->owner) {
-+ char tmpstr[256];
-+ snprintf(tmpstr, sizeof(tmpstr), "%d", (int)e->hangup.aoc_units);
-+ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "AOCEUNITS", tmpstr);
-+ }
- 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");
-+ }
-
- #ifdef SUPPORT_USERUSER
- if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) {
-@@ -9242,8 +9757,9 @@ static void *pri_dchannel(void *vpri)
-
- 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);
-+ 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;
-@@ -9253,15 +9769,23 @@ static void *pri_dchannel(void *vpri)
- 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);
-- } else {
-+ if (pri->nodetype == BRI_NETWORK_PTMP) {
-+ pri_hangup(pri->pri, e->hangup.call, e->hangup.cause, -1);
-+ } 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);
-+ }
-+ } else if ((pri->pvts[chanpos]->priindication_oob != 2) || (!e->hangup.inband_progress) || (!pri->pvts[chanpos]->outgoing)) {
-+ /* dont hang up if we want to hear inband call progress */
- 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;
- if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-@@ -9288,16 +9812,34 @@ static void *pri_dchannel(void *vpri)
- 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 (e->hangup.aoc_units > -1) {
-+ if (pri->pvts[chanpos]->owner) {
-+ char tmpstr[256];
-+ snprintf(tmpstr, sizeof(tmpstr), "%d", (int)e->hangup.aoc_units);
-+ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "AOCEUNITS", tmpstr);
-+ }
-+ 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) {
-+ pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause, -1);
-+ pri->pvts[chanpos]->call = NULL;
-+ pri->pvts[chanpos]->tei = -1;
-+ }
- } else {
-- pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
-+ pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause, -1);
- 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 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;
-+ }
- }
-
- #ifdef SUPPORT_USERUSER
-@@ -9311,9 +9853,27 @@ static void *pri_dchannel(void *vpri)
-
- 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 {
-+ 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_mutex_lock(&pri->pvts[chanpos]->lock);
-+ if (e->hangup.aoc_units > -1) {
-+ char tmpstr[256];
-+ snprintf(tmpstr, sizeof(tmpstr), "%d", (int)e->hangup.aoc_units);
-+ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "AOCEUNITS", tmpstr);
-+ 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");
-+ }
-+ pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
-+ ast_channel_setwhentohangup(pri->pvts[chanpos]->owner, 5);
-+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-+ }
- break;
- case PRI_EVENT_HANGUP_ACK:
- chanpos = pri_find_principle(pri, e->hangup.channel);
-@@ -9325,6 +9885,7 @@ static void *pri_dchannel(void *vpri)
- 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)
-@@ -9431,10 +9992,22 @@ static void *pri_dchannel(void *vpri)
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- switch (e->notify.info) {
- case PRI_NOTIFY_REMOTE_HOLD:
-+ if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
-+ ast_log(LOG_DEBUG, "Received REMOTE_HOLD notification on NETWORK channel. Starting MoH\n");
-+ ast_moh_start(ast_bridged_channel(pri->pvts[chanpos]->owner), NULL, pri->pvts[chanpos]->mohinterpret);
-+ } else {
-+ ast_log(LOG_DEBUG, "Received REMOTE_HOLD notification on CPE channel. Not Starting MoH\n");
-+ }
- f.subclass = AST_CONTROL_HOLD;
- zap_queue_frame(pri->pvts[chanpos], &f, pri);
- break;
- case PRI_NOTIFY_REMOTE_RETRIEVAL:
-+ if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
-+ ast_log(LOG_DEBUG, "Received REMOTE_RETRIEVAL notification on NETWORK channel. Stopping MoH\n");
-+ ast_moh_stop(ast_bridged_channel(pri->pvts[chanpos]->owner));
-+ } else {
-+ ast_log(LOG_DEBUG, "Received REMOTE_RETRIEVAL notification on CPE channel.\n");
-+ }
- f.subclass = AST_CONTROL_UNHOLD;
- zap_queue_frame(pri->pvts[chanpos], &f, pri);
- break;
-@@ -9442,6 +10015,23 @@ static void *pri_dchannel(void *vpri)
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- break;
-+ case PRI_EVENT_FACILITY:
-+ if (e->facility.operation == 0x0D) {
-+ struct ast_channel *owner = pri->pvts[chanpos]->owner;
-+
-+ ast_log(LOG_NOTICE, "call deflection to %s requested.\n", e->facility.forwardnum);
-+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
-+ /* transfer */
-+ if (owner) {
-+ ast_string_field_build(owner, call_forward,
-+ "Local/%s@%s", e->facility.forwardnum,
-+ owner->context);
-+ }
-+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-+ } 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);
- }
-@@ -9503,7 +10093,7 @@ static int start_pri(struct zt_pri *pri)
- 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;
-@@ -9571,39 +10161,77 @@ static char *complete_span_5(const char
-
- 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, 0600);
- if (myfd < 0) {
- ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
- return RESULT_SUCCESS;
- }
-+ for (x=0; x < NUM_SPANS; x++) {
-+ ast_mutex_lock(&pris[x].lock);
-
-- ast_mutex_lock(&pridebugfdlock);
--
-- if (pridebugfd >= 0)
-- close(pridebugfd);
--
-- pridebugfd = myfd;
-- ast_copy_string(pridebugfilename,argv[4],sizeof(pridebugfilename));
--
-- ast_mutex_unlock(&pridebugfdlock);
-+ 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 will be sent to '%s'\n", argv[4]);
-+ 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;
-@@ -9644,6 +10272,7 @@ static int handle_pri_debug(int fd, int
-
-
-
-+
- static int handle_pri_no_debug(int fd, int argc, char *argv[])
- {
- int span;
-@@ -9793,10 +10422,6 @@ static int handle_pri_show_debug(int fd,
- }
-
- }
-- 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");
-@@ -9823,6 +10448,18 @@ static const char pri_show_spans_help[]
- "Usage: pri show spans\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",
-@@ -9847,6 +10484,15 @@ static struct ast_cli_entry zap_pri_cli[
- { { "pri", "show", "debug", NULL },
- handle_pri_show_debug, "Displays current PRI debug settings" },
-
-+ { { "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", "set", "debug", "file", NULL },
- handle_pri_set_debug_file, "Sends PRI debug output to the specified file" },
-
-@@ -9859,8 +10505,76 @@ static struct ast_cli_entry zap_pri_cli[
- #endif
- };
-
-+static char *zapCD_tdesc = "Call Deflection";
-+static char *zapCD_app = "zapCD";
-+static char *zapCD_synopsis = "Call Deflection";
-+
-+static int app_zapCD(struct ast_channel *chan, void *data)
-+{
-+ struct zt_pvt *p = chan->tech_pvt;
-+
-+ if((!p->pri) || (!p->pri->pri)) {
-+ return -1;
-+ }
-+
-+ if(!data) {
-+ ast_log(LOG_WARNING, "zapCD wants a number to deflect to\n");
-+ return -1;
-+ }
-+ return pri_deflect(p->pri->pri, p->call, data);
-+}
-+
-+static char *zapInband_tdesc = "Inband Call Progress (pre-answer)";
-+static char *zapInband_app = "zapInband";
-+static char *zapInband_synopsis = "Inband Call Progress";
-+
-+static int app_zapInband(struct ast_channel *chan, void *data)
-+{
-+ struct zt_pvt *p = chan->tech_pvt;
-+
-+ return pri_acknowledge(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1);
-+}
-+
- #endif /* HAVE_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->tech->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");
-+ res = 0;
-+ }
-+
-+ 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";
-+
- static int zap_destroy_channel(int fd, int argc, char **argv)
- {
- int channel;
-@@ -10441,8 +11155,11 @@ static int __unload_module(void)
- }
- ast_cli_unregister_multiple(zap_pri_cli, sizeof(zap_pri_cli) / sizeof(struct ast_cli_entry));
- ast_unregister_application(zap_send_keypad_facility_app);
-+ ast_unregister_application(zapCD_app);
-+ ast_unregister_application(zapInband_app);
- #endif
- ast_cli_unregister_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
-+ ast_unregister_application(zapEC_app);
- ast_manager_unregister( "ZapDialOffhook" );
- ast_manager_unregister( "ZapHangup" );
- ast_manager_unregister( "ZapTransfer" );
-@@ -10944,6 +11661,22 @@ static int process_zap(struct zt_chan_co
- confp->chan.sig = SIG_GR303FXSKS;
- confp->chan.radio = 0;
- confp->pri.nodetype = PRI_CPE;
-+ } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
-+ confp->chan.radio = 0;
-+ confp->chan.sig = SIG_PRI;
-+ confp->pri.nodetype = BRI_NETWORK_PTMP;
-+ } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
-+ confp->chan.sig = SIG_PRI;
-+ confp->chan.radio = 0;
-+ confp->pri.nodetype = BRI_CPE_PTMP;
-+ } else if (!strcasecmp(v->value, "bri_net")) {
-+ confp->chan.radio = 0;
-+ confp->chan.sig = SIG_PRI;
-+ confp->pri.nodetype = BRI_NETWORK;
-+ } else if (!strcasecmp(v->value, "bri_cpe")) {
-+ confp->chan.sig = SIG_PRI;
-+ confp->chan.radio = 0;
-+ confp->pri.nodetype = BRI_CPE;
- #endif
- } else {
- ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value);
-@@ -11056,9 +11789,21 @@ static int process_zap(struct zt_chan_co
- confp->chan.priindication_oob = 1;
- else if (!strcasecmp(v->value, "inband"))
- confp->chan.priindication_oob = 0;
-+ else if (!strcasecmp(v->value, "passthrough"))
-+ confp->chan.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, "pritransfer")) {
-+ if (!strcasecmp(v->value, "no"))
-+ confp->chan.pritransfer = 0;
-+ else if (!strcasecmp(v->value, "ect"))
-+ confp->chan.pritransfer = 1;
-+ else if (!strcasecmp(v->value, "hangup"))
-+ confp->chan.pritransfer = 2;
-+ else
-+ ast_log(LOG_WARNING, "'%s' is not a valid pri transfer value, should be 'no' , 'ect' or 'hangup' at line %d\n",
-+ v->value, v->lineno);
- } else if (!strcasecmp(v->name, "priexclusive")) {
- confp->chan.priexclusive = ast_true(v->value);
- } else if (!strcasecmp(v->name, "internationalprefix")) {
-@@ -11071,6 +11816,10 @@ static int process_zap(struct zt_chan_co
- ast_copy_string(confp->pri.privateprefix, v->value, sizeof(confp->pri.privateprefix));
- } else if (!strcasecmp(v->name, "unknownprefix")) {
- ast_copy_string(confp->pri.unknownprefix, v->value, sizeof(confp->pri.unknownprefix));
-+ } else if (!strcasecmp(v->name, "nocid")) {
-+ ast_copy_string(confp->pri.nocid, v->value, sizeof(confp->pri.nocid));
-+ } else if (!strcasecmp(v->name, "withheldcid")) {
-+ ast_copy_string(confp->pri.withheldcid, v->value, sizeof(confp->pri.withheldcid));
- } else if (!strcasecmp(v->name, "resetinterval")) {
- if (!strcasecmp(v->value, "never"))
- confp->pri.resetinterval = -1;
-@@ -11087,6 +11836,8 @@ static int process_zap(struct zt_chan_co
- ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext));
- } else if (!strcasecmp(v->name, "idledial")) {
- ast_copy_string(confp->pri.idledial, v->value, sizeof(confp->pri.idledial));
-+ } else if (!strcasecmp(v->name, "pritrustusercid")) {
-+ confp->pri.usercid = ast_true(v->value);
- } else if (!strcasecmp(v->name, "overlapdial")) {
- confp->pri.overlapdial = ast_true(v->value);
- } else if (!strcasecmp(v->name, "pritimer")) {
-@@ -11389,6 +12140,7 @@ static int setup_zap(int reload)
- #ifdef HAVE_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);
-@@ -11436,7 +12188,10 @@ static int load_module(void)
- ast_string_field_init(&inuse, 16);
- ast_string_field_set(&inuse, name, "GR-303InUse");
- ast_cli_register_multiple(zap_pri_cli, sizeof(zap_pri_cli) / sizeof(struct ast_cli_entry));
-+ ast_register_application(zapCD_app, app_zapCD, zapCD_synopsis, zapCD_tdesc);
-+ ast_register_application(zapInband_app, app_zapInband, zapInband_synopsis, zapInband_tdesc);
- #endif
-+ ast_register_application(zapEC_app, app_zapEC, zapEC_synopsis, zapEC_tdesc);
- ast_cli_register_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
-
- memset(round_robin, 0, sizeof(round_robin));
-@@ -11470,6 +12225,7 @@ static int zt_sendtext(struct ast_channe
- 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");
---- a/configs/zapata.conf.sample
-+++ b/configs/zapata.conf.sample
-@@ -123,9 +123,20 @@ switchtype=national
- ;
- ; outofband: Signal Busy/Congestion out of band with RELEASE/DISCONNECT
- ; inband: Signal Busy/Congestion using in-band tones
-+; passthrough: Listen to the telco
- ;
- ; priindication = outofband
- ;
-+; PRI/BRI transfers (HOLD -> SETUP -> ECT/Hangup)
-+;
-+; Configure how transfers are initiated. ECT should be preferred
-+;
-+; no: no transfers allowed (results in hangup)
-+; ect: use ECT (facility)
-+; hangup: transfer on hangup (if your phones dont support ECT)
-+;
-+; pritransfer = ect
-+;
- ; If you need to override the existing channels selection routine and force all
- ; PRI channels to be marked as exclusively selected, set this to yes.
- ; priexclusive = yes
-Change the ABI of ast_channel_tech to add a new function, send_message that is
-to be used by channels wanting to send text messages with a destination number
-(mainly GSM).
-
---- a/include/asterisk/channel.h
-+++ b/include/asterisk/channel.h
-@@ -247,6 +247,11 @@ struct ast_channel_tech {
- /*! \brief Display or transmit text */
- int (* const send_text)(struct ast_channel *chan, const char *text);
-
-+#if 0 /* we (Debian) disable that addition because of ABI breakage */
-+ /*! \brief send a message */
-+ int (* const send_message)(struct ast_channel *chan, const char *dest, const char *text, int ispdu);
-+#endif
-+
- /*! \brief Display or send an image */
- int (* const send_image)(struct ast_channel *chan, struct ast_frame *frame);
-
-@@ -689,6 +694,16 @@ struct ast_channel *ast_request_and_dial
-
- 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);
-
-+/*! \brief "Requests" a channel for sending a message
-+ * \param type type of channel to request
-+ * \param data data to pass to the channel requester
-+ * \param status status
-+ * Request a channel of a given type, with data as optional information used
-+ * by the low level module
-+ * \return Returns 0 on success, -1 on failure.
-+ */
-+int ast_send_message(const char *type, void *data, char *to, char *from, char *message, int ispdu);
-+
- /*!\brief Register a channel technology (a new channel driver)
- * Called by a channel module to register the kind of channels it supports.
- * \param tech Structure defining channel technology or "type"
-@@ -910,6 +925,16 @@ int ast_set_write_format(struct ast_chan
- */
- int ast_sendtext(struct ast_channel *chan, const char *text);
-
-+/*! \brief Sends message to a channel
-+ * Write text to a display on a channel
-+ * \param chan channel to act upon
-+ * \param dest destination number/user
-+ * \param text string of text to send on the channel
-+ * \param ispdu message is in PDU format
-+ * \return Returns 0 on success, -1 on failure
-+ */
-+int ast_sendmessage(struct ast_channel *chan, const char *dest, const char *text, int ispdu);
-+
- /*! \brief Receives a text character from a channel
- * \param chan channel to act upon
- * \param timeout timeout in milliseconds (0 for infinite wait)
---- a/main/channel.c
-+++ b/main/channel.c
-@@ -2472,6 +2472,21 @@ int ast_sendtext(struct ast_channel *cha
- return res;
- }
-
-+int ast_sendmessage(struct ast_channel *chan, const char *dest, const char *text, int ispdu)
-+{
-+ int res = 0;
-+ /* Stop if we're a zombie or need a soft hangup */
-+ if (ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
-+ return -1;
-+ CHECK_BLOCKING(chan);
-+#if 0 /* we (Debian) disable that addition because of ABI breakage */
-+ if (chan->tech->send_message)
-+ res = chan->tech->send_message(chan, dest, text, ispdu);
-+#endif
-+ ast_clear_flag(chan, AST_FLAG_BLOCKING);
-+ return res;
-+}
-+
- int ast_senddigit_begin(struct ast_channel *chan, char digit)
- {
- /* Device does not support DTMF tones, lets fake
-@@ -4515,6 +4530,25 @@ void ast_channel_stop_silence_generator(
- }
-
-
-+int ast_send_message(const char *type, void *data, char *to, char *from, char *message, int ispdu) {
-+ struct ast_channel *chan = NULL;
-+ int status;
-+ int res = -1;
-+
-+ chan = ast_request(type, AST_FORMAT_SLINEAR, data, &status);
-+ if (chan) {
-+ if (from) {
-+ ast_set_callerid(chan, from, from, from);
-+ }
-+ res = ast_sendmessage(chan, to, message, ispdu);
-+ /* XXX what about message CDRs ??? XXX */
-+ ast_hangup(chan);
-+ return res;
-+ }
-+
-+ return res;
-+}
-+
- /*! \ brief Convert channel reloadreason (ENUM) to text string for manager event */
- const char *channelreloadreason2txt(enum channelreloadreason reason)
- {
---- a/main/manager.c
-+++ b/main/manager.c
-@@ -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@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.
-@@ -1427,6 +1430,49 @@ static int action_hangup(struct mansessi
- return 0;
- }
-
-+static char mandescr_message[] =
-+"Description: Send a message\n"
-+"Variables: \n"
-+" Channel: The destination channel(e.g. SIP/phone1)\n"
-+" From: \n"
-+" Message: The message to send\n";
-+
-+static int action_message(struct mansession *s, const struct message *m)
-+{
-+ const char *name = astman_get_header(m, "Channel");
-+ const char *from = astman_get_header(m, "From");
-+ const char *message = astman_get_header(m, "Message");
-+ const char *pdu = astman_get_header(m, "PDU");
-+ char tmp[256];
-+ char *tech, *data;
-+ int res;
-+ if (ast_strlen_zero(name) || (ast_strlen_zero(message) && ast_strlen_zero(pdu))) {
-+ astman_send_error(s, m, "No channel or message/PDU specified");
-+ return 0;
-+ }
-+ ast_copy_string(tmp, name, sizeof(tmp));
-+ tech = tmp;
-+ data = strchr(tmp, '/');
-+ if (!data) {
-+ astman_send_error(s, m, "Invalid channel\n");
-+ return 0;
-+ }
-+ *data = '\0';
-+ data++;
-+ if (ast_strlen_zero(pdu)) {
-+ res = ast_send_message(tech, (char *)data, (char *)name, (char *)from, (char *)message, 0);
-+ } else {
-+ res = ast_send_message(tech, (char *)data, (char *)name, (char *)from, (char *)pdu, 1);
-+ }
-+
-+ if (res) {
-+ astman_send_error(s, m, "Error sending message");
-+ return 0;
-+ }
-+ astman_send_ack(s, m, "Message sent");
-+ return 0;
-+}
-+
- static char mandescr_setvar[] =
- "Description: Set a global or local channel variable.\n"
- "Variables: (Names marked with * are required)\n"
-@@ -2853,6 +2899,7 @@ int init_manager(void)
- ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
- ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
- ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
-+ ast_manager_register2("Message", EVENT_FLAG_CALL, action_message, "Send Message", mandescr_message);
- ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
- ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
- ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
---- a/pbx/pbx_spool.c
-+++ b/pbx/pbx_spool.c
-@@ -87,6 +87,10 @@ struct outgoing {
- char app[256];
- char data[256];
-
-+ /* If SMS */
-+ char message[256];
-+ char pdu[256];
-+
- /* If extension/context/priority */
- char exten[256];
- char context[256];
-@@ -181,6 +185,10 @@ static int apply_outgoing(struct outgoin
- ast_copy_string(o->app, c, sizeof(o->app));
- } else if (!strcasecmp(buf, "data")) {
- ast_copy_string(o->data, c, sizeof(o->data));
-+ } else if (!strcasecmp(buf, "message")) {
-+ strncpy(o->message, c, sizeof(o->message) - 1);
-+ } else if (!strcasecmp(buf, "pdu")) {
-+ strncpy(o->pdu, c, sizeof(o->pdu) - 1);
- } else if (!strcasecmp(buf, "maxretries")) {
- if (sscanf(c, "%d", &o->maxretries) != 1) {
- ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn);
-@@ -241,8 +249,8 @@ static int apply_outgoing(struct outgoin
- }
- }
- ast_copy_string(o->fn, fn, sizeof(o->fn));
-- if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
-- ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn);
-+ if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || ((ast_strlen_zero(o->app) && ast_strlen_zero(o->exten) && ast_strlen_zero(o->message) && ast_strlen_zero(o->pdu)))) {
-+ ast_log(LOG_WARNING, "At least one of app or extension (or keyword message/pdu)must be specified, along with tech and dest in file %s\n", fn);
- return -1;
- }
- return 0;
-@@ -332,6 +340,14 @@ static void *attempt_thread(void *data)
- 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, o->account, NULL);
-+ } else if (!ast_strlen_zero(o->message)) {
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_3 "Attempting to send message on %s/%s (Retry %d)\n", o->tech, o->dest, o->retries);
-+ res = ast_send_message(o->tech, o->dest, o->dest, (ast_strlen_zero(o->cid_name) ? o->cid_num : o->cid_name), o->message, 0);
-+ } else if (!ast_strlen_zero(o->pdu)) {
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_3 "Attempting to send message in PDU format on %s/%s (Retry %d)\n", o->tech, o->dest, o->retries);
-+ res = ast_send_message(o->tech, o->dest, o->dest, (ast_strlen_zero(o->cid_name) ? o->cid_num : o->cid_name), o->pdu, 1);
- } 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);
-@@ -348,9 +364,14 @@ static void *attempt_thread(void *data)
- safe_append(o, time(NULL), "EndRetry");
- }
- } else {
-+ if (!ast_strlen_zero(o->message)) {
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_2 "Message sent to %s/%s\n", o->tech, o->dest);
-+ } else {
- ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest);
- ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest);
-- remove_from_queue(o, "Completed");
-+ }
-+ remove_from_queue(o, "Completed");
- }
- free_outgoing(o);
- return NULL;
---- a/include/asterisk/monitor.h
-+++ b/include/asterisk/monitor.h
-@@ -38,6 +38,8 @@ struct ast_channel_monitor {
- char write_filename[FILENAME_MAX];
- char filename_base[FILENAME_MAX];
- int filename_changed;
-+ char target_url[FILENAME_MAX];
-+ char target_script[FILENAME_MAX];
- char *format;
- int joinfiles;
- enum AST_MONITORING_STATE state;
-@@ -46,7 +48,7 @@ struct ast_channel_monitor {
-
- /* Start monitoring a channel */
- int ast_monitor_start(struct ast_channel *chan, const char *format_spec,
-- const char *fname_base, int need_lock );
-+ const char *fname_base, const char *target_url, const char *target_script, int need_lock );
-
- /* Stop monitoring a channel */
- int ast_monitor_stop(struct ast_channel *chan, int need_lock);
---- a/res/res_monitor.c
-+++ b/res/res_monitor.c
-@@ -130,7 +130,7 @@ static int ast_monitor_set_state(struct
-
- /* Start monitoring a channel */
- int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
-- const char *fname_base, int need_lock)
-+ const char *fname_base, const char *target_url, const char *target_script, int need_lock)
- {
- int res = 0;
- char tmp[256];
-@@ -154,6 +154,11 @@ int ast_monitor_start( struct ast_channe
- return -1;
- }
-
-+ if (target_url)
-+ ast_copy_string(monitor->target_url, target_url, sizeof(monitor->target_url));
-+ if (target_script)
-+ ast_copy_string(monitor->target_script, target_script, sizeof(monitor->target_script));
-+
- /* Determine file names */
- if (!ast_strlen_zero(fname_base)) {
- int directory = strchr(fname_base, '/') ? 1 : 0;
-@@ -297,6 +302,8 @@ int ast_monitor_stop(struct ast_channel
- if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
- char tmp[1024];
- char tmp2[1024];
-+ char tmp3[1024];
-+ int result;
- const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
- char *name = chan->monitor->filename_base;
- int directory = strchr(name, '/') ? 1 : 0;
-@@ -325,8 +332,13 @@ int ast_monitor_stop(struct ast_channel
- snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s%s%s-\"* ) &",tmp, dir, absolute, name); /* remove legs when done mixing */
- ast_copy_string(tmp, tmp2, sizeof(tmp));
- }
-- ast_log(LOG_DEBUG,"monitor executing %s\n",tmp);
-- if (ast_safe_system(tmp) == -1)
-+ if (!ast_strlen_zero(chan->monitor->target_script) && !ast_strlen_zero(chan->monitor->target_url)) {
-+ snprintf(tmp3,sizeof(tmp3), "( %s& nice -19 %s \"%s/%s.%s\" \"%s\" ) &",tmp, chan->monitor->target_script , dir, name, format, chan->monitor->target_url);
-+ ast_copy_string(tmp, tmp3, sizeof(tmp));
-+ }
-+ ast_log(LOG_NOTICE,"monitor executing %s\n",tmp);
-+ result = ast_safe_system(tmp);
-+ if (result == -1)
- ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
- }
-
-@@ -467,7 +479,7 @@ static int start_monitor_exec(struct ast
- return 0;
- }
-
-- res = ast_monitor_start(chan, format, fname_base, 1);
-+ res = ast_monitor_start(chan, format, fname_base, NULL, NULL, 1);
- if (res < 0)
- res = ast_monitor_change_fname(chan, fname_base, 1);
- ast_monitor_setjoinfiles(chan, joinfiles);
-@@ -506,6 +518,8 @@ static int start_monitor_action(struct m
- const char *fname = astman_get_header(m, "File");
- const char *format = astman_get_header(m, "Format");
- const char *mix = astman_get_header(m, "Mix");
-+ const char *target_url = astman_get_header(m, "TargetURL");
-+ const char *target_script = astman_get_header(m, "TargetScript");
- char *d;
-
- if (ast_strlen_zero(name)) {
-@@ -530,7 +544,7 @@ static int start_monitor_action(struct m
- *d = '-';
- }
-
-- if (ast_monitor_start(c, format, fname, 1)) {
-+ if (ast_monitor_start(c, format, fname, target_url, target_script, 1)) {
- if (ast_monitor_change_fname(c, fname, 1)) {
- astman_send_error(s, m, "Could not start monitoring channel");
- ast_channel_unlock(c);
---- a/apps/app_queue.c
-+++ b/apps/app_queue.c
-@@ -2891,13 +2891,13 @@ static int try_calling(struct queue_ent
- else
- which = peer;
- if (monitorfilename)
-- ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
-+ ast_monitor_start(which, qe->parent->monfmt, monitorfilename, NULL, NULL, 1 );
- else if (qe->chan->cdr)
-- ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
-+ ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, NULL, NULL, 1 );
- else {
- /* Last ditch effort -- no CDR, make up something */
- snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
-- ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
-+ ast_monitor_start(which, qe->parent->monfmt, tmpid, NULL, NULL, 1 );
- }
- if (qe->parent->monjoin)
- ast_monitor_setjoinfiles(which, 1);
---- a/channels/chan_agent.c
-+++ b/channels/chan_agent.c
-@@ -419,7 +419,7 @@ static int __agent_start_monitoring(stru
- if ((pointer = strchr(filename, '.')))
- *pointer = '-';
- snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
-- ast_monitor_start(ast, recordformat, tmp, needlock);
-+ ast_monitor_start(ast, recordformat, tmp, NULL, NULL, needlock);
- ast_monitor_setjoinfiles(ast, 1);
- snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
- #if 0
---- a/include/asterisk/devicestate.h
-+++ b/include/asterisk/devicestate.h
-@@ -47,7 +47,7 @@ extern "C" {
- #define AST_DEVICE_ONHOLD 8
-
- /*! \brief Devicestate watcher call back */
--typedef int (*ast_devstate_cb_type)(const char *dev, int state, void *data);
-+typedef int (*ast_devstate_cb_type)(const char *dev, int state, void *data, char *cid_num, char *cid_name);
-
- /*! \brief Devicestate provider call back */
- typedef int (*ast_devstate_prov_cb_type)(const char *data);
-@@ -92,7 +92,7 @@ int ast_device_state_changed(const char
- * callbacks for the changed extensions
- * Returns 0 on success, -1 on failure
- */
--int ast_device_state_changed_literal(const char *device);
-+int ast_device_state_changed_literal(const char *device, const char *cid_num, const char *cid_name);
-
- /*! \brief Registers a device state change callback
- * \param callback Callback
---- a/main/devicestate.c
-+++ b/main/devicestate.c
-@@ -78,6 +78,8 @@ static AST_LIST_HEAD_STATIC(devstate_cbs
-
- struct state_change {
- AST_LIST_ENTRY(state_change) list;
-+ char cid_num[AST_MAX_EXTENSION];
-+ char cid_name[AST_MAX_EXTENSION];
- char device[1];
- };
-
-@@ -277,7 +279,7 @@ void ast_devstate_del(ast_devstate_cb_ty
- /*! \brief Notify callback watchers of change, and notify PBX core for hint updates
- Normally executed within a separate thread
- */
--static void do_state_change(const char *device)
-+static void do_state_change(const char *device, char *cid_num, char *cid_name)
- {
- int state;
- struct devstate_cb *devcb;
-@@ -288,13 +290,13 @@ static void do_state_change(const char *
-
- AST_LIST_LOCK(&devstate_cbs);
- AST_LIST_TRAVERSE(&devstate_cbs, devcb, list)
-- devcb->callback(device, state, devcb->data);
-+ devcb->callback(device, state, devcb->data, cid_num, cid_name);
- AST_LIST_UNLOCK(&devstate_cbs);
-
-- ast_hint_state_changed(device);
-+ ast_hint_state_changed(device, cid_num, cid_name);
- }
-
--static int __ast_device_state_changed_literal(char *buf, int norecurse)
-+static int __ast_device_state_changed_literal(char *buf, int norecurse, char *cid_num, char *cid_name)
- {
- char *device;
- struct state_change *change;
-@@ -308,10 +310,16 @@ static int __ast_device_state_changed_li
- if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
- /* we could not allocate a change struct, or */
- /* there is no background thread, so process the change now */
-- do_state_change(device);
-+ do_state_change(device, cid_num, cid_name);
- } else {
- /* queue the change */
- strcpy(change->device, device);
-+ if (cid_num && (!ast_strlen_zero(cid_num))) {
-+ strncpy(change->cid_num, cid_num, sizeof(change->cid_num) - 1);
-+ }
-+ if (cid_name && (!ast_strlen_zero(cid_name))) {
-+ strncpy(change->cid_name, cid_name, sizeof(change->cid_name) - 1);
-+ }
- AST_LIST_LOCK(&state_changes);
- AST_LIST_INSERT_TAIL(&state_changes, change, list);
- if (AST_LIST_FIRST(&state_changes) == change)
-@@ -329,17 +337,23 @@ static int __ast_device_state_changed_li
- */
- if (!norecurse && (tmp = strrchr(device, '-'))) {
- *tmp = '\0';
-- __ast_device_state_changed_literal(device, 1);
-+ __ast_device_state_changed_literal(device, 1, cid_num, cid_name);
- }
-
- return 1;
- }
-
--int ast_device_state_changed_literal(const char *dev)
-+int ast_device_state_changed_literal(const char *dev, const char *cid_num, const char *cid_name)
- {
- char *buf;
-+ char *buf2 = NULL;
-+ char *buf3 = NULL;
- buf = ast_strdupa(dev);
-- return __ast_device_state_changed_literal(buf, 0);
-+ if (cid_num)
-+ buf2 = ast_strdupa(cid_num);
-+ if (cid_name)
-+ buf3 = ast_strdupa(cid_name);
-+ return __ast_device_state_changed_literal(buf, 0, buf2, buf3);
- }
-
- /*! \brief Accept change notification, add it to change queue */
-@@ -351,7 +365,7 @@ int ast_device_state_changed(const char
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-- return __ast_device_state_changed_literal(buf, 0);
-+ return __ast_device_state_changed_literal(buf, 0, NULL, NULL);
- }
-
- /*! \brief Go through the dev state change queue and update changes in the dev state thread */
-@@ -366,7 +380,7 @@ static void *do_devstate_changes(void *d
- if (cur) {
- /* we got an entry, so unlock the list while we process it */
- AST_LIST_UNLOCK(&state_changes);
-- do_state_change(cur->device);
-+ do_state_change(cur->device, cur->cid_num, cur->cid_name);
- free(cur);
- AST_LIST_LOCK(&state_changes);
- } else {
---- a/include/asterisk/channel.h
-+++ b/include/asterisk/channel.h
-@@ -613,8 +613,13 @@ int ast_channel_datastore_remove(struct
- /*! \brief Find a datastore on a channel */
- struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, char *uid);
-
-+extern ast_mutex_t uniquelock;
-+
-+/*! \brief Change the state of a channel and the callerid of the calling channel*/
-+int ast_setstate_and_callerid(struct ast_channel *chan, enum ast_channel_state state, char *cid_num, char *cid_name);
-+
- /*! \brief Change the state of a channel */
--int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
-+int ast_setstate(struct ast_channel *chan, enum ast_channel_state state);
-
- /*! \brief Create a channel structure
- \return Returns NULL on failure to allocate.
---- a/main/channel.c
-+++ b/main/channel.c
-@@ -1261,7 +1261,7 @@ void ast_channel_free(struct ast_channel
- free(chan);
- AST_LIST_UNLOCK(&channels);
-
-- ast_device_state_changed_literal(name);
-+ ast_device_state_changed_literal(name, NULL, NULL);
- }
-
- struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, char *uid)
-@@ -3673,7 +3673,7 @@ void ast_set_callerid(struct ast_channel
- ast_channel_unlock(chan);
- }
-
--int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
-+int ast_setstate_and_callerid(struct ast_channel *chan, enum ast_channel_state state, char *cid_num, char *cid_name)
- {
- int oldstate = chan->_state;
-
-@@ -3681,7 +3681,7 @@ int ast_setstate(struct ast_channel *cha
- return 0;
-
- chan->_state = state;
-- ast_device_state_changed_literal(chan->name);
-+ ast_device_state_changed_literal(chan->name, cid_num, cid_name);
- /* setstate used to conditionally report Newchannel; this is no more */
- manager_event(EVENT_FLAG_CALL,
- "Newstate",
-@@ -3698,6 +3698,11 @@ int ast_setstate(struct ast_channel *cha
- return 0;
- }
-
-+int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
-+{
-+ return ast_setstate_and_callerid(chan, state, NULL, NULL);
-+}
-+
- /*! \brief Find bridged channel */
- struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
- {
---- a/include/asterisk/pbx.h
-+++ b/include/asterisk/pbx.h
-@@ -63,7 +63,7 @@ struct ast_ignorepat;
- struct ast_sw;
-
- /*! \brief Typedef for devicestate and hint callbacks */
--typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
-+typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data, char *cid_num, char *cid_name);
-
- /*! \brief Data structure associated with a custom dialplan function */
- struct ast_custom_function {
-@@ -875,7 +875,7 @@ int ast_func_read(struct ast_channel *ch
- */
- int ast_func_write(struct ast_channel *chan, char *function, const char *value);
-
--void ast_hint_state_changed(const char *device);
-+void ast_hint_state_changed(const char *device, char *cid_num, char *cid_name);
-
- #if defined(__cplusplus) || defined(c_plusplus)
- }
---- a/main/pbx.c
-+++ b/main/pbx.c
-@@ -2022,7 +2022,7 @@ int ast_extension_state(struct ast_chann
- return ast_extension_state2(e); /* Check all devices in the hint */
- }
-
--void ast_hint_state_changed(const char *device)
-+void ast_hint_state_changed(const char *device, char *cid_num, char *cid_name)
- {
- struct ast_hint *hint;
-
-@@ -2053,11 +2053,11 @@ void ast_hint_state_changed(const char *
-
- /* For general callbacks */
- for (cblist = statecbs; cblist; cblist = cblist->next)
-- cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
-+ cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data, cid_num, cid_name);
-
- /* For extension callbacks */
- for (cblist = hint->callbacks; cblist; cblist = cblist->next)
-- cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
-+ cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data, cid_num, cid_name);
-
- hint->laststate = state; /* record we saw the change */
- }
-@@ -2252,7 +2252,7 @@ static int ast_remove_hint(struct ast_ex
- /* Notify with -1 and remove all callbacks */
- cbprev = cblist;
- cblist = cblist->next;
-- cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
-+ cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data, NULL, NULL);
- free(cbprev);
- }
- hint->callbacks = NULL;
-@@ -4021,7 +4021,7 @@ void ast_merge_contexts_and_delete(struc
- while (thiscb) {
- prevcb = thiscb;
- thiscb = thiscb->next;
-- prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
-+ prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data, NULL, NULL);
- free(prevcb);
- }
- } else {
---- a/channels/chan_sip.c
-+++ b/channels/chan_sip.c
-@@ -1342,7 +1342,7 @@ static void ast_quiet_chan(struct ast_ch
- static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
-
- /*--- Device monitoring and Device/extension state handling */
--static int cb_extensionstate(char *context, char* exten, int state, void *data);
-+static int cb_extensionstate(char *context, char* exten, int state, void *data, char *cid_num, char *cid_name);
- static int sip_devicestate(void *data);
- static int sip_poke_noanswer(const void *data);
- static int sip_poke_peer(struct sip_peer *peer);
-@@ -8593,7 +8593,7 @@ static void sip_peer_hold(struct sip_pvt
- /*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
- \note If you add an "hint" priority to the extension in the dial plan,
- you will get notifications on device state changes */
--static int cb_extensionstate(char *context, char* exten, int state, void *data)
-+static int cb_extensionstate(char *context, char* exten, int state, void *data, char *cid_num, char *cid_name)
- {
- struct sip_pvt *p = data;
-
-@@ -12783,7 +12783,7 @@ static void handle_response(struct sip_p
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
- /* Ready to send the next state we have on queue */
- ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
-- cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
-+ cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p, NULL, NULL);
- }
- }
- } else if (sipmethod == SIP_REGISTER)
-@@ -13036,7 +13036,7 @@ static void handle_response(struct sip_p
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
- /* Ready to send the next state we have on queue */
- ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
-- cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
-+ cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p, NULL, NULL);
- }
- }
- } else if (sipmethod == SIP_BYE)
---- a/apps/app_queue.c
-+++ b/apps/app_queue.c
-@@ -721,7 +721,7 @@ static void *device_state_thread(void *d
- return NULL;
- }
- /*! \brief Producer of the statechange queue */
--static int statechange_queue(const char *dev, int state, void *ign)
-+static int statechange_queue(const char *dev, int state, void *ign, char *cid_num, char *cid_name)
- {
- struct statechange *sc;
-
---- a/include/asterisk/manager.h
-+++ b/include/asterisk/manager.h
-@@ -55,6 +55,7 @@
- #define EVENT_FLAG_AGENT (1 << 5) /* Ability to read/set agent info */
- #define EVENT_FLAG_USER (1 << 6) /* Ability to read/set user info */
- #define EVENT_FLAG_CONFIG (1 << 7) /* Ability to modify configurations */
-+#define EVENT_FLAG_EXTENSIONSTATUS (1 << 8) /* ExtensionStatus events */
-
- /* Export manager structures */
- #define AST_MAX_MANHEADERS 128
---- a/main/manager.c
-+++ b/main/manager.c
-@@ -129,6 +129,7 @@ static struct permalias {
- { EVENT_FLAG_AGENT, "agent" },
- { EVENT_FLAG_USER, "user" },
- { EVENT_FLAG_CONFIG, "config" },
-+ { EVENT_FLAG_EXTENSIONSTATUS, "extensionstatus" },
- { -1, "all" },
- { 0, "none" },
- };
-@@ -2551,10 +2552,12 @@ int ast_manager_unregister(char *action)
- return 0;
- }
-
--static int manager_state_cb(char *context, char *exten, int state, void *data)
-+static int manager_state_cb(char *context, char *exten, int state, void *data, char *cid_num, char *cid_name)
- {
-+ char hint[256] = "";
-+ ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
- /* Notify managers of change */
-- manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
-+ manager_event(EVENT_FLAG_EXTENSIONSTATUS, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\nCallerID: \"%s\" <%s>\r\nHint: %s\r\n", exten, context, state, cid_num, cid_name, hint);
- return 0;
- }
-
---- a/apps/app_devstate.c
-+++ b/apps/app_devstate.c
-@@ -50,7 +50,7 @@ static struct ast_cli_entry cli_dev_sta
- static int devstate_cli(int fd, int argc, char *argv[])
- {
- char devName[128];
-- if (argc != 3)
-+ if ((argc != 3) && (argc != 4) && (argc != 5))
- return RESULT_SHOWUSAGE;
-
- if (ast_db_put("DEVSTATES", argv[1], argv[2]))
-@@ -58,7 +58,15 @@ static int devstate_cli(int fd, int argc
- ast_log(LOG_DEBUG, "ast_db_put failed\n");
- }
- snprintf(devName, sizeof(devName), "DS/%s", argv[1]);
-- ast_device_state_changed_literal(devName);
-+ if (argc == 4) {
-+ ast_log(LOG_NOTICE, "devname %s cid %s\n", devName, argv[3]);
-+ ast_device_state_changed_literal(devName, argv[3], NULL);
-+ } else if (argc == 5) {
-+ ast_log(LOG_NOTICE, "devname %s cid %s cidname %s\n", devName, argv[3], argv[4]);
-+ ast_device_state_changed_literal(devName, argv[3], argv[4]);
-+ } else {
-+ ast_device_state_changed_literal(devName, NULL, NULL);
-+ }
- return RESULT_SUCCESS;
- }
-
-@@ -93,7 +101,7 @@ static int devstate_exec(struct ast_chan
- }
-
- snprintf(devName, sizeof(devName), "DS/%s", device);
-- ast_device_state_changed_literal(devName);
-+ ast_device_state_changed_literal(devName, NULL, NULL);
-
- ast_module_user_remove(u);
- return 0;
-@@ -150,6 +158,8 @@ static int action_devstate(struct manses
- const char *devstate = astman_get_header(m, "Devstate");
- const char *value = astman_get_header(m, "Value");
- const char *id = astman_get_header(m,"ActionID");
-+ const char *cid_num = astman_get_header(m, "CallerID");
-+ const char *cid_name = astman_get_header(m, "CallerIDName");
- char devName[128];
- char idText[256] = "";
-
-@@ -166,7 +176,7 @@ static int action_devstate(struct manses
-
- if (!ast_db_put("DEVSTATES", devstate, (char *)value)) {
- snprintf(devName, sizeof(devName), "DS/%s", devstate);
-- ast_device_state_changed_literal(devName);
-+ ast_device_state_changed_literal(devName, cid_num, cid_name);
- astman_append(s, "Response: Success\r\n%s\r\n", idText);
- } else {
- ast_log(LOG_DEBUG, "ast_db_put failed\n");
---- a/res/res_esel.c
-+++ b/res/res_esel.c
-@@ -51,6 +51,8 @@ typedef struct esel_extension_state {
- char context[AST_MAX_EXTENSION];
- char exten[AST_MAX_EXTENSION];
- int state;
-+ char cid_num[AST_MAX_EXTENSION];
-+ char cid_name[AST_MAX_EXTENSION];
- char devstate[AST_MAX_EXTENSION];
- struct esel_extension_state *next;
- struct esel_extension_state *prev;
-@@ -93,7 +95,7 @@ typedef struct esel_pvt {
-
- static struct esel_pvt *donkeys = NULL;
-
--static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data) {
-+static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data, char *cid_num, char *cid_name) {
- struct esel_extension_state *exstate = NULL;
-
- exstate = malloc(sizeof(struct esel_extension_state));
-@@ -115,6 +117,8 @@ static int esel_queue_extension_state(st
- }
- ast_copy_string(exstate->exten, exten, sizeof(exstate->exten));
- ast_copy_string(exstate->context, context, sizeof(exstate->context));
-+ ast_copy_string(exstate->cid_num, cid_num, sizeof(exstate->cid_num));
-+ ast_copy_string(exstate->cid_name, cid_name, sizeof(exstate->cid_name));
- exstate->state = state;
- if (!queue->head) {
- /* Empty queue */
-@@ -161,7 +165,7 @@ static void esel_export_to_remote(struct
- char msg[1024];
- int sent = 0;
- memset(msg, 0x0, sizeof(msg));
-- snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state));
-+ snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\nCallerID: %s\r\nCallerIDName: %s\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state), exstate->cid_num, exstate->cid_name);
- sent = send(esel->sockfd, msg, strlen(msg), 0);
- if (sent == -1) {
- esel->connected = 0;
-@@ -250,13 +254,13 @@ static void *do_esel_thread(void *data)
- return NULL;
- }
-
--static int esel_state_cb(char *context, char *exten, int state, void *data) {
-+static int esel_state_cb(char *context, char *exten, int state, void *data, char *cid_num, char *cid_name) {
- struct esel_pvt *esel;
-
- esel = donkeys;
- ast_mutex_lock(&listlock);
- while (esel) {
-- esel_queue_extension_state(&esel->queue, context, exten, state, data);
-+ esel_queue_extension_state(&esel->queue, context, exten, state, data, cid_num, cid_name);
- esel = esel->next;
- }
- ast_mutex_unlock(&listlock);
-Add or convert channel operations so they can use the unique ID.
-
---- a/include/asterisk/channel.h
-+++ b/include/asterisk/channel.h
-@@ -682,6 +682,18 @@ void ast_channel_free(struct ast_channe
- */
- struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
-
-+/*! \brief Requests a channel
-+ * \param type type of channel to request
-+ * \param format requested channel format (codec)
-+ * \param data data to pass to the channel requester
-+ * \param status status
-+ * \param uniqueid uniqueid
-+ * Request a channel of a given type, with data as optional information used
-+ * by the low level module. Sets the channels uniqueid to 'uniqueid'.
-+ * \return Returns an ast_channel on success, NULL on failure.
-+ */
-+struct ast_channel *ast_request_with_uniqueid(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
- * by the low level module and attempt to place a call on it
-@@ -697,8 +709,12 @@ struct ast_channel *ast_request(const ch
- */
- 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_uniqueid(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_uniqueid(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 "Requests" a channel for sending a message
- * \param type type of channel to request
- * \param data data to pass to the channel requester
-@@ -990,6 +1006,8 @@ struct ast_channel *ast_get_channel_by_e
- /*! \brief Get next channel by exten (and optionally context) and lock it */
- struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
- const char *context);
-+/*! Get channel by uniqueid (locks channel) */
-+struct ast_channel *ast_get_channel_by_uniqueid_locked(const char *uniqueid);
-
- /*! ! \brief Waits for a digit
- * \param c channel to wait for a digit on
---- a/main/channel.c
-+++ b/main/channel.c
-@@ -1017,7 +1017,7 @@ void ast_channel_undefer_dtmf(struct ast
- */
- static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
- const char *name, const int namelen,
-- const char *context, const char *exten)
-+ const char *context, const char *exten, const char *uniqueid)
- {
- const char *msg = prev ? "deadlock" : "initial deadlock";
- int retries;
-@@ -1045,7 +1045,10 @@ static struct ast_channel *channel_find_
- * XXX Need a better explanation for this ...
- */
- }
-- if (name) { /* want match by name */
-+ if (uniqueid) {
-+ if (!strcasecmp(c->uniqueid, uniqueid))
-+ break;
-+ } else if (name) { /* want match by name */
- if ((!namelen && strcasecmp(c->name, name)) ||
- (namelen && strncasecmp(c->name, name, namelen)))
- continue; /* name match failed */
-@@ -1100,39 +1103,44 @@ static struct ast_channel *channel_find_
- /*! \brief Browse channels in use */
- struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev)
- {
-- return channel_find_locked(prev, NULL, 0, NULL, NULL);
-+ return channel_find_locked(prev, NULL, 0, NULL, NULL, NULL);
- }
-
- /*! \brief Get channel by name and lock it */
- struct ast_channel *ast_get_channel_by_name_locked(const char *name)
- {
-- return channel_find_locked(NULL, name, 0, NULL, NULL);
-+ return channel_find_locked(NULL, name, 0, NULL, NULL, NULL);
- }
-
- /*! \brief Get channel by name prefix and lock it */
- struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen)
- {
-- return channel_find_locked(NULL, name, namelen, NULL, NULL);
-+ return channel_find_locked(NULL, name, namelen, NULL, NULL, NULL);
- }
-
- /*! \brief Get next channel by name prefix and lock it */
- struct ast_channel *ast_walk_channel_by_name_prefix_locked(const struct ast_channel *chan, const char *name,
- const int namelen)
- {
-- return channel_find_locked(chan, name, namelen, NULL, NULL);
-+ return channel_find_locked(chan, name, namelen, NULL, NULL, NULL);
- }
-
- /*! \brief 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)
- {
-- return channel_find_locked(NULL, NULL, 0, context, exten);
-+ return channel_find_locked(NULL, NULL, 0, context, exten, NULL);
- }
-
- /*! \brief Get next channel by exten (and optionally context) and lock it */
- struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
- const char *context)
- {
-- return channel_find_locked(chan, NULL, 0, context, exten);
-+ return channel_find_locked(chan, NULL, 0, context, exten, NULL);
-+}
-+
-+struct ast_channel *ast_get_channel_by_uniqueid_locked(const char *uniqueid)
-+{
-+ return channel_find_locked(NULL, NULL, 0, NULL, NULL, uniqueid);
- }
-
- /*! \brief Wait, look for hangups and condition arg */
-@@ -2862,6 +2870,12 @@ char *ast_channel_reason2str(int reason)
-
- 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)
- {
-+ return __ast_request_and_dial_uniqueid(type, format, data,
-+ timeout, outstate, 0, cid_num, cid_name, oh, NULL);
-+}
-+
-+struct ast_channel *__ast_request_and_dial_uniqueid(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 dummy_outstate;
- int cause = 0;
- struct ast_channel *chan;
-@@ -2873,7 +2887,7 @@ struct ast_channel *__ast_request_and_di
- else
- outstate = &dummy_outstate; /* make outstate always a valid pointer */
-
-- chan = ast_request(type, format, data, &cause);
-+ chan = ast_request_with_uniqueid(type, format, data, &cause, uniqueid);
- if (!chan) {
- ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
- /* compute error and return */
-@@ -2993,8 +3007,12 @@ struct ast_channel *ast_request_and_dial
- {
- return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL);
- }
-+struct ast_channel *ast_request_and_dial_uniqueid(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_uniqueid(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_with_uniqueid(const char *type, int format, void *data, int *cause, char *uniqueid)
- {
- struct chanlist *chan;
- struct ast_channel *c;
-@@ -3033,6 +3051,7 @@ struct ast_channel *ast_request(const ch
- if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
- return NULL;
-
-+ if (uniqueid) strncpy(c->uniqueid, uniqueid, sizeof(c->uniqueid));
- /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
- return c;
- }
-@@ -3044,6 +3063,11 @@ struct ast_channel *ast_request(const ch
- return NULL;
- }
-
-+struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
-+{
-+ return ast_request_with_uniqueid(type, format, data, cause, NULL);
-+}
-+
- int ast_call(struct ast_channel *chan, char *addr, int timeout)
- {
- /* Place an outgoing call, but don't wait any longer than timeout ms before returning.
---- a/include/asterisk/pbx.h
-+++ b/include/asterisk/pbx.h
-@@ -717,9 +717,17 @@ int ast_async_goto_by_name(const char *c
- 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, const char *account, struct ast_channel **locked_channel);
-
- /*! Synchronously or asynchronously make an outbound call and send it to a
-+ particular extension (extended version with callinpres and uniqueid) */
-+int ast_pbx_outgoing_exten_uniqueid(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, const char *account, 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, const char *account, struct ast_channel **locked_channel);
-
-+/*! Synchronously or asynchronously make an outbound call and send it to a
-+ particular application with given extension (extended version with callinpres and uniqueid) */
-+int ast_pbx_outgoing_app_uniqueid(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, const char *account, struct ast_channel **locked_channel, char *uniqueid);
-+
- /*!
- * \brief Evaluate a condition
- *
---- a/main/pbx.c
-+++ b/main/pbx.c
-@@ -4992,7 +4992,7 @@ static int ast_pbx_outgoing_cdr_failed(v
- 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, const char *account, struct ast_channel **channel)
-+int ast_pbx_outgoing_exten_uniqueid(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, const char *account, struct ast_channel **channel, char *uniqueid)
- {
- struct ast_channel *chan;
- struct async_stat *as;
-@@ -5002,7 +5002,7 @@ int ast_pbx_outgoing_exten(const char *t
-
- 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_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
- if (channel) {
- *channel = chan;
- if (chan)
-@@ -5094,7 +5094,7 @@ int ast_pbx_outgoing_exten(const char *t
- res = -1;
- goto outgoing_exten_cleanup;
- }
-- chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
-+ chan = ast_request_and_dial_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
- if (channel) {
- *channel = chan;
- if (chan)
-@@ -5134,6 +5134,10 @@ outgoing_exten_cleanup:
- return res;
- }
-
-+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, const char *account, struct ast_channel **channel)
-+{
-+ return ast_pbx_outgoing_exten_uniqueid(type, format, data, timeout, context, exten, priority, reason, sync, 0, cid_num, cid_name, vars, account, channel, NULL);
-+}
- struct app_tmp {
- char app[256];
- char data[256];
-@@ -5158,7 +5162,7 @@ static void *ast_pbx_run_app(void *data)
- 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, const char *account, struct ast_channel **locked_channel)
-+int ast_pbx_outgoing_app_uniqueid(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, const char *account, struct ast_channel **locked_channel, char *uniqueid)
- {
- struct ast_channel *chan;
- struct app_tmp *tmp;
-@@ -5177,7 +5181,7 @@ int ast_pbx_outgoing_app(const char *typ
- 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_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
- if (chan) {
- if (!chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
- chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
-@@ -5259,7 +5263,7 @@ int ast_pbx_outgoing_app(const char *typ
- res = -1;
- goto outgoing_app_cleanup;
- }
-- chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
-+ chan = __ast_request_and_dial_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
- if (!chan) {
- free(as);
- res = -1;
-@@ -5299,6 +5303,10 @@ outgoing_app_cleanup:
- return res;
- }
-
-+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, const char *account, struct ast_channel **locked_channel)
-+{
-+ return ast_pbx_outgoing_app_uniqueid(type, format, data, timeout, app, appdata, reason, sync, 0, cid_num, cid_name, vars, account, locked_channel, NULL);
-+}
- void __ast_context_destroy(struct ast_context *con, const char *registrar)
- {
- struct ast_context *tmp, *tmpl=NULL;
---- a/res/res_monitor.c
-+++ b/res/res_monitor.c
-@@ -340,6 +340,11 @@ int ast_monitor_stop(struct ast_channel
- result = ast_safe_system(tmp);
- if (result == -1)
- ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
-+ manager_event(EVENT_FLAG_CALL, "MonitorStopped",
-+ "Channel: %s\r\n"
-+ "Uniqueid: %s\r\n"
-+ "Result: %d\r\n"
-+ ,chan->name, chan->uniqueid, result);
- }
-
- free(chan->monitor->format);
-@@ -518,18 +523,28 @@ static int start_monitor_action(struct m
- const char *fname = astman_get_header(m, "File");
- const char *format = astman_get_header(m, "Format");
- const char *mix = astman_get_header(m, "Mix");
-+ const char *uniqueid = astman_get_header(m, "Uniqueid");
- const char *target_url = astman_get_header(m, "TargetURL");
- const char *target_script = astman_get_header(m, "TargetScript");
- char *d;
-
-- if (ast_strlen_zero(name)) {
-- astman_send_error(s, m, "No channel specified");
-+ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
-+ astman_send_error(s, m, "No channel/uniqueid specified");
-+ return 0;
-+ }
-+
-+ if (!ast_strlen_zero(uniqueid)) {
-+ c = ast_get_channel_by_uniqueid_locked(uniqueid);
-+ if (!c) {
-+ astman_send_error(s, m, "No such uniqueid");
- return 0;
-- }
-- c = ast_get_channel_by_name_locked(name);
-- if (!c) {
-+ }
-+ } else {
-+ c = ast_get_channel_by_name_locked(name);
-+ if (!c) {
- astman_send_error(s, m, "No such channel");
- return 0;
-+ }
- }
-
- if (ast_strlen_zero(fname)) {
-@@ -570,16 +585,30 @@ static int stop_monitor_action(struct ma
- {
- struct ast_channel *c = NULL;
- const char *name = astman_get_header(m, "Channel");
-+ const char *uniqueid = astman_get_header(m, "Uniqueid");
- int res;
- if (ast_strlen_zero(name)) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
-- c = ast_get_channel_by_name_locked(name);
-- if (!c) {
-- astman_send_error(s, m, "No such channel");
-+ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
-+ astman_send_error(s, m, "No channel/uniqueid specified");
-+ return 0;
-+ }
-+ if (!ast_strlen_zero(uniqueid)) {
-+ c = ast_get_channel_by_uniqueid_locked(uniqueid);
-+ if (!c) {
-+ astman_send_error(s, m, "No such uniqueid");
- return 0;
-+ }
-+ } else {
-+ c = ast_get_channel_by_name_locked(name);
-+ if (!c) {
-+ astman_send_error(s, m, "No such channel");
-+ return 0;
-+ }
- }
-+
- res = ast_monitor_stop(c, 1);
- ast_channel_unlock(c);
- if (res) {
---- a/apps/app_chanspy.c
-+++ b/apps/app_chanspy.c
-@@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
-
- static const char *tdesc = "Listen to a channel, and optionally whisper into it";
- static const char *app_chan = "ChanSpy";
-+static const char *app_chan_uniqueid = "ChanSpyChan";
- static const char *desc_chan =
- " ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
- "audio from an Asterisk channel. This includes the audio coming in and\n"
-@@ -87,6 +88,27 @@ static const char *desc_chan =
- " channel.\n"
- ;
-
-+static const char *desc_uniqueid =
-+" ChanSpyChan(uniqueid[|options]): This application is used to listen to the\n"
-+"audio from an Asterisk channel. This includes the audio coming in and\n"
-+"out of the channel being spied on. The 'uniqueid' parameter has to be specified,\n"
-+" While spying, the following actions may be performed:\n"
-+" - Dialing # cycles the volume level.\n"
-+" Options:\n"
-+" q - Don't play a beep when beginning to spy on a channel, or speak the\n"
-+" selected channel name.\n"
-+" r[(basename)] - Record the session to the monitor spool directory. An\n"
-+" optional base for the filename may be specified. The\n"
-+" default is 'chanspy'.\n"
-+" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
-+" negative value refers to a quieter setting.\n"
-+" w - Enable 'whisper' mode, so the spying channel can talk to\n"
-+" the spied-on channel.\n"
-+" W - Enable 'private whisper' mode, so the spying channel can\n"
-+" talk to the spied-on channel but cannot listen to that\n"
-+" channel.\n"
-+;
-+
- static const char *app_ext = "ExtenSpy";
- static const char *desc_ext =
- " ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
-@@ -456,7 +478,7 @@ static struct chanspy_ds *setup_chanspy_
-
- static struct chanspy_ds *next_channel(struct ast_channel *chan,
- const struct ast_channel *last, const char *spec,
-- const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
-+ const char *exten, const char *context, struct chanspy_ds *chanspy_ds, const char *uniqueid)
- {
- struct ast_channel *this;
-
-@@ -465,6 +487,8 @@ redo:
- this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
- else if (exten)
- this = ast_walk_channel_by_exten_locked(last, exten, context);
-+ else if (uniqueid)
-+ this = ast_get_channel_by_uniqueid_locked(uniqueid);
- else
- this = ast_channel_walk_locked(last);
-
-@@ -485,7 +509,7 @@ redo:
-
- static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
- int volfactor, const int fd, const char *mygroup, const char *spec,
-- const char *exten, const char *context)
-+ const char *exten, const char *context, const char *uniqueid)
- {
- char nameprefix[AST_NAME_STRLEN];
- char peer_name[AST_NAME_STRLEN + 5];
-@@ -530,11 +554,11 @@ static int common_exec(struct ast_channe
- waitms = 100;
- num_spyed_upon = 0;
-
-- for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
-+ for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds, NULL);
- peer_chanspy_ds;
- chanspy_ds_free(peer_chanspy_ds), prev = peer,
- peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
-- next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
-+ next_channel(chan, prev, spec, exten, context, &chanspy_ds, NULL), next_chanspy_ds = NULL) {
- const char *group;
- int igrp = !mygroup;
- char *groups[25];
-@@ -733,7 +757,7 @@ static int chanspy_exec(struct ast_chann
- }
- }
-
-- res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
-+ res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL, NULL);
-
- if (fd)
- close(fd);
-@@ -818,7 +842,7 @@ static int extenspy_exec(struct ast_chan
- }
- }
-
-- res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
-+ res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context, NULL);
-
- if (fd)
- close(fd);
-@@ -831,14 +855,100 @@ static int extenspy_exec(struct ast_chan
- return res;
- }
-
-+static int chanspychan_exec(struct ast_channel *chan, void *data)
-+{
-+ struct ast_module_user *u;
-+ char *options = NULL;
-+ char *uniqueid = NULL;
-+ char *argv[2];
-+ char *mygroup = NULL;
-+ char *recbase = NULL;
-+ int fd = 0;
-+ struct ast_flags flags;
-+ int oldwf = 0;
-+ int argc = 0;
-+ int volfactor = 0;
-+ int res;
-+
-+ data = ast_strdupa(data);
-+
-+ u = ast_module_user_add(chan);
-+
-+ if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
-+ uniqueid = argv[0];
-+ if (argc > 1)
-+ options = argv[1];
-+
-+ if (ast_strlen_zero(uniqueid)) {
-+ ast_log(LOG_ERROR, "no uniqueid specified.\n");
-+ ast_module_user_remove(u);
-+ return -1;
-+ }
-+ }
-+
-+ if (options) {
-+ char *opts[OPT_ARG_ARRAY_SIZE];
-+
-+ ast_app_parse_options(spy_opts, &flags, opts, options);
-+ if (ast_test_flag(&flags, OPTION_GROUP))
-+ mygroup = opts[OPT_ARG_GROUP];
-+
-+ if (ast_test_flag(&flags, OPTION_RECORD) &&
-+ !(recbase = opts[OPT_ARG_RECORD]))
-+ recbase = "chanspy";
-+
-+ if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
-+ int vol;
-+
-+ if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
-+ ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
-+ else
-+ volfactor = vol;
-+ }
-+
-+ if (ast_test_flag(&flags, OPTION_PRIVATE))
-+ ast_set_flag(&flags, OPTION_WHISPER);
-+ }
-+
-+ oldwf = chan->writeformat;
-+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
-+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
-+ ast_module_user_remove(u);
-+ return -1;
-+ }
-+
-+ if (recbase) {
-+ char filename[512];
-+
-+ snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
-+ if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
-+ ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
-+ fd = 0;
-+ }
-+ }
-+
-+ res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, NULL, uniqueid);
-+
-+ if (fd)
-+ close(fd);
-+
-+ if (oldwf && ast_set_write_format(chan, oldwf) < 0)
-+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
-+
-+ ast_module_user_remove(u);
-+
-+ return res;
-+}
-+
-+
- static int unload_module(void)
- {
- int res = 0;
-
- res |= ast_unregister_application(app_chan);
-+ res |= ast_unregister_application(app_chan_uniqueid);
- res |= ast_unregister_application(app_ext);
-
-- ast_module_user_hangup_all();
-
- return res;
- }
-@@ -849,6 +959,7 @@ static int load_module(void)
-
- res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
- res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
-+ res |= ast_register_application(app_chan_uniqueid, chanspychan_exec, tdesc, desc_uniqueid);
-
- return res;
- }
---- a/main/manager.c
-+++ b/main/manager.c
-@@ -87,6 +87,8 @@ struct fast_originate_helper {
- char idtext[AST_MAX_EXTENSION];
- char account[AST_MAX_ACCOUNT_CODE];
- int priority;
-+ int callingpres;
-+ char uniqueid[64];
- struct ast_variable *vars;
- };
-
-@@ -1416,11 +1418,20 @@ static int action_hangup(struct mansessi
- {
- struct ast_channel *c = NULL;
- const char *name = astman_get_header(m, "Channel");
-- if (ast_strlen_zero(name)) {
-- astman_send_error(s, m, "No channel specified");
-+ const 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;
-@@ -1671,12 +1682,18 @@ static int action_redirect(struct manses
- const char *exten = astman_get_header(m, "Exten");
- const char *context = astman_get_header(m, "Context");
- const char *priority = astman_get_header(m, "Priority");
-+ const char *uniqueid = astman_get_header(m, "Uniqueid");
-+ const char *uniqueid2 = astman_get_header(m, "ExtraUniqueid");
-+ const char *exten2 = astman_get_header(m, "ExtraExten");
-+ const char *context2 = astman_get_header(m, "ExtraContext");
-+ const 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 (ast_strlen_zero(name) && 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)) {
-@@ -1685,8 +1702,18 @@ static int action_redirect(struct manses
- return 0;
- }
- }
-+ if (!ast_strlen_zero(priority2) && (sscanf(priority2, "%d", &pi2) != 1)) {
-+ if ((pi = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL)) < 1) {
-+ astman_send_error(s, m, "Invalid extra priority\n");
-+ return 0;
-+ }
-+ }
- /* XXX watch out, possible deadlock!!! */
-- chan = ast_get_channel_by_name_locked(name);
-+ if (!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);
-@@ -1698,8 +1725,11 @@ static int action_redirect(struct manses
- ast_channel_unlock(chan);
- return 0;
- }
-- if (!ast_strlen_zero(name2))
-+ if (!ast_strlen_zero(uniqueid2)) {
-+ chan2 = ast_get_channel_by_uniqueid_locked(uniqueid2);
-+ } else if (!ast_strlen_zero(name2)) {
- chan2 = ast_get_channel_by_name_locked(name2);
-+ }
- if (chan2 && ast_check_hangup(chan2)) {
- astman_send_error(s, m, "Redirect failed, extra channel not up.\n");
- ast_channel_unlock(chan);
-@@ -1708,9 +1738,9 @@ static int action_redirect(struct manses
- }
- 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)
-@@ -1789,15 +1819,15 @@ static void *fast_originate(void *data)
- char requested_channel[AST_CHANNEL_NAME];
-
- 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_uniqueid(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, in->callingpres,
- S_OR(in->cid_num, NULL),
- S_OR(in->cid_name, NULL),
-- in->vars, in->account, &chan);
-+ in->vars, in->account, &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_uniqueid(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, in->callingpres,
- S_OR(in->cid_num, NULL),
- S_OR(in->cid_name, NULL),
-- in->vars, in->account, &chan);
-+ in->vars, in->account, &chan, in->uniqueid);
- }
-
- if (!chan)
-@@ -1857,6 +1887,7 @@ static int action_originate(struct manse
- const char *appdata = astman_get_header(m, "Data");
- const char *async = astman_get_header(m, "Async");
- const char *id = astman_get_header(m, "ActionID");
-+ const char *callingpres = astman_get_header(m, "CallingPres");
- struct ast_variable *vars = astman_get_variables(m);
- char *tech, *data;
- char *l = NULL, *n = NULL;
-@@ -1866,6 +1897,9 @@ static int action_originate(struct manse
- int reason = 0;
- char tmp[256];
- char tmp2[256];
-+ char *uniqueid;
-+ int cpresi = 0;
-+ char idText[256] = "";
-
- pthread_t th;
- pthread_attr_t attr;
-@@ -1883,6 +1917,10 @@ static int action_originate(struct manse
- 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, '/');
-@@ -1902,6 +1940,7 @@ static int action_originate(struct manse
- if (ast_strlen_zero(l))
- l = NULL;
- }
-+ uniqueid = ast_alloc_uniqueid();
- if (ast_true(async)) {
- struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
- if (!fast) {
-@@ -1921,8 +1960,10 @@ static int action_originate(struct manse
- ast_copy_string(fast->context, context, sizeof(fast->context));
- ast_copy_string(fast->exten, exten, sizeof(fast->exten));
- ast_copy_string(fast->account, account, sizeof(fast->account));
-+ 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)) {
-@@ -1933,19 +1974,28 @@ static int action_originate(struct manse
- pthread_attr_destroy(&attr);
- }
- } else if (!ast_strlen_zero(app)) {
-- res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
-+ res = ast_pbx_outgoing_app_uniqueid(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, cpresi, l, n, vars, account, 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, account, NULL);
-+ res = ast_pbx_outgoing_exten_uniqueid(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, cpresi, l, n, vars, account, 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;
- }
-
---- a/include/asterisk/channel.h
-+++ b/include/asterisk/channel.h
-@@ -89,6 +89,9 @@
-
- #include "asterisk/abstract_jb.h"
-
-+/* Max length of the uniqueid */
-+#define AST_MAX_UNIQUEID 64
-+
- #include <unistd.h>
- #ifdef POLLCOMPAT
- #include "asterisk/poll-compat.h"
-@@ -1039,6 +1042,8 @@ int ast_waitfordigit_full(struct ast_cha
- int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
- int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd);
-
-+char *ast_alloc_uniqueid(void);
-+
- /*! \brief Report DTMF on channel 0 */
- #define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0)
- /*! \brief Report DTMF on channel 1 */
---- a/main/channel.c
-+++ b/main/channel.c
-@@ -706,6 +706,15 @@ static const struct ast_channel_tech nul
- .description = "Null channel (should not see this)",
- };
-
-+/*! \brief Create a uniqueid */
-+char *ast_alloc_uniqueid(void) {
-+ char *uniqueid;
-+ uniqueid = malloc(64);
-+ if (!uniqueid) return NULL;
-+ snprintf(uniqueid, 63, "%s-%d-%li.%d", ast_config_AST_SYSTEM_NAME, ast_mainpid, (long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
-+ return uniqueid;
-+}
-+
- /*! \brief Create a new channel structure */
- struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const int amaflag, const char *name_fmt, ...)
- {
---- a/include/asterisk/features.h
-+++ b/include/asterisk/features.h
-@@ -47,6 +47,8 @@ struct ast_call_feature {
- };
-
-
-+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
---- a/res/res_features.c
-+++ b/res/res_features.c
-@@ -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@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.
-@@ -132,6 +136,20 @@ static char *descrip2 = "Park():"
- "it already exists. In that case, execution will continue at next\n"
- "priority.\n" ;
-
-+static char *autoanswerlogin = "AutoanswerLogin";
-+
-+static char *synopsis3 = "Log in for autoanswer";
-+
-+static char *descrip3 = "AutoanswerLogin([context]|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([context]|exten):"
-+"Used to autoanswer a call for an extension.\n";
-+
- static struct ast_app *monitor_app = NULL;
- static int monitor_ok = 1;
-
-@@ -150,6 +168,23 @@ struct parkeduser {
- struct parkeduser *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;
-
- AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
-@@ -405,11 +440,13 @@ static int park_call_full(struct ast_cha
- "From: %s\r\n"
- "Timeout: %ld\r\n"
- "CallerID: %s\r\n"
-- "CallerIDName: %s\r\n",
-+ "CallerIDName: %s\r\n"
-+ "Uniqueid: %s\r\n",
- pu->parkingexten, pu->chan->name, peer ? peer->name : "",
- (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
- S_OR(pu->chan->cid.cid_num, "<unknown>"),
-- S_OR(pu->chan->cid.cid_name, "<unknown>")
-+ S_OR(pu->chan->cid.cid_name, "<unknown>"),
-+ pu->chan->uniqueid
- );
-
- if (peer && adsipark && ast_adsi_available(peer)) {
-@@ -1656,11 +1693,13 @@ static void post_manager_event(const cha
- "Exten: %s\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",
- parkingexten,
- chan->name,
- S_OR(chan->cid.cid_num, "<unknown>"),
-- S_OR(chan->cid.cid_name, "<unknown>")
-+ S_OR(chan->cid.cid_name, "<unknown>"),
-+ chan->uniqueid
- );
- }
-
-@@ -1928,10 +1967,12 @@ static int park_exec(struct ast_channel
- "Channel: %s\r\n"
- "From: %s\r\n"
- "CallerID: %s\r\n"
-- "CallerIDName: %s\r\n",
-+ "CallerIDName: %s\r\n"
-+ "Uniqueid: %s\r\n",
- pu->parkingexten, pu->chan->name, chan->name,
- S_OR(pu->chan->cid.cid_num, "<unknown>"),
-- S_OR(pu->chan->cid.cid_name, "<unknown>")
-+ S_OR(pu->chan->cid.cid_name, "<unknown>"),
-+ pu->chan->uniqueid
- );
-
- free(pu);
-@@ -2085,15 +2126,10 @@ static struct ast_cli_entry cli_show_fea
- handle_showfeatures, NULL,
- NULL };
-
--static struct ast_cli_entry cli_features[] = {
-- { { "feature", "show", NULL },
-- handle_showfeatures, "Lists configured features",
-- showfeatures_help, NULL, &cli_show_features_deprecated },
-+static char showautoanswer_help[] =
-+"Usage: show autoanswer\n"
-+" Lists currently logged in autoanswer users.\n";
-
-- { { "show", "parkedcalls", NULL },
-- handle_parkedcalls, "Lists parked calls",
-- showparked_help },
--};
-
- /*! \brief Dump lot status */
- static int manager_parking_status( struct mansession *s, const struct message *m)
-@@ -2117,12 +2153,13 @@ static int manager_parking_status( struc
- "Timeout: %ld\r\n"
- "CallerID: %s\r\n"
- "CallerIDName: %s\r\n"
-+ "Uniqueid: %s\r\n\r\n"
- "%s"
- "\r\n",
- cur->parkingnum, cur->chan->name, cur->peername,
- (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
- S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
-- S_OR(cur->chan->cid.cid_name, ""),
-+ S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid,
- idText);
- }
-
-@@ -2197,6 +2234,427 @@ static int manager_park(struct mansessio
- return 0;
- }
-
-+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 struct ast_cli_entry cli_features[] = {
-+ { { "feature", "list", NULL },
-+ handle_showfeatures, "Lists configured features",
-+ showfeatures_help, NULL, &cli_show_features_deprecated },
-+
-+ { { "show", "parkedcalls", NULL },
-+ handle_parkedcalls, "Lists parked calls",
-+ showparked_help },
-+
-+ { { "show", "autoanswer", NULL },
-+ handle_autoanswer, "Lists autoanswer users",
-+ 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, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
-+ if (chan) {
-+ /* Let us keep track of the channel name */
-+ ast_string_field_build(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;
-+ /* might be dirty but we want trackable channels */
-+ ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
-+ /* 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 ast_module_user *u;
-+
-+ u = ast_module_user_add(chan);
-+ if (!data) {
-+ ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
-+ return -1;
-+ }
-+ res = ast_masq_autoanswer_login(chan, data);
-+ ast_module_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, 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 autoanswer_reregister_extensions(void)
-+{
-+ struct aauser *cur;
-+ struct ast_context *con;
-+ char exten[AST_MAX_EXTENSION];
-+ char args[AST_MAX_EXTENSION];
-+
-+ ast_mutex_lock(&autoanswer_lock);
-+
-+ cur=aalot;
-+ while(cur) {
-+ con = ast_context_find(cur->context);
-+ if (!con) {
-+ con = ast_context_create(NULL,cur->context, registrar);
-+ if (!con) {
-+ ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context);
-+ }
-+ }
-+ if (con) {
-+ snprintf(exten, sizeof(exten), "%s", cur->exten);
-+ snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten);
-+ ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar);
-+ }
-+ cur = cur->next;
-+ }
-+
-+ ast_mutex_unlock(&autoanswer_lock);
-+}
-+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))
-+ ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
-+ else
-+ ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
-+ 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 ast_channel *peer=NULL;
-+ struct aauser *pu, *pl=NULL;
-+ struct ast_bridge_config config;
-+ char *s, *stringp, *aacontext, *aaexten = NULL;
-+ char datastring[80];
-+ struct ast_module_user *u;
-+
-+
-+ 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";
-+ }
-+ }
-+
-+ u = ast_module_user_add(chan);
-+ 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;
-+ }
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
-
- int ast_pickup_call(struct ast_channel *chan)
- {
-@@ -2460,6 +2918,7 @@ static int load_config(void)
-
- static int reload(void)
- {
-+ autoanswer_reregister_extensions();
- return load_config();
- }
-
-@@ -2483,6 +2942,12 @@ static int load_module(void)
- "Park a channel", mandescr_park);
- }
-
-+ 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);
-+
- res |= ast_devstate_prov_add("Park", metermaidstate);
-
- return res;
-@@ -2497,6 +2962,8 @@ static int unload_module(void)
- ast_manager_unregister("Park");
- ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
- ast_unregister_application(parkcall);
-+ ast_unregister_application(autoanswer);
-+ ast_unregister_application(autoanswerlogin);
- ast_devstate_prov_del("Park");
- return ast_unregister_application(parkedcall);
- }
---- a/include/asterisk/features.h
-+++ b/include/asterisk/features.h
-@@ -72,6 +72,12 @@ int ast_park_call(struct ast_channel *ch
- */
- 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 */
---- a/res/res_features.c
-+++ b/res/res_features.c
-@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
- #include "asterisk/adsi.h"
- #include "asterisk/devicestate.h"
- #include "asterisk/monitor.h"
-+#include "asterisk/indications.h"
-
- #define DEFAULT_PARK_TIME 45000
- #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
-@@ -84,6 +85,7 @@ enum {
- };
-
- static char *parkedcall = "ParkedCall";
-+static char *holdedcall = "HoldedCall";
-
- static int parkaddhints = 0; /*!< Add parking hints automatically */
- static int parkingtime = DEFAULT_PARK_TIME; /*!< No more than 45 seconds parked before you do something with them */
-@@ -168,6 +170,22 @@ struct parkeduser {
- 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;
-@@ -187,10 +205,16 @@ static pthread_t autoanswer_thread;
-
- static struct parkeduser *parkinglot;
-
-+static struct holdeduser *holdlist;
-+
- AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
-
-+AST_MUTEX_DEFINE_STATIC(holding_lock);
-+
- static pthread_t parking_thread;
-
-+static pthread_t holding_thread;
-+
- char *ast_parking_ext(void)
- {
- return parking_ext;
-@@ -2052,6 +2076,282 @@ static int park_exec(struct ast_channel
- 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, 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, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
-+ if (chan) {
-+ /* Let us keep track of the channel name */
-+ ast_string_field_build(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 */
-+ ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
-+ /* 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.\n", uniqueid);
-+ return NULL;
-+ }
-+ } else {
-+ ast_log(LOG_WARNING, "Could not find held 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))
-+ ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
-+ else
-+ ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
-+ 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 ast_module_user *u;
-+ char *uniqueid = (char *)data;
-+ u = ast_module_user_add(chan);
-+ res = ast_retrieve_call(chan, uniqueid);
-+ ast_module_user_remove(u);
-+ return res;
-+}
-+
- static int handle_showfeatures(int fd, int argc, char *argv[])
- {
- int i;
-@@ -2933,6 +3233,7 @@ static int load_module(void)
- return res;
- ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
- 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);
-@@ -2942,6 +3243,7 @@ static int load_module(void)
- "Park a channel", mandescr_park);
- }
-
-+ 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);
-@@ -2964,6 +3266,7 @@ static int unload_module(void)
- ast_unregister_application(parkcall);
- ast_unregister_application(autoanswer);
- ast_unregister_application(autoanswerlogin);
-+ ast_unregister_application(holdedcall);
- ast_devstate_prov_del("Park");
- return ast_unregister_application(parkedcall);
- }
---- a/channels/chan_zap.c
-+++ b/channels/chan_zap.c
-@@ -77,6 +77,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
- #ifdef HAVE_PRI
- #include <bristuffed/libpri.h>
- #endif
-+#ifdef HAVE_GSMAT
-+#include <libgsmat.h>
-+#endif
-
- #include "asterisk/lock.h"
- #include "asterisk/channel.h"
-@@ -185,6 +188,7 @@ static const char config[] = "zapata.con
- #define SIG_FXOGS ZT_SIG_FXOGS
- #define SIG_FXOKS ZT_SIG_FXOKS
- #define SIG_PRI ZT_SIG_CLEAR
-+#define SIG_GSM (0x100000 | ZT_SIG_CLEAR)
- #define SIG_SF ZT_SIG_SF
- #define SIG_SFWINK (0x0100000 | ZT_SIG_SF)
- #define SIG_SF_FEATD (0x0200000 | ZT_SIG_SF)
-@@ -234,6 +238,8 @@ static int matchdigittimeout = 3000;
- /*! \brief Protect the interface list (of zt_pvt's) */
- AST_MUTEX_DEFINE_STATIC(iflock);
-
-+static char gsm_modem_pin[20];
-+static char gsm_modem_exten[AST_MAX_EXTENSION];
-
- static int ifcount = 0;
-
-@@ -251,6 +257,7 @@ static enum ast_bridge_result zt_bridge(
-
- static int zt_sendtext(struct ast_channel *c, const char *text);
-
-+static int zt_sendmessage(struct ast_channel *c, const char *dest, const char *text, int ispdu);
-
- /*! \brief Avoid the silly zt_getevent which ignores a bunch of events */
- static inline int zt_get_event(int fd)
-@@ -364,6 +371,19 @@ struct zt_pri {
- int debugfd;
- };
-
-+#ifdef HAVE_GSMAT
-+struct zt_gsm {
-+ pthread_t master;
-+ ast_mutex_t lock; /* Mutex */
-+ int fd;
-+ int span;
-+ struct gsm_modul *modul;
-+ char pin[256];
-+ int available;
-+ char exten[AST_MAX_EXTENSION]; /* Where to idle extra calls */
-+ struct zt_pvt *pvt;
-+};
-+#endif
-
- static struct zt_pri pris[NUM_SPANS];
-
-@@ -392,6 +412,7 @@ struct zt_pri;
- #define POLARITY_REV 1
-
-
-+
- static struct zt_distRings drings;
-
- struct distRingData {
-@@ -604,6 +625,9 @@ static struct zt_pvt {
- int prioffset;
- int logicalspan;
- #endif
-+#ifdef HAVE_GSMAT
-+ struct zt_gsm gsm;
-+#endif
- int polarity;
- int dsp_features;
- char begindigit;
-@@ -710,7 +734,7 @@ static struct zt_chan_conf zt_chan_conf_
- static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause);
- static int zt_digit_begin(struct ast_channel *ast, char digit);
- static int zt_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
--static int zt_sendtext(struct ast_channel *c, const char *text);
-+static int zt_sendmessage(struct ast_channel *c, const char *dest, const char *text, int ispdu);
- static int zt_call(struct ast_channel *ast, char *rdest, int timeout);
- static int zt_hangup(struct ast_channel *ast);
- static int zt_answer(struct ast_channel *ast);
-@@ -732,6 +756,9 @@ static const struct ast_channel_tech zap
- .send_digit_begin = zt_digit_begin,
- .send_digit_end = zt_digit_end,
- .send_text = zt_sendtext,
-+#if 0 /* we (Debian) disable that addition because of ABI breakage */
-+ .send_message = zt_sendmessage,
-+#endif
- .call = zt_call,
- .hangup = zt_hangup,
- .answer = zt_answer,
-@@ -1262,6 +1289,8 @@ static char *zap_sig2str(int sig)
- return "GR-303 with FXOKS";
- case SIG_GR303FXSKS:
- return "GR-303 with FXSKS";
-+ case SIG_GSM:
-+ return "GSM";
- case 0:
- return "Pseudo";
- default:
-@@ -1683,7 +1712,7 @@ static inline int zt_confmute(struct zt_
- {
- int x, y, res;
- x = muted;
-- if (p->sig == SIG_PRI) {
-+ if ((p->sig == SIG_PRI) || (p->sig == SIG_GSM)) {
- y = 1;
- res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &y);
- if (res)
-@@ -2098,6 +2127,25 @@ static int zt_call(struct ast_channel *a
- p->dialdest[0] = '\0';
- disable_dtmf_detect(p);
- break;
-+ case SIG_GSM:
-+#ifdef HAVE_GSMAT
-+ if (p->gsm.modul) {
-+ c = strchr(dest, '/');
-+ if (c)
-+ c++;
-+ else
-+ c = dest;
-+ ast_mutex_lock(&p->gsm.lock);
-+ if (gsm_dial(p->gsm.modul, p->use_callingpres ? ast->cid.cid_pres : 0, c)) {
-+ ast_log(LOG_WARNING, "dialing failed on channel %d\n", p->channel);
-+ ast_mutex_unlock(&p->gsm.lock);
-+ ast_mutex_unlock(&p->lock);
-+ return -1;
-+ }
-+ ast_mutex_unlock(&p->gsm.lock);
-+ }
-+#endif
-+ break;
- default:
- ast_log(LOG_DEBUG, "not yet implemented\n");
- ast_mutex_unlock(&p->lock);
-@@ -2737,7 +2785,13 @@ static int zt_hangup(struct ast_channel
- }
- }
- #endif
-- if (p->sig && (p->sig != SIG_PRI))
-+#ifdef HAVE_GSMAT
-+ if (p->gsm.modul) {
-+ if (!p->alreadyhungup)
-+ gsm_hangup(p->gsm.modul);
-+ }
-+#endif
-+ if (p->sig && (p->sig != SIG_PRI) && (p->sig != SIG_GSM))
- res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_ONHOOK);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
-@@ -2914,6 +2968,13 @@ static int zt_answer(struct ast_channel
- zt_train_ec(p);
- break;
- #endif
-+#ifdef HAVE_GSMAT
-+ case SIG_GSM:
-+ if (p->gsm.modul) {
-+ gsm_answer(p->gsm.modul);
-+ }
-+ break;
-+#endif
- case 0:
- ast_mutex_unlock(&p->lock);
- return 0;
-@@ -7302,6 +7363,10 @@ static int pri_create_spanmap(int span,
-
- #endif
-
-+#ifdef HAVE_GSMAT
-+static void *gsm_dchannel(void *vgsm);
-+#endif
-+
- static struct zt_pvt *mkintf(int channel, const struct zt_chan_conf *conf, struct zt_pri *pri, int reloading)
- {
- /* Make a zt_pvt structure for this interface (or CRV if "pri" is specified) */
-@@ -7530,6 +7595,37 @@ static struct zt_pvt *mkintf(int channel
- tmp->prioffset = 0;
- }
- #endif
-+#ifdef HAVE_GSMAT
-+ if (conf->chan.sig == SIG_GSM) {
-+ struct zt_bufferinfo bi;
-+ ast_mutex_init(&tmp->gsm.lock);
-+ strncpy(tmp->gsm.pin, gsm_modem_pin, sizeof(tmp->gsm.pin) - 1);
-+ strncpy(tmp->gsm.exten, gsm_modem_exten, sizeof(tmp->gsm.exten) - 1);
-+ tmp->gsm.available = 0;
-+ snprintf(fn, sizeof(fn), "%d", channel + 1);
-+ /* Open non-blocking */
-+ tmp->gsm.fd = zt_open(fn);
-+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
-+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
-+ bi.numbufs = 16;
-+ bi.bufsize = 1024;
-+ if (ioctl(tmp->gsm.fd, ZT_SET_BUFINFO, &bi)) {
-+ ast_log(LOG_ERROR, "Unable to set buffer info on channel '%s': %s\n", fn, strerror(errno));
-+ return NULL;
-+ }
-+ tmp->gsm.pvt = tmp;
-+ tmp->gsm.span = tmp->span;
-+ tmp->gsm.modul = gsm_new(tmp->gsm.fd, 0, tmp->gsm.pin, tmp->span, tmp->channel);
-+ if (ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, tmp->channel)) {
-+ ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d: %s\n", tmp->channel, strerror(errno));
-+ destroy_zt_pvt(&tmp);
-+ return NULL;
-+ }
-+ if (ast_pthread_create(&tmp->gsm.master, NULL, gsm_dchannel, &tmp->gsm)) {
-+ zt_close(tmp->gsm.fd);
-+ }
-+ }
-+#endif
- } else {
- conf->chan.sig = tmp->sig;
- conf->chan.radio = tmp->radio;
-@@ -7819,6 +7915,12 @@ static inline int available(struct zt_pv
- return 1;
- }
- #endif
-+#ifdef HAVE_GSMAT
-+ if (p->gsm.modul) {
-+ return gsm_available(p->gsm.modul);
-+ }
-+
-+#endif
- if (!(p->radio || (p->oprmode < 0)))
- {
- if (!p->sig || (p->sig == SIG_FXSLS))
-@@ -8176,6 +8278,235 @@ next:
- return tmp;
- }
-
-+#ifdef HAVE_GSMAT
-+static int zt_reset_span(int span, int sleep) {
-+ int ctl;
-+ int res;
-+
-+ ctl = open("/dev/zap/ctl", O_RDWR);
-+ if (ctl < 0) {
-+ ast_log(LOG_WARNING, "Unable to open /dev/zap/ctl: %s\n", strerror(errno));
-+ return -1;
-+ }
-+ ast_verbose(VERBOSE_PREFIX_2 "Shutting down span %d. Please wait...\n", span);
-+ res = ioctl(ctl, ZT_SHUTDOWN, &span);
-+ if (res) {
-+ ast_log(LOG_WARNING, "error shutting down span %d\n", span);
-+ return -1;
-+ }
-+ usleep(sleep * 1000);
-+ ast_verbose(VERBOSE_PREFIX_2 "Starting up span %d. Please wait...\n", span);
-+ res = ioctl(ctl, ZT_STARTUP, &span);
-+ if (res) {
-+ ast_log(LOG_WARNING, "error starting up span %d\n", span);
-+ return -1;
-+ }
-+ ast_verbose(VERBOSE_PREFIX_2 "Reset of span %d completed.\n", span);
-+ return 0;
-+}
-+
-+
-+static void handle_gsm_event(struct zt_gsm *gsm, gsm_event *e)
-+{
-+ struct ast_channel *c = NULL;
-+ int law = ZT_LAW_ALAW;
-+ int res = 0;
-+
-+ switch(e->e) {
-+ case GSM_EVENT_DCHAN_UP:
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_3 "GSM Span %d registered to network!\n", gsm->span);
-+ gsm->available = 1;
-+ break;
-+ case GSM_EVENT_DCHAN_DOWN:
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_3 "GSM Span %d unregistered from network!\n", gsm->span);
-+ gsm->available = 0;
-+/* ast_mutex_lock(&gsm->pvt->lock);
-+ gsm->pvt->alreadyhungup = 1;
-+ if (gsm->pvt->owner) {
-+ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-+ }
-+ ast_mutex_unlock(&gsm->pvt->lock); */
-+ break;
-+ case GSM_EVENT_RING:
-+ ast_mutex_lock(&gsm->pvt->lock);
-+ if (!ast_strlen_zero(e->ring.callingnum)) {
-+ strncpy(gsm->pvt->cid_num, e->ring.callingnum, sizeof(gsm->pvt->cid_num) - 1);
-+ } else {
-+ strncpy(gsm->pvt->cid_name, "CID withheld", sizeof(gsm->pvt->cid_name));
-+ }
-+ if (!ast_strlen_zero(gsm->exten)) {
-+ strncpy(gsm->pvt->exten, gsm->exten, sizeof(gsm->pvt->exten) - 1);
-+ } else {
-+ gsm->pvt->exten[0] = 's';
-+ gsm->pvt->exten[1] = '\0';
-+ }
-+ c = zt_new(gsm->pvt, AST_STATE_RING, 1, SUB_REAL, ZT_LAW_ALAW, AST_TRANS_CAP_SPEECH);
-+ if (c) {
-+ if (option_verbose > 2)
-+ ast_verbose(VERBOSE_PREFIX_3 "Ring on channel %d (from %s to %s)\n", e->ring.channel, e->ring.callingnum, gsm->exten);
-+ gsm->pvt->owner = c;
-+ if (ioctl(gsm->pvt->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
-+ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", gsm->pvt->channel, law);
-+ res = zt_setlaw(gsm->pvt->subs[SUB_REAL].zfd, law);
-+ res = set_actual_gain(gsm->pvt->subs[SUB_REAL].zfd, 0, gsm->pvt->rxgain, gsm->pvt->txgain, law);
-+ if (res < 0) {
-+ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", gsm->pvt->channel);
-+// } else {
-+// ast_log(LOG_NOTICE, "tx gain %f rx gain %f law %d pvt->law %d\n", gsm->pvt->txgain, gsm->pvt->rxgain, law, gsm->pvt->law);
-+ }
-+ }
-+ ast_mutex_unlock(&gsm->pvt->lock);
-+ break;
-+ case GSM_EVENT_HANGUP:
-+ ast_verbose(VERBOSE_PREFIX_3 "Got hang up on channel %d\n", e->hangup.channel);
-+ ast_mutex_lock(&gsm->pvt->lock);
-+ gsm->pvt->alreadyhungup = 1;
-+ if (gsm->pvt->owner) {
-+ gsm->pvt->owner->hangupcause = e->hangup.cause;
-+ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-+ }
-+ ast_mutex_unlock(&gsm->pvt->lock);
-+ break;
-+ case GSM_EVENT_ERROR:
-+ ast_log(LOG_WARNING, "Got error on channel\n");
-+ ast_mutex_lock(&gsm->pvt->lock);
-+ gsm->pvt->alreadyhungup = 1;
-+ if (gsm->pvt->owner) {
-+ gsm->pvt->owner->hangupcause = e->error.cause;
-+ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-+ }
-+ ast_mutex_unlock(&gsm->pvt->lock);
-+ if (e->error.hard) {
-+// gsm_poweroff(gsm->modul);
-+ zt_reset_span(gsm->span, 8000);
-+// gsm_restart(gsm->modul, 10000);
-+ } else {
-+// gsm_poweroff(gsm->modul);
-+ zt_reset_span(gsm->span, 8000);
-+// gsm_restart(gsm->modul, 10000);
-+ }
-+ break;
-+ case GSM_EVENT_ALERTING:
-+ ast_mutex_lock(&gsm->pvt->lock);
-+ gsm->pvt->subs[SUB_REAL].needringing =1;
-+ ast_mutex_unlock(&gsm->pvt->lock);
-+ break;
-+ case GSM_EVENT_ANSWER:
-+ ast_mutex_lock(&gsm->pvt->lock);
-+ gsm->pvt->dialing = 0;
-+ gsm->pvt->subs[SUB_REAL].needanswer =1;
-+ gsm->pvt->ignoredtmf = 0;
-+ ast_mutex_unlock(&gsm->pvt->lock);
-+ break;
-+ case GSM_EVENT_PIN_REQUIRED:
-+ gsm_send_pin(gsm->modul, gsm->pin);
-+ break;
-+ case GSM_EVENT_SM_RECEIVED:
-+ ast_verbose(VERBOSE_PREFIX_3 "SMS from %s received on span %d. (Text: %s) (PDU: %s)\n", e->sm_received.sender, gsm->span, e->sm_received.text, e->sm_received.pdu);
-+ manager_event(EVENT_FLAG_CALL, "Message received",
-+ "Span: %d\r\n"
-+ "Sender: %s\r\n"
-+ "SMSC: %s\r\n"
-+ "Length: %d\r\n"
-+ "Text: %s\r\n"
-+ "PDU: %s\r\n",
-+ gsm->span,
-+ e->sm_received.sender,
-+ e->sm_received.smsc,
-+ e->sm_received.len,
-+ e->sm_received.text,
-+ e->sm_received.pdu);
-+ break;
-+ default:
-+ ast_log(LOG_WARNING,"!! Unknown GSM event %d !!\n", e->e);
-+ }
-+}
-+
-+static void *gsm_dchannel(void *vgsm)
-+{
-+ struct zt_gsm *gsm = vgsm;
-+ gsm_event *e;
-+ struct timeval tv = {0,0}, *next;
-+ fd_set rfds, efds;
-+ int res,x;
-+
-+ if (!gsm) return NULL;
-+
-+ if (!gsm->modul) {
-+ fprintf(stderr, "No gsm_mod\n");
-+ return NULL;
-+ }
-+ gsm_set_debug(gsm->modul, GSM_DEBUG_NONE);
-+ for (;;) {
-+
-+ /* Run the D-Channel */
-+ FD_ZERO(&rfds);
-+ FD_ZERO(&efds);
-+ FD_SET(gsm->fd, &rfds);
-+ FD_SET(gsm->fd, &efds);
-+
-+ if ((next = gsm_schedule_next(gsm->modul))) {
-+ gettimeofday(&tv, NULL);
-+ tv.tv_sec = next->tv_sec - tv.tv_sec;
-+ tv.tv_usec = next->tv_usec - tv.tv_usec;
-+ if (tv.tv_usec < 0) {
-+ tv.tv_usec += 1000000;
-+ tv.tv_sec -= 1;
-+ }
-+ if (tv.tv_sec < 0) {
-+ tv.tv_sec = 0;
-+ tv.tv_usec = 0;
-+ }
-+ }
-+ res = select(gsm->fd + 1, &rfds, NULL, &efds, next ? &tv : NULL);
-+ e = NULL;
-+
-+ ast_mutex_lock(&gsm->lock);
-+ if (!res) {
-+ e = gsm_schedule_run(gsm->modul);
-+ } else if (res > 0) {
-+ e = gsm_check_event(gsm->modul, 1);
-+ } else if (errno == ELAST) {
-+ res = ioctl(gsm->fd, ZT_GETEVENT, &x);
-+ printf("Got Zaptel event: %d\n", x);
-+ } else if (errno != EINTR)
-+ fprintf(stderr, "Error (%d) on select: %s\n", ELAST, strerror(errno));
-+
-+ if (!e) {
-+ e = gsm_check_event(gsm->modul, 0);
-+ }
-+
-+ if (e) {
-+ handle_gsm_event(gsm, e);
-+ }
-+ ast_mutex_unlock(&gsm->lock);
-+
-+ res = ioctl(gsm->fd, ZT_GETEVENT, &x);
-+
-+ if (!res && x) {
-+ switch (x) {
-+ case ZT_EVENT_NOALARM:
-+ ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", gsm->span);
-+ usleep(1000);
-+ gsm_restart(gsm->modul, 10000);
-+ break;
-+ case ZT_EVENT_ALARM:
-+ ast_log(LOG_NOTICE, "Alarm detected on span %d\n", gsm->span);
-+ break;
-+ default:
-+ fprintf(stderr, "Got event on GSM interface: %d\n", x);
-+ }
-+ }
-+
-+
-+ }
-+ return NULL;
-+}
-+
-+#endif
-+
- #ifdef HAVE_PRI
- static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv)
- {
-@@ -8450,6 +8781,18 @@ static void zt_pri_error(char *s, int sp
- ast_log(LOG_WARNING, "%d %s", span, s);
- }
-
-+#ifdef HAVE_GSMAT
-+static void zt_gsm_message(char *s, int channel)
-+{
-+ ast_verbose("GSM %d: %s", channel, s);
-+}
-+
-+static void zt_gsm_error(char *s, int channel)
-+{
-+ ast_log(LOG_WARNING, "GSM %d: %s", channel, s);
-+}
-+#endif
-+
- static int pri_check_restart(struct zt_pri *pri)
- {
- if ((pri->nodetype != PRI_NETWORK) && (pri->nodetype != PRI_CPE)) {
-@@ -10868,6 +11211,243 @@ static int app_zapInband(struct ast_chan
-
- #endif /* HAVE_PRI */
-
-+#ifdef HAVE_GSMAT
-+static int handle_zap_reset_span(int fd, int argc, char *argv[])
-+{
-+ int span;
-+ int sleep = 5000;
-+ if (argc < 4)
-+ return RESULT_SHOWUSAGE;
-+ span = atoi(argv[3]);
-+ if ((span < 1) || (span > NUM_SPANS)) {
-+ ast_cli(fd, "Invalid span '%s'. Should be a number from %d to %d\n", argv[3], 1, NUM_SPANS);
-+ return RESULT_SUCCESS;
-+ }
-+ if (zt_reset_span(span, sleep)) {
-+ return RESULT_FAILURE;
-+ }
-+ return RESULT_SUCCESS;
-+}
-+
-+static int handle_gsm_debug_helper(int fd, int channel, int debug)
-+{
-+/* gsm debug channel <channel> */
-+ struct zt_pvt *pvt = NULL;
-+ if (channel < 1) {
-+ ast_cli(fd, "Invalid channel %d. Should be a number.\n", channel);
-+ return RESULT_SUCCESS;
-+ }
-+ pvt = iflist;
-+ while (pvt) {
-+ if (pvt->channel == channel) {
-+ ast_mutex_lock(&pvt->lock);
-+ gsm_set_debug(pvt->gsm.modul, debug);
-+ ast_mutex_unlock(&pvt->lock);
-+ ast_cli(fd, "%s debugging on channel %d\n", debug ? "Enabled":"Disabled", channel);
-+ return RESULT_SUCCESS;
-+ }
-+ pvt = pvt->next;
-+ }
-+
-+ ast_cli(fd, "No GSM running on channel %d\n", channel);
-+ return RESULT_SUCCESS;
-+}
-+
-+
-+
-+static int handle_gsm_debug(int fd, int argc, char *argv[])
-+{
-+/* gsm debug channel <channel> */
-+ int channel;
-+ if (argc < 4) {
-+ return RESULT_SHOWUSAGE;
-+ }
-+ channel = atoi(argv[3]);
-+ return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_AT);
-+}
-+
-+static int handle_gsm_no_debug(int fd, int argc, char *argv[])
-+{
-+/* gsm no debug channel <channel> */
-+ int channel;
-+ if (argc < 5) {
-+ return RESULT_SHOWUSAGE;
-+ }
-+ channel = atoi(argv[4]);
-+ return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_NONE);
-+}
-+
-+static char zap_reset_help[] =
-+ "Usage: zap reset span <span>\n"
-+ " Reset/Restart a zaptel span\n";
-+
-+static char gsm_debug_help[] =
-+ "Usage: gsm debug channel <channel>\n"
-+ " Enables debugging on a given GSM channel\n";
-+
-+static char gsm_no_debug_help[] =
-+ "Usage: gsm no debug channel <channel>\n"
-+ " Disables debugging on a given GSM channel\n";
-+
-+static struct ast_cli_entry zap_gsm_cli[] = {
-+ { { "zap", "reset", "span", NULL }, handle_zap_reset_span,
-+ "Restart a zaptel span", zap_reset_help, complete_span_4 },
-+ { { "gsm", "debug", "channel", NULL }, handle_gsm_debug,
-+ "Enables GSM debugging on a channel", gsm_debug_help },
-+ { { "gsm", "no", "debug", "channel", NULL }, handle_gsm_no_debug,
-+ "Disables GSM debugging on a channel", gsm_no_debug_help},
-+};
-+
-+
-+
-+static char gsm_send_pdu_help[] =
-+ "Usage: gsm send pdu <channel> <pdu>\n"
-+ " Sends a PDU on a GSM channel\n";
-+
-+
-+
-+static int handle_gsm_send_pdu(int fd, int argc, char *argv[])
-+{
-+/* gsm send sms <channel> <destination> <message> */
-+ int channel;
-+ struct zt_pvt *pvt = NULL;
-+ if (argc < 5) {
-+ return RESULT_SHOWUSAGE;
-+ }
-+ channel = atoi(argv[3]);
-+ if (channel < 1) {
-+ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]);
-+ return RESULT_SUCCESS;
-+ }
-+ pvt = iflist;
-+ while (pvt) {
-+ if (pvt->channel == channel) {
-+ if (pvt->owner) {
-+ ast_cli(fd, "Channel in use.\n");
-+ return RESULT_FAILURE;
-+ } else {
-+ ast_mutex_lock(&pvt->lock);
-+ gsm_sms_send_pdu(pvt->gsm.modul, argv[4]);
-+ ast_mutex_unlock(&pvt->lock);
-+ return RESULT_SUCCESS;
-+ }
-+ }
-+ pvt = pvt->next;
-+ }
-+
-+ return RESULT_SUCCESS;
-+}
-+
-+static struct ast_cli_entry gsm_send_pdu = {
-+ { "gsm", "send", "pdu", NULL }, handle_gsm_send_pdu, "Sends a SM on a GSM channel", gsm_send_pdu_help, complete_span_4 };
-+
-+
-+static char gsm_send_sms_help[] =
-+ "Usage: gsm send sms <channel> <destination> <message>\n"
-+ " Sends a SM on a GSM channel\n";
-+
-+
-+static int handle_gsm_send_sms(int fd, int argc, char *argv[])
-+{
-+/* gsm send sms <channel> <destination> <message> */
-+ int channel;
-+ struct zt_pvt *pvt = NULL;
-+ if (argc < 6) {
-+ return RESULT_SHOWUSAGE;
-+ }
-+ channel = atoi(argv[3]);
-+ if (channel < 1) {
-+ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]);
-+ return RESULT_SUCCESS;
-+ }
-+ pvt = iflist;
-+ while (pvt) {
-+ if (pvt->channel == channel) {
-+ if (pvt->owner) {
-+ ast_cli(fd, "Channel in use.\n");
-+ return RESULT_FAILURE;
-+ } else {
-+ ast_mutex_lock(&pvt->lock);
-+ gsm_sms_send_text(pvt->gsm.modul, argv[4], argv[5]);
-+ ast_mutex_unlock(&pvt->lock);
-+ return RESULT_SUCCESS;
-+ }
-+ }
-+ pvt = pvt->next;
-+ }
-+
-+ return RESULT_SUCCESS;
-+}
-+
-+static int zt_gsm_sendtext(struct ast_channel *chan, const char * dest, const char *text, int ispdu) {
-+ struct zt_pvt *pvt = NULL;
-+ char *c = NULL;
-+ pvt = chan->tech_pvt;
-+
-+ if (!pvt) return -1;
-+
-+ /* parse dialstring */
-+ c = strrchr(dest, '/');
-+ if (c)
-+ c++;
-+ else
-+ c = (char *)dest;
-+
-+ ast_mutex_lock(&pvt->lock);
-+ if (ispdu) {
-+ gsm_sms_send_pdu(pvt->gsm.modul, (char *)text);
-+ } else {
-+ gsm_sms_send_text(pvt->gsm.modul, c, (char *)text);
-+ }
-+ ast_mutex_unlock(&pvt->lock);
-+ gsm_wait(pvt->gsm.modul);
-+ return 0;
-+}
-+
-+static struct ast_cli_entry gsm_send_sms = {
-+ { "gsm", "send", "sms", NULL }, handle_gsm_send_sms, "Sends a SM on a GSM channel", gsm_send_sms_help, complete_span_4 };
-+
-+static char gsm_show_status_help[] =
-+ "Usage: gsm show status <channel>>\n"
-+ " Displays status information about the GSM channel.\n";
-+
-+
-+static int handle_gsm_show_status(int fd, int argc, char *argv[])
-+{
-+ int channel;
-+ struct zt_pvt *pvt = NULL;
-+ if (argc < 4) {
-+ return RESULT_SHOWUSAGE;
-+ }
-+ channel = atoi(argv[3]);
-+ if (channel < 1) {
-+ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]);
-+ return RESULT_SUCCESS;
-+ }
-+ pvt = iflist;
-+ while (pvt) {
-+ if (pvt->channel == channel) {
-+ if (pvt->owner) {
-+ ast_cli(fd, "Channel in use.\n");
-+ return RESULT_FAILURE;
-+ } else {
-+ ast_mutex_lock(&pvt->lock);
-+ gsm_request_status(pvt->gsm.modul);
-+ ast_mutex_unlock(&pvt->lock);
-+ return RESULT_SUCCESS;
-+ }
-+ }
-+ pvt = pvt->next;
-+ }
-+
-+ return RESULT_SUCCESS;
-+}
-+
-+static struct ast_cli_entry gsm_show_status = {
-+ { "gsm", "show", "status", NULL }, handle_gsm_show_status, "Displays status information about the GSM channel.", gsm_show_status_help, complete_span_4 };
-+
-+#endif /* HAVE_GSMAT */
-+
- static int app_zapEC(struct ast_channel *chan, void *data)
- {
- int res=-1;
-@@ -11489,6 +12069,12 @@ static int __unload_module(void)
- ast_unregister_application(zapCD_app);
- ast_unregister_application(zapInband_app);
- #endif
-+#ifdef HAVE_GSMAT
-+ ast_cli_unregister_multiple(zap_gsm_cli, sizeof(zap_gsm_cli) / sizeof(zap_gsm_cli[0]));
-+ ast_cli_unregister(&gsm_send_sms);
-+ ast_cli_unregister(&gsm_send_pdu);
-+ ast_cli_unregister(&gsm_show_status);
-+#endif
- ast_cli_unregister_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
- ast_unregister_application(zapEC_app);
- ast_manager_unregister( "ZapDialOffhook" );
-@@ -12009,6 +12595,11 @@ static int process_zap(struct zt_chan_co
- confp->chan.radio = 0;
- confp->pri.nodetype = BRI_CPE;
- #endif
-+#ifdef HAVE_GSMAT
-+ } else if (!strcasecmp(v->value, "gsm")) {
-+ confp->chan.sig = SIG_GSM;
-+ confp->chan.radio = 0;
-+#endif
- } else {
- ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value);
- }
-@@ -12151,6 +12742,10 @@ static int process_zap(struct zt_chan_co
- ast_copy_string(confp->pri.nocid, v->value, sizeof(confp->pri.nocid));
- } else if (!strcasecmp(v->name, "withheldcid")) {
- ast_copy_string(confp->pri.withheldcid, v->value, sizeof(confp->pri.withheldcid));
-+ } else if (!strcasecmp(v->name, "pin")) {
-+ ast_copy_string(gsm_modem_pin, v->value, sizeof(gsm_modem_pin) - 1);
-+ } else if (!strcasecmp(v->name, "exten")) {
-+ ast_copy_string(gsm_modem_exten, v->value, sizeof(gsm_modem_exten) - 1);
- } else if (!strcasecmp(v->name, "resetinterval")) {
- if (!strcasecmp(v->value, "never"))
- confp->pri.resetinterval = -1;
-@@ -12506,6 +13101,10 @@ static int load_module(void)
- ast_register_application(zap_send_keypad_facility_app, zap_send_keypad_facility_exec,
- zap_send_keypad_facility_synopsis, zap_send_keypad_facility_descrip);
- #endif
-+#ifdef HAVE_GSMAT
-+ gsm_set_error(zt_gsm_error);
-+ gsm_set_message(zt_gsm_message);
-+#endif
- res = setup_zap(0);
- /* Make sure we can register our Zap channel type */
- if (res)
-@@ -12524,6 +13123,12 @@ static int load_module(void)
- #endif
- ast_register_application(zapEC_app, app_zapEC, zapEC_synopsis, zapEC_tdesc);
- ast_cli_register_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
-+#ifdef HAVE_GSMAT
-+ ast_cli_register(&gsm_send_sms);
-+ ast_cli_register(&gsm_send_pdu);
-+ ast_cli_register(&gsm_show_status);
-+ ast_cli_register_multiple(zap_gsm_cli, sizeof(zap_gsm_cli) / sizeof(zap_gsm_cli[0]));
-+#endif
-
- memset(round_robin, 0, sizeof(round_robin));
- ast_manager_register( "ZapTransfer", 0, action_transfer, "Transfer Zap Channel" );
-@@ -12537,7 +13142,66 @@ static int load_module(void)
- return res;
- }
-
--static int zt_sendtext(struct ast_channel *c, const char *text)
-+#ifdef HAVE_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;
-+}
-+#endif
-+
-+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) {
-+#ifdef HAVE_PRI
-+ return zt_pri_sendtext(c, text);
-+#endif
-+ } else if (p->sig == SIG_GSM) {
-+ } else {
-+ return zt_tdd_sendtext(c, text);
-+ }
-+ return -1;
-+}
-+
-+static int zt_sendmessage(struct ast_channel *c, const char *dest, const char *text, int ispdu) {
-+struct zt_pvt *p = c->tech_pvt;
-+ if (!p) return -1;
-+ if (p->sig == SIG_PRI) {
-+#ifdef HAVE_PRI
-+ if (ispdu) {
-+ ast_log(LOG_WARNING, "Dont know how to send PDU on ZAP ISDN channel\n");
-+ return -1;
-+ }
-+ return zt_pri_sendtext(c, text);
-+#endif
-+ } else if (p->sig == SIG_GSM) {
-+#ifdef HAVE_GSMAT
-+ return zt_gsm_sendtext(c, dest, text, ispdu);
-+#endif
-+ } else {
-+ if (ispdu) {
-+ ast_log(LOG_WARNING, "Dont know how to send PDU on ZAP channel\n");
-+ return -1;
-+ }
-+ return zt_tdd_sendtext(c, text);
-+ }
-+ return -1;
-+}
-+
-+static int zt_tdd_sendtext(struct ast_channel *c, const char *text)
- {
- #define END_SILENCE_LEN 400
- #define HEADER_MS 50
---- a/configure.ac
-+++ b/configure.ac
-@@ -178,6 +178,7 @@ AST_EXT_LIB_SETUP([CAP], [POSIX 1.e capa
- AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
- AST_EXT_LIB_SETUP([GNUTLS], [GNU TLS support (used for iksemel only)], [gnutls])
- AST_EXT_LIB_SETUP([GSM], [GSM], [gsm], [, or 'internal'])
-+AST_EXT_LIB_SETUP([GSMAT], [GSMAT], [GSM AT command signalling], [gsmat])
- AST_EXT_LIB_SETUP([IKSEMEL], [Iksemel Jabber Library], [iksemel])
- AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap])
- AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux Library], [isdnnet])
---- a/configure
-+++ b/configure
-@@ -26600,6 +26600,188 @@ echo "$as_me: *** without explicitly spe
- fi
- fi
-
-+{ echo "$as_me:$LINENO: checking for ${GSMAT_DIR}/include/libgsmat.h" >&5
-+echo $ECHO_N "checking for ${GSMAT_DIR}/include/libgsmat.h... $ECHO_C" >&6; }
-+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-+ echo $ECHO_N "(cached) $ECHO_C" >&6
-+else
-+ eval "$as_ac_Header=\$ac_header_preproc"
-+fi
-+ac_res=`eval echo '${'$as_ac_Header'}'`
-+ { echo "$as_me:$LINENO: result: $ac_res" >&5
-+echo "${ECHO_T}$ac_res" >&6; }
-+
-+if test `eval echo '${'$as_ac_Header'}'` = yes; then
-+ GSMAT_HEADER_FOUND=1
-+else
-+ GSMAT_HEADER_FOUND=0
-+fi
-+
-+
-+
-+ if test "${GSMAT_HEADER_FOUND}" = "yes"; then
-+ GSMAT_LIB="-lgsmat "
-+ GSMAT_HEADER_FOUND="1"
-+ if test "x${GSMAT_DIR}" != "x"; then
-+ GSMAT_LIB="${pbxlibdir} ${GSMAT_LIB}"
-+ GSMAT_INCLUDE="-I${GSMAT_DIR}/include"
-+ fi
-+ CPPFLAGS="${saved_cppflags}"
-+ else
-+ if test "xlibgsmat.h" != "x" ; then
-+ if test "${ac_cv_header_libpri_h+set}" = set; then
-+ { echo "$as_me:$LINENO: checking for libgsmat.h" >&5
-+echo $ECHO_N "checking for libgsmat.h... $ECHO_C" >&6; }
-+if test "${ac_cv_header_libgsmat_h+set}" = set; then
-+ echo $ECHO_N "(cached) $ECHO_C" >&6
-+fi
-+{ echo "$as_me:$LINENO: result: $ac_cv_header_libgsmat_h" >&5
-+echo "${ECHO_T}$ac_cv_header_libgsmat_h" >&6; }
-+else
-+ # Is the header compilable?
-+{ echo "$as_me:$LINENO: checking libgsmat.h usability" >&5
-+echo $ECHO_N "checking libgsmat.h usability... $ECHO_C" >&6; }
-+cat >conftest.$ac_ext <<_ACEOF
-+/* confdefs.h. */
-+_ACEOF
-+cat confdefs.h >>conftest.$ac_ext
-+cat >>conftest.$ac_ext <<_ACEOF
-+/* end confdefs.h. */
-+$ac_includes_default
-+#include <libgsmat.h>
-+_ACEOF
-+rm -f conftest.$ac_objext
-+if { (ac_try="$ac_compile"
-+case "(($ac_try" in
-+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-+ *) ac_try_echo=$ac_try;;
-+esac
-+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-+ (eval "$ac_compile") 2>conftest.er1
-+ ac_status=$?
-+ grep -v '^ *+' conftest.er1 >conftest.err
-+ rm -f conftest.er1
-+ cat conftest.err >&5
-+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
-+ (exit $ac_status); } && {
-+ test -z "$ac_c_werror_flag" ||
-+ test ! -s conftest.err
-+ } && test -s conftest.$ac_objext; then
-+ ac_header_compiler=yes
-+else
-+ echo "$as_me: failed program was:" >&5
-+sed 's/^/| /' conftest.$ac_ext >&5
-+
-+ ac_header_compiler=no
-+fi
-+
-+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-+echo "${ECHO_T}$ac_header_compiler" >&6; }
-+
-+# Is the header present?
-+{ echo "$as_me:$LINENO: checking libgsmat.h presence" >&5
-+echo $ECHO_N "checking libgsmat.h presence... $ECHO_C" >&6; }
-+cat >conftest.$ac_ext <<_ACEOF
-+/* confdefs.h. */
-+_ACEOF
-+cat confdefs.h >>conftest.$ac_ext
-+cat >>conftest.$ac_ext <<_ACEOF
-+/* end confdefs.h. */
-+#include <libgsmat.h>
-+_ACEOF
-+if { (ac_try="$ac_cpp conftest.$ac_ext"
-+case "(($ac_try" in
-+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-+ *) ac_try_echo=$ac_try;;
-+esac
-+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-+ ac_status=$?
-+ grep -v '^ *+' conftest.er1 >conftest.err
-+ rm -f conftest.er1
-+ cat conftest.err >&5
-+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
-+ (exit $ac_status); } >/dev/null && {
-+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-+ test ! -s conftest.err
-+ }; then
-+ ac_header_preproc=yes
-+else
-+ echo "$as_me: failed program was:" >&5
-+sed 's/^/| /' conftest.$ac_ext >&5
-+
-+ ac_header_preproc=no
-+fi
-+
-+rm -f conftest.err conftest.$ac_ext
-+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-+echo "${ECHO_T}$ac_header_preproc" >&6; }
-+
-+# So? What about this header?
-+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-+ yes:no: )
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: accepted by the compiler, rejected by the preprocessor!" >&5
-+echo "$as_me: WARNING: libgsmat.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: proceeding with the compiler's result" >&5
-+echo "$as_me: WARNING: libgsmat.h: proceeding with the compiler's result" >&2;}
-+ ac_header_preproc=yes
-+ ;;
-+ no:yes:* )
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: present but cannot be compiled" >&5
-+echo "$as_me: WARNING: libgsmat.h: present but cannot be compiled" >&2;}
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: check for missing prerequisite headers?" >&5
-+echo "$as_me: WARNING: libgsmat.h: check for missing prerequisite headers?" >&2;}
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: see the Autoconf documentation" >&5
-+echo "$as_me: WARNING: libgsmat.h: see the Autoconf documentation" >&2;}
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: section \"Present But Cannot Be Compiled\"" >&5
-+echo "$as_me: WARNING: libgsmat.h: section \"Present But Cannot Be Compiled\"" >&2;}
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: proceeding with the preprocessor's result" >&5
-+echo "$as_me: WARNING: libgsmat.h: proceeding with the preprocessor's result" >&2;}
-+ { echo "$as_me:$LINENO: WARNING: libgsmat.h: in the future, the compiler will take precedence" >&5
-+echo "$as_me: WARNING: libgsmat.h: in the future, the compiler will take precedence" >&2;}
-+
-+ ;;
-+esac
-+{ echo "$as_me:$LINENO: checking for libgsmat.h" >&5
-+echo $ECHO_N "checking for libgsmat.h... $ECHO_C" >&6; }
-+if test "${ac_cv_header_libgsmat_h+set}" = set; then
-+ echo $ECHO_N "(cached) $ECHO_C" >&6
-+else
-+ ac_cv_header_libgsmat_h=$ac_header_preproc
-+fi
-+{ echo "$as_me:$LINENO: result: $ac_cv_header_libgsmat_h" >&5
-+echo "${ECHO_T}$ac_cv_header_libgsmat_h" >&6; }
-+
-+fi
-+
-+
-+ fi
-+ fi
-+ if test "x${GSMAT_HEADER_FOUND}" = "x0" ; then
-+ if test -n "${GSMAT_MANDATORY}" ;
-+ then
-+ { echo "$as_me:$LINENO: ***" >&5
-+echo "$as_me: ***" >&6;}
-+ { echo "$as_me:$LINENO: *** It appears that you do not have the GSMAT development package installed." >&5
-+echo "$as_me: *** It appears that you do not have the GSMAT development package installed." >&6;}
-+ { echo "$as_me:$LINENO: *** Please install it to include ${GSMAT_DESCRIP} support, or re-run configure" >&5
-+echo "$as_me: *** Please install it to include ${GSMAT_DESCRIP} support, or re-run configure" >&6;}
-+ { echo "$as_me:$LINENO: *** without explicitly specifying --with-${GSMAT_OPTION}" >&5
-+echo "$as_me: *** without explicitly specifying --with-${GSMAT_OPTION}" >&6;}
-+ exit 1
-+ fi
-+ GSMAT_LIB=""
-+ GSMAT_INCLUDE=""
-+ PBX_GSMAT=0
-+ else
-+ PBX_GSMAT=1
-+
-+cat >>confdefs.h <<_ACEOF
-+#define HAVE_GSMAT 1
-+_ACEOF
-+
-+fi
-
- if test "${USE_PWLIB}" != "no"; then
- if test -n "${PWLIB_DIR}"; then