From b93165f34f9baed080d28a4b7545c450fc93002c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= Date: Wed, 16 Jul 2008 19:04:57 +0000 Subject: [PATCH] - updated to todays version Changed files: asterisk-bristuff.patch -> 1.7 --- asterisk-bristuff.patch | 10489 ++++++++++++++++++-------------------- 1 file changed, 4901 insertions(+), 5588 deletions(-) diff --git a/asterisk-bristuff.patch b/asterisk-bristuff.patch index acc71fa..12adbed 100644 --- a/asterisk-bristuff.patch +++ b/asterisk-bristuff.patch @@ -57,7 +57,7 @@ --- a/main/asterisk.c +++ b/main/asterisk.c -@@ -2387,6 +2387,7 @@ static void ast_readconfig(void) +@@ -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)); @@ -65,7 +65,7 @@ /* no asterisk.conf? no problem, use buildtime config! */ if (!cfg) { -@@ -2511,6 +2512,8 @@ static void ast_readconfig(void) +@@ -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)); @@ -76,12 +76,10 @@ } --- a/include/asterisk/agi.h +++ b/include/asterisk/agi.h -@@ -29,7 +29,8 @@ extern "C" { - +@@ -30,6 +30,7 @@ extern "C" { typedef struct agi_state { int fd; /* FD for general output */ -- int audio; /* FD for audio output */ -+ int audio_out; /* FD for audio output */ + int audio; /* 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 */ @@ -160,7 +158,7 @@ + return AGI_RESULT_FAILURE; + } + res = fcntl(audio2[0], F_GETFL); -+ if (res > -1) ++ 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)); @@ -195,11 +193,11 @@ /* Close everything but stdin/out/error */ - for (x=STDERR_FILENO + 2;x<1024;x++) -+ for (x=STDERR_FILENO + 3;x<1024;x++) ++ for (x=STDERR_FILENO + 3;x<1024;x++) close(x); /* Execute script */ -@@ -357,12 +398,19 @@ static enum agi_result launch_script(cha +@@ -359,12 +400,19 @@ static enum agi_result launch_script(cha if (efd) { *efd = audio[1]; } @@ -220,7 +218,7 @@ *opid = pid; return AGI_RESULT_SUCCESS; -@@ -392,7 +440,7 @@ static void setup_env(struct ast_channel +@@ -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); @@ -229,88 +227,7 @@ /* User information */ fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : ""); -@@ -421,7 +469,7 @@ static int handle_waitfordigit(struct as - return RESULT_SHOWUSAGE; - if (sscanf(argv[3], "%d", &to) != 1) - return RESULT_SHOWUSAGE; -- res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl); -+ res = ast_waitfordigit_full(chan, to, agi->audio_out, agi->ctrl); - fdprintf(agi->fd, "200 result=%d\n", res); - return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; - } -@@ -596,7 +644,7 @@ static int handle_streamfile(struct ast_ - if (vfs) - ast_playstream(vfs); - -- res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); -+ res = ast_waitstream_full(chan, argv[3], agi->audio_out, agi->ctrl); - /* this is to check for if ast_waitstream closed the stream, we probably are at - * the end of the stream, return that amount, else check for the amount */ - sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length; -@@ -657,7 +705,7 @@ static int handle_getoption(struct ast_c - if (vfs) - ast_playstream(vfs); - -- res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); -+ res = ast_waitstream_full(chan, argv[3], agi->audio_out, agi->ctrl); - /* this is to check for if ast_waitstream closed the stream, we probably are at - * the end of the stream, return that amount, else check for the amount */ - sample_offset = (chan->stream)?ast_tellstream(fs):max_length; -@@ -669,7 +717,7 @@ static int handle_getoption(struct ast_c - - /* If the user didnt press a key, wait for digitTimeout*/ - if (res == 0 ) { -- res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl); -+ res = ast_waitfordigit_full(chan, timeout, agi->audio_out, agi->ctrl); - /* Make sure the new result is in the escape digits of the GET OPTION */ - if ( !strchr(edigits,res) ) - res=0; -@@ -693,7 +741,7 @@ static int handle_saynumber(struct ast_c - return RESULT_SHOWUSAGE; - if (sscanf(argv[2], "%d", &num) != 1) - return RESULT_SHOWUSAGE; -- res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl); -+ res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio_out, agi->ctrl); - if (res == 1) - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); -@@ -710,7 +758,7 @@ static int handle_saydigits(struct ast_c - if (sscanf(argv[2], "%d", &num) != 1) - return RESULT_SHOWUSAGE; - -- res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); -+ res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl); - if (res == 1) /* New command */ - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); -@@ -724,7 +772,7 @@ static int handle_sayalpha(struct ast_ch - if (argc != 4) - return RESULT_SHOWUSAGE; - -- res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); -+ res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl); - if (res == 1) /* New command */ - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); -@@ -802,7 +850,7 @@ static int handle_sayphonetic(struct ast - if (argc != 4) - return RESULT_SHOWUSAGE; - -- res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); -+ res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl); - if (res == 1) /* New command */ - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); -@@ -826,7 +874,7 @@ static int handle_getdata(struct ast_cha - max = atoi(argv[4]); - else - max = 1024; -- res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl); -+ res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio_out, agi->ctrl); - if (res == 2) /* New command */ - return RESULT_SUCCESS; - else if (res == 1) -@@ -1833,8 +1881,13 @@ static enum agi_result run_agi(struct as +@@ -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; @@ -324,12 +241,12 @@ 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) */ -@@ -1848,10 +1901,22 @@ static enum agi_result run_agi(struct as +@@ -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_out > -1) { ++ if (agi->audio > -1) { + enhanced = 1; + } + if (agi->audio_in > -1) { @@ -349,16 +266,7 @@ if (c) { retry = AGI_NANDFS_RETRY; /* Idle the channel until we get a command */ -@@ -1862,13 +1927,23 @@ static enum agi_result run_agi(struct as - break; - } else { - /* If it's voice, write it to the audio pipe */ -- if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) { -+ if ((agi->audio_out > -1) && (f->frametype == AST_FRAME_VOICE)) { - /* Write, ignoring errors */ -- write(agi->audio, f->data, f->datalen); -+ write(agi->audio_out, f->data, f->datalen); - } +@@ -1871,6 +1936,16 @@ static enum agi_result run_agi(struct as ast_frfree(f); } } else if (outfd > -1) { @@ -375,7 +283,7 @@ size_t len = sizeof(buf); size_t buflen = 0; -@@ -1914,6 +1989,7 @@ static enum agi_result run_agi(struct as +@@ -1922,6 +1997,7 @@ static enum agi_result run_agi(struct as if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) { break; } @@ -383,7 +291,7 @@ } else { if (--retry <= 0) { ast_log(LOG_WARNING, "No channel, no fd?\n"); -@@ -2022,6 +2098,7 @@ static int agi_exec_full(struct ast_chan +@@ -2030,6 +2106,7 @@ static int agi_exec_full(struct ast_chan int argc = 0; int fds[2]; int efd = -1; @@ -391,32 +299,31 @@ int pid; char *stringp; AGI agi; -@@ -2047,12 +2124,13 @@ static int agi_exec_full(struct ast_chan - } +@@ -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_out = efd; + 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 */ -@@ -2062,6 +2140,8 @@ static int agi_exec_full(struct ast_chan +@@ -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_unreplace_sigchld(); ast_module_user_remove(u); -@@ -2110,6 +2190,35 @@ static int eagi_exec(struct ast_channel +@@ -2119,6 +2199,35 @@ static int eagi_exec(struct ast_channel return res; } @@ -452,7 +359,7 @@ static int deadagi_exec(struct ast_channel *chan, void *data) { if (!ast_check_hangup(chan)) -@@ -2165,6 +2274,7 @@ static int unload_module(void) +@@ -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)); @@ -460,7 +367,7 @@ ast_unregister_application(eapp); ast_unregister_application(deadapp); return ast_unregister_application(app); -@@ -2175,6 +2285,7 @@ static int load_module(void) +@@ -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); @@ -474,8 +381,8 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * -+ * XAGI sample script -+ * ++ * XAGI sample script ++ * + * Copyright (C) 2005 Junghanns.NET GmbH + * Klaus-Peter Junghanns + * @@ -524,7 +431,7 @@ + + /* Load into normal environment */ + setenv(buf, val, 1); -+ ++ + } + /* Never reached */ + return 0; @@ -599,7 +506,7 @@ + /* drop it, like it's hot */ + } + } -+ ++ +} + +static char *run_command(char *command) @@ -1043,7 +950,7 @@ @@ -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 .... + * @@ -1081,8 +988,8 @@ + +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" ++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[]); @@ -1181,7 +1088,7 @@ + .setoption = NULL, +}; + -+static char mandescr_devstate[] = ++static char mandescr_devstate[] = +"Description: Put a value into astdb\n" +"Variables: \n" +" Family: ...\n" @@ -1224,7 +1131,7 @@ + ast_log(LOG_DEBUG, "Unable to register channel class %s\n", type); + return -1; + } -+ ast_cli_register(&cli_dev_state); ++ 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); +} @@ -1237,7 +1144,7 @@ + ast_manager_unregister( "Devstate"); + ast_cli_unregister(&cli_dev_state); + res = ast_unregister_application(app); -+ ast_channel_unregister(&devstate_tech); ++ ast_channel_unregister(&devstate_tech); + return res; +} + @@ -1871,7 +1778,7 @@ * 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. -@@ -3240,7 +3243,7 @@ static int iax2_hangup(struct ast_channe +@@ -3362,7 +3365,7 @@ static int iax2_hangup(struct ast_channe ast_mutex_lock(&iaxsl[callno]); if (callno && iaxs[callno]) { if (option_debug) @@ -1880,7 +1787,7 @@ 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); -@@ -3294,7 +3297,8 @@ static int iax2_setoption(struct ast_cha +@@ -3416,7 +3419,8 @@ static int iax2_setoption(struct ast_cha static struct ast_frame *iax2_read(struct ast_channel *c) { @@ -1901,9 +1808,22 @@ 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 -@@ -1403,8 +1403,9 @@ static int conf_run(struct ast_channel * +@@ -1405,8 +1405,9 @@ static int conf_run(struct ast_channel * char members[10] = ""; int dtmf, opt_waitmarked_timeout = 0; time_t timeout = 0; @@ -1914,7 +1834,7 @@ char *buf = __buf + AST_FRIENDLY_OFFSET; int setusercount = 0; -@@ -1604,7 +1605,7 @@ static int conf_run(struct ast_channel * +@@ -1615,7 +1616,7 @@ static int conf_run(struct ast_channel * } /* Setup buffering information */ memset(&bi, 0, sizeof(bi)); @@ -1923,7 +1843,7 @@ bi.txbufpolicy = ZT_POLICY_IMMEDIATE; bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; bi.numbufs = audio_buffers; -@@ -1913,6 +1914,14 @@ static int conf_run(struct ast_channel * +@@ -1926,6 +1927,14 @@ static int conf_run(struct ast_channel * f = ast_read(c); if (!f) break; @@ -1943,17 +1863,17 @@ SayCharacters, SayPhonetic). --- a/main/pbx.c +++ b/main/pbx.c -@@ -6060,6 +6060,9 @@ static int pbx_builtin_saynumber(struct +@@ -6076,6 +6076,9 @@ static int pbx_builtin_saynumber(struct return -1; } } + if (chan->_state != AST_STATE_UP) { + ast_answer(chan); + } - return ast_say_number(chan, atoi(tmp), "", chan->language, options); - } -@@ -6067,8 +6070,12 @@ static int pbx_builtin_saydigits(struct + 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; @@ -1967,7 +1887,7 @@ SayCharacters, SayPhonetic). return res; } -@@ -6076,8 +6083,12 @@ static int pbx_builtin_saycharacters(str +@@ -6097,8 +6104,12 @@ static int pbx_builtin_saycharacters(str { int res = 0; @@ -1981,7 +1901,7 @@ SayCharacters, SayPhonetic). return res; } -@@ -6085,8 +6096,12 @@ static int pbx_builtin_sayphonetic(struc +@@ -6106,8 +6117,12 @@ static int pbx_builtin_sayphonetic(struc { int res = 0; @@ -2008,7 +1928,7 @@ SayCharacters, SayPhonetic). * 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. -@@ -125,7 +129,8 @@ static char *descrip = +@@ -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" @@ -2018,7 +1938,7 @@ SayCharacters, SayPhonetic). " 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" -@@ -1300,14 +1305,16 @@ static int dial_exec_full(struct ast_cha +@@ -1292,14 +1297,16 @@ static int dial_exec_full(struct ast_cha } if (!outgoing) { @@ -2039,7 +1959,7 @@ SayCharacters, SayPhonetic). if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) { --- a/apps/app_dial.c +++ b/apps/app_dial.c -@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi +@@ -71,6 +71,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi #include "asterisk/privacy.h" #include "asterisk/stringfields.h" #include "asterisk/global_datastores.h" @@ -2047,7 +1967,7 @@ SayCharacters, SayPhonetic). static char *app = "Dial"; -@@ -1654,23 +1655,25 @@ static int dial_exec_full(struct ast_cha +@@ -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); @@ -2084,7 +2004,7 @@ SayCharacters, SayPhonetic). config.warning_freq = warning_freq; --- a/apps/app_dial.c +++ b/apps/app_dial.c -@@ -193,6 +193,8 @@ static char *descrip = +@@ -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" @@ -2093,7 +2013,7 @@ SayCharacters, SayPhonetic). " 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" -@@ -249,6 +251,7 @@ enum { +@@ -254,6 +256,7 @@ enum { OPT_CALLEE_PARK = (1 << 25), OPT_CALLER_PARK = (1 << 26), OPT_IGNORE_FORWARDING = (1 << 27), @@ -2101,7 +2021,7 @@ SayCharacters, SayPhonetic). } dial_exec_option_flags; #define DIAL_STILLGOING (1 << 30) -@@ -292,6 +295,7 @@ AST_APP_OPTIONS(dial_exec_options, { +@@ -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), @@ -2109,7 +2029,7 @@ SayCharacters, SayPhonetic). 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), -@@ -407,7 +411,7 @@ static struct ast_channel *wait_for_answ +@@ -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 */ @@ -2118,7 +2038,7 @@ SayCharacters, SayPhonetic). if (single) { /* Turn off hold music, etc */ -@@ -628,7 +632,7 @@ static struct ast_channel *wait_for_answ +@@ -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); @@ -2127,7 +2047,7 @@ SayCharacters, SayPhonetic). ast_indicate(in, AST_CONTROL_PROGRESS); break; case AST_CONTROL_VIDUPDATE: -@@ -641,7 +645,7 @@ static struct ast_channel *wait_for_answ +@@ -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); @@ -2136,7 +2056,7 @@ SayCharacters, SayPhonetic). ast_indicate(in, AST_CONTROL_PROCEEDING); break; case AST_CONTROL_HOLD: -@@ -659,7 +663,7 @@ static struct ast_channel *wait_for_answ +@@ -669,7 +673,7 @@ static struct ast_channel *wait_for_answ /* Ignore going off hook and flash */ break; case -1: @@ -2145,7 +2065,7 @@ SayCharacters, SayPhonetic). if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "%s stopped sounds\n", c->name); ast_indicate(in, -1); -@@ -1099,7 +1103,7 @@ static int dial_exec_full(struct ast_cha +@@ -1091,7 +1095,7 @@ static int dial_exec_full(struct ast_cha outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"); } @@ -2154,7 +2074,7 @@ SayCharacters, SayPhonetic). /* loop through the list of dial destinations */ rest = args.peers; while ((cur = strsep(&rest, "&")) ) { -@@ -1124,7 +1128,7 @@ static int dial_exec_full(struct ast_cha +@@ -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 | @@ -2163,7 +2083,7 @@ SayCharacters, SayPhonetic). ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML); } ast_copy_string(numsubst, number, sizeof(numsubst)); -@@ -1327,7 +1331,7 @@ static int dial_exec_full(struct ast_cha +@@ -1319,7 +1323,7 @@ static int dial_exec_full(struct ast_cha ast_moh_start(chan, NULL, NULL); } ast_indicate(chan, AST_CONTROL_PROGRESS); @@ -2172,7 +2092,7 @@ SayCharacters, SayPhonetic). ast_indicate(chan, AST_CONTROL_RINGING); sentringing++; } -@@ -1444,7 +1448,7 @@ static int dial_exec_full(struct ast_cha +@@ -1442,7 +1446,7 @@ static int dial_exec_full(struct ast_cha if (ast_test_flag(&opts, OPT_MUSICBACK)) { ast_moh_stop(chan); @@ -2183,7 +2103,7 @@ SayCharacters, SayPhonetic). } --- a/apps/app_dial.c +++ b/apps/app_dial.c -@@ -196,7 +196,8 @@ static char *descrip = +@@ -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" @@ -2193,7 +2113,7 @@ SayCharacters, SayPhonetic). " 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" -@@ -252,6 +253,7 @@ enum { +@@ -257,6 +258,7 @@ enum { OPT_CALLER_PARK = (1 << 26), OPT_IGNORE_FORWARDING = (1 << 27), OPT_NOINBAND = (1 << 28), @@ -2201,7 +2121,7 @@ SayCharacters, SayPhonetic). } dial_exec_option_flags; #define DIAL_STILLGOING (1 << 30) -@@ -296,6 +298,7 @@ AST_APP_OPTIONS(dial_exec_options, { +@@ -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), @@ -2209,7 +2129,7 @@ SayCharacters, SayPhonetic). 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), -@@ -616,14 +619,20 @@ static struct ast_channel *wait_for_answ +@@ -621,14 +624,20 @@ static struct ast_channel *wait_for_answ HANDLE_CAUSE(AST_CAUSE_CONGESTION, in); break; case AST_CONTROL_RINGING: @@ -2234,7 +2154,7 @@ SayCharacters, SayPhonetic). } break; case AST_CONTROL_PROGRESS: -@@ -1103,7 +1112,7 @@ static int dial_exec_full(struct ast_cha +@@ -1095,7 +1104,7 @@ static int dial_exec_full(struct ast_cha outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"); } @@ -2243,5535 +2163,4787 @@ SayCharacters, SayPhonetic). /* 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 -@@ -104,6 +104,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi - #include "asterisk/abstract_jb.h" - #include "asterisk/smdi.h" - #include "asterisk/astobj.h" -+#include "asterisk/devicestate.h" -+ - #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */ - - /*! Global jitterbuffer configuration - by default, jb is disabled */ -@@ -703,6 +705,7 @@ static const struct ast_channel_tech zap - .fixup = zt_fixup, - .setoption = zt_setoption, - .func_channel_read = zt_func_read, -+/* .devicestate = zt_devicestate, */ - }; +@@ -190,7 +190,7 @@ static const char config[] = "zapata.con + #define SIG_GR303FXOKS (0x0100000 | ZT_SIG_FXOKS) + #define SIG_GR303FXSKS (0x0100000 | ZT_SIG_FXSKS) - #ifdef HAVE_PRI -@@ -761,6 +764,112 @@ static int cidrings[NUM_CADENCE_MAX] = { - #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */) - #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */) +-#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 */ -+static int zt_devicestate(void *data) -+{ -+ int groupmatch = 0; -+ int channelmatch = 0; -+ struct zt_pvt *p; -+ char *dest=NULL; -+ int x; -+ char *s; -+ char opt=0; -+ int res, y=0; -+ struct zt_pvt *exit, *start, *end; -+ ast_mutex_t *lock; -+ -+// ast_log(LOG_NOTICE, "data = %s\n", (char *)data); -+ return AST_DEVICE_UNKNOWN; -+ -+ /* Assume we're locking the iflock */ -+ lock = &iflock; -+ start = iflist; -+ end = ifend; -+ -+ if (data) { -+ dest = ast_strdupa((char *)data); -+ } else { -+ ast_log(LOG_WARNING, "Channel requested with no data\n"); -+ return AST_DEVICE_INVALID; -+ } -+ if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') { -+ /* Retrieve the group number */ -+ char *stringp=NULL; -+ stringp=dest + 1; -+ s = strsep(&stringp, "/"); -+ if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) { -+ ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data); -+ return AST_DEVICE_INVALID; -+ } -+ groupmatch = 1 << x; -+ } else { -+ char *stringp=NULL; -+ stringp=dest; -+ s = strsep(&stringp, "/"); -+ p = iflist; -+ if (!strcasecmp(s, "pseudo")) { -+ /* Special case for pseudo */ -+ x = CHAN_PSEUDO; -+ channelmatch = x; -+ /* bail out */ -+ return AST_DEVICE_INVALID; -+ } -+ -+ else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) { -+ ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data); -+ return AST_DEVICE_INVALID; -+ } else { -+ channelmatch = x; -+ ast_log(LOG_NOTICE, "channelmatch = %d\n", channelmatch); -+ } -+ } -+ /* Search for an unowned channel */ -+ if (ast_mutex_lock(lock)) { -+ ast_log(LOG_ERROR, "Unable to lock interface list???\n"); -+ return AST_DEVICE_INVALID; -+ } -+ p = iflist; -+ exit = iflist; -+ res = AST_DEVICE_INVALID; /* start pessimistic */ -+ while(p) { -+ if (p) { -+ ast_mutex_lock(&p->lock); -+ if ((groupmatch && ((p->group & groupmatch) != 0)) || (channelmatch && (p->channel == channelmatch))) { -+#ifdef ZAPATA_PRI -+ if (p->pri) { -+ for(d=0;dpri->dchanavail[d] & DCHAN_UP) { -+ res = AST_DEVICE_UNKNOWN; -+ } -+ } -+ } -+#endif -+ if ((!ast_strlen_zero(p->cid_num) && (strncasecmp(p->cid_num, dest, strlen(p->cid_num)))) || (!ast_strlen_zero(p->dnid) && (strncasecmp(p->dnid, dest, strlen(p->dnid))))) { -+ res = AST_DEVICE_UNKNOWN; -+ if (p->owner) { -+ if ((p->owner->_state == AST_STATE_RINGING) && (p->outgoing)) { -+ res = AST_DEVICE_RINGING; -+ } -+ if (((p->owner->_state == AST_STATE_RINGING) && (!p->outgoing)) || (p->owner->_state == AST_STATE_UP) || (p->owner->_state == AST_STATE_DIALING) || (p->owner->_state == AST_STATE_RESERVED) || (p->owner->_state == AST_STATE_RING)){ -+ res = AST_DEVICE_INUSE; -+ } -+ } -+ if ((res == AST_DEVICE_INUSE) || (res == AST_DEVICE_RINGING)) { -+ /* stop searching now, one non-idle channel is sufficient */ -+ ast_mutex_unlock(&p->lock); -+ break; -+ } -+ } -+ } -+ ast_mutex_unlock(&p->lock); -+ } -+ p = p->next; -+ } -+ ast_mutex_unlock(lock); -+ -+ return res; -+ -+} -+ - static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok) - { - int res; -Change the API of ast_sendtext and chan->sendtext to add dest and ispdu -parameters, used by ast_send_message which is also introduced by this patch. - --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h -@@ -227,7 +227,7 @@ struct ast_channel_tech { - int (* const write)(struct ast_channel *chan, struct ast_frame *frame); - - /*! \brief Display or transmit text */ -- int (* const send_text)(struct ast_channel *chan, const char *text); -+ int (* const send_text)(struct ast_channel *chan, const char *dest, const char *text, int ispdu); - - /*! \brief Display or send an image */ - int (* const send_image)(struct ast_channel *chan, struct ast_frame *frame); -@@ -671,6 +671,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" -@@ -887,10 +897,12 @@ int ast_set_write_format(struct ast_chan - /*! \brief Sends text 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_sendtext(struct ast_channel *chan, const char *text); -+int ast_sendtext(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 ---- a/main/channel.c -+++ b/main/channel.c -@@ -2694,7 +2694,7 @@ char *ast_recvtext(struct ast_channel *c - return buf; - } - --int ast_sendtext(struct ast_channel *chan, const char *text) -+int ast_sendtext(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 */ -@@ -2702,7 +2702,7 @@ int ast_sendtext(struct ast_channel *cha - return -1; - CHECK_BLOCKING(chan); - if (chan->tech->send_text) -- res = chan->tech->send_text(chan, text); -+ res = chan->tech->send_text(chan, dest, text, ispdu); - ast_clear_flag(chan, AST_FLAG_BLOCKING); - return res; - } -@@ -2881,7 +2881,7 @@ int ast_write(struct ast_channel *chan, - break; - case AST_FRAME_TEXT: - res = (chan->tech->send_text == NULL) ? 0 : -- chan->tech->send_text(chan, (char *) fr->data); -+ chan->tech->send_text(chan, NULL, (char *) fr->data, 0); - break; - case AST_FRAME_HTML: - res = (chan->tech->send_html == NULL) ? 0 : -@@ -4908,6 +4908,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_sendtext(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/apps/app_sendtext.c -+++ b/apps/app_sendtext.c -@@ -103,7 +103,7 @@ static int sendtext_exec(struct ast_chan - } - status = "FAILURE"; - ast_channel_unlock(chan); -- res = ast_sendtext(chan, args.text); -+ res = ast_sendtext(chan, NULL, args.text, 0); - if (!res) - status = "SUCCESS"; - pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status); ---- a/res/res_agi.c -+++ b/res/res_agi.c -@@ -486,7 +486,7 @@ static int handle_sendtext(struct ast_ch - would probably be to strip off the trailing newline before - parsing, then here, add a newline at the end of the string - before sending it to ast_sendtext --DUDE */ -- res = ast_sendtext(chan, argv[2]); -+ res = ast_sendtext(chan, NULL, argv[2], 0); - fdprintf(agi->fd, "200 result=%d\n", res); - return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; - } ---- a/channels/chan_agent.c -+++ b/channels/chan_agent.c -@@ -246,7 +246,7 @@ static int agent_answer(struct ast_chann - static struct ast_frame *agent_read(struct ast_channel *ast); - static int agent_write(struct ast_channel *ast, struct ast_frame *f); - static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); --static int agent_sendtext(struct ast_channel *ast, const char *text); -+static int agent_sendtext(struct ast_channel *ast, const char *dest, const char *text, int ispdu); - static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); - static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); - static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge); -@@ -555,13 +555,13 @@ static int agent_sendhtml(struct ast_cha - return res; - } - --static int agent_sendtext(struct ast_channel *ast, const char *text) -+static int agent_sendtext(struct ast_channel *ast, const char *dest, const char *text, int ispdu) - { - struct agent_pvt *p = ast->tech_pvt; - int res = -1; - ast_mutex_lock(&p->lock); - if (p->chan) -- res = ast_sendtext(p->chan, text); -+ res = ast_sendtext(p->chan, dest, text, ispdu); - ast_mutex_unlock(&p->lock); - return res; - } ---- a/channels/chan_alsa.c -+++ b/channels/chan_alsa.c -@@ -186,7 +186,7 @@ static int nosound = 0; - /* ZZ */ - static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause); - static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration); --static int alsa_text(struct ast_channel *c, const char *text); -+static int alsa_text(struct ast_channel *c, const char *dest, const char *text, int ispdu); - static int alsa_hangup(struct ast_channel *c); - static int alsa_answer(struct ast_channel *c); - static struct ast_frame *alsa_read(struct ast_channel *chan); -@@ -496,7 +496,7 @@ static int alsa_digit(struct ast_channel - return 0; - } - --static int alsa_text(struct ast_channel *c, const char *text) -+static int alsa_text(struct ast_channel *c, const char *dest, const char *text, int ispdu) - { - ast_mutex_lock(&alsalock); - ast_verbose(" << Console Received text %s >> \n", text); ---- a/channels/chan_local.c -+++ b/channels/chan_local.c -@@ -77,7 +77,7 @@ static int local_write(struct ast_channe - static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); - static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); - static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); --static int local_sendtext(struct ast_channel *ast, const char *text); -+static int local_sendtext(struct ast_channel *ast, const char *dest, const char *text, int ispdu); - static int local_devicestate(void *data); - - /* PBX interface structure for channel registration */ -@@ -390,7 +390,7 @@ static int local_digit_end(struct ast_ch - return res; - } - --static int local_sendtext(struct ast_channel *ast, const char *text) -+static int local_sendtext(struct ast_channel *ast, const char *dest, const char *text, int ispdu) - { - struct local_pvt *p = ast->tech_pvt; - int res = -1; ---- a/channels/chan_oss.c -+++ b/channels/chan_oss.c -@@ -405,7 +405,7 @@ static struct ast_channel *oss_request(c - , int *cause); - static int oss_digit_begin(struct ast_channel *c, char digit); - static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration); --static int oss_text(struct ast_channel *c, const char *text); -+static int oss_text(struct ast_channel *c, const char *dest, const char *text, int ispdu); - static int oss_hangup(struct ast_channel *c); - static int oss_answer(struct ast_channel *c); - static struct ast_frame *oss_read(struct ast_channel *chan); -@@ -773,7 +773,7 @@ static int oss_digit_end(struct ast_chan - return 0; - } - --static int oss_text(struct ast_channel *c, const char *text) -+static int oss_text(struct ast_channel *c, const char *dest, const char *text, int ispdu) - { - /* print received messages */ - ast_verbose(" << Console Received text %s >> \n", text); ---- a/channels/chan_phone.c -+++ b/channels/chan_phone.c -@@ -166,7 +166,7 @@ static int phone_answer(struct ast_chann - static struct ast_frame *phone_read(struct ast_channel *ast); - static int phone_write(struct ast_channel *ast, struct ast_frame *frame); - static struct ast_frame *phone_exception(struct ast_channel *ast); --static int phone_send_text(struct ast_channel *ast, const char *text); -+static int phone_send_text(struct ast_channel *ast, const char *dest, const char *text, int ispdu); - static int phone_fixup(struct ast_channel *old, struct ast_channel *new); - static int phone_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen); - -@@ -640,7 +640,7 @@ static int phone_write_buf(struct phone_ - return len; - } - --static int phone_send_text(struct ast_channel *ast, const char *text) -+static int phone_send_text(struct ast_channel *ast, const char *dest, const char *text, int ispdu) - { - int length = strlen(text); - return phone_write_buf(ast->tech_pvt, text, length, length, 0) == ---- a/channels/chan_sip.c -+++ b/channels/chan_sip.c -@@ -1215,7 +1215,7 @@ static struct ast_config *notify_types; - /*--- PBX interface functions */ - static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause); - static int sip_devicestate(void *data); --static int sip_sendtext(struct ast_channel *ast, const char *text); -+static int sip_sendtext(struct ast_channel *ast, const char *dest, const char *text, int ispdu); - static int sip_call(struct ast_channel *ast, char *dest, int timeout); - static int sip_hangup(struct ast_channel *ast); - static int sip_answer(struct ast_channel *ast); -@@ -2347,7 +2347,7 @@ static char *get_in_brackets(char *tmp) - - /*! \brief Send SIP MESSAGE text within a call - Called from PBX core sendtext() application */ --static int sip_sendtext(struct ast_channel *ast, const char *text) -+static int sip_sendtext(struct ast_channel *ast, const char *dest, const char *text, int ispdu) - { - struct sip_pvt *p = ast->tech_pvt; - int debug = sip_debug_test_pvt(p); ---- a/channels/chan_iax2.c -+++ b/channels/chan_iax2.c -@@ -831,7 +831,7 @@ static int iax2_provision(struct sockadd - static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final); - static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen); - static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img); --static int iax2_sendtext(struct ast_channel *c, const char *text); -+static int iax2_sendtext(struct ast_channel *c, const char *dest, const char *text, int ispdu); - static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen); - static int iax2_transfer(struct ast_channel *c, const char *dest); - static int iax2_write(struct ast_channel *c, struct ast_frame *f); -@@ -2642,7 +2642,7 @@ static int iax2_digit_end(struct ast_cha - return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1); - } +@@ -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]; --static int iax2_sendtext(struct ast_channel *c, const char *text) -+static int iax2_sendtext(struct ast_channel *c, const char *dest, const char *text, int ispdu) - { - - return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_TEXT, ---- a/main/manager.c -+++ b/main/manager.c -@@ -11,6 +11,9 @@ + 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-2004, Junghanns.NET Gmbh ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH + * Klaus-Peter Junghanns ++ * + * * 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. -@@ -1426,6 +1429,49 @@ static int action_hangup(struct mansessi - return 0; - } +@@ -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 -+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" -@@ -2835,6 +2881,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]; + /*! \brief Wait up to 16 seconds for first digit (FXO logic) */ +@@ -235,10 +237,6 @@ AST_MUTEX_DEFINE_STATIC(iflock); -+ /* 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 { + static int ifcount = 0; - /* 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 ); +-#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( - /* 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 -@@ -129,7 +129,7 @@ static int ast_monitor_set_state(struct + static int zt_sendtext(struct ast_channel *c, const char *text); - /* 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) ++ + /*! \brief Avoid the silly zt_getevent which ignores a bunch of events */ + static inline int zt_get_event(int fd) { - int res = 0; - char tmp[256]; -@@ -153,6 +153,11 @@ int ast_monitor_start( struct ast_channe - return -1; - } +@@ -297,6 +296,14 @@ static int ringt_base = DEFAULT_RINGT; + #define PRI_SPAN(p) (((p) >> 8) & 0xff) + #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01) -+ 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)); ++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; ++}; + - /* Determine file names */ - if (!ast_strlen_zero(fname_base)) { - int directory = strchr(fname_base, '/') ? 1 : 0; -@@ -295,6 +300,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; -@@ -322,8 +329,13 @@ int ast_monitor_stop(struct ast_channel - snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,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); - } - -@@ -452,7 +464,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); -@@ -491,6 +503,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)) { -@@ -515,7 +529,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 -@@ -2804,13 +2804,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 -@@ -416,7 +416,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]; + 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; }; -@@ -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) -+static int __ast_device_state_changed_literal(char *buf, char *cid_num, char *cid_name) - { - char *device; - struct state_change *change; -@@ -312,10 +314,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) -@@ -327,11 +335,17 @@ static int __ast_device_state_changed_li - return 1; - } +@@ -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, --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); -+ if (cid_num) -+ buf2 = ast_strdupa(cid_num); -+ if (cid_name) -+ buf3 = ast_strdupa(cid_name); -+ return __ast_device_state_changed_literal(buf, buf2, buf3); - } + .resetinterval = 3600 + }, +@@ -630,6 +651,8 @@ static struct zt_chan_conf zt_chan_conf_ + .mohinterpret = "default", + .mohsuggest = "", + .transfertobusy = 1, ++ .priindication_oob = 0, ++ .pritransfer = 0, - /*! \brief Accept change notification, add it to change queue */ -@@ -343,7 +357,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); -+ return __ast_device_state_changed_literal(buf, NULL, NULL); - } + .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); - /*! \brief Go through the dev state change queue and update changes in the dev state thread */ -@@ -358,7 +372,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 -@@ -590,8 +590,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); + 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]; -+extern ast_mutex_t uniquelock; -+ -+/*! \brief Change the state of a channel and the callerid of the calling channel*/ -+int ast_setstate_and_cid(struct ast_channel *chan, enum ast_channel_state state, char *cid_num, char *cid_name); + #ifdef HAVE_PRI ++struct app_tmp { ++ char app[256]; ++ char data[256]; ++ struct ast_channel *chan; ++ pthread_t t; ++}; + - /*! \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 -@@ -1277,7 +1277,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); - } + 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; - struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, char *uid) -@@ -3941,7 +3941,7 @@ void ast_set_callerid(struct ast_channel - ast_channel_unlock(chan); - } +- 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); ++ } ++ --int ast_setstate(struct ast_channel *chan, enum ast_channel_state state) -+int ast_setstate_and_cid(struct ast_channel *chan, enum ast_channel_state state, char *cid_num, char *cid_name) - { - int oldstate = chan->_state; + 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; -@@ -3949,7 +3949,7 @@ int ast_setstate(struct ast_channel *cha - return 0; ++ 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); - 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", -@@ -3966,6 +3966,11 @@ int ast_setstate(struct ast_channel *cha - return 0; +@@ -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 -+int ast_setstate(struct ast_channel *chan, enum ast_channel_state state) ++static int zt_setlaw(int zfd, int law) +{ -+ return ast_setstate_and_cid(chan, state, NULL, NULL); ++ int res; ++ res = ioctl(zfd, ZT_SETLAW, &law); ++ if (res) ++ return res; ++ return 0; +} + - /*! \brief Find bridged channel */ - struct ast_channel *ast_bridged_channel(struct ast_channel *chan) ++ + static int zt_hangup(struct ast_channel *ast) { ---- 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 -@@ -2011,7 +2011,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; - -@@ -2042,11 +2042,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 */ + 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 } -@@ -2241,7 +2241,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; -@@ -4008,7 +4008,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 -@@ -1338,7 +1338,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); -@@ -8459,7 +8459,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; ---- a/apps/app_queue.c -+++ b/apps/app_queue.c -@@ -690,7 +690,7 @@ static void *device_state_thread(void *d - return NULL; - } + 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 --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) +- 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 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 */ + 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; - /* 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" }, - }; -@@ -2538,10 +2539,12 @@ int ast_manager_unregister(char *action) - return 0; + /* 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; } --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) +- + #ifdef HAVE_PRI + static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv) { -+ 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; +@@ -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; } ---- 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[]) +@@ -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) { - char devName[128]; -- if (argc != 3) -+ if ((argc != 3) && (argc != 4) && (argc != 5)) - return RESULT_SHOWUSAGE; +- 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); + } - 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; +-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); } -@@ -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); -Use Asterisk's process ID when building the unique ID. - ---- a/main/channel.c -+++ b/main/channel.c -@@ -808,10 +808,10 @@ struct ast_channel *ast_channel_alloc(in - tmp->fout = global_fout; - - if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { -- ast_string_field_build(tmp, uniqueid, "%li.%d", (long) time(NULL), -+ ast_string_field_build(tmp, uniqueid, "%d-%li.%d", ast_mainpid, (long) time(NULL), - ast_atomic_fetchadd_int(&uniqueint, 1)); - } else { -- ast_string_field_build(tmp, uniqueid, "%s-%li.%d", ast_config_AST_SYSTEM_NAME, -+ ast_string_field_build(tmp, uniqueid, "%s-%d-%li.%d", ast_config_AST_SYSTEM_NAME, ast_mainpid, - (long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1)); - } - -Add or convert channel operations so they can use the unique ID. - ---- a/include/asterisk/channel.h -+++ b/include/asterisk/channel.h -@@ -659,6 +659,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 -@@ -672,9 +684,9 @@ struct ast_channel *ast_request(const ch - * \return Returns an ast_channel on success or no answer, NULL on failure. Check the value of chan->_state - * to know if the call was answered or not. - */ --struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname); -+struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, char *uniqueid); - --struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh); -+struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, struct outgoing_helper *oh, char *uniqueid); - - /*! \brief "Requests" a channel for sending a message - * \param type type of channel to request -@@ -959,6 +971,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 -@@ -1035,7 +1035,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; -@@ -1063,7 +1063,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 */ -@@ -1118,39 +1121,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) + static int pri_check_restart(struct zt_pri *pri) { -- 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 */ -@@ -1220,8 +1228,10 @@ void ast_channel_free(struct ast_channel - free(chan->tech_pvt); - } - -- if (chan->sched) -- sched_context_destroy(chan->sched); -+ if (chan->sched) { -+ sched_context_destroy(chan->sched); -+ chan->sched = NULL; ++ if ((pri->nodetype != PRI_NETWORK) && (pri->nodetype != PRI_CPE)) { ++ return 0; + } - - ast_copy_string(name, chan->name, sizeof(name)); - -@@ -3106,7 +3116,7 @@ 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) -+struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cid_num, const char *cid_name, struct outgoing_helper *oh, char* uniqueid) - { - int dummy_outstate; - int cause = 0; -@@ -3118,7 +3128,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 */ -@@ -3141,7 +3151,7 @@ struct ast_channel *__ast_request_and_di - ast_cdr_setaccount(chan, oh->account); + do { + pri->resetpos++; + } while ((pri->resetpos < pri->numchans) && +@@ -8344,13 +8471,30 @@ static void apply_plan_to_number(char *b } - ast_set_callerid(chan, cid_num, cid_name, cid_num); -- -+ chan->cid.cid_pres = callingpres; - - - if (!chan->cdr) { /* up till now, this insertion hasn't been done. Therefore, -@@ -3230,12 +3240,12 @@ struct ast_channel *__ast_request_and_di - return chan; } --struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname) -+struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cidnum, const char *cidname, char *uniqueid) - { -- return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL); -+ return __ast_request_and_dial(type, format, data, timeout, outstate, 0, cidnum, cidname, NULL, uniqueid); - } - --struct ast_channel *ast_request(const char *type, int format, void *data, int *cause) -+struct ast_channel *ast_request_with_uniqueid(const char *type, int format, void *data, int *cause, char *uniqueid) - { - struct chanlist *chan; - struct ast_channel *c; -@@ -3285,6 +3295,11 @@ struct ast_channel *ast_request(const ch - return NULL; +-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; ++ } } -+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. -@@ -3672,7 +3687,7 @@ int ast_do_masquerade(struct ast_channel - ast_string_field_set(clone, name, masqn); - - /* Notify any managers of the change, first the masq then the other */ -- manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", newn, masqn, clone->uniqueid); -+ manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\nNewUniqueid: %s\r\n", newn, masqn, clone->uniqueid, original->uniqueid); - manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", orig, newn, original->uniqueid); - - /* Swap the technologies */ ---- a/apps/app_parkandannounce.c -+++ b/apps/app_parkandannounce.c -@@ -182,7 +182,7 @@ static int parkandannounce_exec(struct a - memset(&oh, 0, sizeof(oh)); - oh.parent_channel = chan; - oh.vars = ast_variable_new("_PARKEDAT", buf); -- dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh); -+ dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, 0, chan->cid.cid_num, chan->cid.cid_name, &oh, NULL); - - if(dchan) { - if(dchan->_state == AST_STATE_UP) { ---- 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_exten2(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_app2(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 -@@ -4985,7 +4985,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_exten2(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; -@@ -4995,7 +4995,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(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid); - if (channel) { - *channel = chan; - if (chan) -@@ -5080,7 +5080,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(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid); - if (channel) { - *channel = chan; - if (chan) -@@ -5120,6 +5120,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_exten2(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]; -@@ -5144,7 +5148,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_app2(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; -@@ -5163,10 +5167,10 @@ 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(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 */ -- ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name); -+ ast_log(LOG_WARNING, "%s already has a call detail record??\n", chan->name); - } else { - chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */ - if(!chan->cdr) { -@@ -5247,7 +5251,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(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid); - if (!chan) { - free(as); - res = -1; -@@ -5287,6 +5291,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_app2(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 -@@ -337,6 +337,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); -@@ -503,18 +508,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; -+ } - } + 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; inumchans; 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) - if (ast_strlen_zero(fname)) { -@@ -555,16 +570,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; -+ } - } + 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); ++ } + - res = ast_monitor_stop(c, 1); - ast_channel_unlock(c); - if (res) { ---- a/apps/app_chanspy.c -+++ b/apps/app_chanspy.c -@@ -55,6 +55,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_chan2 = "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" -@@ -85,6 +86,27 @@ static const char *desc_chan = - " channel.\n" - ; + if (!pri->pri) pri_find_dchan(pri); -+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" -@@ -404,7 +426,7 @@ static int channel_spy(struct ast_channe - } - - static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec, -- const char *exten, const char *context) -+ const char *exten, const char *context, const char *uniqueid) - { - struct ast_channel *this; - -@@ -413,6 +435,8 @@ static struct ast_channel *next_channel( - 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); - -@@ -427,7 +451,7 @@ static struct ast_channel *next_channel( - - 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) - { - struct ast_channel *peer, *prev, *next; - char nameprefix[AST_NAME_STRLEN]; -@@ -466,9 +490,9 @@ static int common_exec(struct ast_channe - waitms = 100; - peer = prev = next = NULL; - -- for (peer = next_channel(peer, spec, exten, context); -+ for (peer = next_channel(peer, spec, exten, context, NULL); - peer; -- prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) { -+ prev = peer, peer = next ? next : next_channel(peer, spec, exten, context, NULL), next = NULL) { - const char *group; - int igrp = !mygroup; - char *groups[25]; -@@ -625,7 +649,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); -@@ -710,7 +734,92 @@ 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); -+ -+ 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 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); -@@ -723,14 +832,15 @@ static int extenspy_exec(struct ast_chan - return res; - } - -+ - static int unload_module(void) - { - int res = 0; - - res |= ast_unregister_application(app_chan); -+ res |= ast_unregister_application(app_chan2); - res |= ast_unregister_application(app_ext); - -- ast_module_user_hangup_all(); - - return res; - } -@@ -741,6 +851,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_chan2, 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; - }; - -@@ -1415,11 +1417,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; -@@ -1670,12 +1681,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,7 +1702,11 @@ static int action_redirect(struct manses - } - } - /* 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); -@@ -1707,9 +1728,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) -@@ -1788,15 +1809,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_app2(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_exten2(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) -@@ -1856,6 +1877,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; -@@ -1865,6 +1887,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; -@@ -1882,6 +1907,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, '/'); -@@ -1901,6 +1930,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) { -@@ -1920,8 +1950,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)) { -@@ -1932,19 +1964,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_app2(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_exten2(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 - #ifdef POLLCOMPAT - #include "asterisk/poll-compat.h" -@@ -1004,6 +1007,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 -@@ -724,6 +724,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 -+ * - * 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. -@@ -128,6 +132,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; - -@@ -146,6 +164,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 */ -@@ -401,11 +436,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, ""), -- S_OR(pu->chan->cid.cid_name, "") -+ S_OR(pu->chan->cid.cid_name, ""), -+ pu->chan->uniqueid - ); - - if (peer && adsipark && ast_adsi_available(peer)) { -@@ -1628,11 +1665,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, ""), -- S_OR(chan->cid.cid_name, "") -+ S_OR(chan->cid.cid_name, ""), -+ chan->uniqueid - ); - } - -@@ -1887,10 +1926,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, ""), -- S_OR(pu->chan->cid.cid_name, "") -+ S_OR(pu->chan->cid.cid_name, ""), -+ pu->chan->uniqueid - ); - - free(pu); -@@ -2044,15 +2085,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) -@@ -2076,12 +2112,13 @@ static int manager_parking_status( struc - "Timeout: %ld\r\n" - "CallerID: %s\r\n" - "CallerIDName: %s\r\n" -+ "Unqiueid: %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 */ -- S_OR(cur->chan->cid.cid_name, ""), -+ S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid, - idText); - } - -@@ -2156,6 +2193,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]; + /* 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, ""), ++ 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, ""), + 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; ++ } + -+ ast_mutex_lock(&autoanswer_lock); ++ 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; ++ } + -+ 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; -+ } ++ 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"); ++ } + -+ 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;xchan->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"); ++ if (zpc) { ++ zpc->next = zpcl->next; ++ free(zpcl); ++ zpcl = zpc->next; + } else { -+ ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten); ++ // remove head ++ pri->suspended_calls = zpcl->next; ++ free(zpcl); ++ zpcl = pri->suspended_calls; ++ zpc = NULL; + } -+ /* 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; ++ 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 { -+ /* 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 */ ++ ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", ++ PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); + } -+ } -+ } -+ if (x >= AST_MAX_FDS) { -+std: for (x=0;xchan->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]; ++ } 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); + } -+ /* 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; -+} + 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 - int ast_pickup_call(struct ast_channel *chan) - { -@@ -2419,6 +2877,7 @@ static int load_config(void) - - static int reload(void) + static int handle_pri_set_debug_file(int fd, int argc, char **argv) { -+ autoanswer_reregister_extensions(); - return load_config(); - } - -@@ -2442,6 +2901,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; -@@ -2456,6 +2921,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); +- int myfd; ++ int myfd, x, d; ++ int span; + - /*! \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 -@@ -62,6 +62,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 -@@ -80,6 +81,7 @@ enum { - }; ++ if (argc < 6) ++ return RESULT_SHOWUSAGE; - static char *parkedcall = "ParkedCall"; -+static char *holdedcall = "HoldedCall"; + if (!strncasecmp(argv[1], "set", 3)) { +- if (argc < 5) ++ if (argc < 7) + return RESULT_SHOWUSAGE; - 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 */ -@@ -164,6 +166,22 @@ struct parkeduser { - struct parkeduser *next; - }; +- if (ast_strlen_zero(argv[4])) ++ if (!argv[4] || ast_strlen_zero(argv[4])) + return RESULT_SHOWUSAGE; -+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; -+}; ++ if (!argv[5]) ++ return RESULT_SHOWUSAGE; + - /* auto answer user */ - struct aauser { - struct ast_channel *chan; -@@ -183,10 +201,16 @@ static pthread_t autoanswer_thread; - - static struct parkeduser *parkinglot; - -+static struct holdeduser *holdlist; ++ if (!argv[6] || ast_strlen_zero(argv[6])) ++ return RESULT_SHOWUSAGE; + - AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */ - -+AST_MUTEX_DEFINE_STATIC(holding_lock); ++ span = atoi(argv[6]); ++ if ((span < 1) && (span > NUM_SPANS)) { ++ return RESULT_SUCCESS; ++ } + - static pthread_t parking_thread; - -+static pthread_t holding_thread; + - char *ast_parking_ext(void) - { - return parking_ext; -@@ -2011,6 +2035,282 @@ static int park_exec(struct ast_channel - return res; - } + 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); -+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); +- 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; ++ } + -+ 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); ++ for (x=0; x < NUM_SPANS; x++) { ++ ast_mutex_lock(&pris[x].lock); + -+ } else { -+ ast_log(LOG_WARNING, "Out of memory\n"); -+ return -1; -+ } -+ return 0; -+} ++ 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); ++ } + -+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; -+} ++ 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 + + + + -+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; + 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 \n" ++ " Enables debugging on a given BRI span\n"; + -+ peer = ast_get_holded_call(uniqueid); ++static char bri_no_debug_help[] = ++ "Usage: bri no debug span \n" ++ " Disables debugging on a given BRI span\n"; + -+ /* JK02: it helps to answer the channel if not already up */ -+ if (chan->_state != AST_STATE_UP) { -+ ast_answer(chan); -+ } ++static char bri_really_debug_help[] = ++ "Usage: bri intensive debug span \n" ++ " Enables debugging down to the Q.921 level\n"; + -+ 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); + 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 }, + -+ 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); ++ { { "bri", "no", "debug", "span", NULL }, handle_pri_no_debug, ++ "Disables BRI debugging on a span", bri_no_debug_help, complete_span_5 }, + -+ /* 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; -+} ++ { { "bri", "intense", "debug", "span", NULL }, handle_pri_really_debug, ++ "Enables REALLY INTENSE BRI debugging", bri_really_debug_help, complete_span_5 }, + -+int ast_retrieve_call_to_death(char *uniqueid) + { { "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) +{ -+ int res=-1; -+ struct ast_channel *peer=NULL; ++ struct zt_pvt *p = chan->tech_pvt; + -+ peer = ast_get_holded_call(uniqueid); ++ if((!p->pri) || (!p->pri->pri)) { ++ return -1; ++ } + -+ 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; ++ 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); +} + -+struct ast_channel *ast_get_holded_call(char *uniqueid) ++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) +{ -+ int res=-1; -+ struct ast_channel *peer=NULL; -+ struct holdeduser *pu, *pl=NULL; ++ struct zt_pvt *p = chan->tech_pvt; + -+ 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; ++ return pri_acknowledge(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1); +} + -+/* this is our autmagically service thread that keeps channels onhold happy */ -+static void *do_holding_thread(void *ignore) + #endif /* HAVE_PRI */ + ++static int app_zapEC(struct ast_channel *chan, void *data) +{ -+ 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;xchan->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;xchan->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(); ++ 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); + } -+ return NULL; /* Never reached */ -+} ++ } else { ++ ast_log(LOG_WARNING, "zapNoEC only works on ZAP channels, check your extensions.conf!\n"); ++ res = 0; ++ } + -+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; ++ return res; +} + - static int handle_showfeatures(int fd, int argc, char *argv[]) ++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 i; -@@ -2892,6 +3192,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); -@@ -2901,6 +3202,7 @@ static int load_module(void) - "Park a channel", mandescr_park); + int channel; +@@ -10441,8 +11155,11 @@ static int __unload_module(void) } - -+ 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); -@@ -2923,6 +3225,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/include/asterisk/channel.h -+++ b/include/asterisk/channel.h -@@ -423,6 +423,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/main/pbx.c -+++ b/main/pbx.c -@@ -5132,7 +5132,7 @@ struct app_tmp { - }; - - /*! \brief run the application and free the descriptor once done */ --static void *ast_pbx_run_app(void *data) -+void *ast_pbx_run_app(void *data) - { - struct app_tmp *tmp = data; - struct ast_app *app; ---- a/include/asterisk/pbx.h -+++ b/include/asterisk/pbx.h -@@ -145,6 +145,8 @@ void ast_unregister_switch(struct ast_sw - */ - struct ast_app *pbx_findapp(const char *app); - -+void *ast_pbx_run_app(void *data); -+ - /*! - * \brief Execute an application - * ---- 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 -+ * -+ * - * 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. -@@ -192,7 +196,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 128 /*!<"32 spans", muahahaha, us alaws like to have some more... */ - #define NUM_DCHANS 4 /*!< No more than 4 d-channels */ - #define MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */ - -@@ -218,8 +222,6 @@ static struct ast_channel inuse; - #ifdef PRI_GETSET_TIMERS - static int pritimers[PRI_MAX_TIMERS]; + 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 --static int pridebugfd = -1; --static char pridebugfilename[1024] = ""; + 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; - /*! \brief Wait up to 16 seconds for first digit (FXO logic) */ -@@ -237,10 +239,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); -@@ -255,6 +253,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) - { -@@ -299,6 +298,27 @@ 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_holded_call { -+ ast_mutex_t lock; /* Mutex */ -+ char msn[AST_MAX_EXTENSION]; /* the MSN to which this parked call belongs */ -+ char uniqueid[AST_MAX_EXTENSION]; /* unique id of the onhold channel */ -+ int tei; -+ int cref; -+ int alreadyhungup; -+ struct ast_channel *channel; -+ struct ast_channel *bridge; -+ q931_call *call; /* this also covers tei mumbojumbo */ -+ struct zt_holded_call *next; -+}; + - struct zt_pri { - pthread_t master; /*!< Thread of master */ - ast_mutex_t lock; /*!< Mutex */ -@@ -312,6 +332,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) */ -@@ -323,6 +345,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 */ -@@ -338,6 +361,9 @@ 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 */ -+ struct zt_holded_call *holded_calls; /* Calls on hold */ -+ int debugfd; - }; + 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); -@@ -455,6 +481,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; -@@ -468,7 +496,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 */ -@@ -505,6 +534,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]; -@@ -570,6 +600,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 -@@ -615,11 +647,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, +@@ -689,6 +694,16 @@ struct ast_channel *ast_request_and_dial - .resetinterval = 3600 - }, -@@ -631,6 +666,8 @@ static struct zt_chan_conf zt_chan_conf_ - .mohinterpret = "default", - .mohsuggest = "", - .transfertobusy = 1, -+ .priindication_oob = 0, -+ .pritransfer = 0, + 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); - .cid_signalling = CID_SIG_BELL, - .cid_start = CID_START_RING, -@@ -685,6 +722,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); ++/*! \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); - static const struct ast_channel_tech zap_tech = { - .type = "Zap", -@@ -717,6 +756,13 @@ static const struct ast_channel_tech zap - struct zt_pvt *round_robin[32]; ++/*! \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; + } - #ifdef HAVE_PRI -+struct app_tmp { -+ char app[256]; -+ char data[256]; -+ struct ast_channel *chan; -+ pthread_t t; -+}; ++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; ++} + - static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri) - { - int res; -@@ -1525,12 +1571,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) { -@@ -1557,7 +1607,7 @@ static void zt_train_ec(struct zt_pvt *p + int ast_senddigit_begin(struct ast_channel *chan, char digit) { - 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) -@@ -1918,7 +1968,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; + /* Device does not support DTMF tones, lets fake +@@ -4515,6 +4530,25 @@ void ast_channel_stop_silence_generator( + } -- 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); + ++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; + } + - - mysig = p->sig; - if (p->outsigmod > -1) -@@ -2149,6 +2204,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"); -@@ -2169,6 +2225,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... ;-) -+ } ++ return res; ++} + - c = strchr(dest, '/'); - if (c) - c++; -@@ -2191,6 +2253,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'); -@@ -2214,6 +2277,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); -@@ -2243,7 +2308,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); - -@@ -2507,8 +2572,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", -@@ -2518,6 +2585,16 @@ static int pri_find_dchan(struct zt_pri + /*! \ 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 ++ * + * 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; } - #endif -+static int zt_setlaw(int zfd, int law) ++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; -+ res = ioctl(zfd, ZT_SETLAW, &law); -+ if (res) -+ return 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]; + - static int zt_hangup(struct ast_channel *ast) - { - int res; -@@ -2565,8 +2642,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; -@@ -2668,6 +2744,7 @@ static int zt_hangup(struct ast_channel + /* 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 { - 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; -@@ -2710,7 +2787,7 @@ static int zt_hangup(struct ast_channel - pri_call_set_useruser(p->call, useruser); - #endif + /* 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 ); -- 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; -@@ -2730,7 +2807,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"); -@@ -2914,10 +3012,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: -@@ -3554,6 +3656,15 @@ static int zt_fixup(struct ast_channel * + /* 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) { - 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) { -@@ -3763,8 +3874,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) -@@ -3923,7 +4036,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); -@@ -4974,7 +5087,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) { -@@ -4986,8 +5099,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; - } -@@ -5062,7 +5176,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); + 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; } -@@ -5130,7 +5246,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; -@@ -5212,7 +5328,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; -@@ -5406,8 +5522,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; - } -@@ -5537,6 +5657,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 -@@ -5565,10 +5686,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 -@@ -6784,18 +6912,44 @@ static int handle_init_event(struct zt_p - break; - case ZT_EVENT_NOALARM: - i->inalarm = 0; -+#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 { -+ ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel); -+ manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", -+ "Channel: %d\r\n", i->channel); -+ } -+ } -+#else - ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel); - manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", - "Channel: %d\r\n", i->channel); -+#endif - break; - case ZT_EVENT_ALARM: - i->inalarm = 1; - res = get_alarms(i); -+#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 { -+ ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", i->channel, alarm2str(res)); -+ manager_event(EVENT_FLAG_SYSTEM, "Alarm", -+ "Alarm: %s\r\n" -+ "Channel: %d\r\n", -+ alarm2str(res), i->channel); -+ } -+ } -+#else - ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", i->channel, alarm2str(res)); - manager_event(EVENT_FLAG_SYSTEM, "Alarm", - "Alarm: %s\r\n" - "Channel: %d\r\n", - alarm2str(res), i->channel); -+#endif - /* fall thru intentionally */ - case ZT_EVENT_ONHOOK: - if (i->radio) -@@ -6839,8 +6993,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); -@@ -7139,6 +7295,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; - } -@@ -7391,6 +7549,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); -@@ -7408,6 +7571,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; -@@ -7416,9 +7584,14 @@ 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].holded_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)); -@@ -7554,6 +7727,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) { -@@ -7833,7 +8007,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; -@@ -8029,6 +8203,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); +- 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 ); } -@@ -8062,13 +8241,14 @@ next: - *cause = AST_CAUSE_BUSY; - } else if (groupmatched) { - *cause = AST_CAUSE_CONGESTION; -+ } else { -+ *cause = AST_CAUSE_CONGESTION; - } + 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 tmp; + + return 1; } -- - #ifdef HAVE_PRI - static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv) +-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) { -@@ -8082,6 +8262,58 @@ static struct zt_pvt *pri_find_crv(struc - return NULL; + 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); } -+static int pri_find_tei(struct zt_pri *pri, q931_call *c, int tei) -+{ -+ int x=0; -+ for (x=0;xnumchans;x++) { -+ if (!pri->pvts[x]) continue; -+ if ((pri->pvts[x]->tei == tei) && (pri->pvts[x]-> call != c)) { -+ return x; -+ } -+ } -+ return -1; -+} -+ -+static struct zt_holded_call *pri_get_callonhold(struct zt_pri *pri, int cref, int tei) { -+ struct zt_holded_call *zhc = pri->holded_calls; -+ struct zt_holded_call *zhctemp = NULL; -+ -+ while (zhc) { -+ if ((zhc->tei == tei) && ((zhc->cref == cref) || (cref == -1))) { -+ return zhc; -+ } -+ zhctemp = zhc; -+ if (zhc) zhc = zhc->next; -+ } -+ return NULL; -+} -+ -+static int pri_destroy_callonhold(struct zt_pri *pri, struct zt_holded_call *onhold) { -+ struct zt_holded_call *zhc = pri->holded_calls; -+ struct zt_holded_call *zhctemp = NULL; + /*! \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; + -+ while (zhc) { -+ if (zhc == onhold) { -+ if (zhctemp) { -+ zhctemp->next = zhc->next; -+ zhc = zhctemp; -+ } else { -+ pri->holded_calls = zhc->next; -+ zhc = pri->holded_calls; -+ zhctemp = NULL; -+ } -+ } -+ zhctemp = zhc; -+ if (zhc) zhc = zhc->next; -+ } -+ if (onhold) { -+ free(onhold); -+ onhold = NULL; -+ return 1; -+ } -+ return 0; -+} ++/*! \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); - static int pri_find_principle(struct zt_pri *pri, int channel) - { -@@ -8113,7 +8345,9 @@ 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; -+ char tmpname[256]; - if (!c) { - if (principle < 0) - return -1; -@@ -8141,6 +8375,7 @@ static int pri_fixup_principle(struct zt - } - /* Fix it all up now */ - pri->pvts[principle]->owner = pri->pvts[x]->owner; -+ pri->pvts[principle]->outgoing = pri->pvts[x]->outgoing; - if (pri->pvts[principle]->owner) { - ast_string_field_build(pri->pvts[principle]->owner, name, - "Zap/%d:%d-%d", pri->trunkgroup, -@@ -8148,13 +8383,48 @@ static int pri_fixup_principle(struct zt - pri->pvts[principle]->owner->tech_pvt = pri->pvts[principle]; - pri->pvts[principle]->owner->fds[0] = pri->pvts[principle]->subs[SUB_REAL].zfd; - pri->pvts[principle]->subs[SUB_REAL].owner = pri->pvts[x]->subs[SUB_REAL].owner; -- } else -+ } else { - ast_log(LOG_WARNING, "Whoa, there's no owner, and we're having to fix up channel %d to channel %d\n", pri->pvts[x]->channel, pri->pvts[principle]->channel); -+ } - pri->pvts[principle]->call = pri->pvts[x]->call; -+ pri->pvts[principle]->dsp = pri->pvts[x]->dsp; -+ pri->pvts[principle]->alreadyhungup = pri->pvts[x]->alreadyhungup; -+ pri->pvts[principle]->digital = pri->pvts[x]->digital; -+ pri->pvts[principle]->faxhandled = pri->pvts[x]->faxhandled; -+ -+ if ((pri->nodetype == BRI_CPE_PTMP) || (pri->nodetype == BRI_CPE)) { -+ /* this might also apply for other pri types! */ -+ pri->pvts[principle]->law = pri->pvts[x]->law; -+ if (ioctl(pri->pvts[principle]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &pri->pvts[principle]->law) == -1) -+ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", pri->pvts[principle]->channel, pri->pvts[principle]->law); -+ res = zt_setlaw(pri->pvts[principle]->subs[SUB_REAL].zfd, pri->pvts[principle]->law); -+ if (res < 0) -+ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[principle]->channel); -+ if (!pri->pvts[principle]->digital) { -+ res = set_actual_gain(pri->pvts[principle]->subs[SUB_REAL].zfd, 0, pri->pvts[principle]->rxgain, pri->pvts[principle]->txgain, pri->pvts[principle]->law); -+ } else { -+ res = set_actual_gain(pri->pvts[principle]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[principle]->law); -+ } -+ if (res < 0) -+ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[principle]->channel); -+ zt_confmute(pri->pvts[x], 0); -+ update_conf(pri->pvts[x]); -+ reset_conf(pri->pvts[x]); -+ restore_gains(pri->pvts[x]); -+ zt_disable_ec(pri->pvts[x]); -+ zt_setlinear(pri->pvts[x]->subs[SUB_REAL].zfd, 0); -+ } -+ -+ if (pri->pvts[principle]->owner) { -+ snprintf(tmpname, sizeof(tmpname), "Zap/%d-1", pri->pvts[principle]->channel); -+ ast_change_name(pri->pvts[principle]->owner, tmpname); -+ } -+ - /* Free up the old channel, now not in use */ - pri->pvts[x]->subs[SUB_REAL].owner = NULL; - pri->pvts[x]->owner = NULL; - pri->pvts[x]->call = NULL; -+ pri->pvts[x]->dsp = NULL; - } - return principle; - } -@@ -8183,7 +8453,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; - } + /*! \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); -@@ -8242,86 +8514,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); +- ast_device_state_changed_literal(name); ++ ast_device_state_changed_literal(name, NULL, NULL); } --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); + 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); } - static int pri_check_restart(struct zt_pri *pri) +-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) { -+ if ((pri->nodetype != PRI_NETWORK) && (pri->nodetype != PRI_CPE)) { -+ return 0; -+ } - do { - pri->resetpos++; - } while ((pri->resetpos < pri->numchans) && -@@ -8405,13 +8612,30 @@ static void apply_plan_to_number(char *b - } + 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; } --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; -+ } ++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 */ } - static void *pri_dchannel(void *vpri) -@@ -8591,15 +8815,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; inumchans; 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) -@@ -8611,8 +8864,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); -@@ -8625,32 +8877,86 @@ static void *pri_dchannel(void *vpri) +-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; - switch (e->e) { - case PRI_EVENT_DCHAN_UP: -- if (option_verbose > 1) -- ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span); -- pri->dchanavail[which] |= DCHAN_UP; -- if (!pri->pri) pri_find_dchan(pri); -+ if (pri->nodetype == BRI_NETWORK_PTMP) { -+ if (option_verbose > 3) -+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up for TEI %d\n", pri_order(which), pri->span, e->gen.tei); -+ pri->dchanavail[which] |= DCHAN_UP; -+ if (!pri->pri) pri_find_dchan(pri); -+ -+ /* Note presense of D-channel */ -+ time(&pri->lastreset); -+ -+ pri->resetting = 0; -+ /* Take the channels from inalarm condition */ -+ for (i=0; inumchans; i++) -+ if (pri->pvts[i]) { -+ pri->pvts[i]->inalarm = 0; -+ } -+ } else { -+ if (pri->nodetype == BRI_CPE_PTMP) { -+ if (option_verbose > 3) -+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span); -+ } else { -+ if (option_verbose > 1) -+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span); -+ } -+ pri->dchanavail[which] |= DCHAN_UP; -+ if (!pri->pri) pri_find_dchan(pri); - -- /* Note presense of D-channel */ -- time(&pri->lastreset); -+ /* Note presense of D-channel */ -+ time(&pri->lastreset); - -- /* Restart in 5 seconds */ -- if (pri->resetinterval > -1) { -+ /* Restart in 5 seconds */ -+ if (pri->resetinterval > -1) { - pri->lastreset -= pri->resetinterval; - pri->lastreset += 5; -- } -- pri->resetting = 0; -- /* Take the channels from inalarm condition */ -- for (i = 0; i < pri->numchans; i++) -+ } -+ pri->resetting = 0; -+ /* Take the channels from inalarm condition */ -+ for (i = 0; i < pri->numchans; i++) - if (pri->pvts[i]) { - pri->pvts[i]->inalarm = 0; - } -+ } - break; - case PRI_EVENT_DCHAN_DOWN: -- if (option_verbose > 1) -- ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span); -- pri->dchanavail[which] &= ~DCHAN_UP; -- pri_find_dchan(pri); -- if (!pri_is_up(pri)) { -+ if (pri->nodetype == BRI_NETWORK_PTMP) { -+ if (option_verbose > 3) -+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down for TEI %d\n", pri_order(which), pri->span, e->gen.tei); -+ // PTMP BRIs have N dchans, handled by libpri -+ if (e->gen.tei == 0) break; -+ /* Hangup active channels */ -+ for (i=0; inumchans; i++) { -+ struct zt_pvt *p = pri->pvts[i]; -+ if (p) { -+ // ast_log(LOG_NOTICE, "chan %d tei %d\n",i,p->tei); -+ if (p->tei == e->gen.tei) { -+ if (p->call) { -+ if (p->pri && p->pri->pri) { -+ pri_hangup(p->pri->pri, p->call, -1, -1); -+ pri_destroycall(p->pri->pri, p->call); -+ p->call = NULL; -+ } else -+ ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n"); -+ } -+ if (p->owner) -+ p->owner->_softhangup |= AST_SOFTHANGUP_DEV; -+ p->inalarm = 1; -+ p->tei = -1; -+ } -+ } -+ } -+ } else { -+ if (pri->nodetype == BRI_CPE_PTMP) { -+ if (option_verbose > 3) -+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span); -+ } else { -+ if (option_verbose > 1) -+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span); -+ } -+ pri->dchanavail[which] &= ~DCHAN_UP; -+ pri_find_dchan(pri); -+ if (!pri_is_up(pri)) { - pri->resetting = 0; - /* Hangup active channels and put them in alarm mode */ - for (i = 0; i < pri->numchans; i++) { -@@ -8660,12 +8966,13 @@ static void *pri_dchannel(void *vpri) - /* 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) -@@ -8674,6 +8981,7 @@ static void *pri_dchannel(void *vpri) - p->inalarm = 1; - } - } -+ } - } - break; - case PRI_EVENT_RESTART: -@@ -8708,8 +9016,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); -@@ -8743,7 +9051,6 @@ static void *pri_dchannel(void *vpri) - } - } - break; -- - case PRI_EVENT_INFO_RECEIVED: - chanpos = pri_find_principle(pri, e->ring.channel); - if (chanpos < 0) { -@@ -8752,9 +9059,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; -@@ -8766,6 +9075,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); - } -@@ -8773,36 +9090,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)); -@@ -8816,13 +9156,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; - } +@@ -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); } -+ /* 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) { -@@ -8847,34 +9188,82 @@ static void *pri_dchannel(void *vpri) + } + } 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); } - 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)) { -@@ -8893,19 +9282,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; - -@@ -8917,10 +9323,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 */ - } + } + } 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 + #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 { + }; - ast_mutex_unlock(&pri->pvts[chanpos]->lock); -@@ -8928,6 +9341,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); -@@ -8951,8 +9374,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, ""), -+ 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, ""), - 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", -@@ -8960,15 +9383,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]; -@@ -8995,26 +9422,43 @@ static void *pri_dchannel(void *vpri) - ast_mutex_lock(&pri->lock); ++extern int ast_autoanswer_login(struct ast_channel *chan, void *data); ++extern int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data); - 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 { + /*! \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 ++ * + * 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" ; - ast_mutex_lock(&pri->lock); ++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; - 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'; - } -@@ -9023,9 +9467,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: -@@ -9041,7 +9485,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 -@@ -9073,9 +9517,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 -@@ -9122,6 +9573,12 @@ static void *pri_dchannel(void *vpri) - 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, }; - -@@ -9169,6 +9626,295 @@ 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; -+ } +@@ -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, ""), +- S_OR(pu->chan->cid.cid_name, "") ++ S_OR(pu->chan->cid.cid_name, ""), ++ 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, ""), +- S_OR(chan->cid.cid_name, "") ++ S_OR(chan->cid.cid_name, ""), ++ 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, ""), +- S_OR(pu->chan->cid.cid_name, "") ++ S_OR(pu->chan->cid.cid_name, ""), ++ 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 */ +- 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; + -+ 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; -+ } ++ 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); + -+ 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"); -+ } ++ return 0; ++ } else { ++ ast_log(LOG_WARNING, "Out of memory\n"); ++ return -1; ++ } ++ return 0; ++} + -+ if (zpc) { -+ zpc->next = zpcl->next; -+ free(zpcl); -+ zpcl = zpc->next; -+ } else { -+ // remove head -+ pri->suspended_calls = zpcl->next; -+ free(zpcl); -+ zpcl = pri->suspended_calls; -+ zpc = NULL; -+ } -+ unparked = 1; -+ snprintf(temp, sizeof(temp), "Unparked %s", extenstr); -+ pri_resume_acknowledge(pri->pri, e->resume_req.call, chanpos + 1, temp); -+ break; -+ } -+ zpc = zpcl; -+ if (zpcl) zpcl = zpcl->next; -+ } -+ if (!unparked) -+ pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!"); -+ } else { -+ pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!"); -+ } -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ } -+ break; -+ case PRI_EVENT_HOLD_REQ: -+ if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) { -+ pri_hold_reject(pri->pri, e->hold_req.call); -+ break; -+ } -+ chanpos = pri_find_principle(pri, e->hold_req.channel); -+ if (chanpos < 0) { -+ ast_log(LOG_WARNING, "Hold requested on unconfigured channel %d span %d\n", chanpos, pri->span); -+ chanpos = -1; -+ } -+ if (chanpos > -1) { -+ // ast_log(LOG_NOTICE, "Hold request for channel number %d span %d\n", chanpos, pri->span); -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ if (pri->pvts[chanpos]->owner) { -+ struct zt_pvt *p = pri->pvts[chanpos]; -+ struct zt_holded_call *zhc; -+ int holdacked=0; -+ -+// ast_log(LOG_NOTICE,"HOLD request from channel %s tei %d\n",p->owner->name, e->hold_req.tei); -+ if (ast_bridged_channel(p->owner)) { -+ zhc = malloc(sizeof(struct zt_holded_call)); -+ if (!zhc) { -+ ast_log(LOG_ERROR, "unable to malloc zt_holded_call\n"); -+ break; -+ } -+ memset(zhc, 0, sizeof(zhc)); -+ strncpy(zhc->msn, pri->pvts[chanpos]->cid_num, sizeof(zhc->msn)); -+ strncpy(zhc->uniqueid, ast_bridged_channel(p->owner)->uniqueid, sizeof(zhc->uniqueid)); -+ zhc->tei = e->hold_req.tei; -+ zhc->cref = e->hold_req.cref; -+ zhc->call = e->hold_req.call; -+ zhc->channel = p->owner; -+ zhc->alreadyhungup = 0; -+ zhc->bridge = ast_bridged_channel(p->owner); -+ zhc->next = pri->holded_calls; -+ pri->holded_calls = zhc; -+ -+ /* put channel on hold */ -+ ast_masq_hold_call(ast_bridged_channel(p->owner), p->owner); -+ -+ pri_hold_acknowledge(pri->pri, e->hold_req.call); -+ holdacked = 1; -+ p->call = NULL; // free the bchannel withouth destroying the call -+ p->tei = -1; -+ } else { -+ // cant hold a non-bridge,...yet -+ -+ // make a fake channel -+ -+ // masquerade -+ -+ // put on hold -+ pri_hold_reject(pri->pri, e->hold_req.call); -+ } -+ } else { -+ pri_hold_reject(pri->pri, e->hold_req.call); -+ } -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ } else { -+ pri_hold_reject(pri->pri, e->hold_req.call); -+ } -+ break; -+ case PRI_EVENT_RETRIEVE_REQ: -+ if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) { -+ pri_retrieve_reject(pri->pri, e->retrieve_req.call); -+ break; -+ } -+ chanpos = pri_find_empty_chan(pri, 1); -+ if (chanpos < 0) { -+ pri_retrieve_reject(pri->pri, e->retrieve_req.call); -+ ast_log(LOG_WARNING, "Retrieve requested on odd channel number %d span %d\n", chanpos, pri->span); -+ chanpos = -1; -+ break; -+ } else if (!pri->pvts[chanpos]) { -+ ast_log(LOG_WARNING, "Retrieve requested on unconfigured channel number %d span %d\n", chanpos, pri->span); -+ pri_retrieve_reject(pri->pri, e->retrieve_req.call); -+ chanpos = -1; -+ break; -+ } -+ if (chanpos > -1) { -+ struct zt_holded_call *onhold = NULL; -+ int retrieved = 0; -+ int res = -1; -+ struct app_tmp *tmp; -+ pthread_attr_t attr; -+ int law; -+ -+ onhold = pri_get_callonhold(pri, e->retrieve_req.cref, e->retrieve_req.tei); -+ -+ if (!onhold) { -+ pri_retrieve_reject(pri->pri, e->retrieve_req.call); -+ break; -+ } -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ // found a parked call -+ law = 1; -+ if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1) -+ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law); -+ // uhh ohh...what shall we do without the bearer cap??? -+ law = ZT_LAW_ALAW; -+ res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law); -+ if (res < 0) -+ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos])); -+ res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law); -+ if (res < 0) -+ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos])); -+ /* Start PBX */ -+ c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 0, SUB_REAL, law, PRI_TRANS_CAP_SPEECH); -+ if (c) { -+ pri->pvts[chanpos]->owner = c; -+ pri->pvts[chanpos]->outgoing = 1; /* for not sending proceedings... */ -+ pri->pvts[chanpos]->call = e->retrieve_req.call; -+ pri->pvts[chanpos]->tei = e->retrieve_req.tei; -+ zt_enable_ec(pri->pvts[chanpos]); -+ zt_train_ec(pri->pvts[chanpos]); -+ } else { -+ ast_log(LOG_ERROR, "unable to start pbx\n"); -+ } ++static void autoanswer_reregister_extensions(void) ++{ ++ struct aauser *cur; ++ struct ast_context *con; ++ char exten[AST_MAX_EXTENSION]; ++ char args[AST_MAX_EXTENSION]; + -+ retrieved = 1; -+ // ast_log(LOG_NOTICE, "sending RETRIEVE ACK on channel %d, span %d for tei %d cref %d\n",chanpos,pri->span, e->retrieve_req.tei, e->retrieve_req.cref); -+ pri_retrieve_acknowledge(pri->pri, e->retrieve_req.call, chanpos + 1); -+ -+ // the magic begins here: .... -+ tmp = malloc(sizeof(struct app_tmp)); -+ if (tmp) { -+ memset(tmp, 0, sizeof(struct app_tmp)); -+ strncpy(tmp->app, "holdedcall", sizeof(tmp->app) - 1); -+ strncpy(tmp->data, onhold->uniqueid, sizeof(tmp->data) - 1); -+ tmp->chan = c; -+ } -+ pri_destroy_callonhold(pri, onhold); -+ onhold = NULL; -+ -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ pthread_attr_init(&attr); -+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -+ if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) { -+ ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", c->name, strerror(errno)); -+ free(tmp); -+ ast_hangup(c); -+ retrieved = 0; -+ } ++ ast_mutex_lock(&autoanswer_lock); + -+ if (!retrieved) { -+ pri_retrieve_reject(pri->pri, e->retrieve_req.call); -+ } -+ } -+ break; -+ case PRI_EVENT_DISPLAY_RECEIVED: -+ ast_log(LOG_NOTICE, "DISPLAY IE: [ %s ] received\n",e->display.text); -+ chanpos = pri_find_principle(pri, e->display.channel); -+ if (chanpos < 0) { -+ ast_log(LOG_WARNING, "odd channel number %d span %d\n", chanpos, pri->span); -+ chanpos = -1; -+ } -+ if (chanpos > -1) { -+ if (pri->pvts[chanpos]->owner) { -+ // ast_sendtext(pri->pvt[chanpos]->owner, e->display.text); -+ } -+ } -+ break; - case PRI_EVENT_ANSWER: - chanpos = pri_find_principle(pri, e->answer.channel); - if (chanpos < 0) { -@@ -9181,6 +9927,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. -@@ -9210,11 +9957,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 -@@ -9271,20 +10023,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"); ++ 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;xchan->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); + } - - #ifdef SUPPORT_USERUSER - if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) { -@@ -9297,8 +10058,20 @@ 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); -+ struct zt_holded_call *onhold = NULL; -+ /* check calls on hold */ -+ onhold = pri_get_callonhold(pri, e->hangup.cref, e->hangup.tei); -+ -+ if (onhold) { -+ // ast_log(LOG_NOTICE, "hangup, found cref %d, tei %d\n",e->hangup.cref, e->hangup.tei); -+ pri_hangup(pri->pri, onhold->call, e->hangup.cause, -1); -+ pri_destroy_callonhold(pri, onhold); -+ onhold = NULL; -+ } else { -+ ast_log(LOG_NOTICE, "Hangup, did not find cref %d, tei %d\n",e->hangup.cref, e->hangup.tei); -+ ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", -+ PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ } - } - } - break; -@@ -9308,15 +10081,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); ++ /* 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 { -+ 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); ++ /* 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 */ + } -+ } 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; -@@ -9343,16 +10124,86 @@ 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) { -+ // check for bri transfers, not everybody uses ECT... -+ if (pri->pvts[chanpos]->owner) { -+ // find on hold call -+ struct zt_holded_call *onhold = NULL; -+ struct ast_channel *transferee = NULL; -+ int transfer_ok = 0; -+ -+ onhold = pri_get_callonhold(pri, -1, e->hangup.tei); -+ -+ if (onhold) { -+ if (pri->pvts[chanpos]->pritransfer == 2) { -+ if (((pri->pvts[chanpos]->owner->_state != AST_STATE_RING) && (pri->pvts[chanpos]->owner->_state != AST_STATE_RESERVED)) || ((!ast_strlen_zero(pri->pvts[chanpos]->exten)) && (strncasecmp(pri->pvts[chanpos]->exten, "s", sizeof(pri->pvts[chanpos]->exten))))) { -+ transferee = ast_get_holded_call(onhold->uniqueid); -+ -+ if (transferee) { -+ if (pri->pvts[chanpos]->owner->_state == AST_STATE_RINGING) { -+ ast_indicate(transferee, AST_CONTROL_RINGING); -+ } -+ -+ pri->pvts[chanpos]->owner->_softhangup &= ~AST_SOFTHANGUP_DEV; -+ -+ ast_mutex_unlock(&transferee->lock); -+ if (ast_channel_masquerade(pri->pvts[chanpos]->owner, transferee)) { -+ ast_log(LOG_WARNING, "unable to masquerade\n"); -+ } else { -+ /* beware of zombies!!! */ -+ ast_set_flag(transferee, AST_FLAG_ZOMBIE); -+ pri->pvts[chanpos]->owner = NULL; -+ pri->pvts[chanpos]->tei = -1; -+ transfer_ok = 1; -+ } -+ } -+ } -+ } else if (pri->pvts[chanpos]->pritransfer == 0) { -+ ast_log(LOG_NOTICE, "killing channel %s \n", onhold->uniqueid); -+ ast_retrieve_call_to_death(onhold->uniqueid); -+ transfer_ok = 1; -+ } else if (pri->pvts[chanpos]->pritransfer == 1) { -+ /* we use ECT transfers, so just ignore this */ -+ transfer_ok = 0; -+ } -+ -+ if (transfer_ok) { -+ onhold->alreadyhungup = 1; -+ pri_hangup(pri->pri, onhold->call, e->hangup.cause, -1); -+ onhold = NULL; -+ } -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ break; -+ } else { -+ 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 -@@ -9366,9 +10217,39 @@ 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 { -+ // check holded_calls!!! -+ struct zt_holded_call *onhold = NULL; -+ -+ onhold = pri_get_callonhold(pri, e->hangup.cref, e->hangup.tei); -+ -+ if (onhold) { -+ pri_hangup(pri->pri, e->hangup.call, e->hangup.cause, -1); -+ ast_retrieve_call_to_death(onhold->uniqueid); -+ pri_destroy_callonhold(pri, onhold); -+ onhold = NULL; -+ } else { -+ ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ } -+ } - } - } -+ if ((chanpos > -1) && (pri->pvts[chanpos]->owner) && (pri->pvts[chanpos]->priindication_oob == 2) && (e->hangup.inband_progress) && (pri->pvts[chanpos]->outgoing)) { -+ ast_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"); ++ } ++ } ++ if (x >= AST_MAX_FDS) { ++std: for (x=0;xchan->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]; + } -+ 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); -@@ -9380,6 +10261,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) -@@ -9396,7 +10278,9 @@ static void *pri_dchannel(void *vpri) - #endif ++ /* 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; ++} ++ - ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ } - } -+ } - } - break; - case PRI_EVENT_CONFIG_ERR: -@@ -9486,10 +10370,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; -@@ -9497,6 +10393,77 @@ static void *pri_dchannel(void *vpri) - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - } - break; -+ case PRI_EVENT_FACILITY: -+ if (e->facility.operation == 0x06) { -+ struct ast_channel *chan = NULL; -+ struct zt_holded_call *onhold = NULL; -+ if (option_verbose > 2) { -+ ast_verbose(VERBOSE_PREFIX_3 "ECT requested by TEI %d for cref %d\n", e->facility.tei, e->facility.cref); -+ } -+ /* search for cref/tei in held calls */ -+ onhold = pri_get_callonhold(pri, e->facility.cref, e->facility.tei); -+ if (onhold) { -+ chan = ast_get_holded_call(onhold->uniqueid); -+ onhold->alreadyhungup = 1; -+ onhold = NULL; -+ if (!chan) { -+ /* hang up */ -+ pri_hangup(pri->pri, e->facility.call, 16, -1); -+ break; -+ } -+ } else { -+ /* unknown cref/tei */ -+ ast_log(LOG_WARNING, "did not find call on hold for cref %d tei %d\n", e->facility.tei, e->facility.cref); -+ /* hang up */ -+ pri_hangup(pri->pri, e->facility.call, 16, -1); -+ break; -+ } -+ -+ /* find an active call for the same tei */ -+ chanpos = pri_find_tei(pri, e->facility.call, e->facility.tei); -+ if (chanpos < 0) { -+ /* did not find active call, hangup call on hold */ -+ if (chan) { -+ ast_hangup(chan); -+ chan = NULL; -+ } -+ } else { -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ /* transfer */ -+ if (pri->pvts[chanpos]->owner) { -+ if (option_verbose > 3) { -+ ast_verbose(VERBOSE_PREFIX_3 "ECT: found %s on channel %d for tei %d\n", pri->pvts[chanpos]->owner->name ,chanpos, e->facility.tei); -+ } -+ /* pass callprogress if the channel is not up yet */ -+ if (pri->pvts[chanpos]->owner->_state == AST_STATE_RINGING) { -+ ast_indicate(chan, AST_CONTROL_RINGING); -+ } -+ /* unlock the channel we removed from hold */ -+ ast_mutex_unlock(&chan->lock); -+ if (ast_channel_masquerade(pri->pvts[chanpos]->owner, chan)) { -+ ast_log(LOG_WARNING, "unable to masquerade\n"); -+ } else { -+ /* beware of zombies !!! */ -+ ast_set_flag(chan, AST_FLAG_ZOMBIE); -+ // chan->zombie = 1; -+ } -+ } -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ } -+ /* disconnect */ -+ pri_hangup(pri->pri, e->facility.call, 16, -1); -+ } else if (e->facility.operation == 0x0D) { -+ ast_log(LOG_NOTICE, "call deflection to %s requested.\n", e->facility.forwardnum); -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ /* transfer */ -+ if (pri->pvts[chanpos]->owner) { -+ snprintf(pri->pvts[chanpos]->owner->call_forward, sizeof(pri->pvts[chanpos]->owner->call_forward), "Local/%s@%s", e->facility.forwardnum, pri->pvts[chanpos]->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); - } -@@ -9558,7 +10525,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; -@@ -9626,39 +10593,77 @@ static char *complete_span_5(const char + int ast_pickup_call(struct ast_channel *chan) + { +@@ -2460,6 +2918,7 @@ static int load_config(void) - static int handle_pri_set_debug_file(int fd, int argc, char **argv) + static int reload(void) { -- int myfd; -+ int myfd, x, d; -+ int span; -+ -+ if (argc < 6) -+ return RESULT_SHOWUSAGE; ++ autoanswer_reregister_extensions(); + return load_config(); + } - if (!strncasecmp(argv[1], "set", 3)) { -- if (argc < 5) -+ if (argc < 7) - return RESULT_SHOWUSAGE; +@@ -2483,6 +2942,12 @@ static int load_module(void) + "Park a channel", mandescr_park); + } -- if (ast_strlen_zero(argv[4])) -+ if (!argv[4] || ast_strlen_zero(argv[4])) - return RESULT_SHOWUSAGE; ++ 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); -+ 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; -+ } -+ + 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); + - 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; - } -- -- ast_mutex_lock(&pridebugfdlock); -- -- if (pridebugfd >= 0) -- close(pridebugfd); -- -- pridebugfd = myfd; -- ast_copy_string(pridebugfilename,argv[4],sizeof(pridebugfilename)); -- -- ast_mutex_unlock(&pridebugfdlock); -- -- ast_cli(fd, "PRI debug output will be sent to '%s'\n", argv[4]); -+ for (x=0; x < NUM_SPANS; x++) { -+ ast_mutex_lock(&pris[x].lock); -+ -+ if (pris[x].span == span) { -+ if (pris[x].debugfd >= 0) -+ close(pris[x].debugfd); -+ pris[x].debugfd = myfd; -+ for (d=0; d < NUM_DCHANS; d++) { -+ if (pris[x].dchans[d]) -+ pri_set_debug_fd(pris[x].dchans[d], myfd); -+ } -+ } -+ ast_mutex_unlock(&pris[x].lock); -+ } -+ -+ ast_cli(fd, "PRI debug output for span %d will be sent to '%s'\n", span, argv[4]); - } else { -+ if (!argv[5] || ast_strlen_zero(argv[5])) -+ return RESULT_SHOWUSAGE; - /* Assume it is unset */ -- ast_mutex_lock(&pridebugfdlock); -- close(pridebugfd); -- pridebugfd = -1; -- ast_cli(fd, "PRI debug output to file disabled\n"); -- ast_mutex_unlock(&pridebugfdlock); -+ span = atoi(argv[5]); -+ if ((span < 1) && (span > NUM_SPANS)) { -+ return RESULT_SUCCESS; -+ } -+ -+ for (x=0; x < NUM_SPANS; x++) { -+ ast_mutex_lock(&pris[x].lock); -+ -+ if (pris[x].span == span) { -+ if (pris[x].debugfd >= 0) -+ close(pris[x].debugfd); -+ pris[x].debugfd = -1; -+ for (d=0; d < NUM_DCHANS; d++) { -+ if (pris[x].dchans[d]) -+ pri_set_debug_fd(pris[x].dchans[d], -1); -+ } -+ } -+ ast_mutex_unlock(&pris[x].lock); -+ } -+ -+ ast_cli(fd, "PRI debug output to file for span %d disabled\n", span); - } + /*! \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" - return RESULT_SUCCESS; -@@ -9692,6 +10697,7 @@ static int handle_pri_debug(int fd, int + #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; ++}; + - static int handle_pri_no_debug(int fd, int argc, char *argv[]) - { - int span; -@@ -9841,10 +10847,6 @@ static int handle_pri_show_debug(int fd, - } + /* auto answer user */ + struct aauser { + struct ast_channel *chan; +@@ -187,10 +205,16 @@ static pthread_t autoanswer_thread; - } -- 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"); -@@ -9871,6 +10873,18 @@ static const char pri_show_spans_help[] - "Usage: pri show spans\n" - " Displays PRI Information\n"; + static struct parkeduser *parkinglot; -+static char bri_debug_help[] = -+ "Usage: bri debug span \n" -+ " Enables debugging on a given BRI span\n"; -+ -+static char bri_no_debug_help[] = -+ "Usage: bri no debug span \n" -+ " Disables debugging on a given BRI span\n"; ++static struct holdeduser *holdlist; + -+static char bri_really_debug_help[] = -+ "Usage: bri intensive debug span \n" -+ " Enables debugging down to the Q.921 level\n"; + AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */ + ++AST_MUTEX_DEFINE_STATIC(holding_lock); + - static struct ast_cli_entry zap_pri_cli[] = { - { { "pri", "debug", "span", NULL }, - handle_pri_debug, "Enables PRI debugging on a span", -@@ -9895,6 +10909,15 @@ static struct ast_cli_entry zap_pri_cli[ - { { "pri", "show", "debug", NULL }, - handle_pri_show_debug, "Displays current PRI debug settings" }, + 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; + } -+ { { "bri", "debug", "span", NULL }, handle_pri_debug, -+ "Enables BRI debugging on a span", bri_debug_help, complete_span_4 }, ++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; + -+ { { "bri", "no", "debug", "span", NULL }, handle_pri_no_debug, -+ "Disables BRI debugging on a span", bri_no_debug_help, complete_span_5 }, ++ 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); + -+ { { "bri", "intense", "debug", "span", NULL }, handle_pri_really_debug, -+ "Enables REALLY INTENSE BRI debugging", bri_really_debug_help, complete_span_5 }, ++ 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); + - { { "pri", "set", "debug", "file", NULL }, - handle_pri_set_debug_file, "Sends PRI debug output to the specified file" }, - -@@ -9902,8 +10925,76 @@ static struct ast_cli_entry zap_pri_cli[ - handle_pri_set_debug_file, "Ends PRI debug output to file" }, - }; - -+static char *zapCD_tdesc = "Call Deflection"; -+static char *zapCD_app = "zapCD"; -+static char *zapCD_synopsis = "Call Deflection"; ++ } else { ++ ast_log(LOG_WARNING, "Out of memory\n"); ++ return -1; ++ } ++ return 0; ++} + -+static int app_zapCD(struct ast_channel *chan, void *data) ++int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer) +{ -+ struct zt_pvt *p = chan->tech_pvt; ++ 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; ++} + -+ if((!p->pri) || (!p->pri->pri)) { -+ return -1; -+ } ++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; + -+ 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); -+} ++ peer = ast_get_holded_call(uniqueid); + -+static char *zapInband_tdesc = "Inband Call Progress (pre-answer)"; -+static char *zapInband_app = "zapInband"; -+static char *zapInband_synopsis = "Inband Call Progress"; ++ /* JK02: it helps to answer the channel if not already up */ ++ if (chan->_state != AST_STATE_UP) { ++ ast_answer(chan); ++ } + -+static int app_zapInband(struct ast_channel *chan, void *data) ++ 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) +{ -+ struct zt_pvt *p = chan->tech_pvt; ++ int res=-1; ++ struct ast_channel *peer=NULL; + -+ return pri_acknowledge(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1); ++ 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; +} + - #endif /* HAVE_PRI */ - -+static int app_zapEC(struct ast_channel *chan, void *data) ++struct ast_channel *ast_get_holded_call(char *uniqueid) +{ -+ int res=-1; -+ struct zt_pvt *p = NULL; ++ int res=-1; ++ struct ast_channel *peer=NULL; ++ struct holdeduser *pu, *pl=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); -+ } ++ 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, "Unknown argument %s to zapEC\n", (char *)data); ++ 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;xchan->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;xchan->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(); + } -+ } else { -+ ast_log(LOG_WARNING, "zapNoEC only works on ZAP channels, check your extensions.conf!\n"); -+ res = 0; -+ } -+ -+ return res; ++ return NULL; /* Never reached */ +} + -+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 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 zap_destroy_channel(int fd, int argc, char **argv) + static int handle_showfeatures(int fd, int argc, char *argv[]) { - int channel; -@@ -10484,8 +11575,11 @@ static int __unload_module(void) + 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); } - 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" ); -@@ -10987,6 +12081,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); -@@ -11099,9 +12209,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")) { -@@ -11114,6 +12236,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; -@@ -11130,6 +12256,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")) { -@@ -11431,6 +12559,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); -@@ -11478,7 +12607,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)); -@@ -11512,6 +12644,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 ---- a/main/channel.c -+++ b/main/channel.c -@@ -4209,6 +4209,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) || ++ 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 + #include #endif +#ifdef HAVE_GSMAT +#include @@ -7779,7 +6951,7 @@ Add or convert channel operations so they can use the unique ID. #include "asterisk/lock.h" #include "asterisk/channel.h" -@@ -187,6 +190,7 @@ static const char config[] = "zapata.con +@@ -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 @@ -7787,7 +6959,7 @@ Add or convert channel operations so they can use the unique ID. #define SIG_SF ZT_SIG_SF #define SIG_SFWINK (0x0100000 | ZT_SIG_SF) #define SIG_SF_FEATD (0x0200000 | ZT_SIG_SF) -@@ -236,6 +240,8 @@ static int matchdigittimeout = 3000; +@@ -234,6 +238,8 @@ static int matchdigittimeout = 3000; /*! \brief Protect the interface list (of zt_pvt's) */ AST_MUTEX_DEFINE_STATIC(iflock); @@ -7796,16 +6968,15 @@ Add or convert channel operations so they can use the unique ID. static int ifcount = 0; -@@ -251,7 +257,7 @@ static int restart_monitor(void); - - static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms); +@@ -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_sendtext(struct ast_channel *c, const char *dest, const char *text, int ispdu); + 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 */ -@@ -366,6 +372,19 @@ struct zt_pri { + static inline int zt_get_event(int fd) +@@ -364,6 +371,19 @@ struct zt_pri { int debugfd; }; @@ -7825,7 +6996,7 @@ Add or convert channel operations so they can use the unique ID. static struct zt_pri pris[NUM_SPANS]; -@@ -394,6 +413,7 @@ struct zt_pri; +@@ -392,6 +412,7 @@ struct zt_pri; #define POLARITY_REV 1 @@ -7833,7 +7004,7 @@ Add or convert channel operations so they can use the unique ID. static struct zt_distRings drings; struct distRingData { -@@ -605,6 +625,9 @@ static struct zt_pvt { +@@ -604,6 +625,9 @@ static struct zt_pvt { int prioffset; int logicalspan; #endif @@ -7843,16 +7014,26 @@ Add or convert channel operations so they can use the unique ID. int polarity; int dsp_features; char begindigit; -@@ -711,7 +734,7 @@ static struct zt_chan_conf zt_chan_conf_ +@@ -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_sendtext(struct ast_channel *c, const char *dest, const char *text, int ispdu); ++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); -@@ -1370,6 +1393,8 @@ static char *zap_sig2str(int sig) +@@ -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"; @@ -7861,7 +7042,7 @@ Add or convert channel operations so they can use the unique ID. case 0: return "Pseudo"; default: -@@ -1791,7 +1816,7 @@ static inline int zt_confmute(struct zt_ +@@ -1683,7 +1712,7 @@ static inline int zt_confmute(struct zt_ { int x, y, res; x = muted; @@ -7870,7 +7051,7 @@ Add or convert channel operations so they can use the unique ID. y = 1; res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &y); if (res) -@@ -2206,6 +2231,25 @@ static int zt_call(struct ast_channel *a +@@ -2098,6 +2127,25 @@ static int zt_call(struct ast_channel *a p->dialdest[0] = '\0'; disable_dtmf_detect(p); break; @@ -7896,7 +7077,7 @@ Add or convert channel operations so they can use the unique ID. default: ast_log(LOG_DEBUG, "not yet implemented\n"); ast_mutex_unlock(&p->lock); -@@ -2845,7 +2889,13 @@ static int zt_hangup(struct ast_channel +@@ -2737,7 +2785,13 @@ static int zt_hangup(struct ast_channel } } #endif @@ -7911,7 +7092,7 @@ Add or convert channel operations so they can use the unique ID. 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); -@@ -3022,6 +3072,13 @@ static int zt_answer(struct ast_channel +@@ -2914,6 +2968,13 @@ static int zt_answer(struct ast_channel zt_train_ec(p); break; #endif @@ -7925,7 +7106,7 @@ Add or convert channel operations so they can use the unique ID. case 0: ast_mutex_unlock(&p->lock); return 0; -@@ -7384,6 +7441,10 @@ static int pri_create_spanmap(int span, +@@ -7302,6 +7363,10 @@ static int pri_create_spanmap(int span, #endif @@ -7933,15 +7114,15 @@ Add or convert channel operations so they can use the unique ID. +static void *gsm_dchannel(void *vgsm); +#endif + - static struct zt_pvt *mkintf(int channel, struct zt_chan_conf conf, struct zt_pri *pri, int reloading) + 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) */ -@@ -7612,6 +7673,37 @@ static struct zt_pvt *mkintf(int channel +@@ -7530,6 +7595,37 @@ static struct zt_pvt *mkintf(int channel tmp->prioffset = 0; } #endif +#ifdef HAVE_GSMAT -+ if (conf.chan.sig == SIG_GSM) { ++ 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); @@ -7972,9 +7153,9 @@ Add or convert channel operations so they can use the unique ID. + } +#endif } else { - conf.chan.sig = tmp->sig; - conf.chan.radio = tmp->radio; -@@ -7895,6 +7987,12 @@ static inline int available(struct zt_pv + conf->chan.sig = tmp->sig; + conf->chan.radio = tmp->radio; +@@ -7819,6 +7915,12 @@ static inline int available(struct zt_pv return 1; } #endif @@ -7987,7 +7168,7 @@ Add or convert channel operations so they can use the unique ID. if (!(p->radio || (p->oprmode < 0))) { if (!p->sig || (p->sig == SIG_FXSLS)) -@@ -8249,6 +8347,235 @@ next: +@@ -8176,6 +8278,235 @@ next: return tmp; } @@ -8125,7 +7306,7 @@ Add or convert channel operations so they can use the unique ID. + "Length: %d\r\n" + "Text: %s\r\n" + "PDU: %s\r\n", -+ gsm->span, ++ gsm->span, + e->sm_received.sender, + e->sm_received.smsc, + e->sm_received.len, @@ -8153,7 +7334,7 @@ Add or convert channel operations so they can use the unique ID. + } + gsm_set_debug(gsm->modul, GSM_DEBUG_NONE); + for (;;) { -+ ++ + /* Run the D-Channel */ + FD_ZERO(&rfds); + FD_ZERO(&efds); @@ -8184,7 +7365,7 @@ Add or convert channel operations so they can use the unique ID. + } else if (errno == ELAST) { + res = ioctl(gsm->fd, ZT_GETEVENT, &x); + printf("Got Zaptel event: %d\n", x); -+ } else if (errno != EINTR) ++ } else if (errno != EINTR) + fprintf(stderr, "Error (%d) on select: %s\n", ELAST, strerror(errno)); + + if (!e) { @@ -8223,7 +7404,7 @@ Add or convert channel operations so they can use the unique ID. #ifdef HAVE_PRI static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv) { -@@ -8524,6 +8851,18 @@ static void zt_pri_error(char *s, int sp +@@ -8450,6 +8781,18 @@ static void zt_pri_error(char *s, int sp ast_log(LOG_WARNING, "%d %s", span, s); } @@ -8242,7 +7423,7 @@ Add or convert channel operations so they can use the unique ID. static int pri_check_restart(struct zt_pri *pri) { if ((pri->nodetype != PRI_NETWORK) && (pri->nodetype != PRI_CPE)) { -@@ -10957,6 +11296,243 @@ static int app_zapInband(struct ast_chan +@@ -10868,6 +11211,243 @@ static int app_zapInband(struct ast_chan #endif /* HAVE_PRI */ @@ -8283,7 +7464,7 @@ Add or convert channel operations so they can use the unique ID. + } + pvt = pvt->next; + } -+ ++ + ast_cli(fd, "No GSM running on channel %d\n", channel); + return RESULT_SUCCESS; +} @@ -8312,15 +7493,15 @@ Add or convert channel operations so they can use the unique ID. + return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_NONE); +} + -+static char zap_reset_help[] = ++static char zap_reset_help[] = + "Usage: zap reset span \n" + " Reset/Restart a zaptel span\n"; + -+static char gsm_debug_help[] = ++static char gsm_debug_help[] = + "Usage: gsm debug channel \n" + " Enables debugging on a given GSM channel\n"; -+ -+static char gsm_no_debug_help[] = ++ ++static char gsm_no_debug_help[] = + "Usage: gsm no debug channel \n" + " Disables debugging on a given GSM channel\n"; + @@ -8335,7 +7516,7 @@ Add or convert channel operations so they can use the unique ID. + + + -+static char gsm_send_pdu_help[] = ++static char gsm_send_pdu_help[] = + "Usage: gsm send pdu \n" + " Sends a PDU on a GSM channel\n"; + @@ -8369,7 +7550,7 @@ Add or convert channel operations so they can use the unique ID. + } + pvt = pvt->next; + } -+ ++ + return RESULT_SUCCESS; +} + @@ -8377,7 +7558,7 @@ Add or convert channel operations so they can use the unique ID. + { "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[] = ++static char gsm_send_sms_help[] = + "Usage: gsm send sms \n" + " Sends a SM on a GSM channel\n"; + @@ -8410,7 +7591,7 @@ Add or convert channel operations so they can use the unique ID. + } + pvt = pvt->next; + } -+ ++ + return RESULT_SUCCESS; +} + @@ -8418,16 +7599,16 @@ Add or convert channel operations so they can use the unique ID. + 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); @@ -8438,11 +7619,11 @@ Add or convert channel operations so they can use the unique ID. + 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[] = ++static char gsm_show_status_help[] = + "Usage: gsm show status >\n" + " Displays status information about the GSM channel.\n"; + @@ -8474,7 +7655,7 @@ Add or convert channel operations so they can use the unique ID. + } + pvt = pvt->next; + } -+ ++ + return RESULT_SUCCESS; +} + @@ -8486,7 +7667,7 @@ Add or convert channel operations so they can use the unique ID. static int app_zapEC(struct ast_channel *chan, void *data) { int res=-1; -@@ -11578,6 +12154,12 @@ static int __unload_module(void) +@@ -11489,6 +12069,12 @@ static int __unload_module(void) ast_unregister_application(zapCD_app); ast_unregister_application(zapInband_app); #endif @@ -8499,7 +7680,7 @@ Add or convert channel operations so they can use the unique ID. ast_cli_unregister_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry)); ast_unregister_application(zapEC_app); ast_manager_unregister( "ZapDialOffhook" ); -@@ -12098,6 +12680,11 @@ static int process_zap(struct zt_chan_co +@@ -12009,6 +12595,11 @@ static int process_zap(struct zt_chan_co confp->chan.radio = 0; confp->pri.nodetype = BRI_CPE; #endif @@ -8507,11 +7688,11 @@ Add or convert channel operations so they can use the unique ID. + } else if (!strcasecmp(v->value, "gsm")) { + confp->chan.sig = SIG_GSM; + confp->chan.radio = 0; -+#endif ++#endif } else { ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value); } -@@ -12240,6 +12827,10 @@ static int process_zap(struct zt_chan_co +@@ -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)); @@ -8522,7 +7703,7 @@ Add or convert channel operations so they can use the unique ID. } else if (!strcasecmp(v->name, "resetinterval")) { if (!strcasecmp(v->value, "never")) confp->pri.resetinterval = -1; -@@ -12594,6 +13185,10 @@ static int load_module(void) +@@ -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 @@ -8533,7 +7714,7 @@ Add or convert channel operations so they can use the unique ID. res = setup_zap(0); /* Make sure we can register our Zap channel type */ if (res) -@@ -12612,6 +13207,12 @@ static int load_module(void) +@@ -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)); @@ -8546,7 +7727,7 @@ Add or convert channel operations so they can use the unique ID. memset(round_robin, 0, sizeof(round_robin)); ast_manager_register( "ZapTransfer", 0, action_transfer, "Transfer Zap Channel" ); -@@ -12625,7 +13226,48 @@ static int load_module(void) +@@ -12537,7 +13142,66 @@ static int load_module(void) return res; } @@ -8559,7 +7740,7 @@ Add or convert channel operations so they can use the unique ID. + if (!p) return -1; + if (!p->pri) return -1; + if (strlen(text)) { -+ if (p->pri) { ++ 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); @@ -8571,11 +7752,25 @@ Add or convert channel operations so they can use the unique ID. +} +#endif + -+static int zt_sendtext(struct ast_channel *c, const char *dest, const char *text, int ispdu) { ++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; @@ -8587,6 +7782,10 @@ Add or convert channel operations so they can use the unique ID. + 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; @@ -8606,80 +7805,194 @@ Add or convert channel operations so they can use the unique ID. 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]) -@@ -466,6 +466,8 @@ +--- a/configure ++++ b/configure +@@ -26600,6 +26600,188 @@ echo "$as_me: *** without explicitly spe fi fi -+AST_EXT_LIB_CHECK([GSMAT], [gsmat], [gsm_new_call], [libgsmat.h]) -+ - AST_EXT_LIB_CHECK([IKSEMEL], [iksemel], [iks_start_sasl], [iksemel.h]) - - if test "${PBX_IKSEMEL}" = 1; then -diff -ur asterisk-1.4.17.org/channels/chan_zap.c asterisk-1.4.17/channels/chan_zap.c ---- asterisk-1.4.17.org/channels/chan_zap.c 2008-02-09 21:02:04.714653000 +0100 -+++ asterisk-1.4.17/channels/chan_zap.c 2008-02-09 21:05:07.690124195 +0100 -@@ -47,6 +47,7 @@ - zaptel - tonezone - res_features -+ gsmat - pri - ***/ - -Tylko w asterisk-1.4.17/channels: chan_zap.c~ -diff -ur asterisk-1.4.17.org/channels/.chan_zap.moduleinfo asterisk-1.4.17/channels/.chan_zap.moduleinfo ---- asterisk-1.4.17.org/channels/.chan_zap.moduleinfo 2008-01-02 21:30:40.000000000 +0100 -+++ asterisk-1.4.17/channels/.chan_zap.moduleinfo 2008-02-09 21:04:54.802837479 +0100 -@@ -4,5 +4,6 @@ - zaptel - tonezone - res_features -+ gsmat - pri - -Tylko w asterisk-1.4.17/channels: .chan_zap.moduleinfo~ -diff -ur asterisk-1.4.17.org/channels/.moduleinfo asterisk-1.4.17/channels/.moduleinfo ---- asterisk-1.4.17.org/channels/.moduleinfo 2008-01-02 21:30:40.000000000 +0100 -+++ asterisk-1.4.17/channels/.moduleinfo 2008-02-09 21:04:30.284991178 +0100 -@@ -50,6 +50,7 @@ - zaptel - tonezone - res_features -+ gsmat - pri - - -Tylko w asterisk-1.4.17/channels: .moduleinfo~ -diff -ur asterisk-1.4.17.org/menuselect-tree asterisk-1.4.17/menuselect-tree ---- asterisk-1.4.17.org/menuselect-tree 2008-01-02 21:30:44.000000000 +0100 -+++ asterisk-1.4.17/menuselect-tree 2008-02-09 21:03:56.613371109 +0100 -@@ -247,6 +247,7 @@ - zaptel - tonezone - res_features -+ gsmat - pri - - ---- asterisk-1.4.17/makeopts.in.org 2008-02-09 21:32:11.948061985 +0100 -+++ asterisk-1.4.17/makeopts.in 2008-02-09 21:32:27.655480851 +0100 -@@ -83,6 +83,9 @@ - GSM_INCLUDE=@GSM_INCLUDE@ - GSM_LIB=@GSM_LIB@ - -+GSMAT_INCLUDE=@GSMAT_INCLUDE@ -+GSMAT_LIB=@GSMAT_LIB@ -+ - GTK_INCLUDE=@GTK_INCLUDE@ - GTK_LIB=@GTK_LIB@ - ---- a/build_tools/menuselect-deps.in~ 2007-09-14 17:50:49.000000000 +0200 -+++ b/build_tools/menuselect-deps.in 2008-02-09 21:30:40.933703503 +0100 -@@ -2,6 +2,7 @@ - CURL=@PBX_CURL@ - FREETDS=@PBX_FREETDS@ - GSM=@PBX_GSM@ -+GSMAT=@PBX_GSMAT@ - GTK=@PBX_GTK@ - GTK2=@PBX_GTK2@ - H323=@PBX_H323@ ++{ 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 ++_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 ++_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 -- 2.44.0