[Pkg-voip-commits] r3901 - in asterisk/branches/experimental/debian: . patches patches/bristuff
paravoid at alioth.debian.org
paravoid at alioth.debian.org
Sun Aug 5 09:48:16 UTC 2007
Author: paravoid
Date: 2007-08-05 09:48:15 +0000 (Sun, 05 Aug 2007)
New Revision: 3901
Added:
asterisk/branches/experimental/debian/patches/bristuff/
asterisk/branches/experimental/debian/patches/bristuff/answer-before-say
asterisk/branches/experimental/debian/patches/bristuff/app-dial-R-noinband
asterisk/branches/experimental/debian/patches/bristuff/app-dial-c-callback
asterisk/branches/experimental/debian/patches/bristuff/app-dial-etc
asterisk/branches/experimental/debian/patches/bristuff/app-dial-priority-202
asterisk/branches/experimental/debian/patches/bristuff/app-meetme-avoid-overflows
asterisk/branches/experimental/debian/patches/bristuff/app-zapras-fix-audiomode
asterisk/branches/experimental/debian/patches/bristuff/ast-device-state-CID
asterisk/branches/experimental/debian/patches/bristuff/ast-send-message
asterisk/branches/experimental/debian/patches/bristuff/ast-send-message-users
asterisk/branches/experimental/debian/patches/bristuff/ast_channel_masquerade_locked
asterisk/branches/experimental/debian/patches/bristuff/ast_monitor_start-targetscript
asterisk/branches/experimental/debian/patches/bristuff/bristuff-notice
asterisk/branches/experimental/debian/patches/bristuff/chan-capi
asterisk/branches/experimental/debian/patches/bristuff/chan-iax2-hangup-cause
asterisk/branches/experimental/debian/patches/bristuff/configurable-AST_SYSTEM_NAME
asterisk/branches/experimental/debian/patches/bristuff/feature-autoanswer
asterisk/branches/experimental/debian/patches/bristuff/feature-holdedcalls
asterisk/branches/experimental/debian/patches/bristuff/feature-parking_con
asterisk/branches/experimental/debian/patches/bristuff/find-feature
asterisk/branches/experimental/debian/patches/bristuff/misc-app-devstate
asterisk/branches/experimental/debian/patches/bristuff/misc-app-pickup
asterisk/branches/experimental/debian/patches/bristuff/misc-app-segfault
asterisk/branches/experimental/debian/patches/bristuff/misc-manager-dbdel
asterisk/branches/experimental/debian/patches/bristuff/misc-res-esel
asterisk/branches/experimental/debian/patches/bristuff/misc-res-watchdog
asterisk/branches/experimental/debian/patches/bristuff/uniqueid-01-use-pid-on-uniqueid-generation
asterisk/branches/experimental/debian/patches/bristuff/uniqueid-10-channel-ops-uniqueid
asterisk/branches/experimental/debian/patches/bristuff/uniqueid-20-monitor
asterisk/branches/experimental/debian/patches/bristuff/uniqueid-30-app-chanspy
asterisk/branches/experimental/debian/patches/bristuff/uniqueid-40-manager
asterisk/branches/experimental/debian/patches/bristuff/xagi
asterisk/branches/experimental/debian/patches/bristuff/zapata-bri+euroisdn
asterisk/branches/experimental/debian/patches/bristuff/zapata-gsm
asterisk/branches/experimental/debian/patches/use-libpri-bristuffed
Modified:
asterisk/branches/experimental/debian/asterisk-config.examples
asterisk/branches/experimental/debian/changelog
asterisk/branches/experimental/debian/patches/series
asterisk/branches/experimental/debian/rules
Log:
* Split bristuff 0.4.0-test3 into individual patches and add it to the quilt
patchset.
* Use libpri-bristuffed.so.1 and its respective header
(use-libpri-bristuffed).
* Ship xagi-test.c (from bristuff) to examples.
Modified: asterisk/branches/experimental/debian/asterisk-config.examples
===================================================================
--- asterisk/branches/experimental/debian/asterisk-config.examples 2007-08-05 09:07:18 UTC (rev 3900)
+++ asterisk/branches/experimental/debian/asterisk-config.examples 2007-08-05 09:48:15 UTC (rev 3901)
@@ -3,5 +3,6 @@
agi/agi-test.agi
agi/eagi-test.c
agi/eagi-sphinx-test.c
+agi/xagi-test.c
agi/fastagi-test
static-http
Modified: asterisk/branches/experimental/debian/changelog
===================================================================
--- asterisk/branches/experimental/debian/changelog 2007-08-05 09:07:18 UTC (rev 3900)
+++ asterisk/branches/experimental/debian/changelog 2007-08-05 09:48:15 UTC (rev 3901)
@@ -9,8 +9,13 @@
[ Faidon Liambotis ]
* Switch to quilt as a patch management system instead of dpatch.
+ * Split bristuff 0.4.0-test3 into individual patches and add it to the quilt
+ patchset.
+ * Use libpri-bristuffed.so.1 and its respective header
+ (use-libpri-bristuffed).
+ * Ship xagi-test.c (from bristuff) to examples.
- -- Faidon Liambotis <paravoid at debian.org> Sun, 05 Aug 2007 11:40:09 +0300
+ -- Faidon Liambotis <paravoid at debian.org> Sun, 05 Aug 2007 12:43:55 +0300
asterisk (1:1.4.9~dfsg-1) unstable; urgency=high
Added: asterisk/branches/experimental/debian/patches/bristuff/answer-before-say
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/answer-before-say (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/answer-before-say 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,57 @@
+Answer the channel before saying things (SayNumber, SayDigits,
+SayCharacters, SayPhonetic).
+
+--- asterisk-1.4.8~dfsg.orig/main/pbx.c
++++ asterisk-1.4.8~dfsg/main/pbx.c
+@@ -6002,6 +6002,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);
+ }
+
+@@ -6009,8 +6012,12 @@ static int pbx_builtin_saydigits(struct
+ {
+ int res = 0;
+
+- if (data)
++ if (data) {
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
+ res = ast_say_digit_str(chan, data, "", chan->language);
++ }
+ return res;
+ }
+
+@@ -6018,8 +6025,12 @@ static int pbx_builtin_saycharacters(str
+ {
+ int res = 0;
+
+- if (data)
++ if (data) {
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
+ res = ast_say_character_str(chan, data, "", chan->language);
++ }
+ return res;
+ }
+
+@@ -6027,8 +6038,12 @@ static int pbx_builtin_sayphonetic(struc
+ {
+ int res = 0;
+
+- if (data)
++ if (data) {
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
+ res = ast_say_phonetic_str(chan, data, "", chan->language);
++ }
+ return res;
+ }
+
Added: asterisk/branches/experimental/debian/patches/bristuff/app-dial-R-noinband
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/app-dial-R-noinband (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/app-dial-R-noinband 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,99 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_dial.c
++++ asterisk-1.4.8~dfsg/apps/app_dial.c
+@@ -187,6 +187,8 @@ static char *descrip =
+ " family/key is not specified.\n"
+ " r - Indicate ringing to the calling party. Pass no audio to the calling\n"
+ " party until the called channel has answered.\n"
++" R - indicate ringing to the calling party when the called party indicates\n"
++" ringing, pass no audio until answered.\n"
+ " S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
+ " answered the call.\n"
+ " t - Allow the called party to transfer the calling party by sending the\n"
+@@ -247,6 +249,7 @@ enum {
+ OPT_CALLEE_PARK = (1 << 25),
+ OPT_CALLER_PARK = (1 << 26),
+ OPT_IGNORE_FORWARDING = (1 << 27),
++ OPT_NOINBAND = (1 << 28),
+ } dial_exec_option_flags;
+
+ #define DIAL_STILLGOING (1 << 30)
+@@ -288,6 +291,7 @@ AST_APP_OPTIONS(dial_exec_options, {
+ AST_APP_OPTION('p', OPT_SCREENING),
+ AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+ AST_APP_OPTION('r', OPT_RINGBACK),
++ AST_APP_OPTION('R', OPT_NOINBAND),
+ AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+ AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+ AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+@@ -404,7 +408,7 @@ static struct ast_channel *wait_for_answ
+ int orig = *to;
+ struct ast_channel *peer = NULL;
+ /* single is set if only one destination is enabled */
+- int single = outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
++ int single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK | OPT_NOINBAND));
+
+ if (single) {
+ /* Turn off hold music, etc */
+@@ -631,7 +635,7 @@ static struct ast_channel *wait_for_answ
+ /* Setup early media if appropriate */
+ if (single)
+ ast_rtp_early_bridge(in, c);
+- if (!ast_test_flag(outgoing, OPT_RINGBACK))
++ if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND))
+ ast_indicate(in, AST_CONTROL_PROGRESS);
+ break;
+ case AST_CONTROL_VIDUPDATE:
+@@ -644,7 +648,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)
+ ast_rtp_early_bridge(in, c);
+- if (!ast_test_flag(outgoing, OPT_RINGBACK))
++ if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND))
+ ast_indicate(in, AST_CONTROL_PROCEEDING);
+ break;
+ case AST_CONTROL_HOLD:
+@@ -662,7 +666,7 @@ static struct ast_channel *wait_for_answ
+ /* Ignore going off hook and flash */
+ break;
+ case -1:
+- if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
++ if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK | OPT_NOINBAND)) {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "%s stopped sounds\n", c->name);
+ ast_indicate(in, -1);
+@@ -1081,7 +1085,7 @@ static int dial_exec_full(struct ast_cha
+ outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
+ }
+
+- ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING);
++ ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_NOINBAND);
+ /* loop through the list of dial destinations */
+ rest = args.peers;
+ while ((cur = strsep(&rest, "&")) ) {
+@@ -1101,7 +1105,7 @@ static int dial_exec_full(struct ast_cha
+ OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
+ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+ OPT_CALLEE_PARK | OPT_CALLER_PARK |
+- OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
++ OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_NOINBAND);
+ ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);
+ }
+ ast_copy_string(numsubst, number, sizeof(numsubst));
+@@ -1281,7 +1285,7 @@ static int dial_exec_full(struct ast_cha
+ ast_moh_start(chan, NULL, NULL);
+ }
+ ast_indicate(chan, AST_CONTROL_PROGRESS);
+- } else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
++ } else if (ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND)) {
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ sentringing++;
+ }
+@@ -1396,7 +1400,7 @@ static int dial_exec_full(struct ast_cha
+
+ if (ast_test_flag(&opts, OPT_MUSICBACK)) {
+ ast_moh_stop(chan);
+- } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
++ } else if (ast_test_flag(&opts, OPT_RINGBACK | OPT_NOINBAND)) {
+ ast_indicate(chan, -1);
+ sentringing=0;
+ }
Added: asterisk/branches/experimental/debian/patches/bristuff/app-dial-c-callback
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/app-dial-c-callback (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/app-dial-c-callback 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,62 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_dial.c
++++ asterisk-1.4.8~dfsg/apps/app_dial.c
+@@ -190,7 +190,8 @@ static char *descrip =
+ " R - indicate ringing to the calling party when the called party indicates\n"
+ " ringing, pass no audio until answered.\n"
+ " S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
+-" answered the call.\n"
++" answered the call.\n"
++" c - callback initiation, ring once and hangup.\n"
+ " t - Allow the called party to transfer the calling party by sending the\n"
+ " DTMF sequence defined in features.conf.\n"
+ " T - Allow the calling party to transfer the called party by sending the\n"
+@@ -250,6 +251,7 @@ enum {
+ OPT_CALLER_PARK = (1 << 26),
+ OPT_IGNORE_FORWARDING = (1 << 27),
+ OPT_NOINBAND = (1 << 28),
++ OPT_CALLBACK_INIT = (1 << 29),
+ } dial_exec_option_flags;
+
+ #define DIAL_STILLGOING (1 << 30)
+@@ -292,6 +294,7 @@ AST_APP_OPTIONS(dial_exec_options, {
+ AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+ AST_APP_OPTION('r', OPT_RINGBACK),
+ AST_APP_OPTION('R', OPT_NOINBAND),
++ AST_APP_OPTION('c', OPT_CALLBACK_INIT),
+ AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+ AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+ AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+@@ -619,14 +622,20 @@ static struct ast_channel *wait_for_answ
+ HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
+ break;
+ case AST_CONTROL_RINGING:
+- if (option_verbose > 2)
++ if (ast_test_flag(peerflags, OPT_CALLBACK_INIT)) {
++ if (option_verbose > 2)
++ ast_verbose( VERBOSE_PREFIX_3 "%s is ringing, hanging up.\n", o->chan->name);
++ return NULL;
++ } else {
++ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", c->name);
+- /* Setup early media if appropriate */
+- if (single)
++ /* Setup early media if appropriate */
++ if (single)
+ ast_rtp_early_bridge(in, c);
+- if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
++ if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
+ ast_indicate(in, AST_CONTROL_RINGING);
+ (*sentringing)++;
++ }
+ }
+ break;
+ case AST_CONTROL_PROGRESS:
+@@ -1085,7 +1094,7 @@ static int dial_exec_full(struct ast_cha
+ outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
+ }
+
+- ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_NOINBAND);
++ ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_CALLBACK_INIT | OPT_NOINBAND);
+ /* loop through the list of dial destinations */
+ rest = args.peers;
+ while ((cur = strsep(&rest, "&")) ) {
Added: asterisk/branches/experimental/debian/patches/bristuff/app-dial-etc
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/app-dial-etc (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/app-dial-etc 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,45 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_dial.c
++++ asterisk-1.4.8~dfsg/apps/app_dial.c
+@@ -64,6 +64,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+ #include "asterisk/manager.h"
+ #include "asterisk/privacy.h"
+ #include "asterisk/stringfields.h"
++#include "asterisk/transcap.h"
+
+ static char *app = "Dial";
+
+@@ -1604,23 +1605,25 @@ static int dial_exec_full(struct ast_cha
+ ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
+ if (play_to_callee)
+ ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
+- if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
++ if ((chan->transfercapability != AST_TRANS_CAP_DIGITAL) && (chan->transfercapability != AST_TRANS_CAP_RESTRICTED_DIGITAL)) {
++ /* only non-digital calls are allowed to go through userspace */
++ if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
+ ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
+- if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
++ if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
+ ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
+- if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
++ if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
+ ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
+- if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
++ if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
+ ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
+- if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
++ if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
+ ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
+- if (ast_test_flag(peerflags, OPT_CALLER_MONITOR))
++ if (ast_test_flag(peerflags, OPT_CALLER_MONITOR))
+ ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
+- if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
++ if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
+ ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
+- if (ast_test_flag(peerflags, OPT_CALLER_PARK))
++ if (ast_test_flag(peerflags, OPT_CALLER_PARK))
+ ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
+-
++ }
+ config.timelimit = timelimit;
+ config.play_warning = play_warning;
+ config.warning_freq = warning_freq;
Added: asterisk/branches/experimental/debian/patches/bristuff/app-dial-priority-202
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/app-dial-priority-202 (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/app-dial-priority-202 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,38 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_dial.c
++++ asterisk-1.4.8~dfsg/apps/app_dial.c
+@@ -11,6 +11,10 @@
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+@@ -123,7 +127,8 @@ static char *descrip =
+ " H - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
+ " i - Asterisk will ignore any forwarding requests it may receive on this\n"
+ " dial attempt.\n"
+-" j - Jump to priority n+101 if all of the requested channels were busy.\n"
++" j - Jump to priority n+101 if the called party was busy.\n"
++" Jump to priority n+201 if all of the requested channels were busy.\n"
+ " L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
+ " left. Repeat the warning every 'z' ms. The following special\n"
+ " variables can be used with this option:\n"
+@@ -1258,10 +1263,12 @@ static int dial_exec_full(struct ast_cha
+ }
+
+ if (!outgoing) {
+- strcpy(status, "CHANUNAVAIL");
++ ast_copy_string(status, "CHANUNAVAIL", sizeof(status));
++ /* See if there is a special message */
++ ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
+ } else {
+ /* Our status will at least be NOANSWER */
+- strcpy(status, "NOANSWER");
++ ast_copy_string(status, "NOANSWER", sizeof(status));
+ if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
+ moh = 1;
+ if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
Added: asterisk/branches/experimental/debian/patches/bristuff/app-meetme-avoid-overflows
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/app-meetme-avoid-overflows (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/app-meetme-avoid-overflows 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,37 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_meetme.c
++++ asterisk-1.4.8~dfsg/apps/app_meetme.c
+@@ -1392,8 +1392,9 @@ static int conf_run(struct ast_channel *
+ char members[10] = "";
+ int dtmf, opt_waitmarked_timeout = 0;
+ time_t timeout = 0;
++ int dyna_buff = CONF_SIZE;
+ ZT_BUFFERINFO bi;
+- char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
++ char __buf[ZT_MAX_BUF_SPACE / ZT_DEFAULT_NUM_BUFS + AST_FRIENDLY_OFFSET];
+ char *buf = __buf + AST_FRIENDLY_OFFSET;
+
+ if (!(user = ast_calloc(1, sizeof(*user))))
+@@ -1585,7 +1586,7 @@ static int conf_run(struct ast_channel *
+ }
+ /* Setup buffering information */
+ memset(&bi, 0, sizeof(bi));
+- bi.bufsize = CONF_SIZE/2;
++ bi.bufsize = dyna_buff / 2;
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.numbufs = audio_buffers;
+@@ -1901,6 +1902,14 @@ static int conf_run(struct ast_channel *
+ f = ast_read(c);
+ if (!f)
+ break;
++ if (f->datalen && f->datalen != dyna_buff) {
++ ast_log(LOG_NOTICE, "Audio bytes: %d Buffer size: %d\n", f->datalen, dyna_buff);
++ if (f->datalen < ZT_MAX_BUF_SPACE/audio_buffers) { /* skip too large frame to avoid overflow */
++ dyna_buff = f->datalen;
++ close(fd);
++ goto zapretry;
++ }
++ }
+ if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
+ if (user->talk.actual)
+ ast_frame_adjust_volume(f, user->talk.actual);
Added: asterisk/branches/experimental/debian/patches/bristuff/app-zapras-fix-audiomode
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/app-zapras-fix-audiomode (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/app-zapras-fix-audiomode 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,11 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_zapras.c
++++ asterisk-1.4.8~dfsg/apps/app_zapras.c
+@@ -183,7 +183,7 @@ static void run_ras(struct ast_channel *
+ }
+ }
+ /* Throw back into audio mode */
+- x = 1;
++ x = 0;
+ ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
+
+ /* Restore saved values */
Added: asterisk/branches/experimental/debian/patches/bristuff/ast-device-state-CID
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/ast-device-state-CID (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/ast-device-state-CID 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,409 @@
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/devicestate.h
++++ asterisk-1.4.8~dfsg/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
+--- asterisk-1.4.8~dfsg.orig/main/devicestate.c
++++ asterisk-1.4.8~dfsg/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)
++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;
+ }
+
+-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);
+ }
+
+ /*! \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);
+ }
+
+ /*! \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 {
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/channel.h
++++ asterisk-1.4.8~dfsg/include/asterisk/channel.h
+@@ -572,8 +572,13 @@ int ast_channel_datastore_remove(struct
+ /*! \brief Find a datastore on a channel */
+ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, char *uid);
+
++extern ast_mutex_t uniquelock;
++
++/*! \brief Change the state of a channel and the callerid of the calling channel*/
++int ast_setstate_and_cid(struct ast_channel *chan, enum ast_channel_state state, char *cid_num, char *cid_name);
++
+ /*! \brief Change the state of a channel */
+-int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
++int ast_setstate(struct ast_channel *chan, enum ast_channel_state state);
+
+ /*! \brief Create a channel structure
+ \return Returns NULL on failure to allocate.
+--- asterisk-1.4.8~dfsg.orig/main/channel.c
++++ asterisk-1.4.8~dfsg/main/channel.c
+@@ -1261,7 +1261,7 @@ void ast_channel_free(struct ast_channel
+ free(chan);
+ AST_LIST_UNLOCK(&channels);
+
+- ast_device_state_changed_literal(name);
++ ast_device_state_changed_literal(name, NULL, NULL);
+ }
+
+ struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, char *uid)
+@@ -3823,7 +3823,7 @@ void ast_set_callerid(struct ast_channel
+ );
+ }
+
+-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;
+
+@@ -3831,7 +3831,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",
+@@ -3848,6 +3848,11 @@ int ast_setstate(struct ast_channel *cha
+ return 0;
+ }
+
++int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
++{
++ return ast_setstate_and_cid(chan, state, NULL, NULL);
++}
++
+ /*! \brief Find bridged channel */
+ struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
+ {
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/pbx.h
++++ asterisk-1.4.8~dfsg/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 {
+@@ -830,7 +830,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)
+ }
+--- asterisk-1.4.8~dfsg.orig/main/pbx.c
++++ asterisk-1.4.8~dfsg/main/pbx.c
+@@ -1993,7 +1993,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;
+
+@@ -2024,11 +2024,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 */
+ }
+@@ -2223,7 +2223,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;
+@@ -3984,7 +3984,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 {
+--- asterisk-1.4.8~dfsg.orig/channels/chan_sip.c
++++ asterisk-1.4.8~dfsg/channels/chan_sip.c
+@@ -1328,7 +1328,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(void *data);
+ static int sip_poke_peer(struct sip_peer *peer);
+@@ -8282,7 +8282,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;
+
+--- asterisk-1.4.8~dfsg.orig/apps/app_queue.c
++++ asterisk-1.4.8~dfsg/apps/app_queue.c
+@@ -592,7 +592,7 @@ static void *changethread(void *data)
+ return NULL;
+ }
+
+-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)
+ {
+ /* Avoid potential for deadlocks by spawning a new thread to handle
+ the event */
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/manager.h
++++ asterisk-1.4.8~dfsg/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
+--- asterisk-1.4.8~dfsg.orig/main/manager.c
++++ asterisk-1.4.8~dfsg/main/manager.c
+@@ -128,6 +128,7 @@ static struct permalias {
+ { EVENT_FLAG_AGENT, "agent" },
+ { EVENT_FLAG_USER, "user" },
+ { EVENT_FLAG_CONFIG, "config" },
++ { EVENT_FLAG_EXTENSIONSTATUS, "extensionstatus" },
+ { -1, "all" },
+ { 0, "none" },
+ };
+@@ -2451,10 +2452,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;
+ }
+
+--- asterisk-1.4.8~dfsg.orig/apps/app_devstate.c
++++ asterisk-1.4.8~dfsg/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");
+--- asterisk-1.4.8~dfsg.orig/res/res_esel.c
++++ asterisk-1.4.8~dfsg/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);
Added: asterisk/branches/experimental/debian/patches/bristuff/ast-send-message
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/ast-send-message (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/ast-send-message 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,269 @@
+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.
+
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/channel.h
++++ asterisk-1.4.8~dfsg/include/asterisk/channel.h
+@@ -223,7 +223,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);
+@@ -653,6 +653,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"
+@@ -869,10 +879,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
+--- asterisk-1.4.8~dfsg.orig/main/channel.c
++++ asterisk-1.4.8~dfsg/main/channel.c
+@@ -2634,7 +2634,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 */
+@@ -2642,7 +2642,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;
+ }
+@@ -2811,7 +2811,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 :
+@@ -4786,6 +4786,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)
+ {
+--- asterisk-1.4.8~dfsg.orig/apps/app_sendtext.c
++++ asterisk-1.4.8~dfsg/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);
+--- asterisk-1.4.8~dfsg.orig/res/res_agi.c
++++ asterisk-1.4.8~dfsg/res/res_agi.c
+@@ -481,7 +481,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;
+ }
+--- asterisk-1.4.8~dfsg.orig/channels/chan_agent.c
++++ asterisk-1.4.8~dfsg/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);
+@@ -545,13 +545,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;
+ }
+--- asterisk-1.4.8~dfsg.orig/channels/chan_alsa.c
++++ asterisk-1.4.8~dfsg/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);
+@@ -494,7 +494,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);
+--- asterisk-1.4.8~dfsg.orig/channels/chan_local.c
++++ asterisk-1.4.8~dfsg/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;
+--- asterisk-1.4.8~dfsg.orig/channels/chan_oss.c
++++ asterisk-1.4.8~dfsg/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);
+--- asterisk-1.4.8~dfsg.orig/channels/chan_phone.c
++++ asterisk-1.4.8~dfsg/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) ==
+--- asterisk-1.4.8~dfsg.orig/channels/chan_sip.c
++++ asterisk-1.4.8~dfsg/channels/chan_sip.c
+@@ -1204,7 +1204,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);
+@@ -2315,7 +2315,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);
+--- asterisk-1.4.8~dfsg.orig/channels/chan_iax2.c
++++ asterisk-1.4.8~dfsg/channels/chan_iax2.c
+@@ -812,7 +812,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);
+@@ -2464,7 +2464,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);
+ }
+
+-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,
Added: asterisk/branches/experimental/debian/patches/bristuff/ast-send-message-users
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/ast-send-message-users (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/ast-send-message-users 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,136 @@
+--- asterisk-1.4.8~dfsg.orig/main/manager.c
++++ asterisk-1.4.8~dfsg/main/manager.c
+@@ -11,6 +11,9 @@
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
++ * Copyright (C) 2003-2004, Junghanns.NET Gmbh
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+@@ -1354,6 +1357,49 @@ static int action_hangup(struct mansessi
+ return 0;
+ }
+
++static char mandescr_message[] =
++"Description: Send a message\n"
++"Variables: \n"
++" Channel: The destination channel(e.g. SIP/phone1)\n"
++" From: \n"
++" Message: The message to send\n";
++
++static int action_message(struct mansession *s, const struct message *m)
++{
++ const char *name = astman_get_header(m, "Channel");
++ const char *from = astman_get_header(m, "From");
++ const char *message = astman_get_header(m, "Message");
++ const char *pdu = astman_get_header(m, "PDU");
++ char tmp[256];
++ char *tech, *data;
++ int res;
++ if (ast_strlen_zero(name) || (ast_strlen_zero(message) && ast_strlen_zero(pdu))) {
++ astman_send_error(s, m, "No channel or message/PDU specified");
++ return 0;
++ }
++ ast_copy_string(tmp, name, sizeof(tmp));
++ tech = tmp;
++ data = strchr(tmp, '/');
++ if (!data) {
++ astman_send_error(s, m, "Invalid channel\n");
++ return 0;
++ }
++ *data = '\0';
++ data++;
++ if (ast_strlen_zero(pdu)) {
++ res = ast_send_message(tech, (char *)data, (char *)name, (char *)from, (char *)message, 0);
++ } else {
++ res = ast_send_message(tech, (char *)data, (char *)name, (char *)from, (char *)pdu, 1);
++ }
++
++ if (res) {
++ astman_send_error(s, m, "Error sending message");
++ return 0;
++ }
++ astman_send_ack(s, m, "Message sent");
++ return 0;
++}
++
+ static char mandescr_setvar[] =
+ "Description: Set a global or local channel variable.\n"
+ "Variables: (Names marked with * are required)\n"
+@@ -2748,6 +2794,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 );
+--- asterisk-1.4.8~dfsg.orig/pbx/pbx_spool.c
++++ asterisk-1.4.8~dfsg/pbx/pbx_spool.c
+@@ -87,6 +87,10 @@ struct outgoing {
+ char app[256];
+ char data[256];
+
++ /* If SMS */
++ char message[256];
++ char pdu[256];
++
+ /* If extension/context/priority */
+ char exten[256];
+ char context[256];
+@@ -181,6 +185,10 @@ static int apply_outgoing(struct outgoin
+ ast_copy_string(o->app, c, sizeof(o->app));
+ } else if (!strcasecmp(buf, "data")) {
+ ast_copy_string(o->data, c, sizeof(o->data));
++ } else if (!strcasecmp(buf, "message")) {
++ strncpy(o->message, c, sizeof(o->message) - 1);
++ } else if (!strcasecmp(buf, "pdu")) {
++ strncpy(o->pdu, c, sizeof(o->pdu) - 1);
+ } else if (!strcasecmp(buf, "maxretries")) {
+ if (sscanf(c, "%d", &o->maxretries) != 1) {
+ ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn);
+@@ -241,8 +249,8 @@ static int apply_outgoing(struct outgoin
+ }
+ }
+ ast_copy_string(o->fn, fn, sizeof(o->fn));
+- if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
+- ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn);
++ if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || ((ast_strlen_zero(o->app) && ast_strlen_zero(o->exten) && ast_strlen_zero(o->message) && ast_strlen_zero(o->pdu)))) {
++ ast_log(LOG_WARNING, "At least one of app or extension (or keyword message/pdu)must be specified, along with tech and dest in file %s\n", fn);
+ return -1;
+ }
+ return 0;
+@@ -332,6 +340,14 @@ static void *attempt_thread(void *data)
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
+ res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
++ } else if (!ast_strlen_zero(o->message)) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Attempting to send message on %s/%s (Retry %d)\n", o->tech, o->dest, o->retries);
++ res = ast_send_message(o->tech, o->dest, o->dest, (ast_strlen_zero(o->cid_name) ? o->cid_num : o->cid_name), o->message, 0);
++ } else if (!ast_strlen_zero(o->pdu)) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Attempting to send message in PDU format on %s/%s (Retry %d)\n", o->tech, o->dest, o->retries);
++ res = ast_send_message(o->tech, o->dest, o->dest, (ast_strlen_zero(o->cid_name) ? o->cid_num : o->cid_name), o->pdu, 1);
+ } else {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
+@@ -348,9 +364,14 @@ static void *attempt_thread(void *data)
+ safe_append(o, time(NULL), "EndRetry");
+ }
+ } else {
++ if (!ast_strlen_zero(o->message)) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_2 "Message sent to %s/%s\n", o->tech, o->dest);
++ } else {
+ ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest);
+ ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest);
+- remove_from_queue(o, "Completed");
++ }
++ remove_from_queue(o, "Completed");
+ }
+ free_outgoing(o);
+ return NULL;
Added: asterisk/branches/experimental/debian/patches/bristuff/ast_channel_masquerade_locked
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/ast_channel_masquerade_locked (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/ast_channel_masquerade_locked 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,42 @@
+--- asterisk-1.4.8~dfsg-OK.orig/main/channel.c
++++ asterisk-1.4.8~dfsg-OK/main/channel.c
+@@ -3448,6 +3448,29 @@ int ast_channel_masquerade(struct ast_ch
+ return res;
+ }
+
++int ast_channel_masquerade_locked(struct ast_channel *original, struct ast_channel *clone)
++{
++ struct ast_frame null = { AST_FRAME_NULL, };
++ int res = -1;
++ ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
++ clone->name, original->name);
++ if (original->masq) {
++ ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
++ original->masq->name, original->name);
++ } else if (clone->masqr) {
++ ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
++ clone->name, clone->masqr->name);
++ } else {
++ original->masq = clone;
++ clone->masqr = original;
++ ast_queue_frame(original, &null);
++ ast_queue_frame(clone, &null);
++ ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
++ res = 0;
++ }
++ return res;
++}
++
+ void ast_change_name(struct ast_channel *chan, char *newname)
+ {
+ manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", chan->name, newname, chan->uniqueid);
+--- asterisk-1.4.8~dfsg-OK.orig/include/asterisk/channel.h
++++ asterisk-1.4.8~dfsg-OK/include/asterisk/channel.h
+@@ -1033,6 +1033,7 @@ int ast_channel_bridge(struct ast_channe
+ p->owner pointer) that is affected by the change. The physical layer of the original
+ channel is hung up. */
+ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
++int ast_channel_masquerade_locked(struct ast_channel *original, struct ast_channel *clone);
+
+ /*! Gives the string form of a given cause code */
+ /*!
Added: asterisk/branches/experimental/debian/patches/bristuff/ast_monitor_start-targetscript
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/ast_monitor_start-targetscript (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/ast_monitor_start-targetscript 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,125 @@
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/monitor.h
++++ asterisk-1.4.8~dfsg/include/asterisk/monitor.h
+@@ -38,6 +38,8 @@ struct ast_channel_monitor {
+ char write_filename[FILENAME_MAX];
+ char filename_base[FILENAME_MAX];
+ int filename_changed;
++ char target_url[FILENAME_MAX];
++ char target_script[FILENAME_MAX];
+ char *format;
+ int joinfiles;
+ enum AST_MONITORING_STATE state;
+@@ -46,7 +48,7 @@ struct ast_channel_monitor {
+
+ /* Start monitoring a channel */
+ int ast_monitor_start(struct ast_channel *chan, const char *format_spec,
+- const char *fname_base, int need_lock );
++ const char *fname_base, const char *target_url, const char *target_script, int need_lock );
+
+ /* Stop monitoring a channel */
+ int ast_monitor_stop(struct ast_channel *chan, int need_lock);
+--- asterisk-1.4.8~dfsg.orig/res/res_monitor.c
++++ asterisk-1.4.8~dfsg/res/res_monitor.c
+@@ -124,7 +124,7 @@ static int ast_monitor_set_state(struct
+
+ /* Start monitoring a channel */
+ int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
+- const char *fname_base, int need_lock)
++ const char *fname_base, const char *target_url, const char *target_script, int need_lock)
+ {
+ int res = 0;
+ char tmp[256];
+@@ -148,6 +148,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;
+@@ -290,6 +295,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;
+@@ -313,8 +320,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);
+ }
+
+@@ -443,7 +455,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);
+@@ -482,6 +494,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)) {
+@@ -506,7 +520,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);
+--- asterisk-1.4.8~dfsg.orig/apps/app_queue.c
++++ asterisk-1.4.8~dfsg/apps/app_queue.c
+@@ -2528,13 +2528,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);
+--- asterisk-1.4.8~dfsg.orig/channels/chan_agent.c
++++ asterisk-1.4.8~dfsg/channels/chan_agent.c
+@@ -412,7 +412,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
Added: asterisk/branches/experimental/debian/patches/bristuff/bristuff-notice
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/bristuff-notice (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/bristuff-notice 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,52 @@
+--- asterisk-1.4.8~dfsg.orig/README
++++ asterisk-1.4.8~dfsg/README
+@@ -4,6 +4,8 @@ and the Asterisk.org developer community
+
+ Copyright (C) 2001-2006 Digium, Inc.
+ and other copyright holders.
++Copyright (C) 2002-2005 Junghanns.NET GmbH
++and other copyright holders.
+ ================================================================
+
+ * SECURITY
+--- asterisk-1.4.8~dfsg.orig/.version
++++ asterisk-1.4.8~dfsg/.version
+@@ -1 +1 @@
+-1.4.9
++1.4.9-BRIstuffed-0.4.0-test4
+--- asterisk-1.4.8~dfsg.orig/LICENSE
++++ asterisk-1.4.8~dfsg/LICENSE
+@@ -1,7 +1,7 @@
+-Asterisk is distributed under the GNU General Public License version 2
+-and is also available under alternative licenses negotiated directly
+-with Digium, Inc. If you obtained Asterisk under the GPL, then the GPL
+-applies to all loadable Asterisk modules used on your system as well,
++BRIstuffed Asterisk is distributed under the GNU General Public License version 2
++and is not available under any alternative licenses.
++If you obtained BRIstuffed Asterisk under the GPL, then the GPL
++applies to all loadable BRIstuffed Asterisk modules used on your system as well,
+ except as defined below. The GPL (version 2) is included in this
+ source tree in the file COPYING.
+
+--- asterisk-1.4.8~dfsg.orig/doc/hardware.txt
++++ asterisk-1.4.8~dfsg/doc/hardware.txt
+@@ -31,6 +31,19 @@ Zaptel compatible hardware
+ * Wildcard TE410P - Quad T1/E1 switchable interface. Supports PRI and
+ RBS signalling, as well as PPP, FR, and HDLC data modes.
+
++-- Junghanns.NET (Primary author of BRIstuff)
++ http://www.junghanns.net
++
++ * quadBRI PCI ISDN - 4port BRI ISDN interface, supports NT and TE mode
++
++ * octoBRI PCI ISDN - 8port BRI ISDN interface, supports NT and TE mode
++
++ * singleE1 PCI ISDN - Single E1 interface
++
++ * doubleE1 PCI ISDN - Double E1 interface
++
++ * uno/duo/quad GSM PCI - 1/2/4 channel GSM interface cards
++
+ Non-zaptel compatible hardware
+ ==============================
+
Added: asterisk/branches/experimental/debian/patches/bristuff/chan-capi
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/chan-capi (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/chan-capi 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,5765 @@
+--- /dev/null
++++ asterisk-1.4.8~dfsg/apps/app_capiCD.c
+@@ -0,0 +1,164 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Call Deflection, inspired by capircvd by Alexander Brickwedde
++ *
++ * Copyright (C) 2002,2003,2004,2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod at ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ */
++
++/*** MODULEINFO
++ <depend>capi</depend>
++ ***/
++
++#include "asterisk.h"
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <linux/capi.h>
++#include <capi20.h>
++
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/chan_capi.h>
++#include <asterisk/chan_capi_app.h>
++#include <asterisk/app.h>
++
++
++
++static char *tdesc = "(CAPI*) Call Deflection, the magic thing.";
++static char *app = "capiCD";
++static char *synopsis = "call deflection";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int capiCD_exec(struct ast_channel *chan, void *data)
++{
++ struct ast_capi_pvt *i = chan->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR Info;
++ _cmsg CMSG;
++ char bchaninfo[1];
++ char fac[60];
++ int res=0;
++ int ms=3000;
++ struct localuser *u;
++
++ if (!data) {
++ ast_log(LOG_WARNING, "cd requires an argument (destination phone number)\n");
++ return -1;
++ }
++ LOCAL_USER_ADD(u);
++ /* Do our thing here */
++
++ if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_BCONNECTED)) {
++ ast_log(LOG_ERROR, "call deflection does not work with calls that are already connected!\n");
++ LOCAL_USER_REMOVE(u);
++ return -1;
++ }
++ // wait until the channel is alerting, so we dont drop the call and interfer with msgs
++ while ((ms > 0) && (i->state != CAPI_STATE_ALERTING)) {
++ sleep(100);
++ ms -= 100;
++ }
++
++ // make sure we hang up correctly
++ i->state = CAPI_STATE_CONNECTPENDING;
++
++ fac[0]=0; // len
++ fac[1]=0; //len
++ fac[2]=0x01; // Use D-Chan
++ fac[3]=0; // Keypad len
++ fac[4]=31; // user user data? len = 31 = 29 + 2
++ fac[5]=0x1c; // magic?
++ fac[6]=0x1d; // strlen destination + 18 = 29
++ fac[7]=0x91; // ..
++ fac[8]=0xA1;
++ fac[9]=0x1A; // strlen destination + 15 = 26
++ fac[10]=0x02;
++ fac[11]=0x01;
++ fac[12]=0x70;
++ fac[13]=0x02;
++ fac[14]=0x01;
++ fac[15]=0x0d;
++ fac[16]=0x30;
++ fac[17]=0x12; // strlen destination + 7 = 18
++ fac[18]=0x30; // ...hm 0x30
++ fac[19]=0x0d; // strlen destination + 2
++ fac[20]=0x80; // CLIP
++ fac[21]=0x0b; // strlen destination
++ fac[22]=0x01; // destination start
++ fac[23]=0x01; //
++ fac[24]=0x01; //
++ fac[25]=0x01; //
++ fac[26]=0x01; //
++ fac[27]=0x01; //
++ fac[28]=0x01; //
++ fac[29]=0x01; //
++ fac[30]=0x01; //
++ fac[31]=0x01; //
++ fac[32]=0x01; //
++ fac[33]=0x01; // 0x1 = sending complete
++ fac[34]=0x01;
++ fac[35]=0x01;
++
++ memcpy((unsigned char *)fac+22,data,strlen(data));
++ fac[22+strlen(data)]=0x01; // fill with 0x01 if number is only 6 numbers (local call)
++ fac[23+strlen(data)]=0x01;
++ fac[24+strlen(data)]=0x01;
++ fac[25+strlen(data)]=0x01;
++ fac[26+strlen(data)]=0x01;
++
++ fac[6]=18+strlen(data);
++ fac[9]=15+strlen(data);
++ fac[17]=7+strlen(data);
++ fac[19]=2+strlen(data);
++ fac[21]=strlen(data);
++
++ bchaninfo[0] = 0x1;
++ INFO_REQ_HEADER(&CMSG,ast_capi_ApplID,ast_capi_MessageNumber++,0);
++ INFO_REQ_CONTROLLER(&CMSG) = i->controller;
++ INFO_REQ_PLCI(&CMSG) = i->PLCI;
++ INFO_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char*)bchaninfo; // use D-Channel
++ INFO_REQ_KEYPADFACILITY(&CMSG) = 0;
++ INFO_REQ_USERUSERDATA(&CMSG) = 0;
++ INFO_REQ_FACILITYDATAARRAY(&CMSG) = (unsigned char*) fac + 4;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"Error sending INFO_REQ\n");
++ return Info;
++ } else {
++ if (capidebug) {
++ // ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG));
++ ast_log(LOG_NOTICE,"sent INFO_REQ PLCI = %#x\n",i->PLCI);
++ }
++ }
++
++ LOCAL_USER_REMOVE(u);
++ return res;
++}
++
++int unload_module(void)
++{
++ STANDARD_HANGUP_LOCALUSERS;
++ return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++ return ast_register_application(app, capiCD_exec,synopsis,tdesc);
++}
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, tdesc);
+--- /dev/null
++++ asterisk-1.4.8~dfsg/apps/app_capiECT.c
+@@ -0,0 +1,214 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * ECT transfer the held call
++ *
++ * Copyright (C) 2002,2003,2004,2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod at ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ */
++
++/*** MODULEINFO
++ <depend>capi</depend>
++ ***/
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <linux/capi.h>
++#include <capi20.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/say.h>
++#include <asterisk/chan_capi.h>
++#include <asterisk/chan_capi_app.h>
++
++
++static char *tdesc = "(CAPI*) ECT";
++static char *app = "capiECT";
++static char *synopsis = "transfer the call that is on hold";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++
++static int capiECT_exec(struct ast_channel *chan, void *data)
++{
++ struct ast_capi_pvt *i = chan->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR Info;
++ _cmsg CMSG;
++ unsigned char fac[8];
++ int res=0;
++ struct localuser *u;
++ char *ecodes = "*#";
++
++ if (!data) {
++ ast_log(LOG_WARNING, "ECT requires an argument (destination phone number)\n");
++ return -1;
++ }
++ LOCAL_USER_ADD(u);
++ /* Do our thing here */
++ if (i->onholdPLCI <= 0) {
++ ast_log(LOG_WARNING, "no call on hold that could be transfered\n");
++ return -1;
++ }
++
++ ast_log(LOG_NOTICE,"ECT to %s\n",(char *)data);
++ capi_call(chan,data,0);
++
++ while ((i->state != CAPI_STATE_BCONNECTED) && (i->onholdPLCI != 0)) {
++ usleep(10000);
++ }
++
++
++ if (i->state == CAPI_STATE_BCONNECTED) {
++ ast_log(LOG_NOTICE,"call was answered\n");
++
++ capi_detect_dtmf(chan,1);
++
++ // put the stuff to play announcement message here ---> <-----
++ res = ast_say_digit_str(chan,i->cid,ecodes,chan->language);
++ if ( res == '#') {
++ ast_log(LOG_NOTICE,"res = %d\n",res);
++ // user pressed #, hangup
++ // first the holded user
++// ast_exec("capiRETRIEVE",chan);
++
++ DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_REQ_PLCI(&CMSG) = i->onholdPLCI;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",i->onholdPLCI);
++ } else {
++ ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n",i->onholdPLCI);
++ }
++
++ // then the destination
++
++ DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++ } else {
++ ast_log(LOG_NOTICE, "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++ }
++
++ // wait for the B3 layer to go down
++ while (i->state != CAPI_STATE_CONNECTED) {
++ usleep(10000);
++ }
++
++ DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++ } else {
++ ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++ }
++
++
++ LOCAL_USER_REMOVE(u);
++ return -1;
++
++ } else {
++ // now drop the bchannel
++ DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++ } else {
++ ast_log(LOG_NOTICE, "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++ }
++
++ // wait for the B3 layer to go down
++ while (i->state != CAPI_STATE_CONNECTED) {
++ usleep(10000);
++ }
++ }
++ }
++
++ // the caller onhold hungup or died away, drop the answered call
++ if (i->onholdPLCI == 0) {
++ DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++ } else {
++ ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++ }
++ return -1;
++ }
++
++ ast_log(LOG_NOTICE,"onholdPLCI = %d\n",i->onholdPLCI);
++
++
++ fac[0] = 7; // len
++ fac[1] = 0x06; // ECT (function)
++ fac[2] = 0x00;
++ fac[3] = 4; //len //sservice specific parameter , cstruct
++ fac[4] = (i->onholdPLCI << 8 ) >> 8;
++ fac[5] = i->onholdPLCI >> 8;
++ fac[6] = 0;
++ fac[7] = 0;
++
++ FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID,ast_capi_MessageNumber++,0);
++ FACILITY_REQ_CONTROLLER(&CMSG) = i->controller;
++ FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI;
++ FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; // sservices
++ FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (unsigned char *)&fac;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"Error sending FACILITY_REQ\n");
++ return Info;
++ } else {
++ ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x (%#x %#x) onholdPLCI = %#x\n ",i->PLCI,fac[4],fac[5],i->onholdPLCI);
++ ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG));
++ }
++
++// i->outgoing = -1; // incoming + outgoing, this is a magic channel :)
++
++ LOCAL_USER_REMOVE(u);
++ return res;
++}
++
++int unload_module(void)
++{
++ STANDARD_HANGUP_LOCALUSERS;
++ return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++ return ast_register_application(app, capiECT_exec,synopsis,tdesc);
++}
++
++char *description(void)
++{
++ return tdesc;
++}
++
++int usecount(void)
++{
++ int res;
++ STANDARD_USECOUNT(res);
++ return res;
++}
++
++char *key()
++{
++ return ASTERISK_GPL_KEY;
++}
+--- /dev/null
++++ asterisk-1.4.8~dfsg/apps/app_capiNoES.c
+@@ -0,0 +1,100 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Disable echo suppression (useful for fax and voicemail!)
++ *
++ * Copyright (C) 2004,2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod at ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ */
++
++/*** MODULEINFO
++ <depend>capi</depend>
++ ***/
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <linux/capi.h>
++#include <capi20.h>
++
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/chan_capi_app.h>
++
++
++
++#ifdef CAPI_ES
++static char *tdesc = "(CAPI*) No Echo Suppression.";
++static char *app = "capiNoES";
++static char *synopsis = "Disable Echo Suppression";
++#else
++static char *tdesc = "(CAPI*) No Echo Suppression at all!";
++static char *app = "capiNoES";
++static char *synopsis = "Bogus Application";
++#endif
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int capiNoES_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ struct localuser *u;
++ LOCAL_USER_ADD(u);
++
++#ifdef CAPI_ES
++ if (strcasecmp("CAPI",chan->type) == 0) {
++#ifdef CVS_HEAD
++ struct ast_capi_pvt *i = chan->tech_pvt;
++#else
++ struct ast_capi_pvt *i = chan->pvt->pvt;
++#endif
++ if (i->doES == 1) {
++ i->doES = 0;
++ }
++ } else {
++ ast_log(LOG_WARNING, "capiNoES only works on CAPI channels, check your extensions.conf!\n");
++ }
++#endif
++
++ LOCAL_USER_REMOVE(u);
++ return res;
++}
++
++int unload_module(void)
++{
++ STANDARD_HANGUP_LOCALUSERS;
++ return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++ return ast_register_application(app, capiNoES_exec,synopsis,tdesc);
++}
++
++char *description(void)
++{
++ return tdesc;
++}
++
++int usecount(void)
++{
++ int res;
++ STANDARD_USECOUNT(res);
++ return res;
++}
++
++char *key()
++{
++ return ASTERISK_GPL_KEY;
++}
+--- asterisk-1.4.8~dfsg.orig/build_tools/menuselect-deps.in
++++ asterisk-1.4.8~dfsg/build_tools/menuselect-deps.in
+@@ -1,4 +1,5 @@
+ ASOUND=@PBX_ALSA@
++CAPI=@PBX_CAPI@
+ CURL=@PBX_CURL@
+ FREETDS=@PBX_FREETDS@
+ GSM=@PBX_GSM@
+--- /dev/null
++++ asterisk-1.4.8~dfsg/channels/chan_capi.c
+@@ -0,0 +1,2888 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Copyright (C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod at ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ */
++
++/*** MODULEINFO
++ <depend>capi</depend>
++ ***/
++
++#include "asterisk.h"
++
++#include <sys/time.h>
++#include <sys/signal.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <asterisk/lock.h>
++#include <asterisk/frame.h>
++#include <asterisk/channel.h>
++#include <asterisk/logger.h>
++#include <asterisk/module.h>
++#include <asterisk/pbx.h>
++#include <asterisk/config.h>
++#include <asterisk/options.h>
++#include <asterisk/features.h>
++#include <asterisk/utils.h>
++#include <asterisk/cli.h>
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++#include <capi_bsd.h>
++#else
++#include <linux/capi.h>
++#endif
++#include <capi20.h>
++#include <asterisk/dsp.h>
++#include <asterisk/xlaw.h>
++#include <asterisk/chan_capi.h>
++
++unsigned ast_capi_ApplID;
++_cword ast_capi_MessageNumber=1;
++static char desc[] = "Common ISDN API for Asterisk";
++#ifdef CAPI_ULAW
++static char tdesc[] = "Common ISDN API Driver (0.4.0) muLaw";
++#else
++static char tdesc[] = "Common ISDN API Driver (0.4.0) aLaw ";
++#endif
++static char type[] = "CAPI";
++
++
++static int usecnt;
++AST_MUTEX_DEFINE_STATIC(usecnt_lock);
++AST_MUTEX_DEFINE_STATIC(iflock);
++AST_MUTEX_DEFINE_STATIC(pipelock);
++AST_MUTEX_DEFINE_STATIC(monlock);
++AST_MUTEX_DEFINE_STATIC(contrlock);
++AST_MUTEX_DEFINE_STATIC(capi_send_buffer_lock);
++AST_MUTEX_DEFINE_STATIC(capi_put_lock);
++
++#ifdef CAPI_ULAW
++static int capi_capability = AST_FORMAT_ULAW;
++#else
++static int capi_capability = AST_FORMAT_ALAW;
++#endif
++
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++static CAPIProfileBuffer_t profile;
++#else
++static struct ast_capi_profile profile;
++#endif
++static pthread_t monitor_thread = -1;
++
++static struct ast_capi_pvt *iflist = NULL;
++static struct capi_pipe *pipelist = NULL;
++static int capi_last_plci = 0;
++static struct ast_capi_controller *capi_controllers[AST_CAPI_MAX_CONTROLLERS];
++static int capi_num_controllers = 0;
++static int capi_counter = 0;
++static unsigned long capi_used_controllers=0;
++
++static char capi_send_buffer[AST_CAPI_MAX_B3_BLOCKS * AST_CAPI_MAX_B3_BLOCK_SIZE];
++static int capi_send_buffer_handle = 0;
++
++char capi_national_prefix[AST_MAX_EXTENSION];
++char capi_international_prefix[AST_MAX_EXTENSION];
++
++int capidebug = 0;
++
++static const struct ast_channel_tech capi_tech;
++
++MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG) {
++ MESSAGE_EXCHANGE_ERROR error;
++ if (ast_mutex_lock(&capi_put_lock)) {
++ ast_log(LOG_WARNING,"Unable to lock capi put!\n");
++ return -1;
++ }
++ error = capi20_put_cmsg(CMSG);
++ if (ast_mutex_unlock(&capi_put_lock)) {
++ ast_log(LOG_WARNING,"Unable to unlock capi put!\n");
++ return -1;
++ }
++ return error;
++}
++
++
++MESSAGE_EXCHANGE_ERROR check_wait_get_cmsg(_cmsg *CMSG) {
++ MESSAGE_EXCHANGE_ERROR Info;
++ struct timeval tv;
++ tv.tv_sec = 0;
++ tv.tv_usec = 10000;
++ Info = capi20_waitformessage(ast_capi_ApplID,&tv);
++ if ((Info != 0x0000) && (Info != 0x1104)) {
++ if (capidebug) {
++ ast_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info);
++ }
++ return Info;
++ }
++
++ if (Info == 0x0000) {
++ Info = capi_get_cmsg(CMSG,ast_capi_ApplID);
++ }
++ return Info;
++}
++
++
++unsigned ListenOnController(unsigned long CIPmask,unsigned controller) {
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG,CMSG2;
++
++ LISTEN_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, controller);
++#ifdef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++ LISTEN_REQ_INFOMASK(&CMSG) = 0x00ff; // lots of info ;)
++#else
++ LISTEN_REQ_INFOMASK(&CMSG) = 0x03ff; // lots of info ;) + early B3 connect
++#endif
++ LISTEN_REQ_CIPMASK(&CMSG) = CIPmask;
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ return error;
++ }
++ while (!IS_LISTEN_CONF(&CMSG2)) {
++ error = check_wait_get_cmsg(&CMSG2);
++ }
++ return 0;
++}
++
++// Echo cancellation is for cards w/ integrated echo cancellation only
++// (i.e. Eicon active cards support it)
++
++#define EC_FUNCTION_ENABLE 1
++#define EC_FUNCTION_DISABLE 2
++#define EC_FUNCTION_FREEZE 3
++#define EC_FUNCTION_RESUME 4
++#define EC_FUNCTION_RESET 5
++#define EC_OPTION_DISABLE_NEVER 0
++#define EC_OPTION_DISABLE_G165 (1<<1)
++#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2)
++#define EC_DEFAULT_TAIL 64
++
++static int capi_echo_canceller(struct ast_channel *c, int function) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG;
++ unsigned char buf[7];
++
++ /* If echo cancellation is not requested or supported, don't attempt to enable it */
++ ast_mutex_lock(&contrlock);
++ if (!capi_controllers[i->controller]->echocancel || !i->doEC) {
++ ast_mutex_unlock(&contrlock);
++ return 0;
++ }
++ ast_mutex_unlock(&contrlock);
++
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d)\n",i->PLCI,function,i->ecOption,i->ecTail);
++
++ FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ FACILITY_REQ_NCCI(&CMSG) = i->NCCI;
++ FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 6; /* Echo canceller */
++
++ buf[0]=6; /* msg size */
++ buf[1]=function;
++ if (function == EC_FUNCTION_ENABLE) {
++ buf[3]=i->ecOption; /* bit field - ignore echo canceller disable tone */
++ buf[5]=i->ecTail; /* Tail length, ms */
++ }
++ else {
++ buf[3]=0;
++ buf[5]=0;
++ }
++
++ // Always null:
++ buf[2]=0;
++ buf[4]=0;
++ buf[6]=0;
++
++ FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf;
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++ return error;
++ }
++
++ if (option_verbose > 5)
++ ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_REQ (PLCI=%#x)\n",i->PLCI);
++
++ return 0;
++}
++
++int capi_detect_dtmf(struct ast_channel *c, int flag) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG;
++ unsigned char buf[9];
++ // does the controller support dtmf? and do we want to use it?
++ ast_mutex_lock(&contrlock);
++ if ((capi_controllers[i->controller]->dtmf == 1) && (i->doDTMF == 0)) {
++ ast_mutex_unlock(&contrlock);
++ FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ FACILITY_REQ_PLCI(&CMSG) = i->PLCI;
++ FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 1;
++ buf[0] = 8;
++ if (flag == 1) {
++ buf[1] = 1;
++ } else {
++ buf[1] = 2;
++ }
++ buf[2] = 0;
++ buf[3] = AST_CAPI_DTMF_DURATION;
++ buf[4] = 0;
++ buf[5] = AST_CAPI_DTMF_DURATION;
++ buf[6] = 0;
++ buf[7] = 0;
++ buf[8] = 0;
++ FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf;
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++ return error;
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_REQ (PLCI=%#x)\n",i->PLCI);
++ }
++ }
++ } else {
++ ast_mutex_unlock(&contrlock);
++
++#endif
++ // do software dtmf detection
++ i->doDTMF = 1; // just being paranoid again...
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ }
++#endif
++ return 0;
++}
++static int capi_send_digit(struct ast_channel *c,char digit) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG;
++ unsigned char buf[10];
++
++ if (i->state != CAPI_STATE_BCONNECTED) {
++ return 0;
++ }
++
++
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++ if(i->earlyB3 == 1)
++ /* we should really test for the network saying the number is incomplete
++ since i'm only doing a test and this is true at the right time
++ i'm going with this */
++ {
++
++ INFO_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ INFO_REQ_PLCI(&CMSG) = i->PLCI;
++ buf[0] = 2;
++ buf[1] = 0x80;
++ buf[2] = digit;
++ INFO_REQ_CALLEDPARTYNUMBER(&CMSG) = buf;
++
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending CALLEDPARTYNUMBER INFO (error=%#x)\n",error);
++ return error;
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent CALLEDPARTYNUMBER INFO digit = %c (PLCI=%#x)\n", digit, i->PLCI);
++ }
++ }
++
++ } else {
++#endif
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ ast_mutex_lock(&contrlock);
++ if ((capi_controllers[i->controller]->dtmf == 0) || (i->doDTMF == 1)) {
++#endif
++ // let * fake it
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ ast_mutex_unlock(&contrlock);
++#endif
++ return -1;
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ }
++ ast_mutex_unlock(&contrlock);
++
++ FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ FACILITY_REQ_PLCI(&CMSG) = i->NCCI;
++ FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 1;
++ buf[0] = 8;
++
++ buf[1] = 3;
++ buf[2] = 0;
++
++ buf[3] = AST_CAPI_DTMF_DURATION;
++ buf[4] = 0;
++
++ buf[5] = AST_CAPI_DTMF_DURATION;
++ buf[6] = 0;
++
++ buf[7] = 1;
++ buf[8] = digit;
++ buf[9] = 0;
++ FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf;
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++ return error;
++ } else {
++ if (option_verbose > 4) {
++ ast_verbose(VERBOSE_PREFIX_3 "sent dtmf '%c'\n",digit);
++ }
++ }
++#endif
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++ }
++#endif
++ return 0;
++}
++
++static int capi_alert(struct ast_channel *c) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG;
++
++ ALERT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
++ ALERT_REQ_PLCI(&CMSG) = i->PLCI;
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending ALERT_REQ PLCI = %#x\n",i->PLCI);
++ return -1;
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent ALERT_REQ PLCI = %#x\n",i->PLCI);
++ }
++ }
++
++ i->state = CAPI_STATE_ALERTING;
++ return 0;
++}
++
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++static int capi_deflect(struct ast_channel *chan, void *data)
++{
++ struct ast_capi_pvt *i = chan->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR Info;
++ _cmsg CMSG;
++ char bchaninfo[1];
++ char fac[60];
++ int res=0;
++ int ms=3000;
++
++ if (!data) {
++ ast_log(LOG_WARNING, "cd requires an argument (destination phone number)\n");
++ return -1;
++ }
++
++ if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_BCONNECTED)) {
++ ast_log(LOG_ERROR, "call deflection does not work with calls that are already connected!\n");
++ return -1;
++ }
++ // wait until the channel is alerting, so we dont drop the call and interfer with msgs
++ while ((ms > 0) && (i->state != CAPI_STATE_ALERTING)) {
++ sleep(100);
++ ms -= 100;
++ }
++
++ // make sure we hang up correctly
++ i->state = CAPI_STATE_CONNECTPENDING;
++
++ fac[0]=0; // len
++ fac[1]=0; //len
++ fac[2]=0x01; // Use D-Chan
++ fac[3]=0; // Keypad len
++ fac[4]=31; // user user data? len = 31 = 29 + 2
++ fac[5]=0x1c; // magic?
++ fac[6]=0x1d; // strlen destination + 18 = 29
++ fac[7]=0x91; // ..
++ fac[8]=0xA1;
++ fac[9]=0x1A; // strlen destination + 15 = 26
++ fac[10]=0x02;
++ fac[11]=0x01;
++ fac[12]=0x70;
++ fac[13]=0x02;
++ fac[14]=0x01;
++ fac[15]=0x0d;
++ fac[16]=0x30;
++ fac[17]=0x12; // strlen destination + 7 = 18
++ fac[18]=0x30; // ...hm 0x30
++ fac[19]=0x0d; // strlen destination + 2
++ fac[20]=0x80; // CLIP
++ fac[21]=0x0b; // strlen destination
++ fac[22]=0x01; // destination start
++ fac[23]=0x01; //
++ fac[24]=0x01; //
++ fac[25]=0x01; //
++ fac[26]=0x01; //
++ fac[27]=0x01; //
++ fac[28]=0x01; //
++ fac[29]=0x01; //
++ fac[30]=0x01; //
++ fac[31]=0x01; //
++ fac[32]=0x01; //
++ fac[33]=0x01; // 0x1 = sending complete
++ fac[34]=0x01;
++ fac[35]=0x01;
++
++ memcpy((unsigned char *)fac+22,data,strlen(data));
++ fac[22+strlen(data)]=0x01; // fill with 0x01 if number is only 6 numbers (local call)
++ fac[23+strlen(data)]=0x01;
++ fac[24+strlen(data)]=0x01;
++ fac[25+strlen(data)]=0x01;
++ fac[26+strlen(data)]=0x01;
++
++ fac[6]=18+strlen(data);
++ fac[9]=15+strlen(data);
++ fac[17]=7+strlen(data);
++ fac[19]=2+strlen(data);
++ fac[21]=strlen(data);
++
++ bchaninfo[0] = 0x1;
++ INFO_REQ_HEADER(&CMSG,ast_capi_ApplID,ast_capi_MessageNumber++,0);
++ INFO_REQ_CONTROLLER(&CMSG) = i->controller;
++ INFO_REQ_PLCI(&CMSG) = i->PLCI;
++ INFO_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char*)bchaninfo; // use D-Channel
++ INFO_REQ_KEYPADFACILITY(&CMSG) = 0;
++ INFO_REQ_USERUSERDATA(&CMSG) = 0;
++ INFO_REQ_FACILITYDATAARRAY(&CMSG) = (unsigned char*) fac + 4;
++
++ if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"Error sending INFO_REQ\n");
++ return Info;
++ } else {
++ if (capidebug) {
++ // ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG));
++ ast_log(LOG_NOTICE,"sent INFO_REQ PLCI = %#x\n",i->PLCI);
++ }
++ }
++
++ return res;
++}
++#endif
++
++void remove_pipe(int PLCI) {
++ struct capi_pipe *p,*ptmp;
++
++ ast_mutex_lock(&pipelock);
++ p = pipelist;
++ ptmp = NULL;
++ while (p) {
++ if (p->PLCI == PLCI) {
++ if (ptmp == NULL) {
++ // mypipe == head of pipelist
++ pipelist = p->next;
++ if(p->fd > -1) close(p->fd);
++ if(p->i != NULL && p->i->fd > -1) close(p->i->fd);
++ free(p);
++ if (option_verbose > 4) {
++ ast_verbose(VERBOSE_PREFIX_3 "removed pipe for PLCI = %#x\n",PLCI);
++ }
++ break;
++ } else {
++ // somehwere inbetween or at the end
++ ptmp->next = p->next;
++ if (p->next == NULL) {
++ capi_last_plci = p->PLCI;
++ }
++ if(p->fd > -1) close(p->fd);
++ if(p->i != NULL && p->i->fd > -1) close(p->i->fd);
++ free(p);
++ if (option_verbose > 4) {
++ ast_verbose(VERBOSE_PREFIX_3 "removed pipe for PLCI = %#x\n",PLCI);
++ }
++ break;
++ }
++ }
++ ptmp = p;
++ p = p->next;
++ }
++ ast_mutex_unlock(&pipelock);
++}
++
++static int capi_activehangup(struct ast_channel *c) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG;
++
++ if (option_verbose > 2) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "activehangingup\n");
++ }
++
++ if (i == NULL) {
++ return 0;
++ }
++
++ if (c->_state == AST_STATE_RING) {
++ CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
++ CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
++ CONNECT_RESP_REJECT(&CMSG) = 2;
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",i->PLCI);
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",i->PLCI);
++ }
++ }
++ return 0;
++ }
++
++ // active disconnect
++ if (i->state == CAPI_STATE_BCONNECTED) {
++ DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++ }
++ }
++ // wait for the B3 layer to go down
++ while (i->state != CAPI_STATE_CONNECTED) {
++ usleep(10000);
++ }
++ }
++ if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_CONNECTPENDING)){
++ DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
++
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR, "error sending DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++ }
++ }
++ // wait for the B1 layer to go down
++ while (i->state != CAPI_STATE_DISCONNECTED) {
++ usleep(10000);
++ }
++ }
++ return 0;
++}
++
++static int capi_hangup(struct ast_channel *c) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++
++ // hmm....ok...this is called to free the capi interface (passive disconnect)
++ // or to bring down the channel (active disconnect)
++
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_3 "CAPI Hangingup\n");
++
++ if (i == NULL) {
++ ast_log(LOG_ERROR,"channel has no interface!\n");
++ return -1;
++ }
++
++ // are we down, yet?
++ if (i->state != CAPI_STATE_DISCONNECTED) {
++ // no
++ capi_activehangup(c);
++ }
++
++ remove_pipe(i->PLCI);
++ i->PLCI = 0;
++ i->NCCI = 0;
++ if ((i->doDTMF == 1) && (i->vad != NULL)) {
++ ast_dsp_free(i->vad);
++ }
++ ast_smoother_free(i->smoother); // discard any frames left hanging
++ i->smoother=ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE * 2);
++ memset(i->cid,0,sizeof(i->cid));
++ i->owner=NULL;
++ ast_mutex_lock(&usecnt_lock);
++ usecnt--;
++ ast_mutex_unlock(&usecnt_lock);
++ ast_update_use_count();
++ i->mypipe = NULL;
++ i = NULL;
++ c->tech_pvt = NULL;
++ ast_setstate(c,AST_STATE_DOWN);
++ return 0;
++}
++
++static char *capi_number(char *data,int strip) {
++ unsigned len = *data;
++ // XXX fix me
++ // convert a capi struct to a \0 terminated string
++ if (!len || len < (unsigned int) strip) return NULL;
++ len = len - strip;
++ data = (char *)(data + 1 + strip);
++ return strndup((char *)data,len);
++}
++
++int capi_call(struct ast_channel *c, char *idest, int timeout)
++{
++ struct ast_capi_pvt *i;
++ struct capi_pipe *p = NULL;
++ int fds[2];
++ char *dest,*interface;
++ char buffer[AST_MAX_EXTENSION];
++ char called[AST_MAX_EXTENSION],calling[AST_MAX_EXTENSION];
++ char bchaninfo[3];
++ long flags;
++
++ _cmsg CMSG;
++ MESSAGE_EXCHANGE_ERROR error;
++
++ strncpy(buffer,idest,sizeof(buffer)-1);
++ interface = strtok(buffer, "/");
++ dest = strtok(NULL, "/");
++
++
++ if (!dest) {
++ ast_log(LOG_WARNING, "Destination %s requires a real destination\n", idest);
++ return -1;
++ }
++ i = c->tech_pvt;
++ i->doB3 = AST_CAPI_B3_DONT; // <homer>DOH</homer>
++
++ // always B3
++ if (((char *)dest)[0] == 'b') {
++ i->doB3 = AST_CAPI_B3_ALWAYS;
++ }
++ // only do B3 on successfull calls
++ if (((char *)dest)[0] == 'B') {
++ i->doB3 = AST_CAPI_B3_ON_SUCCESS;
++ }
++
++ if (i->doB3 != AST_CAPI_B3_DONT) {
++ dest++;
++ }
++
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_2 "CAPI Call %s %s", c->name, i->doB3?"with B3":"");
++ }
++ switch (c->cid.cid_pres) {
++ case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
++ case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
++ case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
++ case PRES_ALLOWED_NETWORK_NUMBER:
++ case PRES_NUMBER_NOT_AVAILABLE:
++ i->CLIR = 0;
++ break;
++ 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:
++ i->CLIR = 1;
++ break;
++ default:
++ i->CLIR = 0;
++ }
++
++ if (pipe(fds) == 0) {
++ ast_mutex_lock(&pipelock);
++ i->fd = fds[0];
++ flags = fcntl(i->fd,F_GETFL);
++ fcntl(i->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++ p = malloc(sizeof(struct capi_pipe));
++ memset(p, 0, sizeof(struct capi_pipe));
++ p->fd = fds[1];
++ flags = fcntl(i->fd,F_GETFL);
++ fcntl(p->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++ c->fds[0] = i->fd;
++ p->PLCI = -1;
++ p->i = i;
++ p->c = c;
++ i->mypipe = p;
++ p->next = pipelist;
++ pipelist = p;
++ if (option_verbose > 4) {
++ ast_verbose(VERBOSE_PREFIX_3 "creating pipe for PLCI=-1\n");
++ }
++ ast_mutex_unlock(&pipelock);
++ }
++ i->outgoing = 1;
++
++ i->MessageNumber = ast_capi_MessageNumber++;
++ CONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, i->controller);
++ CONNECT_REQ_CONTROLLER(&CMSG) = i->controller;
++ CONNECT_REQ_CIPVALUE(&CMSG) = 0x10; // Telephony, could also use 0x04 (3.1Khz audio)
++ called[0] = strlen(dest)+1;
++ called[1] = 0x80;
++ strncpy(&called[2],dest,sizeof(called)-2);
++ CONNECT_REQ_CALLEDPARTYNUMBER(&CMSG) = (unsigned char *)called;
++ CONNECT_REQ_CALLEDPARTYSUBADDRESS(&CMSG) = NULL;
++
++ if (c->cid.cid_num) {
++ calling[0] = strlen(c->cid.cid_num)+2;
++ calling[1] = 0x0;
++ } else {
++ calling[0] = 0x0;
++ calling[1] = 0x0;
++ }
++
++ if (i->CLIR == 1) {
++ calling[2] = 0xA0; // CLIR
++ } else {
++ calling[2] = 0x80; // CLIP
++ }
++
++ if (c->cid.cid_num) {
++ strncpy(&calling[3],c->cid.cid_num,sizeof(calling)-3);
++ }
++ CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = (unsigned char *)calling;
++ CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = NULL;
++
++ CONNECT_REQ_B1PROTOCOL(&CMSG) = 1;
++ CONNECT_REQ_B2PROTOCOL(&CMSG) = 1; // 1
++ CONNECT_REQ_B3PROTOCOL(&CMSG) = 0;
++
++ bchaninfo[0] = 2;
++ bchaninfo[1] = 0x0;
++ bchaninfo[2] = 0x0;
++ CONNECT_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char *)bchaninfo; // 0
++
++ if ((error = _capi_put_cmsg(&CMSG))) {
++ ast_log(LOG_ERROR,"error sending CONNECT_REQ (error=%#x)\n",error);
++ return error;
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_REQ MN =%#x\n",CMSG.Messagenumber);
++ }
++ }
++
++ i->state = CAPI_STATE_CONNECTPENDING;
++
++ ast_setstate(c, AST_STATE_DIALING);
++
++ // XXX fixme, not nice:
++/* if (i->controller > 0) {
++ capi_controllers[i->controller]->nfreebchannels--;
++ } */
++
++ // now we shall return .... the rest has to be done by handle_msg
++ return 0;
++}
++
++
++static int capi_answer(struct ast_channel *c) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG;
++ char buf[AST_MAX_EXTENSION];
++ char *dnid;
++
++ if (i->isdnmode && (strlen(i->incomingmsn)<strlen(i->dnid)))
++ dnid = i->dnid + strlen(i->incomingmsn);
++ else
++ dnid = i->dnid;
++
++ CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
++ CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
++ CONNECT_RESP_REJECT(&CMSG) = 0;
++ buf[0] = strlen(dnid)+2;
++ buf[1] = 0x0;
++ buf[2] = 0x80;
++ strncpy(&buf[3],dnid,sizeof(buf)-4);
++ CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = (unsigned char *)buf;
++ CONNECT_RESP_CONNECTEDSUBADDRESS(&CMSG) = NULL;
++ CONNECT_RESP_LLC(&CMSG) = NULL;
++ CONNECT_RESP_B1PROTOCOL(&CMSG) = 1;
++ CONNECT_RESP_B2PROTOCOL(&CMSG) = 1;
++ CONNECT_RESP_B3PROTOCOL(&CMSG) = 0;
++
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_3 "CAPI Answering for MSN %s\n", dnid);
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ return -1;
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP PLCI = %#x DNID = %s\n",i->PLCI,i->dnid);
++ }
++ }
++
++ i->state = CAPI_STATE_ANSWERING;
++ i->doB3 = AST_CAPI_B3_DONT;
++ i->outgoing = 0;
++ i->earlyB3 = -1;
++
++ return 0;
++}
++
++struct ast_frame *capi_read(struct ast_channel *c) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ int readsize = 0;
++
++ if ((i->state == CAPI_STATE_REMOTE_HANGUP)) {
++ ast_log(LOG_ERROR,"this channel is not connected\n");
++ return NULL;
++ }
++ if (i->state == CAPI_STATE_ONHOLD) {
++ i->fr.frametype = AST_FRAME_NULL;
++ return &i->fr;
++ }
++
++ if (i == NULL) {
++ ast_log(LOG_ERROR,"channel has no interface\n");
++ return NULL;
++ }
++ i->fr.frametype = AST_FRAME_NULL;
++ i->fr.subclass = 0;
++ i->fr.delivery.tv_sec = 0;
++ i->fr.delivery.tv_usec = 0;
++ readsize = read(i->fd,&i->fr,sizeof(struct ast_frame));
++ if (readsize != sizeof(struct ast_frame)) {
++ ast_log(LOG_ERROR,"did not read a whole frame\n");
++ }
++ if (i->fr.frametype == AST_FRAME_VOICE) {
++ readsize = read(i->fd,i->fr.data,i->fr.datalen);
++ if (readsize != i->fr.datalen) {
++ ast_log(LOG_ERROR,"did not read whole frame data\n");
++ }
++ }
++ i->fr.mallocd = 0;
++ if (i->fr.frametype == AST_FRAME_NULL) {
++ return NULL;
++ }
++ if ((i->fr.frametype == AST_FRAME_DTMF) && (i->fr.subclass == 'f')) {
++ if (strcmp(c->exten, "fax")) {
++ if (ast_exists_extension(c, ast_strlen_zero(c->macrocontext) ? c->context : c->macrocontext, "fax", 1, c->cid.cid_num)) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", c->name);
++ /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
++ pbx_builtin_setvar_helper(c,"FAXEXTEN",c->exten);
++ if (ast_async_goto(c, c->context, "fax", 1))
++ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", c->name, c->context);
++ } else {
++ ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
++ }
++ } else {
++ ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
++ }
++ }
++ return &i->fr;
++}
++
++int capi_write(struct ast_channel *c, struct ast_frame *f) {
++ struct ast_capi_pvt *i = c->tech_pvt;
++ _cmsg CMSG;
++ MESSAGE_EXCHANGE_ERROR error;
++ int j=0;
++ char buf[1000];
++ struct ast_frame *fsmooth;
++#ifdef CAPI_ES
++ int txavg=0;
++#endif
++
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++ // dont send audio to the local exchange!
++ if (i->earlyB3 == 1 || !i->NCCI) {
++ return 0;
++ }
++#endif
++
++ if (!i) {
++ ast_log(LOG_ERROR,"channel has no interface\n");
++ return -1;
++ }
++
++ if (f->frametype == AST_FRAME_NULL) {
++ return 0;
++ }
++ if (f->frametype == AST_FRAME_DTMF) {
++ ast_log(LOG_ERROR,"dtmf frame should be written\n");
++ return 0;
++ }
++ if (f->frametype != AST_FRAME_VOICE) {
++ ast_log(LOG_ERROR,"not a voice frame\n");
++ return -1;
++ }
++ if (f->subclass != capi_capability) {
++ ast_log(LOG_ERROR,"dont know how to write subclass %d\n",f->subclass);
++ return -1;
++ }
++// ast_log(LOG_NOTICE,"writing frame %d %d\n",f->frametype,f->subclass);
++
++ if (ast_smoother_feed(i->smoother, f)!=0) {
++ ast_log(LOG_ERROR,"failed to fill smoother\n");
++ return -1;
++ }
++
++ fsmooth=ast_smoother_read(i->smoother);
++ while(fsmooth != NULL) {
++ DATA_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DATA_B3_REQ_NCCI(&CMSG) = i->NCCI;
++ DATA_B3_REQ_DATALENGTH(&CMSG) = fsmooth->datalen;
++ DATA_B3_REQ_FLAGS(&CMSG) = 0;
++
++ if (ast_mutex_lock(&capi_send_buffer_lock)) {
++ ast_log(LOG_WARNING,"Unable to lock B3 send buffer!\n");
++ return -1;
++ }
++#ifndef CAPI_ES
++#ifdef CAPI_GAIN
++ for (j=0;j<fsmooth->datalen;j++) {
++ buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]];
++ }
++#else
++ for (j=0;j<fsmooth->datalen;j++) {
++ buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ];
++ }
++#endif
++#else
++ if ((i->doES == 1)) {
++ for (j=0;j<fsmooth->datalen;j++) {
++ buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ];
++ txavg += abs( capiXLAW2INT(reversebits[ ((unsigned char*)fsmooth->data)[j]]) );
++ }
++ txavg = txavg/j;
++ for(j=0;j<ECHO_TX_COUNT-1;j++) {
++ i->txavg[j] = i->txavg[j+1];
++ }
++ i->txavg[ECHO_TX_COUNT-1] = txavg;
++
++// ast_log(LOG_NOTICE,"txavg = %d\n",txavg);
++ } else {
++#ifdef CAPI_GAIN
++ for (j=0;j<fsmooth->datalen;j++) {
++ buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]];
++ }
++#else
++ for (j=0;j<fsmooth->datalen;j++) {
++ buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ];
++ }
++#endif
++ }
++#endif
++
++ DATA_B3_REQ_DATAHANDLE(&CMSG) = capi_send_buffer_handle;
++ memcpy((char *)&capi_send_buffer[(capi_send_buffer_handle % AST_CAPI_MAX_B3_BLOCKS) * AST_CAPI_MAX_B3_BLOCK_SIZE],&buf,fsmooth->datalen);
++ DATA_B3_REQ_DATA(&CMSG) = (unsigned char *)&capi_send_buffer[(capi_send_buffer_handle % AST_CAPI_MAX_B3_BLOCKS) * AST_CAPI_MAX_B3_BLOCK_SIZE];
++ capi_send_buffer_handle++;
++
++ if (ast_mutex_unlock(&capi_send_buffer_lock)) {
++ ast_log(LOG_WARNING,"Unable to unlock B3 send buffer!\n");
++ return -1;
++ }
++
++
++#ifdef CAPI_SYNC
++ ast_mutex_lock(&i->lockB3in);
++ if ((i->B3in >= 1) && (i->B3in <= AST_CAPI_MAX_B3_BLOCKS)) {
++ i->B3in--;
++ ast_mutex_unlock(&i->lockB3in);
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending DATA_B3_REQ (error=%#x, datalen=%d) B3in=%d\n",error,fsmooth->datalen,i->B3in);
++// ast_log(LOG_NOTICE,"f: timelen %d b = %d MN = %d \n",fsmooth->timelen,b,CMSG.Messagenumber);
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DATA_B3_REQ (NCCI=%#x) (%d bytes)\n",i->NCCI,fsmooth->datalen);
++ }
++ }
++ } else {
++ if (i->B3in > 0) i->B3in--;
++ ast_mutex_unlock(&i->lockB3in);
++ }
++#else
++ if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending DATA_B3_REQ (error=%#x, datalen=%d)\n",error,fsmooth->datalen);
++// ast_log(LOG_NOTICE,"f: timelen %d b = %d MN = %d \n",fsmooth->timelen,b,CMSG.Messagenumber);
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DATA_B3_REQ (NCCI=%#x) (%d bytes)\n",i->NCCI,fsmooth->datalen);
++ }
++ }
++#endif
++
++// ast_frfree(fsmooth);
++
++ fsmooth=ast_smoother_read(i->smoother);
++ }
++ return 0;
++}
++
++static int capi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) {
++ struct ast_capi_pvt *p = newchan->tech_pvt;
++ p->owner = newchan;
++ return 0;
++}
++
++int capi_indicate(struct ast_channel *c,int condition) {
++ return -1;
++}
++
++int capi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) {
++ return -1;
++}
++
++
++struct ast_channel *capi_new(struct ast_capi_pvt *i,int state) {
++ struct ast_channel *tmp;
++ int fmt;
++
++ tmp = ast_channel_alloc(1);
++ if (tmp != NULL) {
++ snprintf(tmp->name,sizeof(tmp->name),"CAPI/contr%d/%s-%d",i->controller,i->dnid,capi_counter++);
++ tmp->type = type;
++ tmp->tech = &capi_tech;
++ tmp->nativeformats = capi_capability;
++ ast_setstate(tmp,state);
++ tmp->fds[0] = i->fd;
++ i->smoother = ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE);
++ if (i->smoother == NULL) {
++ ast_log(LOG_ERROR, "smoother NULL!\n");
++ }
++ i->fr.frametype = 0;
++ i->fr.subclass = 0;
++ i->fr.delivery.tv_sec = 0;
++ i->fr.delivery.tv_usec = 0;
++ i->state = CAPI_STATE_DISCONNECTED;
++ i->CLIR = 0;
++ i->calledPartyIsISDN = 0; // let's be pessimistic
++ i->earlyB3 = -1;
++ i->doB3 = AST_CAPI_B3_DONT;
++ i->outgoing = 0;
++ i->onholdPLCI = 0;
++#ifdef CAPI_SYNC
++ i->B3in = 0;
++ ast_mutex_init(&i->lockB3in);
++#endif
++#ifdef CAPI_ES
++ memset(i->txavg,0,ECHO_TX_COUNT);
++#endif
++
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ if (i->doDTMF == 1) {
++#endif
++ i->vad = ast_dsp_new();
++ ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ }
++#endif
++
++ tmp->tech_pvt = i;
++ tmp->callgroup = i->callgroup;
++ tmp->nativeformats = capi_capability;
++ fmt = ast_best_codec(tmp->nativeformats);
++// fmt = capi_capability;
++ tmp->readformat = fmt;
++ tmp->writeformat = fmt;
++ tmp->rawreadformat = fmt;
++ tmp->rawwriteformat = fmt;
++ strncpy(tmp->context,i->context,sizeof(tmp->context)-1);
++ tmp->cid.cid_num = strdup(i->cid);
++ tmp->cid.cid_dnid = strdup(i->dnid);
++ strncpy(tmp->exten,i->dnid,sizeof(tmp->exten)-1);
++ strncpy(tmp->accountcode,i->accountcode,sizeof(tmp->accountcode)-1);
++ i->owner = tmp;
++ ast_mutex_lock(&usecnt_lock);
++ usecnt++;
++ ast_mutex_unlock(&usecnt_lock);
++ ast_update_use_count();
++ if (state != AST_STATE_DOWN) {
++ // we are alerting (phones ringing)
++ if (state == AST_STATE_RING)
++ capi_alert(tmp);
++ if (ast_pbx_start(tmp)) {
++ ast_log(LOG_ERROR,"Unable to start pbx on channel!\n");
++ ast_hangup(tmp);
++ tmp = NULL;
++ } else {
++ if (option_verbose > 2) {
++ ast_verbose(VERBOSE_PREFIX_3 "started pbx on channel (callgroup=%d)!\n",tmp->callgroup);
++ }
++ }
++ }
++ } else {
++ ast_log(LOG_ERROR,"Unable to allocate channel!\n");
++ }
++ return tmp;
++}
++
++
++struct ast_channel *capi_request(const char *type, int format, void *data, int *cause)
++{
++ struct ast_capi_pvt *i;
++ struct ast_channel *tmp = NULL;
++ char *dest,*interface;
++ char buffer[AST_MAX_EXTENSION];
++ unsigned int capigroup=0, controller=0;
++ int notfound = 1;
++
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "data = %s\n",(char *)data);
++ }
++ strncpy(buffer,(char *)data,sizeof(buffer)-1);
++
++ interface = strtok(buffer, "/");
++ dest = strtok(NULL, "/");
++
++
++ if (((char *)interface)[0] == 'g') {
++ interface++;
++ capigroup = atoi(interface);
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "capi request group = %d\n",capigroup);
++ }
++ } else if (!strncmp(interface,"contr",5)) {
++ interface += 5;
++ controller = atoi(interface);
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "capi request controller = %d\n",controller);
++ }
++ } else {
++ ast_log(LOG_ERROR,"Syntax error in dialstring. read the docs!\n");
++ }
++
++ ast_mutex_lock(&iflock);
++ i = iflist;
++ while (i && notfound) {
++ // unused channel
++ if (!i->owner) {
++ if (controller && (i->controllers & (1 << controller))) {
++ // DIAL(CAPI/contrX/...)
++ ast_mutex_lock(&contrlock);
++ if (capi_controllers[controller]->nfreebchannels > 0) {
++ strncpy(i->dnid,dest,sizeof(i->dnid)-1);
++ i->controller = controller;
++ tmp = capi_new(i, AST_STATE_DOWN);
++ i->PLCI = -1;
++ i->datahandle = 0;
++ i->outgoing = 1; // this is an outgoing line
++ i->earlyB3 = -1;
++ // capi_detect_dtmf(tmp,1);
++ ast_mutex_unlock(&contrlock);
++ ast_mutex_unlock(&iflock);
++ return tmp;
++ } else {
++ // keep on running!
++ ast_mutex_unlock(&contrlock);
++ }
++ } else if (capigroup && (i->group & (1 << capigroup))) {
++ int c;
++ // DIAL(CAPI/gX/...)
++ ast_mutex_lock(&contrlock);
++ for (c=1;c<=capi_num_controllers;c++) {
++ if (i->controllers & (1 << c)) {
++ if (capi_controllers[c]->nfreebchannels > 0) {
++ strncpy(i->dnid,dest,sizeof(i->dnid)-1);
++ i->controller = c;
++ tmp = capi_new(i, AST_STATE_DOWN);
++ i->PLCI = -1;
++ i->datahandle = 0;
++ i->outgoing = 1; // this is an outgoing line
++ i->earlyB3 = -1;
++ // capi_detect_dtmf(tmp,1);
++ ast_mutex_unlock(&contrlock);
++ ast_mutex_unlock(&iflock);
++ return tmp;
++ } else {
++ // keep on running!
++ }
++ }
++ }
++ ast_mutex_unlock(&contrlock);
++ }
++ }
++// ast_log(LOG_NOTICE,"not contr %d group %d\n",i->controllers, i->group);
++ i = i->next;
++ }
++ ast_mutex_unlock(&iflock);
++ ast_log(LOG_NOTICE,"didn't find capi device with controller = %d or group = %d.\n",controller, capigroup);
++ return NULL;
++}
++
++
++struct capi_pipe *find_pipe(int PLCI,int MN) {
++ struct capi_pipe *p;
++ // find a pipe by PLCI or by MessageNumber (in case this is a CONNECT_CONF)
++ ast_mutex_lock(&pipelock);
++ p = pipelist;
++ if ((p == NULL) && (capi_last_plci != PLCI)){
++ if (capidebug) {
++ ast_log(LOG_NOTICE,"PLCI doesnt match last pipe (PLCI = %#x)\n",PLCI);
++ }
++ ast_mutex_unlock(&pipelock);
++ return NULL;
++ }
++ while(p != NULL) {
++ if ((p->PLCI == PLCI) || ( (p->PLCI == -1) && (p->i->MessageNumber == MN) ) ){
++ ast_mutex_unlock(&pipelock);
++ return p;
++ }
++ p = p->next;
++ }
++ if (capidebug) {
++ ast_log(LOG_ERROR,"unable to find a pipe for PLCI = %#x MN = %#x\n",PLCI,MN);
++ }
++ ast_mutex_unlock(&pipelock);
++ return NULL;
++}
++
++int pipe_frame(struct capi_pipe *p,struct ast_frame *f) {
++ fd_set wfds;
++ int written=0;
++ struct timeval tv;
++ FD_ZERO(&wfds);
++ FD_SET(p->fd,&wfds);
++ tv.tv_sec = 0;
++ tv.tv_usec = 10;
++ if ((f->frametype == AST_FRAME_VOICE) && (p->i->doDTMF == 1) && (p->i->vad != NULL)) {
++ f = ast_dsp_process(p->c,p->i->vad,f);
++ if (f->frametype == AST_FRAME_NULL) {
++ return 0;
++ }
++ }
++ // we dont want the monitor thread to block
++ if (select(p->fd + 1,NULL,&wfds,NULL,&tv) == 1) {
++ written = write(p->fd,f,sizeof(struct ast_frame));
++ if (written < (signed int) sizeof(struct ast_frame)) {
++ ast_log(LOG_ERROR,"wrote %d bytes instead of %d\n", written, (int)sizeof(struct ast_frame));
++ return -1;
++ }
++ if (f->frametype == AST_FRAME_VOICE) {
++ written = write(p->fd,f->data,f->datalen);
++ if (written < f->datalen) {
++ ast_log(LOG_ERROR,"wrote %d bytes instead of %d\n",written,f->datalen);
++ return -1;
++ }
++ }
++ } else {
++ return 0;
++ }
++ return -1;
++}
++
++static int search_did(struct ast_channel *c)
++{
++ // Returns
++ // -1 = Failure
++ // 0 = Match
++ // 1 = possible match
++ struct ast_capi_pvt *i = c->tech_pvt;
++ char *exten;
++
++ if (strlen(i->dnid)<strlen(i->incomingmsn))
++ return -1;
++
++// exten = i->dnid + strlen(i->incomingmsn);
++ exten = i->dnid;
++
++ if (ast_exists_extension(NULL, c->context, exten, 1, NULL)) {
++ c->priority = 1;
++ strncpy(c->exten, exten, sizeof(c->exten) - 1);
++ return 0;
++ }
++
++ if (ast_canmatch_extension(NULL, c->context, exten, 1, NULL)) {
++ return 1;
++ }
++
++
++ return -1;
++}
++
++int pipe_msg(int PLCI,_cmsg *CMSG) {
++ struct capi_pipe *p;
++ _cmsg CMSG2;
++ MESSAGE_EXCHANGE_ERROR error;
++ struct ast_frame fr;
++ char b3buf[1024];
++ int j;
++ int b3len=0;
++ char dtmf;
++ unsigned dtmflen;
++#ifdef CAPI_ES
++ int rxavg = 0;
++ int txavg = 0;
++#endif
++
++ p = find_pipe(PLCI,CMSG->Messagenumber);
++ if (p == NULL) {
++ if (IS_DISCONNECT_IND(CMSG)) {
++ DISCONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber , 0);
++ DISCONNECT_RESP_PLCI(&CMSG2) = PLCI;
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_RESP PLCI=%#x\n",PLCI);
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_RESP PLCI=%#x\n",PLCI);
++ }
++ }
++ return 0;
++ }
++ if (capidebug) {
++ ast_log(LOG_NOTICE,"%s",capi_cmsg2str(CMSG));
++ }
++ return -1;
++ }
++
++ if (CMSG != NULL) {
++ switch (CMSG->Subcommand) {
++ case CAPI_IND:
++ switch (CMSG->Command) {
++ case CAPI_DISCONNECT_B3:
++// ast_log(LOG_NOTICE,"DISCONNECT_B3_IND\n");
++
++ DISCONNECT_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++ DISCONNECT_B3_RESP_NCCI(&CMSG2) = DISCONNECT_B3_IND_NCCI(CMSG);
++
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_B3_RESP NCCI=%#x\n",(int)DISCONNECT_B3_IND_NCCI(CMSG));
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_B3_RESP NCCI=%#x\n",(int)DISCONNECT_B3_IND_NCCI(CMSG));
++ }
++ }
++ if (p->i->state == CAPI_STATE_BCONNECTED) {
++ // passive disconnect
++ p->i->state = CAPI_STATE_CONNECTED;
++ } else
++ if (p->i->state == CAPI_STATE_DISCONNECTING) {
++ // active disconnect
++ memset(&CMSG2,0,sizeof(_cmsg));
++ DISCONNECT_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_REQ_PLCI(&CMSG2) = PLCI;
++
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",PLCI);
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_REQ PLCI=%#x\n",PLCI);
++ }
++ }
++ } else
++ if (p->i->state == CAPI_STATE_ONHOLD) {
++ // no hangup
++ }
++ ast_mutex_lock(&contrlock);
++ if (p->i->controller > 0) {
++ capi_controllers[p->i->controller]->nfreebchannels++;
++ }
++ ast_mutex_unlock(&contrlock);
++ break;
++ case CAPI_DISCONNECT:
++// ast_log(LOG_NOTICE,"DISCONNECT_IND\n");
++ DISCONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber , 0);
++ DISCONNECT_RESP_PLCI(&CMSG2) = PLCI;
++/* if (p->i->controller > 0) {
++ capi_controllers[p->i->controller]->nfreebchannels++;
++ } */
++
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_RESP PLCI=%#x\n",PLCI);
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_RESP PLCI=%#x\n",PLCI);
++ }
++ }
++ if (p->c) {
++ p->c->hangupcause = DISCONNECT_IND_REASON(CMSG) - 0x3480;
++ }
++
++ if (PLCI == p->i->onholdPLCI) {
++ // the caller onhold hung up (or ECTed away)
++ p->i->onholdPLCI = 0;
++ remove_pipe(PLCI);
++ return 0;
++ }
++
++ if (p->i->state == CAPI_STATE_DID) {
++ if ((p->c) != NULL) {
++ ast_hangup(p->c);
++ } else {
++ ast_log(LOG_WARNING, "unable to hangup channel on DID. Channel is NULL.\n");
++ }
++ return 0;
++ }
++
++ p->i->state = CAPI_STATE_DISCONNECTED;
++
++ fr.frametype = AST_FRAME_CONTROL;
++ if (DISCONNECT_IND_REASON(CMSG) == 0x34a2) {
++ fr.subclass = AST_CONTROL_BUSY;
++ } else {
++ fr.frametype = AST_FRAME_NULL;
++ }
++ fr.datalen = 0;
++ if (pipe_frame(p,(struct ast_frame *)&fr) == -1) {
++ // printf("STATE = %#x\n",p->i->state);
++ // in this case * did not read our hangup control frame
++ // so we must hangup the channel!
++ if ( (p->i->state != CAPI_STATE_DISCONNECTED) && (ast_check_hangup(p->c) == 0)) {
++ if (option_verbose > 1) {
++ ast_verbose(VERBOSE_PREFIX_3 "soft hangup by capi\n");
++ }
++ ast_softhangup(p->c,AST_SOFTHANGUP_DEV);
++ } else {
++ // dont ever hangup while hanging up!
++// ast_log(LOG_NOTICE,"no soft hangup by capi\n");
++ }
++ return -1;
++ } else {
++ return 0;
++ }
++
++/* fr.frametype = AST_FRAME_NULL;
++ fr.datalen = 0;
++ pipe_frame(p,(struct ast_frame *)&fr); */
++ break;
++ case CAPI_DATA_B3:
++
++ memcpy(&b3buf[AST_FRIENDLY_OFFSET],(char *)DATA_B3_IND_DATA(CMSG),DATA_B3_IND_DATALENGTH(CMSG));
++ b3len = DATA_B3_IND_DATALENGTH(CMSG);
++
++ // send a DATA_B3_RESP very quickly to free the buffer in capi
++ DATA_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber,0);
++ DATA_B3_RESP_NCCI(&CMSG2) = DATA_B3_IND_NCCI(CMSG);
++ DATA_B3_RESP_DATAHANDLE(&CMSG2) = DATA_B3_IND_DATAHANDLE(CMSG);
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending DATA_B3_RESP (error=%#x)\n",error);
++ } else {
++ if (option_verbose > 6) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DATA_B3_RESP (NCCI=%#x)\n",(int)DATA_B3_IND_NCCI(CMSG));
++ }
++ }
++#ifdef CAPI_SYNC
++ ast_mutex_lock(&p->i->lockB3in);
++ p->i->B3in++;
++ if (p->i->B3in > AST_CAPI_MAX_B3_BLOCKS) p->i->B3in = AST_CAPI_MAX_B3_BLOCKS;
++ ast_mutex_unlock(&p->i->lockB3in);
++#endif
++#ifdef CAPI_ES
++ if ((p->i->doES == 1)) {
++ for (j=0;j<b3len;j++) {
++ b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]];
++ rxavg += abs(capiXLAW2INT( reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]));
++ }
++ rxavg = rxavg/j;
++ for(j=0;j<ECHO_EFFECTIVE_TX_COUNT;j++) {
++ txavg += p->i->txavg[j];
++ }
++ txavg = txavg/j;
++
++ if( (txavg/ECHO_TXRX_RATIO) > rxavg) {
++#ifdef CAPI_ULAW
++ memset(&b3buf[AST_FRIENDLY_OFFSET],255,b3len);
++#else
++ memset(&b3buf[AST_FRIENDLY_OFFSET],84,b3len);
++#endif
++ if (capidebug) {
++ ast_log(LOG_NOTICE,"SUPPRESSING ECHOrx=%d, tx=%d\n",rxavg,txavg);
++ }
++ }
++ } else {
++#ifdef CAPI_GAIN
++ for (j=0;j<b3len;j++) {
++ b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[p->i->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]];
++ }
++#else
++ for (j=0;j<b3len;j++) {
++ b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]];
++ }
++#endif
++ }
++#else
++
++#ifdef CAPI_GAIN
++ for (j=0;j<b3len;j++) {
++ b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[p->i->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]];
++ }
++#else
++ for (j=0;j<b3len;j++) {
++ b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]];
++ }
++#endif
++
++#endif
++ // just being paranoid ...
++ /* if (p->c->_state != AST_STATE_UP) {
++ ast_setstate(p->c,AST_STATE_UP);
++ } */
++
++ fr.frametype = AST_FRAME_VOICE;
++ fr.subclass = capi_capability;
++ fr.data = (char *)&b3buf[AST_FRIENDLY_OFFSET];
++ fr.datalen = b3len;
++ fr.samples = b3len;
++ fr.offset = AST_FRIENDLY_OFFSET;
++ fr.mallocd = 0;
++ fr.delivery.tv_sec = 0;
++ fr.delivery.tv_usec = 0;
++ fr.src = NULL;
++ // ast_verbose(VERBOSE_PREFIX_3 "DATA_B3_IND (len=%d) fr.datalen=%d fr.subclass=%d\n",(int)DATA_B3_IND_DATALENGTH(CMSG),fr.datalen,fr.subclass);
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ break;
++ case CAPI_FACILITY:
++ if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0001) {
++ // DTMF received
++ if (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] != (0xff)) {
++ dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0];
++ FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 1;
++ } else {
++ dtmflen = ((__u16 *) (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) + 1))[0];
++ FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 3;
++ }
++ if (dtmflen == 1) {
++ dtmf = (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG))[0];
++ fr.frametype = AST_FRAME_DTMF;
++ fr.subclass = dtmf;
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "c_dtmf = %c\n",dtmf);
++ }
++ pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ }
++ if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0003) {
++ // sservices
++ /* ast_log(LOG_NOTICE,"FACILITY_IND PLCI = %#x\n",(int)FACILITY_IND_PLCI(CMSG));
++ ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]);
++ ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]);
++ ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2]);
++ ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3]);
++ ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]);
++ ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5]); */
++ // RETRIEVE
++ if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x3) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2)) {
++ p->i->state = CAPI_STATE_CONNECTED;
++ p->i->PLCI = p->i->onholdPLCI;
++ p->i->onholdPLCI = 0;
++ }
++ if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x2) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2)) {
++ if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) {
++ // reason != 0x0000 == problem
++ p->i->onholdPLCI = 0;
++ p->i->state = CAPI_STATE_ONHOLD;
++ ast_log(LOG_WARNING, "unable to put PLCI=%#x onhold, REASON = %#x%#x, maybe you need to subscribe for this...\n",(int)FACILITY_IND_PLCI(CMSG),FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5],FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]);
++ } else {
++ // reason = 0x0000 == call on hold
++ p->i->state = CAPI_STATE_ONHOLD;
++ if (capidebug)
++ ast_log(LOG_NOTICE, "PLCI=%#x put onhold\n",(int)FACILITY_IND_PLCI(CMSG));
++ }
++ }
++ }
++
++ error = FACILITY_RESP(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber,FACILITY_IND_PLCI(CMSG),FACILITY_IND_FACILITYSELECTOR(CMSG),FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG));
++
++ if (error != 0) {
++ ast_log(LOG_ERROR,"error sending FACILITY_RESP (error=%#x)\n",error);
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_RESP (PLCI=%#x)\n",(int)FACILITY_IND_PLCI(CMSG));
++ }
++ }
++ break;
++ case CAPI_INFO:
++ // ast_log(LOG_ERROR,"INFO_IND PLCI=%#x INFO# = %#x\n",PLCI,INFO_IND_INFONUMBER(CMSG));
++
++ memset(&CMSG2,0,sizeof(_cmsg));
++ error = INFO_RESP(&CMSG2,ast_capi_ApplID,CMSG->Messagenumber,PLCI);
++ if (error != 0) {
++ ast_log(LOG_ERROR,"error sending INFO_RESP (error=%#x)\n",error);
++ return -1;
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent INFO_RESP (PLCI=%#x)\n",PLCI);
++ }
++ }
++/* if ((INFO_IND_INFONUMBER(CMSG) >> 8) == 0x00) {
++ ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[0]);
++ ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[1]);
++ ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[2]);
++ ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[3]);
++ } */
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x001e) && (p->i->doB3 != AST_CAPI_B3_DONT) && (p->i->earlyB3 == -1) && (p->i->state != CAPI_STATE_BCONNECTED)){
++ // ETSI 300 102-1 Progress Indicator
++ // we do early B3 Connect
++ if(INFO_IND_INFOELEMENT(CMSG)[0] >= 2) {
++ if(INFO_IND_INFOELEMENT(CMSG)[2] & 0x2) {
++ p->i->calledPartyIsISDN = 0;
++ // ast_log(LOG_NOTICE,"A N A L O G \n");
++ } else {
++ p->i->calledPartyIsISDN = 1;
++ // ast_log(LOG_NOTICE,"I S D N\n");
++ }
++ if(INFO_IND_INFOELEMENT(CMSG)[2] & 0x88) {
++ // in-band info available
++ p->i->earlyB3 = 1;
++ memset(&CMSG2,0,sizeof(_cmsg));
++ CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++,0);
++ CONNECT_B3_REQ_PLCI(&CMSG2) = PLCI;
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending early CONNECT_B3_REQ (error=%#x)\n",error);
++ return -1;
++ } else {
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent early CONNECT_B3_REQ (PLCI=%#x)\n",PLCI);
++ }
++ }
++ }
++ }
++ }
++ // DISCONNECT
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (PLCI == p->i->onholdPLCI)) {
++ // the caller onhold hung up (or ECTed away)
++ // send a disconnect_req , we cannot hangup the channel here!!!
++ memset(&CMSG2,0,sizeof(_cmsg));
++ DISCONNECT_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ DISCONNECT_REQ_PLCI(&CMSG2) = p->i->onholdPLCI;
++
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",PLCI);
++ } else {
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_REQ for onholdPLCI=%#x\n",PLCI);
++ }
++ }
++ return 0;
++ }
++
++ // case 1: B3 on success or no B3 at all
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->doB3 != AST_CAPI_B3_ALWAYS) && (p->i->outgoing == 1)) {
++ p->i->earlyB3 = 0; // !!!
++ fr.frametype = AST_FRAME_NULL;
++ fr.datalen = 0;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ // case 2: we are doing B3, and receive the 0x8045 after a successful call
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->doB3 != AST_CAPI_B3_DONT) && (p->i->earlyB3 == 0) && (p->i->outgoing == 1)) {
++ fr.frametype = AST_FRAME_NULL;
++ fr.datalen = 0;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ // case 3: this channel is an incoming channel! the user hung up!
++ // it is much better to hangup now instead of waiting for a timeout and
++ // network caused DISCONNECT_IND!
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->outgoing == 0)) {
++ // ast_log(LOG_NOTICE,"case 3\n");
++ fr.frametype = AST_FRAME_NULL;
++ fr.datalen = 0;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ // case 4 (a.k.a. the italian case): B3 always. call is unsuccessful
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->doB3 == AST_CAPI_B3_ALWAYS) && (p->i->earlyB3 == -1) && (p->i->outgoing == 1)) {
++ // wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network
++ return 0;
++ }
++#endif
++ // Handle DID digits
++ if ((INFO_IND_INFONUMBER(CMSG) == 0x0070) && p->i->isdnmode && (p->c != NULL)) {
++ int search = -1;
++ char name[AST_CHANNEL_NAME] = "";
++ char *did;
++
++ did = capi_number((char *)INFO_IND_INFOELEMENT(CMSG),1);
++ if (strcasecmp(p->i->dnid, did)) {
++ strncat(p->i->dnid, did, sizeof(p->i->dnid)-1);
++ }
++
++ snprintf(name,sizeof(name),"CAPI/contr%d/%s/-%d",p->i->controller,p->i->dnid,capi_counter++);
++ ast_change_name(p->c, name);
++
++ search = search_did(p->c);
++ if (search != -1) {
++ if (!search) {
++ ast_setstate(p->c, AST_STATE_RING);
++ // we are alerting (phones ringing)
++ capi_alert(p->c); // Do this here after pbx_start the Channel can be destroyed
++ if (ast_pbx_start(p->c)) {
++ ast_log(LOG_ERROR,"Unable to start pbx on channel!\n");
++ ast_hangup(p->c);
++ } else {
++ if (option_verbose > 2) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "started pbx on channel!\n");
++ }
++ }
++ }
++ } else {
++ ast_log(LOG_ERROR,"did not find device for msn = %s\n",p->i->dnid);
++ CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++ CONNECT_RESP_PLCI(&CMSG2) = PLCI;
++ CONNECT_RESP_REJECT(&CMSG2) = 1; // ignore
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++ }
++ }
++
++ return 0;
++ }
++ }
++ if (INFO_IND_INFONUMBER(CMSG) == 0x8001) {
++ fr.frametype = AST_FRAME_CONTROL;
++ fr.subclass = AST_CONTROL_RINGING;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ if (INFO_IND_INFONUMBER(CMSG) == 0x800d) {
++ fr.frametype = AST_FRAME_CONTROL;
++ fr.subclass = AST_CONTROL_PROGRESS;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ if (INFO_IND_INFONUMBER(CMSG) == 0x74) {
++ strncpy(p->i->owner->exten,capi_number((char *)INFO_IND_INFOELEMENT(CMSG),3),sizeof(p->i->owner->exten)-1);
++ ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(CMSG));
++ }
++ if (INFO_IND_INFONUMBER(CMSG) == 0x28) {
++ // ast_sendtext(p->i->owner,capi_number(INFO_IND_INFOELEMENT(CMSG),0));
++ // struct ast_frame ft = { AST_FRAME_TEXT, capi_number(INFO_IND_INFOELEMENT(CMSG),0), };
++ // ast_queue_frame(p->i->owner, &ft);
++ // ast_log(LOG_NOTICE,"%s\n",capi_number(INFO_IND_INFOELEMENT(CMSG),0));
++ }
++ break;
++ case CAPI_CONNECT_ACTIVE:
++// ast_log(LOG_NOTICE,"CONNECT_ACTIVE_IND PLCI=%#x\n",(int)CONNECT_ACTIVE_IND_PLCI(CMSG));
++ CONNECT_ACTIVE_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber,0);
++ CONNECT_ACTIVE_RESP_PLCI(&CMSG2) = PLCI;
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_ACTIVE_RESP (error=%#x)\n",error);
++ return -1;
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_ACTIVE_RESP (PLCI=%#x)\n",PLCI);
++ }
++ }
++ // normal processing
++ if (p->i->earlyB3 != 1) {
++ p->i->state = CAPI_STATE_CONNECTED;
++
++ // send a CONNECT_B3_REQ
++ if (p->i->outgoing == 1) {
++ // outgoing call
++ memset(&CMSG2,0,sizeof(_cmsg));
++ CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++,0);
++ CONNECT_B3_REQ_PLCI(&CMSG2) = PLCI;
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_B3_REQ (error=%#x)\n",error);
++ return -1;
++ } else {
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "sent CONNECT_B3_REQ (PLCI=%#x)\n",PLCI);
++ }
++ }
++ } else {
++ // incoming call
++ // RESP already sent ... wait for CONNECT_B3_IND
++// ast_log(LOG_NOTICE,"waiting for CONNECT_B3_IND\n");
++ }
++ } else {
++ // special treatment for early B3 connects
++ p->i->state = CAPI_STATE_BCONNECTED;
++ if (p->c->_state != AST_STATE_UP) {
++ ast_setstate(p->c,AST_STATE_UP);
++ }
++ p->i->earlyB3 = 0; // not early anymore
++ fr.frametype = AST_FRAME_CONTROL;
++ fr.subclass = AST_CONTROL_ANSWER;
++ fr.datalen = 0;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++
++ }
++ break;
++ case CAPI_CONNECT_B3:
++ // then send a CONNECT_B3_RESP
++ memset(&CMSG2,0,sizeof(_cmsg));
++ CONNECT_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++ CONNECT_B3_RESP_NCCI(&CMSG2) = CONNECT_B3_IND_NCCI(CMSG);
++ p->NCCI = CONNECT_B3_IND_NCCI(CMSG);
++ p->i->NCCI = p->NCCI;
++ CONNECT_B3_RESP_REJECT(&CMSG2) = 0;
++
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_B3_RESP (error=%#x)\n",error);
++ return -1;
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_B3_RESP (NCCI=%#x)\n",p->i->NCCI);
++ }
++ }
++ /* if (p->i->controller > 0) {
++ capi_controllers[p->i->controller]->nfreebchannels--;
++ } */
++ break;
++ case CAPI_CONNECT_B3_ACTIVE:
++// ast_log(LOG_NOTICE,"CONNECT_B3_ACTIVE_IND NCCI=%#x\n",p->i->NCCI);
++ // then send a CONNECT_B3__ACTIVERESP
++
++ CONNECT_B3_ACTIVE_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++ CONNECT_B3_ACTIVE_RESP_NCCI(&CMSG2) = p->i->NCCI;
++
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_B3_ACTIVE_RESP (error=%#x)\n",error);
++ return -1;
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_B3_ACTIVE_RESP (NCCI=%#x)\n",p->i->NCCI);
++ }
++ }
++
++ ast_mutex_lock(&contrlock);
++ if (p->i->controller > 0) {
++ capi_controllers[p->i->controller]->nfreebchannels--;
++ }
++ ast_mutex_unlock(&contrlock);
++
++ p->i->state = CAPI_STATE_BCONNECTED;
++ capi_echo_canceller(p->c,EC_FUNCTION_ENABLE);
++ capi_detect_dtmf(p->c,1);
++
++ if (p->i->earlyB3 != 1) {
++ ast_setstate(p->c,AST_STATE_UP);
++ fr.frametype = AST_FRAME_CONTROL;
++ fr.subclass = AST_CONTROL_ANSWER;
++ fr.datalen = 0;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ return 0;
++ break;
++ }
++ break;
++
++ case CAPI_CONF:
++ switch (CMSG->Command) {
++ case CAPI_FACILITY:
++ if (FACILITY_CONF_FACILITYSELECTOR(CMSG) == 0x3) {
++ if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[1] == 0x2) && (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[2] == 0x0)) {
++ if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[4] == 0x0) && (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[5] == 0x0)) {
++ } else {
++ p->i->state = CAPI_STATE_BCONNECTED;
++ if (capidebug)
++ ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(CMSG));
++ }
++ }
++ }
++ break;
++ case CAPI_DATA_B3:
++// ast_log(LOG_NOTICE,"DATA_B3_CONF (NCCI %#x) for DATAHANDLE %#x\n",DATA_B3_CONF_NCCI(CMSG),DATA_B3_CONF_DATAHANDLE(CMSG));
++ break;
++ case CAPI_ALERT:
++// ast_log(LOG_NOTICE,"ALERT_CONF (PLCI=%#x)\n",(int)ALERT_CONF_PLCI(CMSG));
++ p->i->state = CAPI_STATE_ALERTING;
++ if (p->c->_state == AST_STATE_RING) {
++ p->c->rings = 1;
++ }
++ break;
++ case CAPI_CONNECT:
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_2 "received CONNECT_CONF PLCI = %#x INFO = %#x\n",(int)CONNECT_CONF_PLCI(CMSG),CONNECT_CONF_INFO(CMSG));
++ }
++ if (CONNECT_CONF_INFO(CMSG) == 0) {
++ p->i->PLCI = CONNECT_CONF_PLCI(CMSG);
++ p->PLCI = p->i->PLCI;
++ ast_setstate(p->c,AST_STATE_DIALING);
++ } else {
++ // here, something has to be done -->
++ fr.frametype = AST_FRAME_CONTROL;
++ fr.subclass = AST_CONTROL_BUSY;
++ fr.datalen = 0;
++ return pipe_frame(p,(struct ast_frame *)&fr);
++ }
++ break;
++ case CAPI_CONNECT_B3:
++// ast_log(LOG_NOTICE,"received CONNECT_B3_CONF NCCI = %#x INFO = %#x\n",(int)CONNECT_B3_CONF_NCCI(CMSG),CONNECT_B3_CONF_INFO(CMSG));
++ if (CONNECT_B3_CONF_INFO(CMSG) == 0) {
++ p->i->NCCI = CONNECT_B3_CONF_NCCI(CMSG);
++ } else {
++ p->i->earlyB3 = -1;
++ p->i->doB3 = AST_CAPI_B3_DONT;
++ }
++ break;
++ }
++ break;
++ }
++ }
++// ast_log(LOG_NOTICE,"returning\n");
++ return 0;
++}
++
++static void capi_handle_msg(_cmsg *CMSG) {
++ struct ast_capi_pvt *i;
++ char *DNID;
++ char *CID;
++ char *msn;
++ _cmsg CMSG2;
++ MESSAGE_EXCHANGE_ERROR error;
++ int PLCI=0,NCCI;
++ int NPLAN=0;
++ int fds[2];
++ int controller=0;
++ char buffer[AST_MAX_EXTENSION];
++ struct capi_pipe *p;
++ char *magicmsn = "*\0";
++ char *emptyid = "\0";
++ char *emptydnid = "s\0";
++ long flags;
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++ int deflect=0;
++#endif
++
++ switch (CMSG->Subcommand) {
++ // indication msgs
++ case CAPI_IND:
++
++ switch (CMSG->Command) {
++ case CAPI_CONNECT: // only connect_ind are global (not channel specific)
++ if (capidebug)
++ ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(CMSG));
++ DNID = capi_number((char *)CONNECT_IND_CALLEDPARTYNUMBER(CMSG),1);
++ if ((DNID && *DNID == 0) || !DNID) {
++ DNID = emptydnid;
++ }
++ NPLAN = (CONNECT_IND_CALLINGPARTYNUMBER(CMSG)[1] & 0x70);
++ CID = capi_number((char *)CONNECT_IND_CALLINGPARTYNUMBER(CMSG),2);
++ PLCI = CONNECT_IND_PLCI(CMSG);
++ controller = PLCI & 0xff;
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_2 "CONNECT_IND (PLCI=%#x,DID=%s,CID=%s,CIP=%#x,CONTROLLER=%#x)\n",PLCI,DNID,CID,CONNECT_IND_CIPVALUE(CMSG),controller);
++ }
++ if(CONNECT_IND_BCHANNELINFORMATION(CMSG))
++ if ((CONNECT_IND_BCHANNELINFORMATION(CMSG)[1] == 0x02) && (!capi_controllers[controller]->isdnmode)) {
++ // this is a call waiting CONNECT_IND with BChannelinformation[1] == 0x02
++ // meaning "no B or D channel for this call", since we can't do anything with call waiting now
++ // just reject it with "user busy"
++ // however...if we are a p2p BRI then the telco switch will allow us to choose the b channel
++ // so it will look like a callwaiting connect_ind to us
++
++ ast_log(LOG_ERROR,"received a call waiting CONNECT_IND\n");
++#ifndef CAPI_DEFLECT_ON_CIRCUITBUSY
++ CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++ CONNECT_RESP_PLCI(&CMSG2) = CONNECT_IND_PLCI(CMSG);
++ CONNECT_RESP_REJECT(&CMSG2) = 3; // user is busy
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++ }
++ }
++ // no need to pipe this
++ PLCI = 0;
++ break;
++#else
++ deflect = 1;
++#endif
++ }
++ // well...somebody is calling us. let's set up a channel
++ ast_mutex_lock(&iflock);
++ i = iflist;
++ while(i) {
++ //XXX test this!
++ // has no owner
++ if ((!i->owner) && (i->incomingmsn != NULL)){
++ strncpy(buffer,i->incomingmsn,sizeof(buffer)-1);
++ msn = strtok(buffer,",");
++ while (msn != NULL) {
++// ast_log(LOG_NOTICE,"msn=%s\n",msn);
++ if (DNID && ((!strcasecmp(msn,DNID)) ||
++ (i->isdnmode && (strlen(msn)<strlen(DNID)) && !strncasecmp(msn, DNID, strlen(msn))) || (!strncasecmp(msn,magicmsn,strlen(msn)))) &&
++ (i->controllers & (1 << controller))) {
++ if (CID != NULL) {
++ if(NPLAN == CAPI_ETSI_NPLAN_NATIONAL)
++ snprintf(i->cid, (sizeof(i->cid)-1), "%s%s%s", i->prefix, capi_national_prefix, CID);
++ else if(NPLAN == CAPI_ETSI_NPLAN_INTERNAT)
++ snprintf(i->cid, (sizeof(i->cid)-1), "%s%s%s", i->prefix, capi_international_prefix, CID);
++ else
++ snprintf(i->cid, (sizeof(i->cid)-1), "%s%s", i->prefix, CID);
++ } else
++ strncpy(i->cid,emptyid,sizeof(i->cid)-1);
++
++ if (DNID != NULL)
++ strncpy(i->dnid,DNID,sizeof(i->dnid)-1);
++ else
++ strncpy(i->dnid,emptydnid,sizeof(i->dnid)-1);
++
++ i->controller=controller;
++ i->PLCI = PLCI;
++ i->MessageNumber = CMSG->Messagenumber;
++ if (pipe(fds) == 0) {
++ if (option_verbose > 4) {
++ ast_verbose(VERBOSE_PREFIX_3 "creating pipe for PLCI=%#x msn = %s\n",PLCI,msn);
++ }
++ i->fd = fds[0];
++ flags = fcntl(i->fd,F_GETFL);
++ fcntl(i->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++// ast_log(LOG_NOTICE,"i->fd = %d\n",i->fd);
++ p = malloc(sizeof(struct capi_pipe));
++ memset(p, 0, sizeof(struct capi_pipe));
++ p->fd = fds[1];
++ flags = fcntl(i->fd,F_GETFL);
++ fcntl(p->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++// ast_log(LOG_NOTICE,"p->fd = %d\n",p->fd);
++ p->PLCI = PLCI;
++ p->i = i;
++ ast_mutex_init(&(p->lock));
++ i->mypipe = p;
++ if (i->isdnmode) {
++ p->c = capi_new(i,AST_STATE_DOWN);
++ i->state = CAPI_STATE_DID;
++ } else {
++ p->c = capi_new(i,AST_STATE_RING);
++ }
++ p->next = pipelist;
++ pipelist = p;
++ // hmmm....
++ ast_mutex_unlock(&iflock);
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++ if ((deflect == 1) && (i->deflect2)) {
++ capi_deflect(p->c,i->deflect2);
++ }
++#endif
++ return;
++ } else {
++ ast_log(LOG_ERROR,"creating pipe for PLCI=%#x failed\n",PLCI);
++ }
++ break;
++ } // if strcasecmp
++ msn = strtok(NULL,",");
++ } // while strtok
++ } // if
++ i = i->next;
++ } // while interface list
++ ast_mutex_unlock(&iflock); // obviously we are not called...so tell capi to ignore this call
++ if (capidebug) {
++ ast_log(LOG_ERROR,"did not find device for msn = %s\n",DNID);
++ }
++ CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++ CONNECT_RESP_PLCI(&CMSG2) = CONNECT_IND_PLCI(CMSG);
++ CONNECT_RESP_REJECT(&CMSG2) = 1; // ignore
++ if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++ ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++ } else {
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++ }
++ }
++ ast_mutex_lock(&pipelock);
++ if (pipelist == NULL) {
++ capi_last_plci = PLCI;
++ }
++ ast_mutex_unlock(&pipelock);
++ // no need to pipe this
++ PLCI = 0;
++// ast_mutex_unlock(&iflock);
++// return;
++ break;
++ case CAPI_FACILITY:
++ PLCI = FACILITY_IND_PLCI(CMSG) & 0xffff; // this is for you eicon
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"FACILITY_IND PLCI=%#x\n",PLCI);
++ break;
++ case CAPI_INFO:
++ PLCI = INFO_IND_PLCI(CMSG);
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"INFO_IND PLCI=%#x INFO# = %#x\n",PLCI,INFO_IND_INFONUMBER(CMSG));
++ break;
++ case CAPI_CONNECT_ACTIVE:
++ PLCI = CONNECT_ACTIVE_IND_PLCI(CMSG);
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"CONNECT_ACTIVE_IND PLCI=%#x\n",PLCI);
++ break;
++ case CAPI_CONNECT_B3:
++ NCCI = CONNECT_B3_IND_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"CONNECT_B3_IND NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++ break;
++ case CAPI_CONNECT_B3_ACTIVE:
++ NCCI = CONNECT_B3_IND_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"CONNECT_B3_ACTIVE_IND NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++ break;
++ case CAPI_DATA_B3:
++ NCCI = DATA_B3_IND_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++// ast_log(LOG_ERROR,"DATA_B3_IND NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++ break;
++ case CAPI_DISCONNECT_B3:
++ NCCI = DISCONNECT_B3_IND_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_2 "DISCONNECT_B3_IND NCCI=%#x\n",NCCI);
++ }
++ break;
++ case CAPI_DISCONNECT:
++ PLCI = DISCONNECT_IND_PLCI(CMSG);
++ if (option_verbose > 1) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_2 "DISCONNECT_IND PLCI=%#x REASON=%#x\n",PLCI,DISCONNECT_IND_REASON(CMSG));
++ }
++ break;
++ default:
++ ast_log(LOG_ERROR,"Command.Subcommand = %#x.%#x\n",CMSG->Command,CMSG->Subcommand);
++ }
++ break;
++ // confirmation msgs
++ case CAPI_CONF:
++ switch (CMSG->Command) {
++ case CAPI_FACILITY:
++ NCCI = FACILITY_CONF_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 2) {
++ if (FACILITY_CONF_FACILITYSELECTOR(CMSG) == 6) {
++ if (FACILITY_CONF_INFO(CMSG))
++ ast_verbose (VERBOSE_PREFIX_3 "Error setting up echo canceller (PLCI=%#x, Info=%#04x)\n", PLCI, FACILITY_CONF_INFO(CMSG));
++ else
++ ast_verbose (VERBOSE_PREFIX_3 "Echo canceller successfully set up (PLCI=%#x)\n",PLCI);
++ }
++ }
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"FACILITY_CONF NCCI=%#x INFO=%#x\n",(int)FACILITY_CONF_NCCI(CMSG),FACILITY_CONF_INFO(CMSG));
++ break;
++ case CAPI_INFO:
++ PLCI = INFO_CONF_PLCI(CMSG);
++// ast_log(LOG_ERROR,"INFO_CONF PLCI=%#x INFO=%#x\n",PLCI,INFO_CONF_INFO(CMSG));
++ break;
++ case CAPI_CONNECT:
++ PLCI = CONNECT_CONF_PLCI(CMSG);
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"CONNECT_CONF PLCI=%#x INFO=%#x MN=%#x\n",PLCI,CONNECT_CONF_INFO(CMSG),CMSG->Messagenumber);
++ break;
++ case CAPI_DISCONNECT:
++ PLCI = DISCONNECT_CONF_PLCI(CMSG);
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"DISCONNECT_CONF PLCI=%#x INFO=%#x MN=%#x\n",PLCI,DISCONNECT_CONF_INFO(CMSG),CMSG->Messagenumber);
++ break;
++ case CAPI_DISCONNECT_B3:
++ NCCI = DISCONNECT_B3_CONF_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"DISCONNECT_B3_CONF NCCI=%#x INFO=%#x MN=%#x\n",NCCI,DISCONNECT_B3_CONF_INFO(CMSG),CMSG->Messagenumber);
++ break;
++ case CAPI_CONNECT_B3:
++ NCCI = CONNECT_B3_CONF_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"CONNECT_B3_CONF PLCI=%#x INFO=%#x MN=%#x\n",PLCI,CONNECT_B3_CONF_INFO(CMSG),CMSG->Messagenumber);
++ break;
++ case CAPI_ALERT:
++ PLCI = ALERT_CONF_PLCI(CMSG);
++ if (option_verbose > 3) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"ALERT_CONF PLCI=%#x\n",PLCI);
++ break;
++ case CAPI_DATA_B3:
++ NCCI = DATA_B3_CONF_NCCI(CMSG);
++ PLCI = (NCCI << 16) >> 16;
++ if (option_verbose > 5) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++ }
++// ast_log(LOG_ERROR,"DATA_B3_CONF NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++ break;
++ default:
++ ast_log(LOG_ERROR,"Command.Subcommand = %#x.%#x\n",CMSG->Command,CMSG->Subcommand);
++ }
++ break;
++ }
++ if (PLCI > 0) {
++ pipe_msg(PLCI,CMSG);
++ }
++
++}
++
++// module stuff, monitor...
++
++static void *do_monitor(void *data) {
++ unsigned int Info;
++ _cmsg *monCMSG;
++ for (;;) {
++/*
++ if (ast_mutex_lock(&monlock)) {
++ ast_log(LOG_ERROR,"Unable to get monitor lock!\n");
++ return NULL;
++ }
++ // do some nifty stuff
++ ast_mutex_unlock(&monlock);
++*/
++ monCMSG = malloc(sizeof(_cmsg));
++ memset(monCMSG,0,sizeof(_cmsg));
++ switch(Info = check_wait_get_cmsg(monCMSG)) {
++ case 0x0000:
++ if (option_verbose > 8) {
++ if (capidebug)
++ ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(monCMSG));
++ }
++ capi_handle_msg(monCMSG);
++ break;
++ case 0x1104:
++ // CAPI queue is empty
++ break;
++ default:
++ // something is wrong!
++ break;
++ } //switch
++ free(monCMSG);
++ } // for
++ // never reached
++ return NULL;
++}
++
++#ifdef CAPI_GAIN
++static void capi_gains(struct ast_capi_gains *g,float rxgain,float txgain) {
++ int i=0;
++ int x=0;
++ if (rxgain != 1.0) {
++ for (i=0;i<256;i++) {
++ x = (int)(((float)capiXLAW2INT(i)) * rxgain);
++ if (x > 32767) x = 32767;
++ if (x < -32767) x = -32767;
++ g->rxgains[i] = capiINT2XLAW(x);
++ }
++ } else {
++ for (i=0;i<256;i++) {
++ g->rxgains[i] = i;
++ }
++ }
++ if (txgain != 1.0) {
++ for (i=0;i<256;i++) {
++ x = (int)(((float)capiXLAW2INT(i)) * txgain);
++ if (x > 32767) x = 32767;
++ if (x < -32767) x = -32767;
++ g->txgains[i] = capiINT2XLAW(x);
++ }
++ } else {
++ for (i=0;i<256;i++) {
++ g->txgains[i] = i;
++ }
++ }
++
++}
++#endif
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++int mkif(char *incomingmsn,char *context,char *controllerstr,int devices,int softdtmf,int echocancel,int ecoption,int ectail, char *prefix, int isdnmode, int es,float rxgain,float txgain, char *deflect2, char *accountcode, unsigned int callgroup, unsigned int group) {
++#else
++int mkif(char *incomingmsn,char *context,char *controllerstr,int devices,int softdtmf,int echocancel,int ecoption,int ectail, char *prefix, int isdnmode, int es,float rxgain,float txgain, char *accountcode, unsigned int callgroup, unsigned int group) {
++#endif
++ struct ast_capi_pvt *tmp;
++ int i=0;
++ char buffer[100];
++ char *contr;
++ unsigned long contrmap=0;
++
++ for (i=0;i<devices;i++) {
++ tmp = malloc(sizeof(struct ast_capi_pvt));
++ memset(tmp, 0, sizeof(struct ast_capi_pvt));
++ if (tmp) {
++ ast_mutex_init(&(tmp->lock));
++ strncpy(tmp->context, context, sizeof(tmp->context)-1);
++ strncpy(tmp->incomingmsn, incomingmsn, sizeof(tmp->incomingmsn)-1);
++ strncpy(tmp->prefix, prefix, sizeof(tmp->prefix)-1);
++ strncpy(tmp->accountcode, accountcode, sizeof(tmp->accountcode)-1);
++
++ strncpy(buffer,controllerstr,sizeof(buffer)-1);
++ contr = strtok(buffer,",");
++ while (contr != NULL) {
++ contrmap |= (1 << atoi(contr));
++ if (capi_controllers[atoi(contr)]) {
++ capi_controllers[atoi(contr)]->isdnmode = isdnmode;
++ // ast_log(LOG_NOTICE, "contr %d isdnmode %d\n",atoi(contr),isdnmode);
++ }
++ contr = strtok(NULL,",");
++ }
++ tmp->controllers = contrmap;
++ capi_used_controllers |= contrmap;
++ tmp->controller = 0;
++ tmp->CLIR = 0;
++ tmp->earlyB3 = -1;
++ tmp->onholdPLCI = 0;
++ tmp->doEC = echocancel;
++ tmp->ecOption = ecoption;
++ tmp->ecTail = ectail;
++ tmp->isdnmode = isdnmode;
++ tmp->doES = es;
++ tmp->callgroup = callgroup;
++ tmp->group = group;
++#ifdef CAPI_ES
++#endif
++#ifdef CAPI_GAIN
++ tmp->rxgain = rxgain;
++ tmp->txgain = txgain;
++ capi_gains(&tmp->g,rxgain,txgain);
++#endif
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++ strncpy(tmp->deflect2, deflect2, sizeof(tmp->deflect2)-1);
++#endif
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ if (softdtmf == 1) {
++#endif
++ tmp->doDTMF = 1;
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++ } else {
++ tmp->doDTMF = 0;
++ }
++#endif
++ tmp->next = iflist; // prepend
++ iflist = tmp;
++ // ast_log(LOG_NOTICE, "ast_capi_pvt(%s,%s,%#x,%d) (%d,%d,%d) (%d)(%f/%f) %d\n",tmp->incomingmsn,tmp->context,(int)tmp->controllers,devices,tmp->doEC,tmp->ecOption,tmp->ecTail,tmp->doES,tmp->rxgain,tmp->txgain,callgroup);
++ if (option_verbose > 2) {
++ ast_verbose(VERBOSE_PREFIX_2 "ast_capi_pvt(%s,%s,%d,%d) (%d,%d,%d)\n",tmp->incomingmsn,tmp->context,tmp->controller,devices,tmp->doEC,tmp->ecOption,tmp->ecTail);
++ }
++
++ } else {
++ return -1;
++ }
++ }
++ return 0;
++}
++
++void supported_sservices(struct ast_capi_controller *cp) {
++ MESSAGE_EXCHANGE_ERROR error;
++ _cmsg CMSG,CMSG2;
++ struct timeval tv;
++ char fac[20];
++
++ FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++ FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller;
++ FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; // sservices
++ fac[0] = 3;
++ fac[1] = 0;
++ fac[2] = 0;
++ fac[3] = 0;
++ FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (unsigned char *)&fac;
++ if ((error= _capi_put_cmsg(&CMSG)) != 0) {
++ ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++ } else {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_REQ (CONTROLLER=%#x)\n",cp->controller);
++ }
++ }
++
++ tv.tv_sec = 1;
++ tv.tv_usec = 0;
++ for (;;){
++ error = capi20_waitformessage(ast_capi_ApplID,&tv);
++ error = capi_get_cmsg(&CMSG2,ast_capi_ApplID);
++// error = check_wait_get_cmsg(&CMSG2);
++ if (error == 0) {
++ if (IS_FACILITY_CONF(&CMSG2)) {
++ if (option_verbose > 5) {
++ ast_verbose(VERBOSE_PREFIX_4 "FACILITY_CONF INFO = %#x\n",FACILITY_CONF_INFO(&CMSG2));
++ }
++ break;
++ }
++ }
++ }
++ // parse supported sservices
++ if (FACILITY_CONF_FACILITYSELECTOR(&CMSG2) == 0x0003) {
++ // success
++ if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[4] == 0) {
++ if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 1) == 1) {
++ cp->holdretrieve = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "HOLD/RETRIEVE\n");
++ } else {
++ cp->holdretrieve = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 2) >> 1) == 1) {
++ cp->terminalportability = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "TERMINAL PORTABILITY\n");
++ } else {
++ cp->terminalportability = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 4) >> 2) == 1) {
++ cp->ECT = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "ECT\n");
++ } else {
++ cp->ECT = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 8) >> 3) == 1) {
++ cp->threePTY = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "3PTY\n");
++ } else {
++ cp->threePTY = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 16) >> 4) == 1) {
++ cp->CF = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "CF\n");
++ } else {
++ cp->CF = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 32) >> 5) == 1) {
++ cp->CD = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "CD\n");
++ } else {
++ cp->CD = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 64) >> 6) == 1) {
++ cp->MCID = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "MCID\n");
++ } else {
++ cp->MCID = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 128) >> 7) == 1) {
++ cp->CCBS = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "CCBS\n");
++ } else {
++ cp->CCBS = 0;
++ }
++ if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 1) == 1) {
++ cp->MWI = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "MWI\n");
++ } else {
++ cp->MWI = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 2) >> 1) == 1) {
++ cp->CCNR = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "CCNR\n");
++ } else {
++ cp->CCNR = 0;
++ }
++ if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 4) >> 2) == 1) {
++ cp->CONF = 1;
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_4 "CONF\n");
++ } else {
++ cp->CONF = 0;
++ }
++ } else {
++ ast_log(LOG_NOTICE,"supplementary services info = %#x\n",(short)FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[1]);
++ }
++ } else {
++ ast_log(LOG_NOTICE,"unexpected FACILITY_SELECTOR = %#x\n",FACILITY_CONF_FACILITYSELECTOR(&CMSG2));
++ }
++}
++
++static int capi_info(int fd, int argc, char *argv[])
++{
++ int i=0;
++ if (argc != 2)
++ return RESULT_SHOWUSAGE;
++ for (i=1;i<=capi_num_controllers;i++) {
++ ast_mutex_lock(&contrlock);
++ if (capi_controllers[i] != NULL) {
++ ast_cli(fd,"Contr%d: %d B channels total, %d B channels free.\n",i,capi_controllers[i]->nbchannels,capi_controllers[i]->nfreebchannels);
++ }
++ ast_mutex_unlock(&contrlock);
++ }
++ return RESULT_SUCCESS;
++}
++
++static int capi_do_debug(int fd, int argc, char *argv[])
++{
++ if (argc != 2)
++ return RESULT_SHOWUSAGE;
++ capidebug = 1;
++ ast_cli(fd, "CAPI Debugging Enabled\n");
++ return RESULT_SUCCESS;
++}
++
++static int capi_no_debug(int fd, int argc, char *argv[])
++{
++ if (argc != 3)
++ return RESULT_SHOWUSAGE;
++ capidebug = 0;
++ ast_cli(fd, "CAPI Debugging Disabled\n");
++ return RESULT_SUCCESS;
++}
++
++static char info_usage[] =
++"Usage: capi info\n"
++" Show info about B channels.\n";
++
++static char debug_usage[] =
++"Usage: capi debug\n"
++" Enables dumping of CAPI packets for debugging purposes\n";
++
++static char no_debug_usage[] =
++"Usage: capi no debug\n"
++" Disables dumping of CAPI packets for debugging purposes\n";
++
++static struct ast_cli_entry cli_info =
++ { { "capi", "info", NULL }, capi_info, "Show CAPI info", info_usage };
++static struct ast_cli_entry cli_debug =
++ { { "capi", "debug", NULL }, capi_do_debug, "Enable CAPI debugging", debug_usage };
++static struct ast_cli_entry cli_no_debug =
++ { { "capi", "no", "debug", NULL }, capi_no_debug, "Disable CAPI debugging", no_debug_usage };
++
++static const struct ast_channel_tech capi_tech = {
++ .type = type,
++ .description = tdesc,
++#ifdef CAPI_ULAW
++ .capabilities = AST_FORMAT_ULAW,
++#else
++ .capabilities = AST_FORMAT_ALAW,
++#endif
++ .requester = capi_request,
++ .send_digit = capi_send_digit,
++ .send_text = NULL,
++ .call = capi_call,
++ .hangup = capi_hangup,
++ .answer = capi_answer,
++ .read = capi_read,
++ .write = capi_write,
++ .bridge = NULL,
++ .exception = NULL,
++ .indicate = capi_indicate,
++ .fixup = capi_fixup,
++ .setoption = NULL,
++};
++
++static int load_module(void)
++{
++ struct ast_config *cfg;
++ struct ast_variable *v;
++ char *config = "capi.conf";
++ char incomingmsn[AST_MAX_EXTENSION]="";
++ char context[AST_MAX_EXTENSION]="";
++ char prefix[AST_MAX_EXTENSION]="";
++ char accountcode[20]="";
++ char *empty = "\0";
++ char deflect2[AST_MAX_EXTENSION]="";
++ char controllerstr[AST_MAX_EXTENSION]="";
++ int res = 0;
++ int controller=0;
++ int softdtmf=0;
++ int echocancel=1;
++ int ecoption=EC_OPTION_DISABLE_G165;
++ int ectail=EC_DEFAULT_TAIL;
++ int es=0;
++ float rxgain = 1.0;
++ float txgain = 1.0;
++ int isdnmode = 0;
++ unsigned int callgroup=0;
++ unsigned int group=0;
++ struct ast_capi_controller *cp;
++
++ cfg = ast_config_load(config);
++
++ /* We *must* have a config file otherwise stop immediately, well no... */
++ if (!cfg) {
++ ast_log(LOG_ERROR, "Unable to load config %s, CAPI disabled\n", config);
++ return 0;
++ }
++ if (ast_mutex_lock(&iflock)) {
++ ast_log(LOG_ERROR, "Unable to lock interface list???\n");
++ return -1;
++ }
++
++ strncpy(capi_national_prefix, AST_CAPI_NATIONAL_PREF, sizeof(capi_national_prefix)-1);
++ strncpy(capi_international_prefix, AST_CAPI_NATIONAL_PREF, sizeof(capi_national_prefix)-1);
++ v = ast_variable_browse(cfg, "general");
++ while(v) {
++ if (!strcasecmp(v->name, "nationalprefix")) {
++ strncpy(capi_national_prefix, v->value, sizeof(capi_national_prefix)-1);
++ } else if (!strcasecmp(v->name, "internationalprefix")) {
++ strncpy(capi_international_prefix, v->value, sizeof(capi_international_prefix)-1);
++ } else if (!strcasecmp(v->name, "rxgain")) {
++ if (sscanf(v->value,"%f",&rxgain) != 1) {
++ ast_log(LOG_ERROR,"invalid rxgain\n");
++ }
++ } else if (!strcasecmp(v->name, "txgain")) {
++ if (sscanf(v->value,"%f",&txgain) != 1) {
++ ast_log(LOG_ERROR,"invalid txgain\n");
++ }
++ }
++ v = v->next;
++ }
++
++
++
++
++ if (capi20_isinstalled() != 0) {
++ ast_log(LOG_WARNING,"CAPI not installed, CAPI disabled!\n");
++ return 0;
++ }
++
++ if (capi20_register(AST_CAPI_BCHANS,AST_CAPI_MAX_B3_BLOCKS,AST_CAPI_MAX_B3_BLOCK_SIZE,&ast_capi_ApplID) != 0) {
++ ast_log(LOG_NOTICE,"unable to register application at CAPI!\n");
++ return -1;
++ }
++
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++ if (capi20_get_profile(0,&profile) != 0) {
++#else
++ if (capi20_get_profile(0,(unsigned char *)&profile) != 0) {
++#endif
++ ast_log(LOG_NOTICE,"unable to get CAPI profile!\n");
++ return -1;
++ } else {
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++ capi_num_controllers = profile.wCtlr;
++#else
++ capi_num_controllers = profile.ncontrollers;
++#endif
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_3 "This box has %d capi controller(s).\n",capi_num_controllers);
++ for (controller=1;controller<=capi_num_controllers;controller++) {
++
++ memset(&profile,0,sizeof(profile));
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++ capi20_get_profile(controller,&profile);
++#else
++ capi20_get_profile(controller,(unsigned char *)&profile);
++#endif
++ cp = malloc(sizeof(struct ast_capi_controller));
++ cp->controller = controller;
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++ cp->nbchannels = profile.wNumBChannels;
++ cp->nfreebchannels = profile.wNumBChannels;
++ if (profile.dwGlobalOptions & CAPI_PROFILE_DTMF_SUPPORT) {
++#else
++ cp->nbchannels = profile.nbchannels;
++ cp->nfreebchannels = profile.nbchannels;
++ if ((profile.globaloptions & 8) >> 3 == 1) {
++#endif
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_3 "CAPI/contr%d supports DTMF\n",controller);
++ cp->dtmf = 1;
++ } else {
++ cp->dtmf = 0;
++ }
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++ if (profile.dwGlobalOptions & CAPI_PROFILE_ECHO_CANCELLATION) {
++#else
++ if (profile.globaloptions2 & 1) {
++#endif
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_3 "CAPI/contr%d supports echo cancellation\n",controller);
++ cp->echocancel = 1;
++ } else {
++ cp->echocancel = 0;
++ }
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++ if (profile.dwGlobalOptions & CAPI_PROFILE_SUPPLEMENTARY_SERVICES) {
++#else
++ if ((profile.globaloptions & 16) >> 4 == 1) {
++#endif
++ cp->sservices = 1;
++ } else {
++ cp->sservices = 0;
++ }
++ capi_controllers[controller] = cp;
++ if (cp->sservices == 1) {
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_3 "CAPI/contr%d supports supplementary services\n",controller);
++ supported_sservices(cp);
++ }
++ }
++ }
++
++ v = ast_variable_browse(cfg, "interfaces");
++ while(v) {
++ /* Create the interface list */
++ if (!strcasecmp(v->name, "devices")) {
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++ if (mkif(incomingmsn,context,controllerstr,atoi(v->value),softdtmf,echocancel,ecoption,ectail, prefix, isdnmode, es,rxgain,txgain,deflect2,accountcode,callgroup, group)) {
++#else
++ if (mkif(incomingmsn,context,controllerstr,atoi(v->value),softdtmf,echocancel,ecoption,ectail, prefix, isdnmode, es,rxgain,txgain,accountcode,callgroup, group)) {
++#endif
++ ast_log(LOG_ERROR,"Error creating interface list\n");
++ return -1;
++ }
++ es=0;
++ strncpy(deflect2, empty, sizeof(deflect2)-1);
++ } else if (!strcasecmp(v->name, "context")) {
++ strncpy(context, v->value, sizeof(context)-1);
++ } else if (!strcasecmp(v->name, "incomingmsn")) {
++ strncpy(incomingmsn, v->value, sizeof(incomingmsn)-1);
++ } else if (!strcasecmp(v->name, "controller")) {
++ strncpy(controllerstr, v->value, sizeof(controllerstr)-1);
++ } else if (!strcasecmp(v->name, "softdtmf")) {
++ softdtmf = atoi(v->value);
++ } else if (!strcasecmp(v->name, "echosquelch")) {
++ es = atoi(v->value);
++ } else if (!strcasecmp(v->name, "callgroup")) {
++ callgroup = ast_get_group(v->value);
++ } else if (!strcasecmp(v->name, "group")) {
++ group = ast_get_group(v->value);
++ } else if (!strcasecmp(v->name, "deflect")) {
++ strncpy(deflect2, v->value, sizeof(deflect2)-1);
++ } else if (!strcasecmp(v->name, "rxgain")) {
++ if (sscanf(v->value,"%f",&rxgain) != 1) {
++ ast_log(LOG_ERROR,"invalid rxgain\n");
++ }
++ } else if (!strcasecmp(v->name, "txgain")) {
++ if (sscanf(v->value,"%f",&txgain) != 1) {
++ ast_log(LOG_ERROR,"invalid txgain\n");
++ }
++ } else if (!strcasecmp(v->name, "echocancel")) {
++ if (!strcasecmp(v->value, "yes") || !strcasecmp(v->value, "1") || !strcasecmp(v->value, "on")) {
++ echocancel=1;
++ ecoption=EC_OPTION_DISABLE_G165;
++ }
++ else if (!strcasecmp(v->value, "no") || !strcasecmp(v->value, "0") || !strcasecmp(v->value, "off")) {
++ echocancel=0;
++ ecoption=0;
++ }
++ else if (!strcasecmp(v->value, "g165") || !strcasecmp(v->value, "g.165")) {
++ echocancel=1;
++ ecoption=EC_OPTION_DISABLE_G165;
++ }
++ else if (!strcasecmp(v->value, "g164") || !strcasecmp(v->value, "g.164")) {
++ echocancel=1;
++ ecoption=EC_OPTION_DISABLE_G164_OR_G165;
++ }
++ else if (!strcasecmp(v->value, "force")) {
++ echocancel=1;
++ ecoption=EC_OPTION_DISABLE_NEVER;
++ }
++ else {
++ ast_log(LOG_ERROR,"Unknown echocancel parameter \"%s\" -- ignoring\n",v->value);
++ }
++ } else if (!strcasecmp(v->name, "echotail")) {
++ ectail = atoi(v->value);
++ if (ectail > 255)
++ ectail = 255;
++ } else if (!strcasecmp(v->name, "prefix")) {
++ strncpy(prefix, v->value, sizeof(prefix)-1);
++ } else if (!strcasecmp(v->name, "accountcode")) {
++ strncpy(accountcode, v->value, sizeof(accountcode)-1);
++ } else if (!strcasecmp(v->name, "isdnmode")) {
++ if (!strcasecmp(v->value, "ptp") || !strcasecmp(v->value, "1"))
++ isdnmode = 1;
++ else if (!strcasecmp(v->value, "ptm") || !strcasecmp(v->value, "0") || !strcasecmp(v->value, "ptmp"))
++ isdnmode = 0;
++ else
++ ast_log(LOG_ERROR,"Unknown isdnmode parameter \"%s\" -- ignoring\n",v->value);
++
++ }
++
++ v = v->next;
++ }
++ ast_config_destroy(cfg);
++
++ for (controller=1;controller<=capi_num_controllers;controller++) {
++ if (capi_used_controllers & (1 << controller)) {
++ if (ListenOnController(ALL_SERVICES,controller) != 0) {
++ ast_log(LOG_ERROR,"Unable to listen on contr%d\n",controller);
++ } else {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "listening on contr%d CIPmask = %#x\n",controller,ALL_SERVICES);
++ }
++ } else {
++ ast_log(LOG_WARNING,"Unused contr%d\n",controller);
++ }
++ }
++
++
++ ast_mutex_unlock(&iflock);
++
++ if (ast_channel_register(&capi_tech)) {
++ ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
++ unload_module();
++ return -1;
++ }
++
++ ast_cli_register(&cli_info);
++ ast_cli_register(&cli_debug);
++ ast_cli_register(&cli_no_debug);
++
++ if (ast_mutex_lock(&monlock)) {
++ ast_log(LOG_WARNING,"Unable to get monitor lock!\n");
++ return -1;
++ }
++ if (monitor_thread == pthread_self()) {
++ ast_mutex_unlock(&monlock);
++ ast_log(LOG_WARNING,"Unable to kill myself!\n");
++ return -1;
++ }
++
++ if (ast_pthread_create(&monitor_thread,NULL,do_monitor,NULL) < 0) {
++ ast_mutex_unlock(&monlock);
++ ast_log(LOG_ERROR,"Unable to start monitor thread!\n");
++ return -1;
++ }
++
++ return res;
++}
++
++
++static int unload_module()
++{
++ if (capi20_release(ast_capi_ApplID) != 0)
++ ast_log(LOG_WARNING,"Unable to unregister from CAPI!\n");
++ ast_channel_unregister(&capi_tech);
++ return 0;
++}
++
++int usecount()
++{
++ int res;
++ ast_mutex_lock(&usecnt_lock);
++ res = usecnt;
++ ast_mutex_unlock(&usecnt_lock);
++ return res;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, desc,
++ .load = load_module,
++ .unload = unload_module,
++);
+--- /dev/null
++++ asterisk-1.4.8~dfsg/configs/capi.conf.sample
+@@ -0,0 +1,44 @@
++;
++; CAPI config
++;
++;
++[general]
++nationalprefix=0
++internationalprefix=00
++rxgain=0.8
++txgain=0.8
++
++[interfaces]
++
++; mode: ptmp (point-to-multipoint) or ptp (point-to-point)
++isdnmode=ptmp
++; allow incoming calls to this list of MSNs, * == any
++incomingmsn=*
++; capi controller number
++controller=1
++; dialout group
++group=1
++; enable/disable software dtmf detection, recommended for AVM cards
++softdtmf=1
++; accountcode to use in CDRs
++accountcode=
++; context for incoming calls
++context=capi-in
++; _VERY_PRIMITIVE_ echo suppression
++;echosquelch=1
++; EICON DIVA SERVER echo cancelation
++;echocancel=yes
++;echotail=64
++; call group
++;callgroup=1
++; deflect incoming calls to 12345678 if all B channels are busy
++;deflect=12345678
++; number of concurrent calls on this controller (2 makes sense for single BRI)
++devices => 2
++
++
++;PointToPoint (55512-0)
++;isdnmode=ptp
++;msn=55512
++;controller=2
++;devices => 30
+--- /dev/null
++++ asterisk-1.4.8~dfsg/doc/README.chan_capi
+@@ -0,0 +1,146 @@
++(CAPI*) chan_capi a Common ISDN API 2.0 implementation for Asterisk
++(C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH
++Klaus-Peter Junghanns <kpj at junghanns.net>
++
++This program is free software and may be modified and distributed under
++the terms of the GNU Public License. There is _NO_ warranty for this!
++
++Thanks go to the debuggers and bugfixers (listed in chronological order) :)
++===========================================================================
++Lele Forzani <lele at windmill.it>
++Florian Overkamp <florian at obsimref.com>
++Gareth Watts <gareth at omnipotent.net>
++Jeff Noxon <jeff at planetfall.com>
++Petr Michalek <petr.michalek at aca.cz>
++Jan Stocker
++(...and all the others that i forgot..) :-)
++
++chan_capi version 0.4.0-PRE1 includes:
++======================================
++
++- multiple controller support
++- CID,DNID (callling party, called party)
++- CLIR/CLIP
++- supplementary services, CD,HOLD,RETRIEVE,ECT
++- DTMF (dependend on card) + software DTMF support
++- early B3 connects (always,success,never)
++- digital audio (what did you think?)
++- incoming/outgoing calls
++- overlap sending (dialtone)
++- E(xplicit) C(all) T(ransfer) (...although it's done implicit .. but dont tell!)
++- tuneable latency ;) you can configure the size of B3 blocks at compile time
++ (in chan_capi_pvt.h, AST_CAPI_MAX_B3_BLOCK_SIZE)
++ the default is 160 samples, for non-VoIP use you can tune it down to 130
++- use asterisk's internal dsp functions for dtmf
++- alaw support
++- ulaw support!
++- Eicon CAPI echo cancelation (echocancel=1)
++- reject call waiting (ACO)
++- DID for Point to Point mode (a.k.a overlap receiving)
++- experimental echo squelching (echosquelch=1)
++- call progress, no need to add ||r to your dialstring anymore
++- rx/tx gains (rxgain=1.0)
++- call deflection on circuitbusy (makefile option) (deflect=12345678)
++- (inter)national dialing prefix (for callerid) configurable in capi.conf
++- CLI command "capi info" shows B channel status
++- capiECT will announce the callerID since it gets lost on most isdn pbxes
++ the called party can press # to drop the call
++- audio syncing (timing outgoing dataB3 on incoming dataB3), supposed to fix
++ the DATA_B3_REQ (error = 0x1103) problem
++- catch all MSN (incomingmsn=*)
++- some configuration enhancements (msn=123,124,125 and controller=1,2,3,4)
++- accountcode= added.
++- finally the echo squelching works!
++- callgroup support
++- fixed pipe leak
++- updated to support the new frame->delivery field
++- compiles with latest cvs with a makefile option (LOOK AT THE MAKEFILE)
++- fixed channel name bug in p2p mode
++- added app_capiNoES for disabling the primitive echo suppressor, use this before
++ you start recording voicemail or your files may get choppy
++- fixed for latest cvs (AST_MUTEX_DEFINE_STATIC)
++- fixed for latest cvs (asterisk/parking.h -> asterisk/features.h)
++- fixed for latest cvs ast_pthread_create
++
++- ATTENTION! the dialstring syntax now uses the zaptel dialstring syntax
++ it used to be: Dial(CAPI/[@]<outgoingMSN>:[b|B]<destination>)
++
++ now it is: Dial(CAPI/g<group>/[b|B]<destination>)
++ or: Dial(CAPI/contr<controller>/[b|B]<destination>)
++
++ CLIP/CLIR is now uses the calling presentation of the calling channel, this can
++ be modified using the CallingPres() application. Use CallinPres(32) for CLIR.
++ That is why the msn= param in capi.conf is now obsolete. The callerID is also
++ taken from the calling channel.
++
++- fixes for BSD (Jan Stocker)
++
++Helper applications
++===================
++kapejod says: "No No No, dont use those yet....!" (except maybe HOLD,ECT...)
++
++app_capiCD.c forwards an unanswered call to another phone (does not rely on sservice CD)
++ example:
++ exten => s,1,Wait,1
++ exten => s,2,capiCD,12345678
++
++app_capiHOLD.c puts an answered call on hold, this has nothing to do with asterisk's onhold thingie (music et al)
++ after putting a call onhold, never use the Wait application!
++
++app_capiRETRIEVE.c gets the holded call back
++
++app_capiECT.c explicit call transfer of the holded call (must put call on hold first!)
++ example:
++ exten => s,1,Answer
++ exten => s,2,capiHOLD
++ exten => s,3,capiECT,55:50
++ will ECT the call to 50 using 55 as the callerid/outgoing msn
++
++
++Using CLIR
++==========
++Use the CallingPres() application before you dial:
++exten => _X.,1,CallingPres(32)
++exten => _X.,2,Dial(CAPI/contr1/${EXTEN})
++
++Enjoying early B3 connects (inband call progress, tones and announcements)
++==========================================================================
++early B3 is now configurable in the dialstring :)
++if you prefix the destination number with a 'b' early B3 will always be used, also if the call fails
++because the number is unprovisioned, etc ...
++if you prefix it with a 'B' early B3 will only be used on successful calls, giving you ring indication,etc...
++
++dont use indications in the Dial command, your local exchange will do that for you:
++exten => _X.,1,Dial(CAPI/contr1/B${EXTEN},30) (early B3 on success)
++exten => _X.,1,Dial(CAPI/contr1/b${EXTEN},30) (always early B3)
++exten => _X.,1,Dial(CAPI/contr1/${EXTEN},30,r) (no early B3, fake ring indication)
++
++exten => _X.,1,Dial(CAPI/contr1/b${EXTEN},30,r) (always early B3, fake indicatons if the exchange
++ does not give us indications)
++exten => _X.,1,Dial(CAPI/contr1/B${EXTEN},30,r) (early B3 on success, fake indicatons if the exchange
++ does not give us indications)
++
++you can totally turn B3 off in the Makefile at buildtime (-DNEVER_EVER_EARLY_B3_CONNECTS).
++
++For normal PBX usage you would use the "b" option, always early B3.
++
++Overlap sending (a.k.a. real dialtone)
++======================================
++when you dial an empty number, and have early B3 enabled, with:
++ Dial(CAPI/g1/b)
++the channel will come up at once and give you the dialtone it gets from the local exchange.
++at this point the channel is like a legacy phone, now you can send dtmf digits to dial.
++
++Example context for incoming calls on MSN 12345678:
++===================================================
++
++[capi-in]
++exten => 12345678,1,Dial(SIP/phone1)
++exten => 12345678,2,Hangup
++
++
++More information/documentation and commercial support can be found at:
++ http://www.junghanns.net/asterisk/
++
++
++
+--- /dev/null
++++ asterisk-1.4.8~dfsg/include/asterisk/chan_capi_app.h
+@@ -0,0 +1,30 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * include file for helper applications
++ *
++ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod at ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ */
++
++#ifndef _ASTERISK_CAPI_IF_H
++#define _ASTERISK_CAPI_IF_H
++
++// exported symbols from chan_capi
++
++// important things we need
++extern unsigned ast_capi_ApplID;
++extern unsigned ast_capi_MessageNumber;
++extern int capidebug;
++
++extern int capi_call(struct ast_channel *c, char *idest, int timeout);
++extern int capi_detect_dtmf(struct ast_channel *c, int flag);
++extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG);
++
++#endif
+--- /dev/null
++++ asterisk-1.4.8~dfsg/include/asterisk/chan_capi.h
+@@ -0,0 +1,276 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod at ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ */
++
++#ifndef _ASTERISK_CAPI_H
++#define _ASTERISK_CAPI_H
++
++#define AST_CAPI_MAX_CONTROLLERS 16
++#define AST_CAPI_MAX_DEVICES 30
++#define AST_CAPI_MAX_BUF 160
++
++#define AST_CAPI_MAX_B3_BLOCKS 7
++
++/* was : 130 bytes Alaw = 16.25 ms audio not suitable for VoIP */
++/* now : 160 bytes Alaw = 20 ms audio */
++/* you can tune this to your need. higher value == more latency */
++#define AST_CAPI_MAX_B3_BLOCK_SIZE 160
++
++#define AST_CAPI_BCHANS 120
++#define ALL_SERVICES 0x1FFF03FF
++
++/* duration in ms for sending and detecting dtmfs */
++#define AST_CAPI_DTMF_DURATION 0x40
++
++#define AST_CAPI_NATIONAL_PREF "0"
++#define AST_CAPI_INTERNAT_PREF "00"
++
++#ifdef CAPI_ES
++#define ECHO_TX_COUNT 5 // 5 x 20ms = 100ms
++#define ECHO_EFFECTIVE_TX_COUNT 3 // 2 x 20ms = 40ms == 40-100ms ... ignore first 40ms
++#define ECHO_TXRX_RATIO 2.3 // if( rx < (txavg/ECHO_TXRX_RATIO) ) rx=0;
++#endif
++
++/*
++ * state combination for a normal incoming call:
++ * DIS -> ALERT -> CON -> BCON -> CON -> DIS
++ *
++ * outgoing call:
++ * DIS -> CONP -> BCONNECTED -> CON -> DIS
++ */
++
++#define CAPI_STATE_ALERTING 1
++#define CAPI_STATE_CONNECTED 2
++#define CAPI_STATE_BCONNECTED 3
++
++#define CAPI_STATE_DISCONNECTING 4
++#define CAPI_STATE_DISCONNECTED 5
++#define CAPI_STATE_REMOTE_HANGUP 6
++
++#define CAPI_STATE_CONNECTPENDING 7
++#define CAPI_STATE_ONHOLD 8
++#define CAPI_STATE_NETWORKHANGUP 9
++#define CAPI_STATE_ANSWERING 10
++#define CAPI_STATE_PUTTINGONHOLD 11
++#define CAPI_STATE_RETRIEVING 12
++
++#define CAPI_STATE_DID 13
++
++#define AST_CAPI_B3_DONT 0
++#define AST_CAPI_B3_ALWAYS 1
++#define AST_CAPI_B3_ON_SUCCESS 2
++
++#ifdef CAPI_GAIN
++struct ast_capi_gains {
++ unsigned char txgains[256];
++ unsigned char rxgains[256];
++};
++#endif
++
++#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00
++#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01
++#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02
++#define PRES_ALLOWED_NETWORK_NUMBER 0x03
++#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20
++#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21
++#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22
++#define PRES_PROHIB_NETWORK_NUMBER 0x23
++#define PRES_NUMBER_NOT_AVAILABLE 0x43
++
++
++//! Private data for a capi device
++struct ast_capi_pvt {
++ ast_mutex_t lock;
++ int fd;
++
++ /*! Channel we belong to, possibly NULL */
++ struct ast_channel *owner;
++ /*! Frame */
++ struct ast_frame fr;
++
++ char offset[AST_FRIENDLY_OFFSET];
++
++ // capi message number
++ _cword MessageNumber;
++ int NCCI;
++ int PLCI;
++ /* on which controller we do live */
++ int controller;
++
++ /* we could live on those */
++ unsigned long controllers;
++
++ int datahandle;
++
++ short buf[AST_CAPI_MAX_BUF];
++ int buflen;
++ /*! Immediate, or wait for an answer */
++ int mode;
++ /*! State of modem in miniature */
++ int state;
++ /*! Digits to strip on outgoing numbers */
++ int stripmsd;
++ /*! ringer timeout */
++ int ringt;
++ /*! actual time of last ring */
++ time_t lastring;
++ /*! dtmf receive state/data */
++ char dtmfrx;
++
++ char context[AST_MAX_EXTENSION];
++ /*! Multiple Subscriber Number we listen to (, seperated list) */
++ char incomingmsn[AST_MAX_EXTENSION];
++ /*! Prefix to Build CID */
++ char prefix[AST_MAX_EXTENSION];
++ /*! Caller ID if available */
++ char cid[AST_MAX_EXTENSION];
++ /*! Dialed Number if available */
++ char dnid[AST_MAX_EXTENSION];
++
++ char accountcode[20];
++
++ unsigned int callgroup;
++ unsigned int group;
++
++ /*! default language */
++ char language[MAX_LANGUAGE];
++ /*! Static response buffer */
++ char response[256];
++
++ int calledPartyIsISDN;
++ // this is an outgoing channel
++ int outgoing;
++ // use CLIR
++ int CLIR;
++ // are we doing early B3 connect on this interface?
++ int earlyB3;
++ // should we do early B3 on this interface?
++ int doB3;
++ // store plci here for the call that is onhold
++ int onholdPLCI;
++ // do software dtmf detection
++ int doDTMF;
++ // CAPI echo cancellation
++ int doEC;
++ int ecOption;
++ int ecTail;
++ // isdnmode ptp or ptm
++ int isdnmode;
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++ // deflect on circuitbusy
++ char deflect2[AST_MAX_EXTENSION];
++#endif
++
++ // not all codecs supply frames in nice 320 byte chunks
++ struct ast_smoother *smoother;
++ // ok, we stop to be nice and give them the lowest possible latency 130 samples * 2 = 260 bytes */
++#ifdef CAPI_SYNC
++ int B3in;
++ ast_mutex_t lockB3in;
++#endif
++
++ // do ECHO SURPRESSION
++ int doES;
++#ifdef CAPI_ES
++ short txavg[ECHO_TX_COUNT];
++ float rxmin;
++ float txmin;
++#endif
++#ifdef CAPI_GAIN
++ struct ast_capi_gains g;
++#endif
++ float txgain;
++ float rxgain;
++ struct ast_dsp *vad;
++
++
++ struct capi_pipe *mypipe;
++ /*! Next channel in list */
++ struct ast_capi_pvt *next;
++};
++
++
++struct ast_capi_profile {
++ unsigned short ncontrollers;
++ unsigned short nbchannels;
++ unsigned char globaloptions;
++ unsigned char globaloptions2;
++ unsigned char globaloptions3;
++ unsigned char globaloptions4;
++ unsigned int b1protocols;
++ unsigned int b2protocols;
++ unsigned int b3protocols;
++ unsigned int reserved3[6];
++ unsigned int manufacturer[5];
++};
++
++struct capi_pipe {
++ // lock
++ ast_mutex_t lock;
++
++ // fd for writing to the channel
++ int fd;
++
++ // PLCI and NCCI of the B3 CON
++ int PLCI;
++ int NCCI;
++ // pointer to the interface
++ struct ast_capi_pvt *i;
++ // pointer to the channel
++ struct ast_channel *c;
++ // next pipe
++ struct capi_pipe *next;
++};
++
++struct ast_capi_controller {
++ // which controller is this?
++ int controller;
++ // how many bchans?
++ int nbchannels;
++ // free bchans
++ int nfreebchannels;
++ // DID
++ int isdnmode;
++ // features:
++ int dtmf;
++ int echocancel;
++ int sservices; // supplementray services
++ // supported sservices:
++ int holdretrieve;
++ int terminalportability;
++ int ECT;
++ int threePTY;
++ int CF;
++ int CD;
++ int MCID;
++ int CCBS;
++ int MWI;
++ int CCNR;
++ int CONF;
++};
++
++
++// ETSI 300 102-1 information element identifiers
++#define CAPI_ETSI_IE_CAUSE 0x08;
++#define CAPI_ETSI_IE_PROGRESS_INDICATOR 0x1e;
++#define CAPI_ETSI_IE_CALLED_PARTY_NUMBER 0x70;
++
++// ETIS 300 102-1 message types
++#define CAPI_ETSI_ALERTING 0x01;
++#define CAPI_ETSI_SETUP_ACKKNOWLEDGE 0x0d;
++#define CAPI_ETSI_DISCONNECT 0x45;
++
++// ETSI 300 102-1 Numbering Plans
++#define CAPI_ETSI_NPLAN_NATIONAL 0x20
++#define CAPI_ETSI_NPLAN_INTERNAT 0x10
++
++#endif
+--- /dev/null
++++ asterisk-1.4.8~dfsg/include/asterisk/xlaw.h
+@@ -0,0 +1,1665 @@
++#ifndef _ASTERISK_XLAW_H
++#define _ASTERISK_XLAW_H
++
++#ifdef CAPI_ULAW
++#define capiXLAW2INT(x) capiULAW2INT[x]
++#define capiINT2XLAW(x) capiINT2ULAW[((unsigned short)x) >> 2]
++#else
++#define capiXLAW2INT(x) capiALAW2INT[x]
++#define capiINT2XLAW(x) capiINT2ALAW[(x>>4)+4096]
++#endif
++
++static unsigned char reversebits[256] =
++{
++0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
++0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
++0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
++0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
++0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
++0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
++0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
++0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
++0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
++0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
++0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
++0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
++0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
++0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
++0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
++0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
++0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
++0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
++0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
++0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
++0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
++0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
++0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
++0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
++0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
++0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
++0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
++0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
++0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
++0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
++0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
++0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
++};
++
++#ifdef CAPI_ULAW
++static short capiULAW2INT[] =
++{
++0x8284, 0x7d7c, 0xf8a4, 0x075c, 0xe104, 0x1efc, 0xfe8c, 0x0174,
++0xc184, 0x3e7c, 0xfc94, 0x036c, 0xf0c4, 0x0f3c, 0xff88, 0x0078,
++0xa284, 0x5d7c, 0xfaa4, 0x055c, 0xe904, 0x16fc, 0xff0c, 0x00f4,
++0xd184, 0x2e7c, 0xfd94, 0x026c, 0xf4c4, 0x0b3c, 0xffc8, 0x0038,
++0x9284, 0x6d7c, 0xf9a4, 0x065c, 0xe504, 0x1afc, 0xfecc, 0x0134,
++0xc984, 0x367c, 0xfd14, 0x02ec, 0xf2c4, 0x0d3c, 0xffa8, 0x0058,
++0xb284, 0x4d7c, 0xfba4, 0x045c, 0xed04, 0x12fc, 0xff4c, 0x00b4,
++0xd984, 0x267c, 0xfe14, 0x01ec, 0xf6c4, 0x093c, 0xffe8, 0x0018,
++0x8a84, 0x757c, 0xf924, 0x06dc, 0xe304, 0x1cfc, 0xfeac, 0x0154,
++0xc584, 0x3a7c, 0xfcd4, 0x032c, 0xf1c4, 0x0e3c, 0xff98, 0x0068,
++0xaa84, 0x557c, 0xfb24, 0x04dc, 0xeb04, 0x14fc, 0xff2c, 0x00d4,
++0xd584, 0x2a7c, 0xfdd4, 0x022c, 0xf5c4, 0x0a3c, 0xffd8, 0x0028,
++0x9a84, 0x657c, 0xfa24, 0x05dc, 0xe704, 0x18fc, 0xfeec, 0x0114,
++0xcd84, 0x327c, 0xfd54, 0x02ac, 0xf3c4, 0x0c3c, 0xffb8, 0x0048,
++0xba84, 0x457c, 0xfc24, 0x03dc, 0xef04, 0x10fc, 0xff6c, 0x0094,
++0xdd84, 0x227c, 0xfe54, 0x01ac, 0xf7c4, 0x083c, 0xfff8, 0x0008,
++0x8684, 0x797c, 0xf8e4, 0x071c, 0xe204, 0x1dfc, 0xfe9c, 0x0164,
++0xc384, 0x3c7c, 0xfcb4, 0x034c, 0xf144, 0x0ebc, 0xff90, 0x0070,
++0xa684, 0x597c, 0xfae4, 0x051c, 0xea04, 0x15fc, 0xff1c, 0x00e4,
++0xd384, 0x2c7c, 0xfdb4, 0x024c, 0xf544, 0x0abc, 0xffd0, 0x0030,
++0x9684, 0x697c, 0xf9e4, 0x061c, 0xe604, 0x19fc, 0xfedc, 0x0124,
++0xcb84, 0x347c, 0xfd34, 0x02cc, 0xf344, 0x0cbc, 0xffb0, 0x0050,
++0xb684, 0x497c, 0xfbe4, 0x041c, 0xee04, 0x11fc, 0xff5c, 0x00a4,
++0xdb84, 0x247c, 0xfe34, 0x01cc, 0xf744, 0x08bc, 0xfff0, 0x0010,
++0x8e84, 0x717c, 0xf964, 0x069c, 0xe404, 0x1bfc, 0xfebc, 0x0144,
++0xc784, 0x387c, 0xfcf4, 0x030c, 0xf244, 0x0dbc, 0xffa0, 0x0060,
++0xae84, 0x517c, 0xfb64, 0x049c, 0xec04, 0x13fc, 0xff3c, 0x00c4,
++0xd784, 0x287c, 0xfdf4, 0x020c, 0xf644, 0x09bc, 0xffe0, 0x0020,
++0x9e84, 0x617c, 0xfa64, 0x059c, 0xe804, 0x17fc, 0xfefc, 0x0104,
++0xcf84, 0x307c, 0xfd74, 0x028c, 0xf444, 0x0bbc, 0xffc0, 0x0040,
++0xbe84, 0x417c, 0xfc64, 0x039c, 0xf004, 0x0ffc, 0xff7c, 0x0084,
++0xdf84, 0x207c, 0xfe74, 0x018c, 0xf844, 0x07bc, 0x0000, 0x0000
++};
++
++const unsigned char capiINT2ULAW[16384] = {
++255,127,127,191,191,63,63,223,223,95,95,159,159,31,31,239,
++239,111,111,175,175,47,47,207,207,79,79,143,143,15,15,247,
++247,247,247,119,119,119,119,183,183,183,183,55,55,55,55,215,
++215,215,215,87,87,87,87,151,151,151,151,23,23,23,23,231,
++231,231,231,103,103,103,103,167,167,167,167,39,39,39,39,199,
++199,199,199,71,71,71,71,135,135,135,135,7,7,7,7,251,
++251,251,251,251,251,251,251,123,123,123,123,123,123,123,123,187,
++187,187,187,187,187,187,187,59,59,59,59,59,59,59,59,219,
++219,219,219,219,219,219,219,91,91,91,91,91,91,91,91,155,
++155,155,155,155,155,155,155,27,27,27,27,27,27,27,27,235,
++235,235,235,235,235,235,235,107,107,107,107,107,107,107,107,171,
++171,171,171,171,171,171,171,43,43,43,43,43,43,43,43,203,
++203,203,203,203,203,203,203,75,75,75,75,75,75,75,75,139,
++139,139,139,139,139,139,139,11,11,11,11,11,11,11,11,243,
++243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,115,
++115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,179,
++179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,51,
++51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,211,
++211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,83,
++83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,147,
++147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,19,
++19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,227,
++227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,99,
++99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,163,
++163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,35,
++35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,195,
++195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,67,
++67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,131,
++131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,3,
++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,253,
++253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
++253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,125,
++125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,
++125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,189,
++189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
++189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,61,
++61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
++61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,221,
++221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
++221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,93,
++93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,
++93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,157,
++157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
++157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,29,
++29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,
++29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,237,
++237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
++237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,109,
++109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
++109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,173,
++173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
++173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,45,
++45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,
++45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,205,
++205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
++205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,77,
++77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
++77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,141,
++141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
++141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,13,
++13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
++13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++12,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++140,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++76,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++204,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++44,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++172,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++108,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++236,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++28,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++156,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++92,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++220,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++60,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++188,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++124,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++252,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
++2,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
++130,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
++66,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,
++194,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
++34,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
++162,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,
++98,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,
++226,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
++18,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
++146,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,
++82,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,
++210,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
++50,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
++178,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
++114,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,
++242,10,10,10,10,10,10,10,10,138,138,138,138,138,138,138,
++138,74,74,74,74,74,74,74,74,202,202,202,202,202,202,202,
++202,42,42,42,42,42,42,42,42,170,170,170,170,170,170,170,
++170,106,106,106,106,106,106,106,106,234,234,234,234,234,234,234,
++234,26,26,26,26,26,26,26,26,154,154,154,154,154,154,154,
++154,90,90,90,90,90,90,90,90,218,218,218,218,218,218,218,
++218,58,58,58,58,58,58,58,58,186,186,186,186,186,186,186,
++186,122,122,122,122,122,122,122,122,250,250,250,250,250,250,250,
++250,6,6,6,6,134,134,134,134,70,70,70,70,198,198,198,
++198,38,38,38,38,166,166,166,166,102,102,102,102,230,230,230,
++230,22,22,22,22,150,150,150,150,86,86,86,86,214,214,214,
++214,54,54,54,54,182,182,182,182,118,118,118,118,246,246,246,
++246,14,14,142,142,78,78,206,206,46,46,174,174,110,110,238,
++238,30,30,158,158,94,94,222,222,62,62,190,190,126,126,254,
++};
++#else
++static short capiALAW2INT[] =
++{
++ 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
++ 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
++ 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
++ 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
++ 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
++ 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
++ 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
++ 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
++ 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
++ 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
++ 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
++ 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
++ 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
++ 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
++ 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
++ 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
++ 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
++ 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
++ 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
++ 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
++ 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
++ 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
++ 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
++ 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
++ 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
++ 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
++ 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
++ 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
++ 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
++ 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
++ 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
++ 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
++};
++
++const unsigned char capiINT2ALAW[8192] = {
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++ 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++ 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++ 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++ 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++ 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++ 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++ 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++ 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++ 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++ 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++ 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++ 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++ 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++ 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++ 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++ 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++ 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++ 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++ 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++ 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++ 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++ 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++ 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++ 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++ 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++ 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++ 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++ 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++ 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++ 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++ 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++ 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++ 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++ 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++ 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++ 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++ 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++ 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++ 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++ 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++ 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++ 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++ 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++ 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++ 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++ 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++ 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++ 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++ 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++ 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++ 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++ 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++ 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++ 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++ 220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++ 220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++ 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++ 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++ 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++ 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++ 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++ 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++ 252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++ 252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++ 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++ 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++ 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++ 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++ 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++ 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++ 204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++ 204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++ 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++ 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++ 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++ 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++ 236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++ 236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++ 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++ 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++ 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++ 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++ 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++ 208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++ 144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++ 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++ 240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++ 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++ 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++ 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++ 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++ 96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++ 224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++ 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++ 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++ 88,88,88,88,88,88,88,88,216,216,216,216,216,216,216,216,
++ 24,24,24,24,24,24,24,24,152,152,152,152,152,152,152,152,
++ 120,120,120,120,120,120,120,120,248,248,248,248,248,248,248,248,
++ 56,56,56,56,56,56,56,56,184,184,184,184,184,184,184,184,
++ 72,72,72,72,72,72,72,72,200,200,200,200,200,200,200,200,
++ 8,8,8,8,8,8,8,8,136,136,136,136,136,136,136,136,
++ 104,104,104,104,104,104,104,104,232,232,232,232,232,232,232,232,
++ 40,40,40,40,40,40,40,40,168,168,168,168,168,168,168,168,
++ 86,86,86,86,214,214,214,214,22,22,22,22,150,150,150,150,
++ 118,118,118,118,246,246,246,246,54,54,54,54,182,182,182,182,
++ 70,70,70,70,198,198,198,198,6,6,6,6,134,134,134,134,
++ 102,102,102,102,230,230,230,230,38,38,38,38,166,166,166,166,
++ 94,94,222,222,30,30,158,158,126,126,254,254,62,62,190,190,
++ 78,78,206,206,14,14,142,142,110,110,238,238,46,46,174,174,
++ 82,210,18,146,114,242,50,178,66,194,2,130,98,226,34,162,
++ 90,218,26,154,122,250,58,186,74,202,10,138,106,234,42,170,
++ 171,43,235,107,139,11,203,75,187,59,251,123,155,27,219,91,
++ 163,35,227,99,131,3,195,67,179,51,243,115,147,19,211,83,
++ 175,175,47,47,239,239,111,111,143,143,15,15,207,207,79,79,
++ 191,191,63,63,255,255,127,127,159,159,31,31,223,223,95,95,
++ 167,167,167,167,39,39,39,39,231,231,231,231,103,103,103,103,
++ 135,135,135,135,7,7,7,7,199,199,199,199,71,71,71,71,
++ 183,183,183,183,55,55,55,55,247,247,247,247,119,119,119,119,
++ 151,151,151,151,23,23,23,23,215,215,215,215,87,87,87,87,
++ 169,169,169,169,169,169,169,169,41,41,41,41,41,41,41,41,
++ 233,233,233,233,233,233,233,233,105,105,105,105,105,105,105,105,
++ 137,137,137,137,137,137,137,137,9,9,9,9,9,9,9,9,
++ 201,201,201,201,201,201,201,201,73,73,73,73,73,73,73,73,
++ 185,185,185,185,185,185,185,185,57,57,57,57,57,57,57,57,
++ 249,249,249,249,249,249,249,249,121,121,121,121,121,121,121,121,
++ 153,153,153,153,153,153,153,153,25,25,25,25,25,25,25,25,
++ 217,217,217,217,217,217,217,217,89,89,89,89,89,89,89,89,
++ 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++ 33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++ 225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++ 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++ 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++ 193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++ 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++ 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++ 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++ 241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++ 113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++ 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++ 209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++ 81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++ 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
++ 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
++ 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,
++ 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,
++ 237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
++ 237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
++ 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
++ 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
++ 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
++ 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
++ 205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
++ 205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
++ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
++ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
++ 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
++ 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
++ 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
++ 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
++ 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
++ 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
++ 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,
++ 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,
++ 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
++ 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
++ 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,
++ 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,
++ 221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
++ 221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
++ 93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,
++ 93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,
++ 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++ 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++ 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++ 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++ 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++ 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++ 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++ 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++ 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++ 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++ 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++ 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++ 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++ 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++ 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++ 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++ 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++ 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++ 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++ 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++ 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++ 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++ 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++ 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++ 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++ 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++ 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++ 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++ 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++ 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++ 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++ 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++ 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++ 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++ 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++ 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++ 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++ 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++ 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++ 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++ 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++ 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++ 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++ 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++ 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++ 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++ 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++ 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++ 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++ 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++ 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++ 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++ 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++ 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++ 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++ 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++ 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85
++};
++
++#endif // CAPI_ULAW
++#endif
++
+--- asterisk-1.4.8~dfsg.orig/configure.ac
++++ asterisk-1.4.8~dfsg/configure.ac
+@@ -171,6 +171,7 @@ AC_SUBST(AST_DEVMODE)
+ # by the --with option name, to make things easier for the users :-)
+
+ AST_EXT_LIB_SETUP([ALSA], [Advanced Linux Sound Architecture], [asound])
++AST_EXT_LIB_SETUP([CAPI], [CAPI 2.0], [capi])
+ AST_EXT_LIB_SETUP([CURL], [cURL], [curl])
+ AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
+ AST_EXT_LIB_SETUP([GNUTLS], [GNU TLS support (used for iksemel only)], [gnutls])
+@@ -374,6 +375,8 @@ AC_CHECK_SIZEOF(int)
+
+ AST_EXT_LIB_CHECK([ALSA], [asound], [snd_spcm_init], [alsa/asoundlib.h], [-lm -ldl])
+
++AST_EXT_LIB_CHECK([CAPI], [capi], [capi20_isinstalled], [capi20.h], [-lcapi20])
++
+ AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
+
+ GSM_INTERNAL="yes"
+--- asterisk-1.4.8~dfsg.orig/configure
++++ asterisk-1.4.8~dfsg/configure
+@@ -720,6 +720,9 @@ ALSA_LIB
+ ALSA_INCLUDE
+ ALSA_DIR
+ PBX_ALSA
++CAPI_LIB
++CAPI_INCLUDE
++PBX_CAPI
+ CURL_LIB
+ CURL_INCLUDE
+ CURL_DIR
+@@ -1499,6 +1502,7 @@ Optional Packages:
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-asound=PATH use Advanced Linux Sound Architecture files in PATH
++ --with-capi=PATH use CAPI 2.0 files in PATH
+ --with-curl=PATH use cURL files in PATH
+ --with-curses=PATH use curses files in PATH
+ --with-gnutls=PATH use GNU TLS support (used for iksemel only) files in
+@@ -7630,6 +7634,33 @@ PBX_CURL=0
+
+
+
++CAPI_DESCRIP="CAPI 2.0"
++CAPI_OPTION="capi"
++
++# Check whether --with-capi was given.
++if test "${with_capi+set}" = set; then
++ withval=$with_capi;
++case ${withval} in
++ n|no)
++ USE_CAPI=no
++ ;;
++ y|ye|yes)
++ CAPI_MANDATORY="yes"
++ ;;
++ *)
++ CAPI_DIR="${withval}"
++ CAPI_MANDATORY="yes"
++ ;;
++esac
++
++fi
++
++PBX_CAPI=0
++
++
++
++
++
+ CURSES_DESCRIP="curses"
+ CURSES_OPTION="curses"
+
+@@ -16063,11 +16094,11 @@ cat >>conftest.$ac_ext <<_ACEOF
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+-char snd_spcm_init ();
++char capi20_isinstalled ();
+ int
+ main ()
+ {
+-return snd_spcm_init ();
++return capi20_isinstalled ();
+ ;
+ return 0;
+ }
+@@ -16132,8 +16163,8 @@ ac_res=`eval echo '${'$as_ac_Header'}'`
+ echo "${ECHO_T}$ac_res" >&6; }
+ else
+ # Is the header compilable?
+-{ echo "$as_me:$LINENO: checking ${ALSA_DIR}/include/alsa/asoundlib.h usability" >&5
+-echo $ECHO_N "checking ${ALSA_DIR}/include/alsa/asoundlib.h usability... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking ${CAPI_DIR}/include/capi20.h usability" >&5
++echo $ECHO_N "checking ${CAPI_DIR}/include/capi20.h usability... $ECHO_C" >&6; }
+ cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h. */
+ _ACEOF
+@@ -16141,7 +16172,7 @@ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h. */
+ $ac_includes_default
+-#include <${ALSA_DIR}/include/alsa/asoundlib.h>
++#include <${CAPI_DIR}/include/capi20.h>
+ _ACEOF
+ rm -f conftest.$ac_objext
+ if { (ac_try="$ac_compile"
+@@ -16173,15 +16204,15 @@ rm -f core conftest.err conftest.$ac_obj
+ echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+ # Is the header present?
+-{ echo "$as_me:$LINENO: checking ${ALSA_DIR}/include/alsa/asoundlib.h presence" >&5
+-echo $ECHO_N "checking ${ALSA_DIR}/include/alsa/asoundlib.h presence... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking ${CAPI_DIR}/include/capi20.h presence" >&5
++echo $ECHO_N "checking ${CAPI_DIR}/include/capi20.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 <${ALSA_DIR}/include/alsa/asoundlib.h>
++#include <${CAPI_DIR}/include/capi20.h>
+ _ACEOF
+ if { (ac_try="$ac_cpp conftest.$ac_ext"
+ case "(($ac_try" in
+@@ -16214,30 +16245,30 @@ 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: ${ALSA_DIR}/include/alsa/asoundlib.h: accepted by the compiler, rejected by the preprocessor!" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: proceeding with the compiler's result" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: proceeding with the compiler's result" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: accepted by the compiler, rejected by the preprocessor!" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: proceeding with the compiler's result" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: present but cannot be compiled" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: present but cannot be compiled" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: check for missing prerequisite headers?" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: check for missing prerequisite headers?" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: see the Autoconf documentation" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: see the Autoconf documentation" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: section \"Present But Cannot Be Compiled\"" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: section \"Present But Cannot Be Compiled\"" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: proceeding with the preprocessor's result" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: proceeding with the preprocessor's result" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: in the future, the compiler will take precedence" >&5
+-echo "$as_me: WARNING: ${ALSA_DIR}/include/alsa/asoundlib.h: in the future, the compiler will take precedence" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: present but cannot be compiled" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: present but cannot be compiled" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: check for missing prerequisite headers?" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: check for missing prerequisite headers?" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: see the Autoconf documentation" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: see the Autoconf documentation" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: section \"Present But Cannot Be Compiled\"" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: section \"Present But Cannot Be Compiled\"" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: proceeding with the preprocessor's result" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: proceeding with the preprocessor's result" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${CAPI_DIR}/include/capi20.h: in the future, the compiler will take precedence" >&5
++echo "$as_me: WARNING: ${CAPI_DIR}/include/capi20.h: in the future, the compiler will take precedence" >&2;}
+
+ ;;
+ esac
+-{ echo "$as_me:$LINENO: checking for ${ALSA_DIR}/include/alsa/asoundlib.h" >&5
+-echo $ECHO_N "checking for ${ALSA_DIR}/include/alsa/asoundlib.h... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking for ${CAPI_DIR}/include/capi20.h" >&5
++echo $ECHO_N "checking for ${CAPI_DIR}/include/capi20.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
+@@ -16278,7 +16309,7 @@ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h. */
+ $ac_includes_default
+-#include <alsa/asoundlib.h>
++#include <capi20.h>
+ _ACEOF
+ rm -f conftest.$ac_objext
+ if { (ac_try="$ac_compile"
+@@ -16310,15 +16341,15 @@ rm -f core conftest.err conftest.$ac_obj
+ echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+ # Is the header present?
+-{ echo "$as_me:$LINENO: checking alsa/asoundlib.h presence" >&5
+-echo $ECHO_N "checking alsa/asoundlib.h presence... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking capi20.h presence" >&5
++echo $ECHO_N "checking capi20.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 <alsa/asoundlib.h>
++#include <capi20.h>
+ _ACEOF
+ if { (ac_try="$ac_cpp conftest.$ac_ext"
+ case "(($ac_try" in
Added: asterisk/branches/experimental/debian/patches/bristuff/chan-iax2-hangup-cause
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/chan-iax2-hangup-cause (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/chan-iax2-hangup-cause 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,31 @@
+--- asterisk-1.4.8~dfsg.orig/channels/chan_iax2.c
++++ asterisk-1.4.8~dfsg/channels/chan_iax2.c
+@@ -11,6 +11,9 @@
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
++ * Hangup cause signalling implementation by
++ * Levent Guendogdu <levon at feature-it.com>
++ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+@@ -3004,7 +3007,7 @@ static int iax2_hangup(struct ast_channe
+ memset(&ied, 0, sizeof(ied));
+ ast_mutex_lock(&iaxsl[callno]);
+ if (callno && iaxs[callno]) {
+- ast_log(LOG_DEBUG, "We're hanging up %s now...\n", c->name);
++ ast_log(LOG_DEBUG, "We're hanging up %s with cause %i now...\n", c->name, c->hangupcause);
+ alreadygone = ast_test_flag(iaxs[callno], IAX_ALREADYGONE);
+ /* Send the hangup unless we have had a transmission error or are already gone */
+ iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, (unsigned char)c->hangupcause);
+@@ -3052,7 +3055,8 @@ static int iax2_setoption(struct ast_cha
+
+ static struct ast_frame *iax2_read(struct ast_channel *c)
+ {
+- ast_log(LOG_NOTICE, "I should never be called!\n");
++ if (option_verbose > 3)
++ ast_log(LOG_NOTICE, "I should never be called!\n");
+ return &ast_null_frame;
+ }
+
Added: asterisk/branches/experimental/debian/patches/bristuff/configurable-AST_SYSTEM_NAME
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/configurable-AST_SYSTEM_NAME (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/configurable-AST_SYSTEM_NAME 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,29 @@
+--- asterisk-1.4.8~dfsg.orig/build_tools/make_defaults_h
++++ asterisk-1.4.8~dfsg/build_tools/make_defaults_h
+@@ -17,6 +17,7 @@ cat << END
+ #define AST_KEY_DIR "${INSTALL_PATH}${ASTVARLIBDIR}/keys"
+ #define AST_DB "${INSTALL_PATH}${ASTVARLIBDIR}/astdb"
+ #define AST_TMP_DIR "${INSTALL_PATH}${ASTSPOOLDIR}/tmp"
++#define AST_SYSTEM_NAME "asterisk"
+
+ #define AST_CONFIG_FILE "${INSTALL_PATH}${ASTCONFPATH}"
+
+--- asterisk-1.4.8~dfsg.orig/main/asterisk.c
++++ asterisk-1.4.8~dfsg/main/asterisk.c
+@@ -2368,6 +2368,7 @@ static void ast_readconfig(void)
+ ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
+ ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
+ ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
++ ast_copy_string(ast_config_AST_SYSTEM_NAME, AST_SYSTEM_NAME, sizeof(ast_config_AST_SYSTEM_NAME));
+
+ /* no asterisk.conf? no problem, use buildtime config! */
+ if (!cfg) {
+@@ -2492,6 +2493,8 @@ static void ast_readconfig(void)
+ ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
+ } else if (!strcasecmp(v->name, "systemname")) {
+ ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
++ } else if (!strcasecmp(v->name, "uniquename")) {
++ ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
+ } else if (!strcasecmp(v->name, "languageprefix")) {
+ ast_language_is_prefix = ast_true(v->value);
+ }
Added: asterisk/branches/experimental/debian/patches/bristuff/feature-autoanswer
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/feature-autoanswer (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/feature-autoanswer 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,608 @@
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/features.h
++++ asterisk-1.4.8~dfsg/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
+--- asterisk-1.4.8~dfsg.orig/res/res_features.c
++++ asterisk-1.4.8~dfsg/res/res_features.c
+@@ -11,6 +11,10 @@
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+@@ -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 */
+@@ -404,11 +439,13 @@ int ast_park_call(struct ast_channel *ch
+ "From: %s\r\n"
+ "Timeout: %ld\r\n"
+ "CallerID: %s\r\n"
+- "CallerIDName: %s\r\n",
++ "CallerIDName: %s\r\n"
++ "Uniqueid: %s\r\n",
+ pu->parkingexten, pu->chan->name, peer ? peer->name : "",
+ (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
+ S_OR(pu->chan->cid.cid_num, "<unknown>"),
+- S_OR(pu->chan->cid.cid_name, "<unknown>")
++ S_OR(pu->chan->cid.cid_name, "<unknown>"),
++ pu->chan->uniqueid
+ );
+
+ if (peer && adsipark && ast_adsi_available(peer)) {
+@@ -1613,11 +1650,13 @@ static void post_manager_event(const cha
+ "Exten: %s\r\n"
+ "Channel: %s\r\n"
+ "CallerID: %s\r\n"
+- "CallerIDName: %s\r\n\r\n",
++ "CallerIDName: %s\r\n"
++ "Uniqueid: %s\r\n\r\n",
+ parkingexten,
+ chan->name,
+ S_OR(chan->cid.cid_num, "<unknown>"),
+- S_OR(chan->cid.cid_name, "<unknown>")
++ S_OR(chan->cid.cid_name, "<unknown>"),
++ chan->uniqueid
+ );
+ }
+
+@@ -1868,10 +1907,12 @@ static int park_exec(struct ast_channel
+ "Channel: %s\r\n"
+ "From: %s\r\n"
+ "CallerID: %s\r\n"
+- "CallerIDName: %s\r\n",
++ "CallerIDName: %s\r\n"
++ "Uniqueid: %s\r\n",
+ pu->parkingexten, pu->chan->name, chan->name,
+ S_OR(pu->chan->cid.cid_num, "<unknown>"),
+- S_OR(pu->chan->cid.cid_name, "<unknown>")
++ S_OR(pu->chan->cid.cid_name, "<unknown>"),
++ pu->chan->uniqueid
+ );
+
+ free(pu);
+@@ -2022,15 +2063,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)
+@@ -2054,12 +2090,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 <unknown> */
+- S_OR(cur->chan->cid.cid_name, ""),
++ S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid,
+ idText);
+ }
+
+@@ -2134,6 +2171,427 @@ static int manager_park(struct mansessio
+ return 0;
+ }
+
++static int handle_autoanswer(int fd, int argc, char *argv[])
++{
++ struct aauser *cur;
++
++ ast_cli(fd, "%25s %10s %15s \n", "Channel"
++ , "Extension", "Context");
++
++ ast_mutex_lock(&autoanswer_lock);
++
++ cur=aalot;
++ while(cur) {
++ ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
++
++ cur = cur->next;
++ }
++
++ ast_mutex_unlock(&autoanswer_lock);
++
++ return RESULT_SUCCESS;
++}
++
++static struct ast_cli_entry cli_features[] = {
++ { { "feature", "list", NULL },
++ handle_showfeatures, "Lists configured features",
++ showfeatures_help, NULL, &cli_show_features_deprecated },
++
++ { { "show", "parkedcalls", NULL },
++ handle_parkedcalls, "Lists parked calls",
++ showparked_help },
++
++ { { "show", "autoanswer", NULL },
++ handle_autoanswer, "Lists autoanswer users",
++ showautoanswer_help },
++};
++int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data)
++{
++ struct ast_channel *chan;
++ struct ast_frame *f;
++ /* Make a new, fake channel that we'll use to masquerade in the real one */
++ chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
++ if (chan) {
++ /* Let us keep track of the channel name */
++ ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
++ /* Make formats okay */
++ chan->readformat = rchan->readformat;
++ chan->writeformat = rchan->writeformat;
++ ast_channel_masquerade(chan, rchan);
++ /* Setup the extensions and such */
++ strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
++ strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
++ chan->priority = rchan->priority;
++ /* might be dirty but we want trackable channels */
++ ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
++ /* Make the masq execute */
++ f = ast_read(chan);
++ if (f)
++ ast_frfree(f);
++ ast_autoanswer_login(chan, data);
++ } else {
++ ast_log(LOG_WARNING, "Unable to create aa channel\n");
++ return -1;
++ }
++ return 0;
++}
++
++static int autoanswer_login_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ struct ast_module_user *u;
++
++ u = ast_module_user_add(chan);
++ if (!data) {
++ ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
++ return -1;
++ }
++ res = ast_masq_autoanswer_login(chan, data);
++ ast_module_user_remove(u);
++ return res;
++}
++
++int ast_autoanswer_login(struct ast_channel *chan, void *data)
++{
++ /* We put the user in the parking list, then wake up the parking thread to be sure it looks
++ after these channels too */
++ struct ast_context *con;
++ char exten[AST_MAX_EXTENSION];
++ struct aauser *pu,*pl = NULL;
++ char *s, *stringp, *aacontext, *aaexten = NULL;
++
++ s = ast_strdupa((void *) data);
++ stringp=s;
++ aacontext = strsep(&stringp, "|");
++ aaexten = strsep(&stringp, "|");
++ if (!aaexten) {
++ aaexten = aacontext;
++ aacontext = NULL;
++ }
++ if (!aaexten) {
++ ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
++ return -1;
++ } else {
++ if (!aacontext) {
++ aacontext = "default";
++ }
++ }
++
++ ast_mutex_lock(&autoanswer_lock);
++ pu = aalot;
++ while(pu) {
++ if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
++ if (pl)
++ pl->next = pu->next;
++ else
++ aalot = pu->next;
++ break;
++ }
++ pl = pu;
++ pu = pu->next;
++ }
++ ast_mutex_unlock(&autoanswer_lock);
++ if (pu) {
++ ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
++ manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
++ "Channel: %s\r\n"
++ "Uniqueid: %s\r\n"
++ "Context: %s\r\n"
++ "Exten: %s\r\n"
++ ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++ ast_hangup(pu->chan);
++ free(pu);
++ }
++ pu = malloc(sizeof(struct aauser));
++ if (pu) {
++ memset(pu, 0, sizeof(pu));
++ ast_mutex_lock(&autoanswer_lock);
++ chan->appl = "Autoanswer";
++ chan->data = NULL;
++
++ pu->chan = chan;
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++
++ /* Start music on hold */
++ ast_moh_start(pu->chan, NULL, NULL);
++ gettimeofday(&pu->start, NULL);
++ strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
++ strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
++ pu->next = aalot;
++ aalot = pu;
++ con = ast_context_find(aacontext);
++ if (!con) {
++ con = ast_context_create(NULL,aacontext, registrar);
++ if (!con) {
++ ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
++ }
++ }
++ if (con) {
++ snprintf(exten, sizeof(exten), "%s", aaexten);
++ ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
++ }
++
++ ast_mutex_unlock(&autoanswer_lock);
++ /* Wake up the (presumably select()ing) thread */
++ pthread_kill(autoanswer_thread, SIGURG);
++ if (option_verbose > 1)
++ ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
++ manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
++ "Channel: %s\r\n"
++ "Uniqueid: %s\r\n"
++ "Context: %s\r\n"
++ "Exten: %s\r\n"
++ ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++
++ return 0;
++ } else {
++ ast_log(LOG_WARNING, "Out of memory\n");
++ return -1;
++ }
++ return 0;
++}
++
++static void autoanswer_reregister_extensions(void)
++{
++ struct aauser *cur;
++ struct ast_context *con;
++ char exten[AST_MAX_EXTENSION];
++ char args[AST_MAX_EXTENSION];
++
++ ast_mutex_lock(&autoanswer_lock);
++
++ cur=aalot;
++ while(cur) {
++ con = ast_context_find(cur->context);
++ if (!con) {
++ con = ast_context_create(NULL,cur->context, registrar);
++ if (!con) {
++ ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context);
++ }
++ }
++ if (con) {
++ snprintf(exten, sizeof(exten), "%s", cur->exten);
++ snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten);
++ ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar);
++ }
++ cur = cur->next;
++ }
++
++ ast_mutex_unlock(&autoanswer_lock);
++}
++static void *do_autoanswer_thread(void *ignore)
++{
++ int ms, tms, max;
++ struct ast_context *con;
++ char exten[AST_MAX_EXTENSION];
++ struct aauser *pu, *pl, *pt = NULL;
++ struct timeval tv;
++ struct ast_frame *f;
++ int x;
++ fd_set rfds, efds;
++ fd_set nrfds, nefds;
++ FD_ZERO(&rfds);
++ FD_ZERO(&efds);
++ for (;;) {
++ ms = -1;
++ max = -1;
++ ast_mutex_lock(&autoanswer_lock);
++ pl = NULL;
++ pu = aalot;
++ gettimeofday(&tv, NULL);
++ FD_ZERO(&nrfds);
++ FD_ZERO(&nefds);
++ while(pu) {
++ tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
++ for (x=0;x<AST_MAX_FDS;x++) {
++ if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
++ if (FD_ISSET(pu->chan->fds[x], &efds))
++ ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
++ else
++ ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
++ pu->chan->fdno = x;
++ /* See if they need servicing */
++ f = ast_read(pu->chan);
++ if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
++ /* There's a problem, hang them up*/
++ if (option_verbose > 1)
++ ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
++ manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
++ "Channel: %s\r\n"
++ "Uniqueid: %s\r\n"
++ "Context: %s\r\n"
++ "Exten: %s\r\n"
++ ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++ ast_hangup(pu->chan);
++ con = ast_context_find(pu->context);
++ if (con) {
++ snprintf(exten, sizeof(exten), "%s", pu->exten);
++ if (ast_context_remove_extension2(con, exten, 1, registrar))
++ ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
++ } else {
++ ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
++ }
++ /* And take them out of the parking lot */
++ if (pl)
++ pl->next = pu->next;
++ else
++ aalot = pu->next;
++ pt = pu;
++ pu = pu->next;
++ free(pt);
++ break;
++ } else {
++ /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
++ ast_frfree(f);
++ goto std; /* XXX Ick: jumping into an else statement??? XXX */
++ }
++ }
++ }
++ if (x >= AST_MAX_FDS) {
++std: for (x=0;x<AST_MAX_FDS;x++) {
++ /* Keep this one for next one */
++ if (pu->chan->fds[x] > -1) {
++ FD_SET(pu->chan->fds[x], &nrfds);
++ FD_SET(pu->chan->fds[x], &nefds);
++ if (pu->chan->fds[x] > max)
++ max = pu->chan->fds[x];
++ }
++ }
++ /* Keep track of our longest wait */
++ if ((tms < ms) || (ms < 0))
++ ms = tms;
++ pl = pu;
++ pu = pu->next;
++ }
++ }
++ ast_mutex_unlock(&autoanswer_lock);
++ rfds = nrfds;
++ efds = nefds;
++ tv.tv_sec = ms / 1000;
++ tv.tv_usec = (ms % 1000) * 1000;
++ /* Wait for something to happen */
++ ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
++ pthread_testcancel();
++ }
++ return NULL; /* Never reached */
++}
++
++static int autoanswer_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ struct ast_channel *peer=NULL;
++ struct aauser *pu, *pl=NULL;
++ struct ast_bridge_config config;
++ char *s, *stringp, *aacontext, *aaexten = NULL;
++ char datastring[80];
++ struct ast_module_user *u;
++
++
++ if (!data) {
++ ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
++ return -1;
++ }
++ s = ast_strdupa((void *) data);
++ stringp=s;
++ aacontext = strsep(&stringp, "|");
++ aaexten = strsep(&stringp, "|");
++ if (!aaexten) {
++ aaexten = aacontext;
++ aacontext = NULL;
++ }
++ if (!aaexten) {
++ ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
++ return -1;
++ } else {
++ if (!aacontext) {
++ aacontext = "default";
++ }
++ }
++
++ u = ast_module_user_add(chan);
++ ast_mutex_lock(&autoanswer_lock);
++ pu = aalot;
++ while(pu) {
++ if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
++ if (pl)
++ pl->next = pu->next;
++ else
++ aalot = pu->next;
++ break;
++ }
++ pl = pu;
++ pu = pu->next;
++ }
++ ast_mutex_unlock(&autoanswer_lock);
++ if (pu) {
++ peer = pu->chan;
++ free(pu);
++ pu = NULL;
++ }
++ /* JK02: it helps to answer the channel if not already up */
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++
++ if (peer) {
++ ast_moh_stop(peer);
++ /* Play a courtesy beep in the callED channel to prefix the bridge connecting */
++ if (!ast_strlen_zero(courtesytone)) {
++ if (!ast_streamfile(peer, courtesytone, peer->language)) {
++ if (ast_waitstream(peer, "") < 0) {
++ ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
++ ast_hangup(peer);
++ return -1;
++ }
++ }
++ }
++
++ res = ast_channel_make_compatible(chan, peer);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
++ ast_hangup(peer);
++ return -1;
++ }
++ /* This runs sorta backwards, since we give the incoming channel control, as if it
++ were the person called. */
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered %s\n", peer->name, chan->name);
++ manager_event(EVENT_FLAG_CALL, "Autoanswer",
++ "Channel: %s\r\n"
++ "Uniqueid: %s\r\n"
++ "Channel2: %s\r\n"
++ "Uniqueid2: %s\r\n"
++ "Context: %s\r\n"
++ "Exten: %s\r\n"
++ ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
++
++
++ memset(&config,0,sizeof(struct ast_bridge_config));
++ ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
++ ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
++ config.timelimit = 0;
++ config.play_warning = 0;
++ config.warning_freq = 0;
++ config.warning_sound=NULL;
++ res = ast_bridge_call(chan,peer,&config);
++
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
++ /* relogin */
++ snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
++ ast_autoanswer_login(peer, datastring);
++ return res;
++ } else {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
++ res = -1;
++ }
++ ast_module_user_remove(u);
++ return res;
++}
++
+
+ int ast_pickup_call(struct ast_channel *chan)
+ {
+@@ -2397,6 +2855,7 @@ static int load_config(void)
+
+ static int reload(void)
+ {
++ autoanswer_reregister_extensions();
+ return load_config();
+ }
+
+@@ -2420,6 +2879,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;
+@@ -2434,6 +2899,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);
+ }
Added: asterisk/branches/experimental/debian/patches/bristuff/feature-holdedcalls
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/feature-holdedcalls (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/feature-holdedcalls 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,380 @@
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/features.h
++++ asterisk-1.4.8~dfsg/include/asterisk/features.h
+@@ -72,6 +72,12 @@ int ast_park_call(struct ast_channel *ch
+ */
+ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
+
++extern int ast_hold_call(struct ast_channel *chan, struct ast_channel *host);
++extern int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *host);
++extern int ast_retrieve_call(struct ast_channel *chan, char *uniqueid);
++extern int ast_retrieve_call_to_death(char *uniqueid);
++extern struct ast_channel *ast_get_holded_call(char *uniqueid);
++
+ /*! \brief Determine system parking extension
+ * Returns the call parking extension for drivers that provide special
+ call parking help */
+--- asterisk-1.4.8~dfsg.orig/res/res_features.c
++++ asterisk-1.4.8~dfsg/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 {
+ };
+
+ 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 */
+@@ -164,6 +166,22 @@ struct parkeduser {
+ struct parkeduser *next;
+ };
+
++struct holdeduser {
++ struct ast_channel *chan;
++ struct timeval start;
++ int parkingnum;
++ int cref;
++ int tei;
++ /* Where to go if our parking time expires */
++ char context[AST_MAX_EXTENSION];
++ char exten[AST_MAX_EXTENSION];
++ int priority;
++ int parkingtime;
++ char uniqueid[AST_MAX_UNIQUEID];
++ char uniqueidpeer[AST_MAX_UNIQUEID];
++ struct holdeduser *next;
++};
++
+ /* auto answer user */
+ struct aauser {
+ struct ast_channel *chan;
+@@ -183,10 +201,16 @@ static pthread_t autoanswer_thread;
+
+ static struct parkeduser *parkinglot;
+
++static struct holdeduser *holdlist;
++
+ AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
+
++AST_MUTEX_DEFINE_STATIC(holding_lock);
++
+ static pthread_t parking_thread;
+
++static pthread_t holding_thread;
++
+ char *ast_parking_ext(void)
+ {
+ return parking_ext;
+@@ -1989,6 +2013,282 @@ static int park_exec(struct ast_channel
+ return res;
+ }
+
++int ast_hold_call(struct ast_channel *chan, struct ast_channel *peer)
++{
++ /* We put the user in the parking list, then wake up the parking thread to be sure it looks
++ after these channels too */
++ struct holdeduser *pu;
++ pu = malloc(sizeof(struct holdeduser));
++ if (pu) {
++ memset(pu, 0, sizeof(pu));
++ ast_mutex_lock(&holding_lock);
++ chan->appl = "Holded Call";
++ chan->data = NULL;
++
++ pu->chan = chan;
++ strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
++ strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
++ /* Start music on hold */
++ ast_moh_start(pu->chan, NULL, NULL);
++ gettimeofday(&pu->start, NULL);
++ pu->next = holdlist;
++ holdlist = pu;
++ ast_mutex_unlock(&holding_lock);
++ /* Wake up the (presumably select()ing) thread */
++ pthread_kill(holding_thread, SIGURG);
++
++ manager_event(EVENT_FLAG_CALL, "HoldedCall",
++ "Channel1: %s\r\n"
++ "Channel2: %s\r\n"
++ "Uniqueid1: %s\r\n"
++ "Uniqueid2: %s\r\n"
++ ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
++
++ } else {
++ ast_log(LOG_WARNING, "Out of memory\n");
++ return -1;
++ }
++ return 0;
++}
++
++int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer)
++{
++ struct ast_channel *chan;
++ struct ast_frame *f;
++ /* Make a new, fake channel that we'll use to masquerade in the real one */
++ chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
++ if (chan) {
++ /* Let us keep track of the channel name */
++ ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
++ /* Make formats okay */
++ chan->readformat = rchan->readformat;
++ chan->writeformat = rchan->writeformat;
++ ast_channel_masquerade(chan, rchan);
++ /* Setup the extensions and such */
++ strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
++ strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
++ chan->priority = rchan->priority;
++ /* this might be dirty, but we need to preserve the uniqueid */
++ ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
++ /* Make the masq execute */
++ f = ast_read(chan);
++ if (f)
++ ast_frfree(f);
++ ast_hold_call(chan, peer);
++ return -1;
++ } else {
++ ast_log(LOG_WARNING, "Unable to create holded channel\n");
++ return -1;
++ }
++ return 0;
++}
++
++int ast_retrieve_call(struct ast_channel *chan, char *uniqueid)
++{
++ int res=-1, dres=-1;
++ struct ast_channel *peer=NULL;
++ struct ast_bridge_config config;
++
++ peer = ast_get_holded_call(uniqueid);
++
++ /* JK02: it helps to answer the channel if not already up */
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++
++ if (peer) {
++ ast_mutex_unlock(&peer->lock);
++ ast_moh_stop(peer);
++ res = ast_channel_make_compatible(chan, peer);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
++ ast_hangup(peer);
++ return -1;
++ }
++ /* This runs sorta backwards, since we give the incoming channel control, as if it
++ were the person called. */
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
++
++ memset(&config,0,sizeof(struct ast_bridge_config));
++ ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
++ ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
++ config.timelimit = 0;
++ config.play_warning = 0;
++ config.warning_freq = 0;
++ config.warning_sound=NULL;
++ res = ast_bridge_call(chan,peer,&config);
++
++ /* Simulate the PBX hanging up */
++ if (res != AST_PBX_NO_HANGUP_PEER)
++ ast_hangup(peer);
++ return res;
++ } else {
++ /* XXX Play a message XXX */
++ dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
++ if (!dres)
++ dres = ast_waitstream(chan, "");
++ else {
++ ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
++ dres = 0;
++ }
++ }
++ return res;
++}
++
++int ast_retrieve_call_to_death(char *uniqueid)
++{
++ int res=-1;
++ struct ast_channel *peer=NULL;
++
++ peer = ast_get_holded_call(uniqueid);
++
++ if (peer) {
++ res=0;
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
++ ast_mutex_unlock(&peer->lock);
++ ast_hangup(peer);
++ } else {
++ ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
++ }
++ return res;
++}
++
++struct ast_channel *ast_get_holded_call(char *uniqueid)
++{
++ int res=-1;
++ struct ast_channel *peer=NULL;
++ struct holdeduser *pu, *pl=NULL;
++
++ ast_mutex_lock(&holding_lock);
++ pu = holdlist;
++ while(pu) {
++ if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
++ if (pl)
++ pl->next = pu->next;
++ else
++ holdlist = pu->next;
++ break;
++ }
++ pl = pu;
++ pu = pu->next;
++ }
++ ast_mutex_unlock(&holding_lock);
++ if (pu) {
++ peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
++ free(pu);
++ if (peer) {
++ res=0;
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
++ ast_moh_stop(peer);
++ return peer;
++ } else {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
++ return NULL;
++ }
++ } else {
++ ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
++ }
++ return NULL;
++}
++
++/* this is our autmagically service thread that keeps channels onhold happy */
++static void *do_holding_thread(void *ignore)
++{
++ int ms, tms, max;
++ struct holdeduser *pu, *pl, *pt = NULL;
++ struct timeval tv;
++ struct ast_frame *f;
++ int x;
++ fd_set rfds, efds;
++ fd_set nrfds, nefds;
++ FD_ZERO(&rfds);
++ FD_ZERO(&efds);
++ for (;;) {
++ ms = -1;
++ max = -1;
++ ast_mutex_lock(&holding_lock);
++ pl = NULL;
++ pu = holdlist;
++ gettimeofday(&tv, NULL);
++ FD_ZERO(&nrfds);
++ FD_ZERO(&nefds);
++ while(pu) {
++ tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
++ for (x=0;x<AST_MAX_FDS;x++) {
++ if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
++ if (FD_ISSET(pu->chan->fds[x], &efds))
++ ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
++ else
++ ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
++ pu->chan->fdno = x;
++ /* See if they need servicing */
++ f = ast_read(pu->chan);
++ if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
++ /* There's a problem, hang them up*/
++ if (option_verbose > 1)
++ ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
++ ast_hangup(pu->chan);
++ /* find the corresponding channel and hang them up too! */
++ /* but only if it is not bridged yet! */
++ /* And take them out of the parking lot */
++ if (pl)
++ pl->next = pu->next;
++ else
++ holdlist = pu->next;
++ pt = pu;
++ pu = pu->next;
++ free(pt);
++ break;
++ } else {
++ /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
++ ast_frfree(f);
++ goto std; /* XXX Ick: jumping into an else statement??? XXX */
++ }
++ }
++ }
++ if (x >= AST_MAX_FDS) {
++std: for (x=0;x<AST_MAX_FDS;x++) {
++ /* Keep this one for next one */
++ if (pu->chan->fds[x] > -1) {
++ FD_SET(pu->chan->fds[x], &nrfds);
++ FD_SET(pu->chan->fds[x], &nefds);
++ if (pu->chan->fds[x] > max)
++ max = pu->chan->fds[x];
++ }
++ }
++ /* Keep track of our longest wait */
++ if ((tms < ms) || (ms < 0))
++ ms = tms;
++ pl = pu;
++ pu = pu->next;
++ }
++ }
++ ast_mutex_unlock(&holding_lock);
++ rfds = nrfds;
++ efds = nefds;
++ tv.tv_sec = ms / 1000;
++ tv.tv_usec = (ms % 1000) * 1000;
++ /* Wait for something to happen */
++ ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
++ pthread_testcancel();
++ }
++ return NULL; /* Never reached */
++}
++
++static int retrieve_call_exec(struct ast_channel *chan, void *data) {
++ int res=0;
++ struct ast_module_user *u;
++ char *uniqueid = (char *)data;
++ u = ast_module_user_add(chan);
++ res = ast_retrieve_call(chan, uniqueid);
++ ast_module_user_remove(u);
++ return res;
++}
++
+ static int handle_showfeatures(int fd, int argc, char *argv[])
+ {
+ int i;
+@@ -2870,6 +3170,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);
+@@ -2879,6 +3180,7 @@ static int load_module(void)
+ "Park a channel", mandescr_park);
+ }
+
++ res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
+ ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
+ if (!res)
+ res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
+@@ -2901,6 +3203,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);
+ }
Added: asterisk/branches/experimental/debian/patches/bristuff/feature-parking_con
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/feature-parking_con (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/feature-parking_con 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,26 @@
+--- asterisk-1.4.8~dfsg-OK.orig/include/asterisk/features.h
++++ asterisk-1.4.8~dfsg-OK/include/asterisk/features.h
+@@ -86,6 +86,8 @@ char *ast_parking_ext(void);
+ /*! \brief Determine system call pickup extension */
+ char *ast_pickup_ext(void);
+
++extern char *ast_parking_con(void);
++
+ /*! \brief Bridge a call, optionally allowing redirection */
+ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);
+
+--- asterisk-1.4.8~dfsg-OK.orig/res/res_features.c
++++ asterisk-1.4.8~dfsg-OK/res/res_features.c
+@@ -216,6 +216,12 @@ char *ast_parking_ext(void)
+ return parking_ext;
+ }
+
++char *ast_parking_con(void)
++{
++ return parking_con;
++}
++
++
+ char *ast_pickup_ext(void)
+ {
+ return pickup_ext;
Added: asterisk/branches/experimental/debian/patches/bristuff/find-feature
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/find-feature (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/find-feature 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,36 @@
+--- asterisk-1.4.8~dfsg-OK.orig/include/asterisk/features.h
++++ asterisk-1.4.8~dfsg-OK/include/asterisk/features.h
+@@ -102,4 +102,12 @@ void ast_register_feature(struct ast_cal
+ \param feature the ast_call_feature object which was registered before*/
+ void ast_unregister_feature(struct ast_call_feature *feature);
+
++/*! \brief find a feature by name
++ \param name of the feature to be returned */
++extern struct ast_call_feature *ast_find_feature(char *name);
++
++/*! \brief find a builtin feature by name
++ \param name of the feature to be returned */
++extern struct ast_call_feature *ast_find_builtin_feature(char *name);
++
+ #endif /* _AST_FEATURES_H */
+--- asterisk-1.4.8~dfsg-OK.orig/res/res_features.c
++++ asterisk-1.4.8~dfsg-OK/res/res_features.c
+@@ -1008,6 +1008,18 @@ static struct ast_call_feature *find_dyn
+ return tmp;
+ }
+
++struct ast_call_feature *ast_find_builtin_feature(char *name)
++{
++ int x = 0;
++
++ for (x = 0; x < FEATURES_COUNT; x++) {
++ if (!strcasecmp(name, builtin_features[x].sname)) {
++ return &builtin_features[x];
++ }
++ }
++ return NULL;
++}
++
+ /*! \brief exec an app by feature */
+ static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+ {
Added: asterisk/branches/experimental/debian/patches/bristuff/misc-app-devstate
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/misc-app-devstate (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/misc-app-devstate 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,205 @@
+--- /dev/null
++++ asterisk-1.4.8~dfsg/apps/app_devstate.c
+@@ -0,0 +1,202 @@
++/*
++ * Devstate application
++ *
++ * Since we like the snom leds so much, a little app to
++ * light the lights on the snom on demand ....
++ *
++ * Copyright (C) 2005, Druid Software
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include "asterisk.h"
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++
++#include "asterisk/lock.h"
++#include "asterisk/file.h"
++#include "asterisk/logger.h"
++#include "asterisk/channel.h"
++#include "asterisk/pbx.h"
++#include "asterisk/astdb.h"
++#include "asterisk/cli.h"
++#include "asterisk/manager.h"
++#include "asterisk/devicestate.h"
++#include "asterisk/module.h"
++
++
++static char type[] = "DS";
++static char tdesc[] = "Application for sending device state messages";
++
++static char app[] = "Devstate";
++
++static char synopsis[] = "Generate a device state change event given the input parameters";
++
++static char descrip[] = " Devstate(device|state): Generate a device state change event given the input parameters. Returns 0. State values match the asterisk device states. They are 0 = unknown, 1 = not inuse, 2 = inuse, 3 = busy, 4 = invalid, 5 = unavailable, 6 = ringing\n";
++
++static char devstate_cli_usage[] =
++"Usage: devstate device state\n"
++" Generate a device state change event given the input parameters.\n Mainly used for lighting the LEDs on the snoms.\n";
++
++static int devstate_cli(int fd, int argc, char *argv[]);
++static struct ast_cli_entry cli_dev_state =
++ { { "devstate", NULL }, devstate_cli, "Set the device state on one of the \"pseudo devices\".", devstate_cli_usage };
++
++
++static int devstate_cli(int fd, int argc, char *argv[])
++{
++ char devName[128];
++ if (argc != 3)
++ return RESULT_SHOWUSAGE;
++
++ if (ast_db_put("DEVSTATES", argv[1], argv[2]))
++ {
++ ast_log(LOG_DEBUG, "ast_db_put failed\n");
++ }
++ snprintf(devName, sizeof(devName), "DS/%s", argv[1]);
++ ast_device_state_changed_literal(devName);
++ return RESULT_SUCCESS;
++}
++
++static int devstate_exec(struct ast_channel *chan, void *data)
++{
++ char *device, *state, *info;
++ char devName[128];
++ struct ast_module_user *u;
++
++
++ if (!(info = ast_strdupa(data))) {
++ ast_log(LOG_WARNING, "Unable to dupe data :(\n");
++ return -1;
++ }
++
++ u = ast_module_user_add(chan);
++ device = info;
++ state = strchr(info, '|');
++ if (state) {
++ *state = '\0';
++ state++;
++ }
++ else
++ {
++ ast_log(LOG_DEBUG, "No state argument supplied\n");
++ return -1;
++ }
++
++ if (ast_db_put("DEVSTATES", device, state))
++ {
++ ast_log(LOG_DEBUG, "ast_db_put failed\n");
++ }
++
++ snprintf(devName, sizeof(devName), "DS/%s", device);
++ ast_device_state_changed_literal(devName);
++
++ ast_module_user_remove(u);
++ return 0;
++}
++
++
++static int ds_devicestate(void *data)
++{
++ char *dest = data;
++ char stateStr[16];
++ if (ast_db_get("DEVSTATES", dest, stateStr, sizeof(stateStr)))
++ {
++ ast_log(LOG_DEBUG, "ds_devicestate couldnt get state in astdb\n");
++ return 0;
++ }
++ else
++ {
++ ast_log(LOG_DEBUG, "ds_devicestate dev=%s returning state %d\n",
++ dest, atoi(stateStr));
++ return (atoi(stateStr));
++ }
++}
++
++static struct ast_channel_tech devstate_tech = {
++ .type = type,
++ .description = tdesc,
++ .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
++ .devicestate = ds_devicestate,
++ .requester = NULL,
++ .send_digit_begin = NULL,
++ .send_digit_end = NULL,
++ .send_text = NULL,
++ .call = NULL,
++ .hangup = NULL,
++ .answer = NULL,
++ .read = NULL,
++ .write = NULL,
++ .bridge = NULL,
++ .exception = NULL,
++ .indicate = NULL,
++ .fixup = NULL,
++ .setoption = NULL,
++};
++
++static char mandescr_devstate[] =
++"Description: Put a value into astdb\n"
++"Variables: \n"
++" Family: ...\n"
++" Key: ...\n"
++" Value: ...\n";
++
++static int action_devstate(struct mansession *s, const struct message *m)
++{
++ const char *devstate = astman_get_header(m, "Devstate");
++ const char *value = astman_get_header(m, "Value");
++ const char *id = astman_get_header(m,"ActionID");
++ char devName[128];
++ char idText[256] = "";
++
++ if (!strlen(devstate)) {
++ astman_send_error(s, m, "No Devstate specified");
++ return 0;
++ }
++ if (!strlen(value)) {
++ astman_send_error(s, m, "No Value specified");
++ return 0;
++ }
++ if (!ast_strlen_zero(id))
++ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
++
++ if (!ast_db_put("DEVSTATES", devstate, (char *)value)) {
++ snprintf(devName, sizeof(devName), "DS/%s", devstate);
++ ast_device_state_changed_literal(devName);
++ astman_append(s, "Response: Success\r\n%s\r\n", idText);
++ } else {
++ ast_log(LOG_DEBUG, "ast_db_put failed\n");
++ astman_append(s, "Response: Failed\r\n%s\r\n", idText);
++ }
++ return 0;
++}
++
++static int load_module(void)
++{
++ if (ast_channel_register(&devstate_tech)) {
++ ast_log(LOG_DEBUG, "Unable to register channel class %s\n", type);
++ return -1;
++ }
++ ast_cli_register(&cli_dev_state);
++ ast_manager_register2( "Devstate", EVENT_FLAG_CALL, action_devstate, "Change a device state", mandescr_devstate );
++ return ast_register_application(app, devstate_exec, synopsis, descrip);
++}
++
++static int unload_module(void)
++{
++ int res = 0;
++
++ ast_module_user_hangup_all();
++ ast_manager_unregister( "Devstate");
++ ast_cli_unregister(&cli_dev_state);
++ res = ast_unregister_application(app);
++ ast_channel_unregister(&devstate_tech);
++ return res;
++}
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Devstate Application");
++
Added: asterisk/branches/experimental/debian/patches/bristuff/misc-app-pickup
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/misc-app-pickup (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/misc-app-pickup 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,314 @@
+--- asterisk-1.4.8~dfsg-OK.orig/apps/app_directed_pickup.c
++++ asterisk-1.4.8~dfsg-OK/apps/app_directed_pickup.c
+@@ -45,7 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+
+ #define PICKUPMARK "PICKUPMARK"
+
+-static const char *app = "Pickup";
++static const char *app = "DPickup";
+ static const char *synopsis = "Directed Call Pickup";
+ static const char *descrip =
+ " Pickup(extension[@context][&extension2 at context...]): This application can pickup any ringing channel\n"
+--- /dev/null
++++ asterisk-1.4.8~dfsg-OK/apps/app_pickup.c
+@@ -0,0 +1,300 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Pickup, channel independent call pickup
++ *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * Copyright (C) 2004, Florian Overkamp <florian at obsimref.com>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include "asterisk.h"
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <signal.h>
++#include <pthread.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/features.h>
++#include <asterisk/options.h>
++
++
++static char *app = "PickUp";
++
++static char *synopsis = "Channel independent call pickup.";
++
++static char *descrip =
++" PickDown([group]): Tries to pickup the first ringing channel with callgroup == group.\n"
++" If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app2 = "Steal";
++
++static char *synopsis2 = "Channel independent call stealing. Just like pickup but for answered channels.";
++
++static char *descrip2 =
++" Steal([group]): Tries to steal the first bridged channel with callgroup == group.\n"
++" If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app3 = "PickDown";
++
++static char *synopsis3 = "Channel independent call pickdown.";
++
++static char *descrip3 =
++" PickDown([group]): Tries to hangup the first ringing channel with callgroup == group.\n"
++" If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app4 = "PickupChan";
++
++static char *synopsis4 = "Channel independent call pickup.";
++
++static char *descrip4 =
++" PickupChan(Technology/resource[&Technology2/resource2...]): Tries to pickup the first ringing channel in the parameter list.\n";
++
++static char *app5 = "StealChan";
++
++static char *synopsis5 = "Channel independent call stealing. Just like pickup but for answered channels.";
++
++static char *descrip5 =
++" StealChan(Technology/resource[&Technology2/resource2...]): Tries to steal the first ringing channel in the parameter list.\n";
++
++
++static int my_pickup_call(struct ast_channel *chan, unsigned int pickupgroup, int chanstate, int bridge) {
++ struct ast_channel *cur;
++ int res = -1;
++ cur = ast_channel_walk_locked(NULL);
++ while(cur) {
++ if ((cur != chan) &&
++ (pickupgroup & cur->callgroup) &&
++ (cur->_state == chanstate)) {
++ break;
++ }
++ ast_mutex_unlock(&cur->lock);
++ cur = ast_channel_walk_locked(cur);
++ }
++ if (cur) {
++ if(option_verbose > 2) {
++ if (chanstate == AST_STATE_RINGING) {
++ if (bridge == 1) {
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s picked up ringing channel %s\n",chan->name,cur->name);
++ } else {
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n",chan->name,cur->name);
++ }
++ } else {
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n",chan->name,cur->name);
++ }
++ }
++ if (bridge == 1) {
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++ if (ast_channel_masquerade(cur, chan)) {
++ ast_log(LOG_ERROR, "unable to masquerade\n");
++ }
++ ast_mutex_unlock(&cur->lock);
++ ast_mutex_unlock(&chan->lock);
++ } else {
++ cur->_softhangup = AST_SOFTHANGUP_DEV;
++ ast_mutex_unlock(&cur->lock);
++ }
++ } else {
++ if(option_verbose > 2) {
++ ast_verbose(VERBOSE_PREFIX_3 "No channel found %d.\n",pickupgroup);
++ }
++ }
++ return res;
++}
++
++static int my_pickup_channel(struct ast_channel *chan, void *data, int chanstate, int bridge) {
++ struct ast_channel *cur;
++ char channels[256];
++ char evalchan[256];
++ char *endptr;
++ int res = -1;
++ cur = ast_channel_walk_locked(NULL);
++ strncpy(channels, (char *)data, sizeof(channels) - 1);
++ while(cur) {
++ if ((cur != chan) &&
++ (cur->_state == chanstate)) {
++ /* This call is a candidate (correct ringstate and not ourselves), now check if the channel is in our list */
++ strncpy(evalchan, (char *)cur->name, sizeof(evalchan) - 1);
++ /* strip the subchannel tag */
++ endptr = strrchr(evalchan, '-');
++ if(endptr) {
++ *endptr = '\0';
++ }
++ /* check for each of the members if they match (probably a stristr will do ?) */
++ /* if we match the code, break */
++ if(strstr(channels, evalchan) != NULL) {
++ ast_verbose(VERBOSE_PREFIX_1 "Nice channel, I'll take it: %s\n",evalchan);
++ break;
++ }
++ }
++ ast_mutex_unlock(&cur->lock);
++ cur = ast_channel_walk_locked(cur);
++ }
++ if (cur) {
++ if(option_verbose > 2) {
++ if (chanstate == AST_STATE_RINGING) {
++ if (bridge == 1) {
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s picked up ringing channel %s\n",chan->name,cur->name);
++ } else {
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n",chan->name,cur->name);
++ }
++ } else {
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n",chan->name,cur->name);
++ }
++ }
++ if (bridge == 1) {
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++ if (ast_channel_masquerade(cur, chan)) {
++ ast_log(LOG_ERROR, "unable to masquerade\n");
++ }
++ ast_mutex_unlock(&cur->lock);
++ ast_mutex_unlock(&chan->lock);
++ } else {
++ cur->_softhangup = AST_SOFTHANGUP_DEV;
++ ast_mutex_unlock(&cur->lock);
++ }
++ } else {
++ if(option_verbose > 2) {
++ ast_verbose(VERBOSE_PREFIX_3 "No channel found %s.\n",channels);
++ }
++ }
++ return res;
++}
++
++
++static int pickup_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ unsigned int pickupgroup=0;
++ struct ast_module_user *u;
++ if (!data || !strlen(data)) {
++ pickupgroup = chan->pickupgroup;
++ } else {
++ pickupgroup = ast_get_group(data);
++ }
++ u = ast_module_user_add(chan);
++ if (!res) {
++ res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 1);
++ }
++ if (res > 0)
++ res = 0;
++ ast_module_user_remove(u);
++ return res;
++}
++
++static int steal_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ unsigned int pickupgroup=0;
++ struct ast_module_user *u;
++ if (!data || !strlen(data)) {
++ pickupgroup = chan->pickupgroup;
++ } else {
++ pickupgroup = ast_get_group(data);
++ }
++ u = ast_module_user_add(chan);
++ if (!res) {
++ res = my_pickup_call(chan, pickupgroup, AST_STATE_UP, 1);
++ }
++ if (res > 0)
++ res = 0;
++ ast_module_user_remove(u);
++ return res;
++}
++
++static int pickdown_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ unsigned int pickupgroup=0;
++ struct ast_module_user *u;
++ if (!data || !strlen(data)) {
++ pickupgroup = chan->pickupgroup;
++ } else {
++ pickupgroup = ast_get_group(data);
++ }
++ u = ast_module_user_add(chan);
++ if (!res) {
++ res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 0);
++ }
++ if (res > 0)
++ res = 0;
++ ast_module_user_remove(u);
++ return res;
++}
++
++static int pickupchan_exec(struct ast_channel *chan, void *data) {
++ int res=0;
++ struct ast_module_user *u;
++ if (!data) {
++ ast_log(LOG_WARNING, "PickupChan requires an argument (technology1/number1&technology2/number2...)\n");
++ return -1;
++ }
++ u = ast_module_user_add(chan);
++ if (!res) {
++ res = my_pickup_channel(chan, data, AST_STATE_RINGING, 1);
++ }
++ if (res > 0)
++ res = 0;
++ ast_module_user_remove(u);
++ return res;
++}
++
++static int stealchan_exec(struct ast_channel *chan, void *data)
++{
++ int res=0;
++ struct ast_module_user *u;
++ if (!data) {
++ ast_log(LOG_WARNING, "StealChan requires an argument (technology1/number1&technology2/number2...)\n");
++ return -1;
++ }
++
++ u = ast_module_user_add(chan);
++ if (!res) {
++ res = my_pickup_channel(chan, data, AST_STATE_UP, 1);
++ }
++ if (res > 0)
++ res = 0;
++ ast_module_user_remove(u);
++ return res;
++}
++
++
++static int unload_module(void)
++{
++ ast_module_user_hangup_all();
++ ast_unregister_application(app5);
++ ast_unregister_application(app4);
++ ast_unregister_application(app3);
++ ast_unregister_application(app2);
++ return ast_unregister_application(app);
++}
++
++static int load_module(void)
++{
++ ast_register_application(app5, stealchan_exec, synopsis5, descrip5);
++ ast_register_application(app4, pickupchan_exec, synopsis4, descrip4);
++ ast_register_application(app3, pickdown_exec, synopsis3, descrip3);
++ ast_register_application(app2, steal_exec, synopsis2, descrip2);
++ return ast_register_application(app, pickup_exec, synopsis, descrip);
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PickUp/PickDown/Steal/PickupChan/StealChan",
++ .load = load_module,
++ .unload = unload_module,
++);
Added: asterisk/branches/experimental/debian/patches/bristuff/misc-app-segfault
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/misc-app-segfault (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/misc-app-segfault 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,58 @@
+--- /dev/null
++++ asterisk-1.4.8~dfsg/apps/app_segfault.c
+@@ -0,0 +1,55 @@
++/*
++ * Segfault application
++ *
++ * An application to provoke a segmentation fault from the dialplan.
++ * (I know what you are thinking now...., but since Asterisk is too stable...
++ * I needed something to test my failover switches.)
++ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License. THIS APPLICATION _WILL_ CRASH YOUR
++ * ASTERISK SERVER SO OF COURSE THERE IS NOT LIABILITY FOR NOTHING!
++ */
++
++#include "asterisk.h"
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++
++static char *app = "Segfault";
++
++static char *synopsis = "This application will crash Asterisk with a segmentation fault.";
++
++static char *descrip =
++" Segfault(): Crash with a segfault. Never returns nufin.\n";
++
++static int segfault_exec(struct ast_channel *chan, void *data)
++{
++ ((char *)0)[0] = 0;
++ return 0;
++}
++
++static int unload_module(void)
++{
++ return ast_unregister_application(app);
++}
++
++static int load_module(void)
++{
++ return ast_register_application(app, segfault_exec, synopsis, descrip);
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Application for crashing Asterisk with a segmentation fault",
++ .load = load_module,
++ .unload = unload_module,
++);
Added: asterisk/branches/experimental/debian/patches/bristuff/misc-manager-dbdel
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/misc-manager-dbdel (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/misc-manager-dbdel 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,49 @@
+--- asterisk-1.4.8~dfsg.orig/main/db.c
++++ asterisk-1.4.8~dfsg/main/db.c
+@@ -573,7 +573,7 @@ static int manager_dbget(struct mansessi
+ astman_append(s, "Event: DBGetResponse\r\n"
+ "Family: %s\r\n"
+ "Key: %s\r\n"
+- "Val: %s\r\n"
++ "Value: %s\r\n"
+ "%s"
+ "\r\n",
+ family, key, tmp, idText);
+@@ -581,11 +581,35 @@ static int manager_dbget(struct mansessi
+ return 0;
+ }
+
++static int manager_dbdel(struct mansession *s, const struct message *m)
++{
++ const char *family = astman_get_header(m, "Family");
++ const char *key = astman_get_header(m, "Key");
++
++ if (!strlen(family)) {
++ astman_send_error(s, m, "No family specified");
++ return 0;
++ }
++ if (!strlen(key)) {
++ astman_send_error(s, m, "No key specified");
++ return 0;
++ }
++
++ if (ast_db_del(family, key)) {
++ astman_send_error(s, m, "Failed to delete entry");
++ } else {
++ astman_send_ack(s, m, "Deleted entry successfully");
++ }
++
++ return 0;
++}
++
+ int astdb_init(void)
+ {
+ dbinit();
+ ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
+- ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
+- ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
++ ast_manager_register("DBget", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
++ ast_manager_register("DBput", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
++ ast_manager_register("DBdel", EVENT_FLAG_SYSTEM, manager_dbdel, "Delete DB Entry");
+ return 0;
+ }
Added: asterisk/branches/experimental/debian/patches/bristuff/misc-res-esel
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/misc-res-esel (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/misc-res-esel 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,402 @@
+--- /dev/null
++++ asterisk-1.4.8~dfsg/configs/esel.conf.sample
+@@ -0,0 +1,12 @@
++;
++; Configuration file for res_esel
++;
++
++;[asterisk-2]
++;host = 192.168.0.1
++;port = 5038
++;username = manager
++;secret = donkey
++
++; export the extension snom in context phones to DS/100
++;export => snom at phones,100
+--- /dev/null
++++ asterisk-1.4.8~dfsg/res/res_esel.c
+@@ -0,0 +1,384 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Extension State Export Logic (E.S.E.L) (Sorry, i couldnt resist...)
++ *
++ * Resource to export extension states to other Asterisk servers
++ *
++ * Copyright (C) 2006, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include "asterisk.h"
++
++#include <stdlib.h>
++#include <errno.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/time.h>
++#include <sys/signal.h>
++#include <netinet/in.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++
++#include "asterisk/file.h"
++#include "asterisk/logger.h"
++#include "asterisk/channel.h"
++#include "asterisk/pbx.h"
++#include "asterisk/options.h"
++#include "asterisk/module.h"
++#include "asterisk/translate.h"
++#include "asterisk/say.h"
++#include "asterisk/features.h"
++#include "asterisk/musiconhold.h"
++#include "asterisk/config.h"
++#include "asterisk/cli.h"
++#include "asterisk/manager.h"
++#include "asterisk/utils.h"
++#include "asterisk/lock.h"
++#include "asterisk/adsi.h"
++
++
++AST_MUTEX_DEFINE_STATIC(listlock);
++
++typedef struct esel_extension_state {
++ char context[AST_MAX_EXTENSION];
++ char exten[AST_MAX_EXTENSION];
++ int state;
++ char devstate[AST_MAX_EXTENSION];
++ struct esel_extension_state *next;
++ struct esel_extension_state *prev;
++} esel_extension_state;
++
++typedef struct esel_export {
++ char context[AST_MAX_EXTENSION];
++ char exten[AST_MAX_EXTENSION];
++ char devstate[AST_MAX_EXTENSION];
++ struct esel_export *next;
++} esel_export;
++
++typedef struct esel_queue {
++ struct esel_extension_state *head;
++ struct esel_extension_state *tail;
++ int count;
++ ast_cond_t cond;
++ ast_mutex_t lock;
++} esel_queue;
++
++typedef struct esel_pvt {
++ char name[80];
++ char username[80];
++ char secret[80];
++ char host[80];
++ int port;
++ struct sockaddr_in raddr;
++ int sockfd;
++ int connected;
++ pthread_t esel_thread;
++
++ /* list of extensions to export */
++ struct esel_export *extensions;
++
++ /* queue */
++ struct esel_queue queue;
++
++ struct esel_pvt *next;
++} esel_pvt;
++
++static struct esel_pvt *donkeys = NULL;
++
++static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data) {
++ struct esel_extension_state *exstate = NULL;
++
++ exstate = malloc(sizeof(struct esel_extension_state));
++ if (!exstate) {
++ ast_log(LOG_ERROR, "Unable to malloc!\n");
++ return 1;
++ }
++ memset(exstate,0,sizeof(struct esel_extension_state));
++ exstate->next = NULL;
++ exstate->prev = NULL;
++
++ ast_mutex_lock(&queue->lock);
++ if (queue->count > 100) {
++ ast_mutex_unlock(&queue->lock);
++ free(exstate);
++ if (option_verbose > 5)
++ ast_log(LOG_WARNING, "E.S.E.L Queue too long.\n");
++ return -1;
++ }
++ ast_copy_string(exstate->exten, exten, sizeof(exstate->exten));
++ ast_copy_string(exstate->context, context, sizeof(exstate->context));
++ exstate->state = state;
++ if (!queue->head) {
++ /* Empty queue */
++ queue->head = exstate;
++ queue->tail = exstate;
++ } else {
++ /* Double link */
++ queue->tail->next = exstate;
++ exstate->prev = queue->tail;
++ queue->tail = exstate;
++ }
++ queue->count++;
++ ast_cond_signal(&queue->cond);
++ ast_mutex_unlock(&queue->lock);
++ return 0;
++}
++
++static int esel_is_exported(struct esel_export *extensions, struct esel_extension_state *exstate) {
++ struct esel_export *export = NULL;
++ export = extensions;
++ while (export) {
++ if ((!strcasecmp(export->exten, exstate->exten)) && (!strcasecmp(export->context, exstate->context))) {
++ /* copy mapping */
++ ast_copy_string(exstate->devstate, export->devstate, sizeof(exstate->devstate));
++ return 1;
++ }
++ export = export->next;
++ }
++ return 0;
++}
++
++static int esel_state2devstate(int state) {
++ switch(state) {
++ case 1:
++ return 2;
++ case 8:
++ return 6;
++ default:
++ return state;
++ }
++}
++
++static void esel_export_to_remote(struct esel_extension_state *exstate, struct esel_pvt *esel) {
++ char msg[1024];
++ int sent = 0;
++ memset(msg, 0x0, sizeof(msg));
++ snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state));
++ sent = send(esel->sockfd, msg, strlen(msg), 0);
++ if (sent == -1) {
++ esel->connected = 0;
++ }
++// ast_log(LOG_NOTICE, "%s", msg);
++}
++
++static void *do_esel_thread(void *data) {
++ struct esel_pvt *esel = (struct esel_pvt *)data;
++ struct esel_queue *queue = &esel->queue;
++ struct esel_extension_state *exstate = NULL;
++ char msg[1024];
++ char buf[1024];
++ int numbytes = 0;
++ int sent = 0;
++ int res = 0;
++ for (;;) {
++ if (esel->connected) {
++ ast_mutex_lock(&queue->lock);
++ if (queue->count == 0)
++ ast_cond_wait(&queue->cond, &queue->lock);
++ exstate = queue->head;
++ if (exstate) {
++ if (exstate->next) {
++ queue->head = exstate->next;
++ } else {
++ queue->head = NULL;
++ queue->tail = NULL;
++ }
++ queue->count--;
++ } else {
++ ast_log(LOG_ERROR, "I SHOULD NEVER HAPPEN! EXPECT SOME MAJOR KABOOM! DUCK AND COVER!\n");
++ }
++ ast_mutex_unlock(&queue->lock);
++
++ if (exstate) {
++ if (esel_is_exported(esel->extensions, exstate)) {
++ esel_export_to_remote(exstate, esel);
++ }
++ free(exstate);
++ exstate = NULL;
++ }
++ } else {
++ if (esel->sockfd > 0)
++ close(esel->sockfd);
++ if ((esel->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
++ ast_log(LOG_ERROR, "unable to request socket!\n");
++ return NULL;
++ }
++ /* try to connect */
++ res = connect(esel->sockfd, (struct sockaddr *)&esel->raddr, sizeof(struct sockaddr));
++ if (res) {
++ ast_log(LOG_NOTICE, "error connecting to %s:%d\n", esel->host, esel->port);
++ } else {
++ while (strncasecmp(buf, "Asterisk Call Manager:", 21)) {
++ if ((numbytes=recv(esel->sockfd, buf, sizeof(buf), 0)) == -1) {
++ esel->connected = 0;
++ continue;
++ }
++ buf[numbytes] = '\0';
++ // ast_log(LOG_NOTICE, "read: %s", buf);
++ }
++ /* log into remote manager */
++ memset(msg, 0x0, sizeof(msg));
++ snprintf(msg, sizeof(msg) - 1, "Action: Login\r\nUsername: %s\r\nSecret: %s\r\n\r\n", esel->username, esel->secret);
++ sent = send(esel->sockfd, msg, strlen(msg), 0);
++
++ while (strncasecmp(buf, "Response:", 9)) {
++ if ((numbytes=recv(esel->sockfd, buf, sizeof(buf), 0)) == -1) {
++ continue;
++ }
++ buf[numbytes] = '\0';
++ // ast_log(LOG_NOTICE, "read: %s", buf);
++ }
++
++ if (!strncasecmp(buf, "Response: Success", 17)) {
++ esel->connected = 1;
++ } else {
++ ast_log(LOG_ERROR, "error login into remote asterisk %s\n", esel->name);
++ }
++ }
++ /* time heals everything... */
++ sleep(10);
++ }
++ }
++ return NULL;
++}
++
++static int esel_state_cb(char *context, char *exten, int state, void *data) {
++ struct esel_pvt *esel;
++
++ esel = donkeys;
++ ast_mutex_lock(&listlock);
++ while (esel) {
++ esel_queue_extension_state(&esel->queue, context, exten, state, data);
++ esel = esel->next;
++ }
++ ast_mutex_unlock(&listlock);
++ return 0;
++}
++
++
++static int load_module(void)
++{
++ int res = 0;
++ const char *cat, *host, *port, *username, *secret, *name;
++ struct ast_config *cfg;
++ struct ast_variable *var;
++ struct esel_pvt *esel = NULL;
++ struct esel_export *export = NULL;
++ struct hostent *he;
++ struct ast_hostent h;
++
++ cfg = ast_config_load("esel.conf");
++ if (cfg) {
++ cat = ast_category_browse(cfg, NULL);
++ while(cat) {
++ name = cat;
++ host = ast_variable_retrieve(cfg, cat, "host");
++ username = ast_variable_retrieve(cfg, cat, "username");
++ secret = ast_variable_retrieve(cfg, cat, "secret");
++ port = ast_variable_retrieve(cfg, cat, "port");
++
++ if (name && host && username && secret && port) {
++ esel = malloc(sizeof(struct esel_pvt));
++ if (!esel) {
++ ast_log(LOG_ERROR, "unable to malloc!\n");
++ return -1;
++ }
++ memset(esel, 0x0, sizeof(struct esel_pvt));
++ ast_copy_string(esel->name, name, sizeof(esel->name));
++ ast_copy_string(esel->host, host, sizeof(esel->host));
++ ast_copy_string(esel->username, username, sizeof(esel->username));
++ ast_copy_string(esel->secret, secret, sizeof(esel->secret));
++
++ esel->port = atoi(port);
++ if ((he=ast_gethostbyname(host, &h)) == NULL) {
++ ast_log(LOG_ERROR, "unknown host!\n");
++ return -1;
++ }
++
++ esel->raddr.sin_family = AF_INET;
++ esel->raddr.sin_port = htons(esel->port);
++ esel->raddr.sin_addr = *((struct in_addr *)he->h_addr);
++ bzero(&(esel->raddr.sin_zero), 8);
++
++ esel->connected = 0;
++
++ ast_mutex_init(&esel->queue.lock);
++ ast_cond_init(&esel->queue.cond, NULL);
++
++
++ /* read exports */
++ var = ast_variable_browse(cfg, cat);
++ while (var) {
++ if (!strcasecmp(var->name, "export")) {
++ char *extenp = NULL, *contextp = NULL, *devstatep = NULL;
++ extenp = var->value;
++ devstatep = strchr(var->value, ',') + 1;
++ contextp = strchr(var->value, '@') + 1;
++ if (devstatep && contextp) {
++ export = malloc(sizeof(struct esel_export));
++ if (!export) {
++ ast_log(LOG_ERROR, "unable to malloc!\n");
++ return -1;
++ }
++ memset(export, 0x0, sizeof(struct esel_export));
++ ast_copy_string(export->exten, extenp, contextp - extenp);
++ ast_copy_string(export->context, contextp, devstatep - contextp);
++ ast_copy_string(export->devstate, devstatep, sizeof(export->devstate));
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "exporting %s @ %s as %s to %s\n", export->exten, export->context , export->devstate , esel->name);
++ export->next = esel->extensions;
++ esel->extensions = export;
++ export = NULL;
++ }
++ }
++ var = var->next;
++ }
++
++
++
++ esel->next = donkeys;
++ donkeys = esel;
++
++ ast_pthread_create(&esel->esel_thread, NULL, do_esel_thread, esel);
++
++ }
++ cat = ast_category_browse(cfg, cat);
++ }
++ ast_config_destroy(cfg);
++ }
++ ast_extension_state_add(NULL, NULL, esel_state_cb, NULL);
++ return res;
++}
++
++
++static int unload_module(void)
++{
++ struct esel_pvt *esel, *eseln;
++ ast_module_user_hangup_all();
++ esel = donkeys;
++ ast_mutex_lock(&listlock);
++ while (esel) {
++ pthread_cancel(esel->esel_thread);
++ pthread_join(esel->esel_thread, NULL);
++ ast_mutex_destroy(&esel->queue.lock);
++ close(esel->sockfd);
++ eseln = esel->next;
++ free(esel);
++ esel = eseln;
++ }
++ ast_mutex_unlock(&listlock);
++ return 0;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Extension State Export Logic (E.S.E.L.) Resource",
++ .load = load_module,
++ .unload = unload_module,
++);
Added: asterisk/branches/experimental/debian/patches/bristuff/misc-res-watchdog
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/misc-res-watchdog (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/misc-res-watchdog 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,165 @@
+--- /dev/null
++++ asterisk-1.4.8~dfsg/configs/watchdog.conf.sample
+@@ -0,0 +1,22 @@
++;
++; Configuration file for res_watchdog
++;
++; type = isdnguard | watchdog
++; device = /dev/...
++; interval = interval to trigger the watchdog in ms
++
++;[ISDNguard-direct]
++;type = isdnguard
++;device = /dev/ttyS0
++;interval = 200
++
++;[ISDNguard-with-daemon]
++;type = isdnguard
++;device = /var/run/guard.ctl
++;interval = 200
++
++;[kernel_watchdog]
++;type = watchdog
++;device = /dev/watchdog
++;interval = 100
++
+--- /dev/null
++++ asterisk-1.4.8~dfsg/res/res_watchdog.c
+@@ -0,0 +1,137 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Resource to make watchdogs happy
++ *
++ * Copyright (C) 2005, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include "asterisk.h"
++#include <stdlib.h>
++#include <errno.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/time.h>
++#include <sys/signal.h>
++#include <netinet/in.h>
++
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/options.h>
++#include <asterisk/module.h>
++#include <asterisk/translate.h>
++#include <asterisk/say.h>
++#include <asterisk/features.h>
++#include <asterisk/musiconhold.h>
++#include <asterisk/config.h>
++#include <asterisk/cli.h>
++#include <asterisk/manager.h>
++#include <asterisk/utils.h>
++#include <asterisk/lock.h>
++#include <asterisk/adsi.h>
++
++static struct watchdog_pvt *watchdogs = NULL;
++
++typedef struct watchdog_pvt {
++ char device[80];
++ int fd;
++ int type;
++ int interval;
++ pthread_t watchdog_thread;
++ struct watchdog_pvt *next;
++} watchdog_pvt;
++
++static void *do_watchdog_thread(void *data) {
++ struct watchdog_pvt *woof = (struct watchdog_pvt *)data;
++ for (;;) {
++ if (woof->fd) {
++ write(woof->fd, "PING\n", 5);
++ }
++ usleep(woof->interval * 1000);
++ }
++ return NULL;
++}
++
++
++static int load_module(void)
++{
++ int res = 0;
++ const char *cat, *utype, *udevice, *uinterval;
++ struct ast_config *cfg;
++ struct watchdog_pvt *woof = NULL;
++
++ cfg = ast_config_load("watchdog.conf");
++ if (cfg) {
++ cat = ast_category_browse(cfg, NULL);
++ while(cat) {
++ cat = ast_category_browse(cfg, cat);
++ utype = ast_variable_retrieve(cfg, cat, "type");
++/* if (utype) {
++ ast_log(LOG_NOTICE, "type = %s\n", utype);
++ } */
++ udevice = ast_variable_retrieve(cfg, cat, "device");
++/* if (udevice) {
++ ast_log(LOG_NOTICE, "device = %s\n", udevice);
++ } */
++ uinterval = ast_variable_retrieve(cfg, cat, "interval");
++/* if (uinterval) {
++ ast_log(LOG_NOTICE, "interval = %s\n", uinterval);
++ } */
++ if (uinterval && udevice && utype) {
++ woof = malloc(sizeof(struct watchdog_pvt));
++ if (!woof) {
++ ast_log(LOG_ERROR, "unable to malloc!\n");
++ return -1;
++ }
++ memset(woof, 0x0, sizeof(struct watchdog_pvt));
++ strncpy(woof->device, udevice, sizeof(woof->device) - 1);
++
++ woof->interval = atoi(uinterval);;
++ woof->next = watchdogs;
++ watchdogs = woof;
++ woof->fd = open(woof->device, O_WRONLY | O_SYNC);
++ if (woof->fd) {
++ if (!strncmp(utype, "isdnguard", sizeof(utype))) {
++ woof->type = 1;
++ write(woof->fd, "START\n", 6);
++ }
++ ast_pthread_create(&woof->watchdog_thread, NULL, do_watchdog_thread, woof);
++ } else {
++ ast_log(LOG_WARNING, "error opening watchdog device %s !\n", woof->device);
++ }
++ }
++ }
++ ast_config_destroy(cfg);
++ }
++ return res;
++}
++
++
++static int unload_module(void)
++{
++ struct watchdog_pvt *dogs, *woof;
++ dogs = watchdogs;
++ while (dogs) {
++ pthread_cancel(dogs->watchdog_thread);
++ pthread_join(dogs->watchdog_thread, NULL);
++ close(dogs->fd);
++ woof = dogs->next;
++ free(dogs);
++ dogs = woof;
++ }
++ return 0;
++}
++
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Watchdog Resource",
++ .load = load_module,
++ .unload = unload_module,
++);
Added: asterisk/branches/experimental/debian/patches/bristuff/uniqueid-01-use-pid-on-uniqueid-generation
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/uniqueid-01-use-pid-on-uniqueid-generation (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/uniqueid-01-use-pid-on-uniqueid-generation 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,17 @@
+Use Asterisk's process ID when building the unique ID.
+
+--- asterisk-1.4.8~dfsg.orig/main/channel.c
++++ asterisk-1.4.8~dfsg/main/channel.c
+@@ -803,10 +803,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));
+ }
+
Added: asterisk/branches/experimental/debian/patches/bristuff/uniqueid-10-channel-ops-uniqueid
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/uniqueid-10-channel-ops-uniqueid (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/uniqueid-10-channel-ops-uniqueid 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,308 @@
+Add or convert channel operations so they can use the unique ID.
+
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/channel.h
++++ asterisk-1.4.8~dfsg/include/asterisk/channel.h
+@@ -641,6 +641,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
+@@ -654,9 +666,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
+@@ -941,6 +953,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
+--- asterisk-1.4.8~dfsg.orig/main/channel.c
++++ asterisk-1.4.8~dfsg/main/channel.c
+@@ -1027,7 +1027,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;
+@@ -1052,7 +1052,10 @@ static struct ast_channel *channel_find_
+ * set this to NULL the logic would just blow up
+ */
+ }
+- 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 */
+@@ -1102,39 +1105,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 */
+@@ -1204,8 +1212,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;
++ }
+
+ ast_copy_string(name, chan->name, sizeof(name));
+
+@@ -3013,7 +3023,7 @@ int ast_set_write_format(struct ast_chan
+ &chan->writetrans, 1);
+ }
+
+-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
++struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cid_num, const char *cid_name, struct outgoing_helper *oh, char* uniqueid)
+ {
+ int dummy_outstate;
+ int cause = 0;
+@@ -3025,7 +3035,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 */
+@@ -3048,7 +3058,7 @@ struct ast_channel *__ast_request_and_di
+ ast_cdr_setaccount(chan, oh->account);
+ }
+ 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,
+@@ -3137,12 +3147,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;
+@@ -3192,6 +3202,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.
+@@ -3564,7 +3579,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 */
+--- asterisk-1.4.8~dfsg.orig/apps/app_parkandannounce.c
++++ asterisk-1.4.8~dfsg/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) {
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/pbx.h
++++ asterisk-1.4.8~dfsg/include/asterisk/pbx.h
+@@ -715,9 +715,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
+ *
+--- asterisk-1.4.8~dfsg.orig/main/pbx.c
++++ asterisk-1.4.8~dfsg/main/pbx.c
+@@ -4957,7 +4957,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;
+@@ -4967,7 +4967,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)
+@@ -5049,7 +5049,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)
+@@ -5089,6 +5089,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];
+@@ -5113,7 +5117,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;
+@@ -5132,10 +5136,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) {
+@@ -5216,7 +5220,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;
+@@ -5256,6 +5260,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;
Added: asterisk/branches/experimental/debian/patches/bristuff/uniqueid-20-monitor
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/uniqueid-20-monitor (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/uniqueid-20-monitor 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,82 @@
+--- asterisk-1.4.8~dfsg.orig/res/res_monitor.c
++++ asterisk-1.4.8~dfsg/res/res_monitor.c
+@@ -328,6 +328,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);
+@@ -494,18 +499,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)) {
+@@ -546,16 +561,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) {
Added: asterisk/branches/experimental/debian/patches/bristuff/uniqueid-30-app-chanspy
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/uniqueid-30-app-chanspy (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/uniqueid-30-app-chanspy 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,205 @@
+--- asterisk-1.4.8~dfsg.orig/apps/app_chanspy.c
++++ asterisk-1.4.8~dfsg/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"
+ ;
+
++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;
+ }
Added: asterisk/branches/experimental/debian/patches/bristuff/uniqueid-40-manager
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/uniqueid-40-manager (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/uniqueid-40-manager 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,222 @@
+--- asterisk-1.4.8~dfsg.orig/main/manager.c
++++ asterisk-1.4.8~dfsg/main/manager.c
+@@ -86,6 +86,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;
+ };
+
+@@ -1343,11 +1345,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;
+@@ -1598,12 +1609,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)) {
+@@ -1613,7 +1630,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);
+@@ -1635,9 +1656,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)
+@@ -1716,15 +1737,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)
+@@ -1784,6 +1805,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;
+@@ -1793,6 +1815,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;
+@@ -1810,6 +1835,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, '/');
+@@ -1829,6 +1858,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) {
+@@ -1848,8 +1878,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)) {
+@@ -1860,19 +1892,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;
+ }
+
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/channel.h
++++ asterisk-1.4.8~dfsg/include/asterisk/channel.h
+@@ -89,6 +89,9 @@
+
+ #include "asterisk/abstract_jb.h"
+
++/* Max length of the uniqueid */
++#define AST_MAX_UNIQUEID 64
++
+ #include <unistd.h>
+ #ifdef POLLCOMPAT
+ #include "asterisk/poll-compat.h"
+@@ -986,6 +989,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 */
+--- asterisk-1.4.8~dfsg.orig/main/channel.c
++++ asterisk-1.4.8~dfsg/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, ...)
+ {
Added: asterisk/branches/experimental/debian/patches/bristuff/xagi
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/xagi (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/xagi 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,592 @@
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/agi.h
++++ asterisk-1.4.8~dfsg/include/asterisk/agi.h
+@@ -29,7 +29,8 @@ 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_in; /* FD for audio output */
+ int ctrl; /* FD for input control */
+ } AGI;
+
+--- asterisk-1.4.8~dfsg.orig/res/res_agi.c
++++ asterisk-1.4.8~dfsg/res/res_agi.c
+@@ -11,6 +11,9 @@
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+@@ -73,16 +76,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+
+ static char *app = "AGI";
+
++static char *xapp = "XAGI";
++
+ static char *eapp = "EAGI";
+
+ static char *deadapp = "DeadAGI";
+
+ static char *synopsis = "Executes an AGI compliant application";
++static char *xsynopsis = "Executes an XAGI compliant application";
+ static char *esynopsis = "Executes an EAGI compliant application";
+ static char *deadsynopsis = "Executes AGI on a hungup channel";
+
+ static char *descrip =
+-" [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
++" [E|Dead|X]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
+ "program on a channel. AGI allows Asterisk to launch external programs\n"
+ "written in any language to control a telephony channel, play audio,\n"
+ "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
+@@ -95,6 +101,8 @@ static char *descrip =
+ "variable to \"no\" before executing the AGI application.\n"
+ " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
+ "on file descriptor 3\n\n"
++"Using 'XAGI' provides enhanced AGI, with incoming audio available out of band"
++" on file descriptor 3 and outgoing audio available out of band on file descriptor 4\n\n"
+ " Use the CLI command 'agi show' to list available agi commands\n"
+ " This application sets the following channel variable upon completion:\n"
+ " AGISTATUS The status of the attempt to the run the AGI script\n"
+@@ -231,13 +239,14 @@ static enum agi_result launch_netscript(
+ return AGI_RESULT_SUCCESS;
+ }
+
+-static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
++static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *efd2, int *opid)
+ {
+ char tmp[256];
+ int pid;
+ int toast[2];
+ int fromast[2];
+ int audio[2];
++ int audio2[2];
+ int x;
+ int res;
+ sigset_t signal_set, old_set;
+@@ -282,6 +291,33 @@ static enum agi_result launch_script(cha
+ return AGI_RESULT_FAILURE;
+ }
+ }
++ if (efd2) {
++ if (pipe(audio2)) {
++ ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
++ close(fromast[0]);
++ close(fromast[1]);
++ close(toast[0]);
++ close(toast[1]);
++ close(audio[0]);
++ close(audio[1]);
++ return AGI_RESULT_FAILURE;
++ }
++ res = fcntl(audio2[0], F_GETFL);
++ if (res > -1)
++ res = fcntl(audio2[0], F_SETFL, res | O_NONBLOCK);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
++ close(fromast[0]);
++ close(fromast[1]);
++ close(toast[0]);
++ close(toast[1]);
++ close(audio[0]);
++ close(audio[1]);
++ close(audio2[0]);
++ close(audio2[1]);
++ return AGI_RESULT_FAILURE;
++ }
++ }
+
+ /* Block SIGHUP during the fork - prevents a race */
+ sigfillset(&signal_set);
+@@ -317,6 +353,11 @@ static enum agi_result launch_script(cha
+ } else {
+ close(STDERR_FILENO + 1);
+ }
++ if (efd2) {
++ dup2(audio2[1], STDERR_FILENO + 2);
++ } else {
++ close(STDERR_FILENO + 2);
++ }
+
+ /* Before we unblock our signals, return our trapped signals back to the defaults */
+ signal(SIGHUP, SIG_DFL);
+@@ -334,7 +375,7 @@ static enum agi_result launch_script(cha
+ }
+
+ /* Close everything but stdin/out/error */
+- for (x=STDERR_FILENO + 2;x<1024;x++)
++ for (x=STDERR_FILENO + 3;x<1024;x++)
+ close(x);
+
+ /* Execute script */
+@@ -352,12 +393,19 @@ static enum agi_result launch_script(cha
+ if (efd) {
+ *efd = audio[1];
+ }
++ if (efd2) {
++ *efd2 = audio2[0];
++ }
+ /* close what we're not using in the parent */
+ close(toast[1]);
+ close(fromast[0]);
+
+- if (efd)
++ if (efd) {
+ close(audio[0]);
++ }
++ if (efd2) {
++ close(audio2[1]);
++ }
+
+ *opid = pid;
+ return AGI_RESULT_SUCCESS;
+@@ -387,7 +435,7 @@ static void setup_env(struct ast_channel
+ fdprintf(fd, "agi_context: %s\n", chan->context);
+ fdprintf(fd, "agi_extension: %s\n", chan->exten);
+ fdprintf(fd, "agi_priority: %d\n", chan->priority);
+- fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
++ fdprintf(fd, "agi_enhanced: %d%s\n", enhanced, ".0");
+
+ /* User information */
+ fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
+@@ -416,7 +464,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;
+ }
+@@ -591,7 +639,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;
+@@ -652,7 +700,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;
+@@ -664,7 +712,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;
+@@ -688,7 +736,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);
+@@ -705,7 +753,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);
+@@ -719,7 +767,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);
+@@ -797,7 +845,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);
+@@ -821,7 +869,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)
+@@ -1828,7 +1876,12 @@ static enum agi_result run_agi(struct as
+ int ms;
+ enum agi_result returnstatus = AGI_RESULT_SUCCESS;
+ struct ast_frame *f;
++ struct ast_frame fr;
+ char buf[2048];
++ char audiobuf[2048];
++ int audiobytes;
++ int fds[2];
++ int enhanced = 0;
+ FILE *readf;
+ /* how many times we'll retry if ast_waitfor_nandfs will return without either
+ channel or file descriptor in case select is interrupted by a system call (EINTR) */
+@@ -1842,10 +1895,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) {
++ enhanced = 1;
++ }
++ if (agi->audio_in > -1) {
++ enhanced++;
++ }
++ setup_env(chan, request, agi->fd, enhanced);
++ fds[0] = agi->ctrl;
++ fds[1] = agi->audio_in;
+ for (;;) {
+ ms = -1;
+- c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
++ if (agi->audio_in > -1) {
++ c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, fds, 2, NULL, &outfd, &ms);
++ } else {
++ c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
++ }
+ if (c) {
+ retry = RETRY;
+ /* Idle the channel until we get a command */
+@@ -1856,13 +1921,24 @@ 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);
+ }
+ ast_frfree(f);
+ }
+ } else if (outfd > -1) {
++ if ((agi->audio_in > -1) && (outfd == agi->audio_in)) {
++ audiobytes = read(agi->audio_in, audiobuf, sizeof(audiobuf));
++ if (audiobytes > 0) {
++ // ast_log(LOG_NOTICE, "read %d bytes of audio\n", audiobytes);
++ fr.frametype = AST_FRAME_VOICE;
++ fr.subclass = AST_FORMAT_SLINEAR;
++ fr.datalen = audiobytes;
++ fr.data = audiobuf;
++ ast_write(chan, &fr);
++ }
++ } else {
+ retry = RETRY;
+ if (!fgets(buf, sizeof(buf), readf)) {
+ /* Program terminated */
+@@ -1886,6 +1962,7 @@ static enum agi_result run_agi(struct as
+ if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
+ break;
+ }
++ }
+ } else {
+ if (--retry <= 0) {
+ ast_log(LOG_WARNING, "No channel, no fd?\n");
+@@ -1994,6 +2071,7 @@ static int agi_exec_full(struct ast_chan
+ int argc = 0;
+ int fds[2];
+ int efd = -1;
++ int efd2 = -1;
+ int pid;
+ char *stringp;
+ AGI agi;
+@@ -2019,12 +2097,13 @@ static int agi_exec_full(struct ast_chan
+ }
+ }
+ #endif
+- res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
++ res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, (enhanced == 2) ? &efd2 : NULL, &pid);
+ if (res == AGI_RESULT_SUCCESS) {
+ int status = 0;
+ agi.fd = fds[1];
+ agi.ctrl = fds[0];
+- agi.audio = efd;
++ agi.audio_out = efd;
++ agi.audio_in = efd2;
+ res = run_agi(chan, argv[0], &agi, pid, &status, dead);
+ /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
+ if (res == AGI_RESULT_SUCCESS && status)
+@@ -2033,6 +2112,8 @@ static int agi_exec_full(struct ast_chan
+ close(fds[1]);
+ if (efd > -1)
+ close(efd);
++ if (efd2 > -1)
++ close(efd2);
+ ast_unreplace_sigchld();
+ }
+ ast_module_user_remove(u);
+@@ -2080,6 +2161,35 @@ static int eagi_exec(struct ast_channel
+ return res;
+ }
+
++static int xagi_exec(struct ast_channel *chan, void *data)
++{
++ int readformat, writeformat;
++ int res;
++
++ if (chan->_softhangup)
++ ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
++ readformat = chan->readformat;
++ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
++ ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
++ return -1;
++ }
++ writeformat = chan->writeformat;
++ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
++ ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
++ return -1;
++ }
++ res = agi_exec_full(chan, data, 2, 0);
++ if (!res) {
++ if (ast_set_read_format(chan, readformat)) {
++ ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
++ }
++ if (ast_set_write_format(chan, writeformat)) {
++ ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(writeformat));
++ }
++ }
++ return res;
++}
++
+ static int deadagi_exec(struct ast_channel *chan, void *data)
+ {
+ if (!ast_check_hangup(chan))
+@@ -2135,6 +2245,7 @@ static int unload_module(void)
+ {
+ ast_module_user_hangup_all();
+ ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
++ ast_unregister_application(xapp);
+ ast_unregister_application(eapp);
+ ast_unregister_application(deadapp);
+ return ast_unregister_application(app);
+@@ -2145,6 +2256,7 @@ static int load_module(void)
+ ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
+ ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
+ ast_register_application(eapp, eagi_exec, esynopsis, descrip);
++ ast_register_application(xapp, xagi_exec, xsynopsis, descrip);
+ return ast_register_application(app, agi_exec, synopsis, descrip);
+ }
+
+--- /dev/null
++++ asterisk-1.4.8~dfsg/agi/xagi-test.c
+@@ -0,0 +1,175 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * XAGI sample script
++ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * based on eagi-test.c
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/select.h>
++#ifdef SOLARIS
++#include <solaris-compat/compat.h>
++#endif
++
++#define AUDIO_FILENO_IN (STDERR_FILENO + 1)
++#define AUDIO_FILENO_OUT (STDERR_FILENO + 2)
++
++static int read_environment(void)
++{
++ char buf[256];
++ char *val;
++ /* Read environment */
++ for(;;) {
++ fgets(buf, sizeof(buf), stdin);
++ if (feof(stdin))
++ return -1;
++ buf[strlen(buf) - 1] = '\0';
++ /* Check for end of environment */
++ if (!strlen(buf))
++ return 0;
++ val = strchr(buf, ':');
++ if (!val) {
++ fprintf(stderr, "Invalid environment: '%s'\n", buf);
++ return -1;
++ }
++ *val = '\0';
++ val++;
++ val++;
++ /* Skip space */
++ // fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
++
++ /* Load into normal environment */
++ setenv(buf, val, 1);
++
++ }
++ /* Never reached */
++ return 0;
++}
++
++static void app_echo(void)
++{
++ fd_set fds;
++ int res;
++ int bytes = 0;
++ static char astresp[256];
++ char audiobuf[16000]; /* 1 second of audio */
++ for (;;) {
++ FD_ZERO(&fds);
++ FD_SET(STDIN_FILENO, &fds);
++ FD_SET(AUDIO_FILENO_IN, &fds);
++ /* Wait for *some* sort of I/O */
++ res = select(AUDIO_FILENO_IN + 1, &fds, NULL, NULL, NULL);
++ if (res < 0) {
++ fprintf(stderr, "Error in select: %s\n", strerror(errno));
++ return;
++ }
++ if (FD_ISSET(STDIN_FILENO, &fds)) {
++ fgets(astresp, sizeof(astresp), stdin);
++ if (feof(stdin)) {
++ return;
++ }
++ astresp[strlen(astresp) - 1] = '\0';
++ fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
++ return;
++ }
++ if (FD_ISSET(AUDIO_FILENO_IN, &fds)) {
++ /* what goes in.... */
++ res = read(AUDIO_FILENO_IN, audiobuf, sizeof(audiobuf));
++ if (res > 0) {
++ bytes = res;
++ /* must come out */
++ write(AUDIO_FILENO_OUT, audiobuf, bytes);
++ }
++ }
++ }
++}
++
++static char *wait_result(void)
++{
++ fd_set fds;
++ int res;
++ static char astresp[256];
++ char audiobuf[4096];
++ for (;;) {
++ FD_ZERO(&fds);
++ FD_SET(STDIN_FILENO, &fds);
++ FD_SET(AUDIO_FILENO_IN, &fds);
++ /* Wait for *some* sort of I/O */
++ res = select(AUDIO_FILENO_IN + 1, &fds, NULL, NULL, NULL);
++ if (res < 0) {
++ fprintf(stderr, "Error in select: %s\n", strerror(errno));
++ return NULL;
++ }
++ if (FD_ISSET(STDIN_FILENO, &fds)) {
++ fgets(astresp, sizeof(astresp), stdin);
++ if (feof(stdin)) {
++ fprintf(stderr, "Got hungup on apparently\n");
++ return NULL;
++ }
++ astresp[strlen(astresp) - 1] = '\0';
++ fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
++ return astresp;
++ }
++ if (FD_ISSET(AUDIO_FILENO_IN, &fds)) {
++ res = read(AUDIO_FILENO_IN, audiobuf, sizeof(audiobuf));
++ /* drop it, like it's hot */
++ }
++ }
++
++}
++
++static char *run_command(char *command)
++{
++ fprintf(stdout, "%s\n", command);
++ return wait_result();
++}
++
++
++static int run_script(void)
++{
++ char *res;
++ res = run_command("STREAM FILE demo-echotest \"\"");
++ if (!res) {
++ fprintf(stderr, "Failed to execute command\n");
++ return -1;
++ }
++ app_echo();
++ return 0;
++}
++
++int main(int argc, char *argv[])
++{
++ char *tmp;
++ int ver = 0;
++ int subver = 0;
++ /* Setup stdin/stdout for line buffering */
++ setlinebuf(stdin);
++ setlinebuf(stdout);
++ if (read_environment()) {
++ fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
++ exit(1);
++ }
++ tmp = getenv("agi_enhanced");
++ if (tmp) {
++ if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
++ ver = 0;
++ }
++ if (ver < 2) {
++ fprintf(stderr, "No XAGI services available. Use XAGI, not AGI or EAGI\n");
++ exit(1);
++ }
++ if (run_script())
++ return -1;
++ exit(0);
++}
+--- asterisk-1.4.8~dfsg.orig/agi/Makefile
++++ asterisk-1.4.8~dfsg/agi/Makefile
+@@ -13,7 +13,7 @@
+
+ .PHONY: clean all uninstall
+
+-AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi
++AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi xagi-test
+
+ ifeq ($(OSARCH),SunOS)
+ LIBS+=-lsocket -lnsl
+@@ -38,7 +38,7 @@ uninstall:
+ for x in $(AGIS); do rm -f $(DESTDIR)$(AGI_DIR)/$$x ; done
+
+ clean:
+- rm -f *.so *.o look eagi-test eagi-sphinx-test
++ rm -f *.so *.o look eagi-test eagi-sphinx-test xagi-test
+ rm -f .*.o.d .*.oo.d
+ rm -f strcompat.c
+
Added: asterisk/branches/experimental/debian/patches/bristuff/zapata-bri+euroisdn
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/zapata-bri+euroisdn (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/zapata-bri+euroisdn 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,2752 @@
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/channel.h
++++ asterisk-1.4.8~dfsg/include/asterisk/channel.h
+@@ -413,6 +413,8 @@ 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 */
++ char highlayercompat[4]; /*!< ISDN High Layer Compatibility */
+ int alertpipe[2];
+
+ int nativeformats; /*!< Kinds of data this channel can natively handle */
+--- asterisk-1.4.8~dfsg.orig/main/pbx.c
++++ asterisk-1.4.8~dfsg/main/pbx.c
+@@ -5101,7 +5101,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;
+--- asterisk-1.4.8~dfsg.orig/include/asterisk/pbx.h
++++ asterisk-1.4.8~dfsg/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
+ *
+--- asterisk-1.4.8~dfsg.orig/channels/chan_zap.c
++++ asterisk-1.4.8~dfsg/channels/chan_zap.c
+@@ -11,6 +11,10 @@
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
++ * Copyright (C) 2003-2006 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+@@ -103,6 +107,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 */
+@@ -189,7 +195,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 */
+
+@@ -204,6 +210,9 @@ static const char config[] = "zapata.con
+ static char defaultcic[64] = "";
+ static char defaultozz[64] = "";
+
++static char nocid[256] = "No CID available";
++static char withheldcid[256] = "CID withheld";
++
+ static char progzone[10] = "";
+
+ static int distinctiveringaftercid = 0;
+@@ -215,8 +224,6 @@ static struct ast_channel inuse;
+ #ifdef PRI_GETSET_TIMERS
+ static int pritimers[PRI_MAX_TIMERS];
+ #endif
+-static int pridebugfd = -1;
+-static char pridebugfilename[1024] = "";
+ #endif
+
+ /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
+@@ -234,10 +241,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);
+@@ -252,6 +255,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)
+ {
+@@ -296,6 +300,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 */
+@@ -309,6 +334,8 @@ struct zt_pri {
+ int nsf; /*!< Network-Specific Facilities */
+ int dialplan; /*!< Dialing plan */
+ int localdialplan; /*!< Local dialing plan */
++ char nocid[256];
++ char withheldcid[256];
+ char internationalprefix[10]; /*!< country access code ('00' for european dialplans) */
+ char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
+ char localprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
+@@ -320,6 +347,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 */
+@@ -335,6 +363,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;
+ };
+
+
+@@ -452,6 +483,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;
+@@ -465,7 +498,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 */
+@@ -502,6 +536,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];
+@@ -567,6 +602,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
+@@ -617,6 +654,7 @@ static struct zt_chan_conf zt_chan_conf_
+ .localprefix = "",
+ .privateprefix = "",
+ .unknownprefix = "",
++ .usercid = 0,
+
+ .resetinterval = 3600
+ },
+@@ -628,6 +666,8 @@ static struct zt_chan_conf zt_chan_conf_
+ .mohinterpret = "default",
+ .mohsuggest = "",
+ .transfertobusy = 1,
++ .priindication_oob = 0,
++ .pritransfer = 0,
+
+ .cid_signalling = CID_SIG_BELL,
+ .cid_start = CID_START_RING,
+@@ -682,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);
+
+ static const struct ast_channel_tech zap_tech = {
+ .type = "Zap",
+@@ -702,6 +744,7 @@ static const struct ast_channel_tech zap
+ .fixup = zt_fixup,
+ .setoption = zt_setoption,
+ .func_channel_read = zt_func_read,
++/* .devicestate = zt_devicestate, */
+ };
+
+ #ifdef HAVE_PRI
+@@ -713,6 +756,13 @@ static const struct ast_channel_tech zap
+ struct zt_pvt *round_robin[32];
+
+ #ifdef HAVE_PRI
++struct app_tmp {
++ char app[256];
++ char data[256];
++ struct ast_channel *chan;
++ pthread_t t;
++};
++
+ static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri)
+ {
+ int res;
+@@ -760,6 +810,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) */)
+
++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;d<NUM_DCHANS;d++) {
++ if (p->pri->dchanavail[d] & DCHAN_UP) {
++ res = AST_DEVICE_UNKNOWN;
++ }
++ }
++ }
++#endif
++ if ((!ast_strlen_zero(p->cid_num) && (strncasecmp(p->cid_num, dest, strlen(p->cid_num)))) || (!ast_strlen_zero(p->dnid) && (strncasecmp(p->dnid, dest, strlen(p->dnid))))) {
++ res = AST_DEVICE_UNKNOWN;
++ if (p->owner) {
++ if ((p->owner->_state == AST_STATE_RINGING) && (p->outgoing)) {
++ res = AST_DEVICE_RINGING;
++ }
++ if (((p->owner->_state == AST_STATE_RINGING) && (!p->outgoing)) || (p->owner->_state == AST_STATE_UP) || (p->owner->_state == AST_STATE_DIALING) || (p->owner->_state == AST_STATE_RESERVED) || (p->owner->_state == AST_STATE_RING)){
++ res = AST_DEVICE_INUSE;
++ }
++ }
++ if ((res == AST_DEVICE_INUSE) || (res == AST_DEVICE_RINGING)) {
++ /* stop searching now, one non-idle channel is sufficient */
++ ast_mutex_unlock(&p->lock);
++ break;
++ }
++ }
++ }
++ ast_mutex_unlock(&p->lock);
++ }
++ p = p->next;
++ }
++ ast_mutex_unlock(lock);
++
++ return res;
++
++}
++
+ static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
+ {
+ int res;
+@@ -1409,12 +1565,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) {
+@@ -1441,7 +1601,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)
+@@ -1808,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;
+
+- set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
++ if (IS_DIGITAL(ast->transfercapability)) {
++ set_actual_gain(p->subs[SUB_REAL].zfd, 0, 0, 0, p->law);
++ } else {
++ set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
++ }
++
+
+ mysig = p->sig;
+ if (p->outsigmod > -1)
+@@ -2039,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");
+@@ -2059,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... ;-)
++ }
++
+ c = strchr(dest, '/');
+ if (c)
+ c++;
+@@ -2080,6 +2252,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');
+@@ -2103,6 +2276,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);
+@@ -2132,7 +2307,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);
+
+@@ -2396,8 +2571,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",
+@@ -2407,6 +2584,16 @@ static int pri_find_dchan(struct zt_pri
+ }
+ #endif
+
++static int zt_setlaw(int zfd, int law)
++{
++ int res;
++ res = ioctl(zfd, ZT_SETLAW, &law);
++ if (res)
++ return res;
++ return 0;
++}
++
++
+ static int zt_hangup(struct ast_channel *ast)
+ {
+ int res;
+@@ -2454,8 +2641,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;
+@@ -2557,6 +2743,7 @@ static int zt_hangup(struct ast_channel
+ }
+
+ if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
++ int outgoing = p->outgoing;
+ p->owner = NULL;
+ p->ringt = 0;
+ p->distinctivering = 0;
+@@ -2599,7 +2786,7 @@ static int zt_hangup(struct ast_channel
+ pri_call_set_useruser(p->call, useruser);
+ #endif
+
+- pri_hangup(p->pri->pri, p->call, -1);
++ pri_hangup(p->pri->pri, p->call, -1, -1);
+ p->call = NULL;
+ if (p->bearer)
+ p->bearer->call = NULL;
+@@ -2619,7 +2806,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");
+@@ -2803,10 +3011,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:
+@@ -3432,6 +3644,15 @@ static int zt_fixup(struct ast_channel *
+ {
+ struct zt_pvt *p = newchan->tech_pvt;
+ int x;
++ if (newchan && newchan->tech_pvt) {
++ p = newchan->tech_pvt;
++ }
++ if (!p) {
++ if (newchan) {
++ ast_log(LOG_ERROR, "channel %s has no tech_pvt structure\n", newchan->name);
++ }
++ return 0;
++ }
+ ast_mutex_lock(&p->lock);
+ ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name);
+ if (p->owner == oldchan) {
+@@ -3641,8 +3862,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)
+@@ -3796,7 +4019,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);
+@@ -4855,7 +5078,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) {
+@@ -4867,8 +5090,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;
+ }
+@@ -4944,7 +5168,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;
+ }
+@@ -5016,7 +5242,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;
+@@ -5098,7 +5324,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;
+@@ -5292,8 +5518,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;
+ }
+@@ -5427,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
+@@ -5455,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
+@@ -6664,18 +6902,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_PTMP)) {
++ /* 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_PTMP)) {
++ /* 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)
+@@ -6719,8 +6983,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);
+@@ -7010,6 +7276,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;
+ }
+@@ -7262,6 +7530,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);
+@@ -7279,6 +7552,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;
+@@ -7287,9 +7565,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) - 1);
++ ast_copy_string(pris[span].withheldcid, conf.pri.withheldcid, sizeof(pris[span].withheldcid) - 1);
+ 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));
+@@ -7425,6 +7708,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) {
+@@ -7704,7 +7988,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;
+@@ -7900,6 +8184,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);
+ }
+@@ -7933,13 +8222,14 @@ next:
+ *cause = AST_CAUSE_BUSY;
+ } else if (groupmatched) {
+ *cause = AST_CAUSE_CONGESTION;
++ } else {
++ *cause = AST_CAUSE_CONGESTION;
+ }
+ }
+
+ return tmp;
+ }
+
+-
+ #ifdef HAVE_PRI
+ static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv)
+ {
+@@ -7953,6 +8243,58 @@ static struct zt_pvt *pri_find_crv(struc
+ return NULL;
+ }
+
++static int pri_find_tei(struct zt_pri *pri, q931_call *c, int tei)
++{
++ int x=0;
++ for (x=0;x<pri->numchans;x++) {
++ if (!pri->pvts[x]) continue;
++ if ((pri->pvts[x]->tei == tei) && (pri->pvts[x]-> call != c)) {
++ return x;
++ }
++ }
++ return -1;
++}
++
++static struct zt_holded_call *pri_get_callonhold(struct zt_pri *pri, int cref, int tei) {
++ struct zt_holded_call *zhc = pri->holded_calls;
++ struct zt_holded_call *zhctemp = NULL;
++
++ while (zhc) {
++ if ((zhc->tei == tei) && ((zhc->cref == cref) || (cref == -1))) {
++ return zhc;
++ }
++ zhctemp = zhc;
++ if (zhc) zhc = zhc->next;
++ }
++ return NULL;
++}
++
++static int pri_destroy_callonhold(struct zt_pri *pri, struct zt_holded_call *onhold) {
++ struct zt_holded_call *zhc = pri->holded_calls;
++ struct zt_holded_call *zhctemp = NULL;
++
++ while (zhc) {
++ if (zhc == onhold) {
++ if (zhctemp) {
++ zhctemp->next = zhc->next;
++ zhc = zhctemp;
++ } else {
++ pri->holded_calls = zhc->next;
++ zhc = pri->holded_calls;
++ zhctemp = NULL;
++ }
++ }
++ zhctemp = zhc;
++ if (zhc) zhc = zhc->next;
++ }
++ if (onhold) {
++ free(onhold);
++ onhold = NULL;
++ return 1;
++ }
++ return 0;
++}
++
+
+ static int pri_find_principle(struct zt_pri *pri, int channel)
+ {
+@@ -7984,7 +8326,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;
+@@ -8012,6 +8356,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,
+@@ -8019,13 +8364,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;
+ }
+@@ -8054,7 +8434,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;
+ }
+
+@@ -8113,86 +8495,21 @@ static void *do_idle_thread(void *vchan)
+ #ifndef PRI_RESTART
+ #error "Upgrade your libpri"
+ #endif
+-static void zt_pri_message(struct pri *pri, char *s)
++static void zt_pri_message(char *s, int span)
+ {
+- int x, y;
+- int dchan = -1, span = -1;
+- int dchancount = 0;
+-
+- if (pri) {
+- for (x = 0; x < NUM_SPANS; x++) {
+- for (y = 0; y < NUM_DCHANS; y++) {
+- if (pris[x].dchans[y])
+- dchancount++;
+-
+- if (pris[x].dchans[y] == pri)
+- dchan = y;
+- }
+- if (dchan >= 0) {
+- span = x;
+- break;
+- }
+- dchancount = 0;
+- }
+- if ((dchan >= 0) && (span >= 0)) {
+- if (dchancount > 1)
+- ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
+- else
+- ast_verbose("%s", s);
+- } else
+- ast_log(LOG_ERROR, "PRI debug error: could not find pri associated it with debug message output\n");
+- } else
+- ast_verbose("%s", s);
+-
+- ast_mutex_lock(&pridebugfdlock);
+-
+- if (pridebugfd >= 0)
+- write(pridebugfd, s, strlen(s));
+-
+- ast_mutex_unlock(&pridebugfdlock);
++ ast_verbose("%d %s", span, s);
+ }
+
+-static void zt_pri_error(struct pri *pri, char *s)
++static void zt_pri_error(char *s, int span)
+ {
+- int x, y;
+- int dchan = -1, span = -1;
+- int dchancount = 0;
+-
+- if (pri) {
+- for (x = 0; x < NUM_SPANS; x++) {
+- for (y = 0; y < NUM_DCHANS; y++) {
+- if (pris[x].dchans[y])
+- dchancount++;
+-
+- if (pris[x].dchans[y] == pri)
+- dchan = y;
+- }
+- if (dchan >= 0) {
+- span = x;
+- break;
+- }
+- dchancount = 0;
+- }
+- if ((dchan >= 0) && (span >= 0)) {
+- if (dchancount > 1)
+- ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
+- else
+- ast_log(LOG_ERROR, "%s", s);
+- } else
+- ast_log(LOG_ERROR, "PRI debug error: could not find pri associated it with debug message output\n");
+- } else
+- ast_log(LOG_ERROR, "%s", s);
+-
+- ast_mutex_lock(&pridebugfdlock);
+-
+- if (pridebugfd >= 0)
+- write(pridebugfd, s, strlen(s));
+-
+- ast_mutex_unlock(&pridebugfdlock);
++ ast_log(LOG_WARNING, "%d %s", span, s);
+ }
+
+ static int pri_check_restart(struct zt_pri *pri)
+ {
++ if ((pri->nodetype != PRI_NETWORK) && (pri->nodetype != PRI_CPE)) {
++ return 0;
++ }
+ do {
+ pri->resetpos++;
+ } while ((pri->resetpos < pri->numchans) &&
+@@ -8276,13 +8593,30 @@ static void apply_plan_to_number(char *b
+ }
+ }
+
+-static int zt_setlaw(int zfd, int law)
+-{
+- int res;
+- res = ioctl(zfd, ZT_SETLAW, &law);
+- if (res)
+- return res;
+- return 0;
++static void pri_make_callerid(struct zt_pri *pri, char *callerid, int callerid_len, char *callingnum, int callingnum_len, int callingplan, int callingpres, int stripmsd) {
++ if (callingnum && (callingnum_len > stripmsd)) {
++ callingnum += stripmsd;
++ }
++ switch (callingplan) {
++ case PRI_INTERNATIONAL_ISDN:
++ snprintf(callerid, callerid_len, "%s%s", pri->internationalprefix, callingnum);
++ break;
++ case PRI_NATIONAL_ISDN:
++ snprintf(callerid, callerid_len, "%s%s", pri->nationalprefix, callingnum);
++ break;
++ case PRI_LOCAL_ISDN:
++ snprintf(callerid, callerid_len, "%s%s", pri->localprefix, callingnum);
++ break;
++ case PRI_PRIVATE:
++ snprintf(callerid, callerid_len, "%s%s", pri->privateprefix, callingnum);
++ break;
++ case PRI_UNKNOWN:
++ snprintf(callerid, callerid_len, "%s%s", pri->unknownprefix, callingnum);
++ break;
++ default:
++ snprintf(callerid, callerid_len, "%s", callingnum);
++ break;
++ }
+ }
+
+ static void *pri_dchannel(void *vpri)
+@@ -8462,15 +8796,44 @@ static void *pri_dchannel(void *vpri)
+ /* Check for an event */
+ x = 0;
+ res = ioctl(pri->fds[which], ZT_GETEVENT, &x);
+- if (x)
++ if ((pri->nodetype != BRI_CPE) && (pri->nodetype != BRI_CPE_PTMP)) {
++ /* dont annoy BRI TE mode users with layer2layer alarms */
++ if (x)
+ ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span);
++ }
+ /* Keep track of alarm state */
+ if (x == ZT_EVENT_ALARM) {
+ pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
+ pri_find_dchan(pri);
++ if ((pri->nodetype == BRI_CPE) || (pri->nodetype == BRI_CPE_PTMP)) {
++ if (pri->pri) {
++ for (i=0; i<pri->numchans; i++) {
++ struct zt_pvt *p = pri->pvts[i];
++ if (p) {
++ if (p->call) {
++ if (p->pri && p->pri->pri) {
++ pri_destroycall(p->pri->pri, p->call);
++ p->call = NULL;
++ p->tei = -1;
++ } else
++ ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
++ }
++ if (p->owner)
++ p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ p->inalarm = 1;
++ }
++ }
++ pri_shutdown(pri->pri);
++ }
++ }
+ } else if (x == ZT_EVENT_NOALARM) {
+- pri->dchanavail[which] |= DCHAN_NOTINALARM;
+- pri_restart(pri->dchans[which]);
++ if ((pri->nodetype == BRI_CPE) || (pri->nodetype == BRI_CPE_PTMP)) {
++ pri->dchanavail[which] |= DCHAN_NOTINALARM;
++ // pri->dchanavail[which] |= DCHAN_UP;
++ } else {
++ pri->dchanavail[which] |= DCHAN_NOTINALARM;
++ pri_restart(pri->dchans[which]);
++ }
+ }
+
+ if (option_debug)
+@@ -8482,8 +8845,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);
+@@ -8496,32 +8858,86 @@ static void *pri_dchannel(void *vpri)
+
+ 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; i<pri->numchans; i++)
++ if (pri->pvts[i]) {
++ pri->pvts[i]->inalarm = 0;
++ }
++ } else {
++ if (pri->nodetype == BRI_CPE_PTMP) {
++ if (option_verbose > 3)
++ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
++ } else {
++ if (option_verbose > 1)
++ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
++ }
++ pri->dchanavail[which] |= DCHAN_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; i<pri->numchans; i++) {
++ struct zt_pvt *p = pri->pvts[i];
++ if (p) {
++ // ast_log(LOG_NOTICE, "chan %d tei %d\n",i,p->tei);
++ if (p->tei == e->gen.tei) {
++ if (p->call) {
++ if (p->pri && p->pri->pri) {
++ pri_hangup(p->pri->pri, p->call, -1, -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++) {
+@@ -8531,12 +8947,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)
+@@ -8545,6 +8962,7 @@ static void *pri_dchannel(void *vpri)
+ p->inalarm = 1;
+ }
+ }
++ }
+ }
+ break;
+ case PRI_EVENT_RESTART:
+@@ -8579,8 +8997,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);
+@@ -8614,7 +9032,6 @@ static void *pri_dchannel(void *vpri)
+ }
+ }
+ break;
+-
+ case PRI_EVENT_INFO_RECEIVED:
+ chanpos = pri_find_principle(pri, e->ring.channel);
+ if (chanpos < 0) {
+@@ -8623,9 +9040,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;
+@@ -8637,6 +9056,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);
+ }
+@@ -8644,36 +9071,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));
+@@ -8687,13 +9137,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) {
+@@ -8718,29 +9169,78 @@ 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:
++ strncpy(pri->pvts[chanpos]->cid_name, pri->withheldcid, sizeof(pri->pvts[chanpos]->cid_name));
++ break;
++ case PRES_NUMBER_NOT_AVAILABLE:
++ strncpy(pri->pvts[chanpos]->cid_name, pri->nocid, sizeof(pri->pvts[chanpos]->cid_name));
++ break;
++ }
+ /* If immediate=yes go to s|1 */
+ if (pri->pvts[chanpos]->immediate) {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of immediate=yes\n");
+ pri->pvts[chanpos]->exten[0] = 's';
+ pri->pvts[chanpos]->exten[1] = '\0';
+- }
+- /* Get called number */
+- else if (!ast_strlen_zero(e->ring.callednum)) {
+- ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+- ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+- } else
+- pri->pvts[chanpos]->exten[0] = '\0';
+- /* Set DNID on all incoming calls -- even immediate */
+- if (!ast_strlen_zero(e->ring.callednum))
+- ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+- /* No number yet, but received "sending complete"? */
+- if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
++ } else if (ast_strlen_zero(e->ring.callednum)) {
++ /* called party number is empty */
++ if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
++ if (!pri->overlapdial) {
++ // be able to set digittimeout for BRI phones
++ pri->pvts[chanpos]->exten[0] = 's';
++ pri->pvts[chanpos]->exten[1] = '\0';
++ tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++ } else {
++ pri->pvts[chanpos]->exten[0] = '\0';
++ }
++ } else {
++ if (pri->nodetype == BRI_CPE) {
++ /* fix for .at p2p bri lines */
++ pri->pvts[chanpos]->exten[0] = 's';
++ pri->pvts[chanpos]->exten[1] = '\0';
++ } else {
++ pri->pvts[chanpos]->exten[0] = '\0';
++ }
++ }
++ /* No number yet, but received "sending complete"? */
++ if (e->ring.complete) {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of Complete received\n");
+ pri->pvts[chanpos]->exten[0] = 's';
+ pri->pvts[chanpos]->exten[1] = '\0';
+- }
++ }
++ } else {
++ /* Get called number */
++ pri_make_callerid(pri, pri->pvts[chanpos]->dnid, sizeof(pri->pvts[chanpos]->dnid), e->ring.callednum, sizeof(e->ring.callednum), e->ring.calledplan, 0, pri->pvts[chanpos]->stripmsd);
++ pri_make_callerid(pri, pri->pvts[chanpos]->exten, sizeof(pri->pvts[chanpos]->exten), e->ring.callednum, sizeof(e->ring.callednum), e->ring.calledplan, 0, pri->pvts[chanpos]->stripmsd);
++ if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
++ /* if we get the next digit we should stop the dialtone */
++ if (!pri->overlapdial) {
++ // with overlapdial=no the exten is always prefixed by "s"
++ if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten + 1)) {
++ tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++ } else {
++ tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++ }
++ } else {
++ if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten)) {
++ tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++ } else {
++ tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++ }
++ }
++ }
++ }
++ /* Part 3: create channel, setup audio... */
++ /* Set DNID on all incoming calls -- even immediate */
++ if (!ast_strlen_zero(e->ring.callednum))
++ strncpy(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid) - 1);
+ /* Make sure extension exists (or in overlap dial mode, can exist) */
+ if ((pri->overlapdial && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+ ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+@@ -8759,19 +9259,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;
+
+@@ -8783,14 +9300,31 @@ 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 */
+ }
+ 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);
+@@ -8812,8 +9346,8 @@ static void *pri_dchannel(void *vpri)
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (c && !ast_pthread_create(&threadid, &attr, ss_thread, c)) {
+ if (option_verbose > 2)
+- ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+- plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
++ ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap %s call from '%s' to '%s' on channel %d/%d, span %d\n",
++ pri->pvts[chanpos]->digital ? "data" : "voice", plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+ } else {
+ ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+@@ -8821,15 +9355,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));
++ }
+ ast_mutex_lock(&pri->lock);
+ if (c) {
+ char calledtonstr[10];
+@@ -8850,23 +9388,40 @@ static void *pri_dchannel(void *vpri)
+ snprintf(calledtonstr, sizeof(calledtonstr)-1, "%d", e->ring.calledplan);
+ pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+ if (option_verbose > 2)
+- ast_verbose(VERBOSE_PREFIX_3 "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+- plancallingnum, pri->pvts[chanpos]->exten,
++ ast_verbose(VERBOSE_PREFIX_3 "Accepting %s call from '%s' to '%s' on channel %d/%d, span %d\n",
++ pri->pvts[chanpos]->digital ? "data" : "voice", e->ring.callingnum, pri->pvts[chanpos]->exten,
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+ zt_enable_ec(pri->pvts[chanpos]);
++ if(!ast_strlen_zero(e->ring.callingsubaddr)) {
++ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
++ }
++ if (!ast_strlen_zero(e->ring.callingnum)) {
++ char tmpstr[256];
++ pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingnum, sizeof(e->ring.callingnum), e->ring.callingplan, e->ring.callingpres, 0);
++ pbx_builtin_setvar_helper(c, "PRI_NETWORK_CID", tmpstr);
++ }
++ if (!ast_strlen_zero(e->ring.callingani)) {
++ char tmpstr[256];
++ pri_make_callerid(pri, tmpstr,sizeof(tmpstr), e->ring.callingani, sizeof(e->ring.callingani), e->ring.callingplanuser, e->ring.callingpresuser, 0);
++ pbx_builtin_setvar_helper(c, "PRI_USER_CID", e->ring.callednum);
++ }
++ if (!ast_strlen_zero(e->ring.useruserinfo)) {
++ pbx_builtin_setvar_helper(c, "UUI", e->ring.useruserinfo);
++ }
+ } else {
+ ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+- 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';
+ }
+@@ -8875,9 +9430,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:
+@@ -8893,7 +9448,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
+@@ -8922,9 +9477,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
+@@ -8971,6 +9533,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, };
+
+@@ -9018,6 +9586,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;
++ }
++
++ if (chanpos > -1) {
++ ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ if (pri->pvts[chanpos]->owner) {
++ if (ast_bridged_channel(pri->pvts[chanpos]->owner)) {
++ struct zt_suspended_call *zpc;
++ char tmpstr[256];
++ zpc = malloc(sizeof(struct zt_suspended_call));
++ if (!zpc) {
++ ast_log(LOG_ERROR, "unable to malloc zt_suspended_call\n");
++ break;
++ }
++ strncpy(zpc->msn, pri->pvts[chanpos]->cid_num, sizeof(zpc->msn));
++ strncpy(zpc->callid, e->suspend_req.callid, sizeof(zpc->callid));
++ ast_masq_park_call(ast_bridged_channel(pri->pvts[chanpos]->owner), NULL, 0, &zpc->parked_at);
++ zpc->next = pri->suspended_calls;
++ pri->suspended_calls = zpc;
++ snprintf(tmpstr, sizeof(tmpstr), "Parked at %d", zpc->parked_at);
++ pri_suspend_acknowledge(pri->pri, e->suspend_req.call,tmpstr);
++ pri->pvts[chanpos]->call = NULL;
++ pri->pvts[chanpos]->tei = -1;
++ pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ } else {
++ pri_suspend_reject(pri->pri, e->suspend_req.call, "cant park a non-bridge");
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ break;
++ }
++ } else {
++ pri_suspend_reject(pri->pri, e->suspend_req.call, "");
++ }
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ }
++ break;
++ case PRI_EVENT_RESUME_REQ:
++ if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++ break;
++ }
++ chanpos = pri_find_empty_chan(pri, 1);
++ if (chanpos < 0) {
++ pri_resume_reject(pri->pri, e->resume_req.call,"All channels busy");
++ ast_log(LOG_WARNING, "Resume requested on odd channel number %d span %d\n", chanpos, pri->span);
++ chanpos = -1;
++ } else if (!pri->pvts[chanpos]) {
++ pri_resume_reject(pri->pri, e->resume_req.call,"General protection fault in module 0x0BRI");
++ chanpos = -1;
++ }
++
++ if (chanpos > -1) {
++ ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ if (!pri->pvts[chanpos]->owner) {
++ struct zt_suspended_call *zpc, *zpcl;
++ int unparked=0;
++ char extenstr[255], temp[255];
++ zpc = NULL;
++ zpcl = pri->suspended_calls;
++ while (zpcl) {
++ // ast_log(LOG_NOTICE, "zpc->parked_at %d zpcl->callid %s\n",zpcl->parked_at, zpcl->callid);
++ if (((strlen(zpcl->callid) == 0) && (strlen(e->resume_req.callid)==0)) || (!strcmp(zpcl->callid,e->resume_req.callid))) {
++ int law;
++ // found a parked call
++ snprintf(extenstr, sizeof(extenstr), "%d", zpcl->parked_at);
++ strncpy(pri->pvts[chanpos]->exten, extenstr, sizeof(pri->pvts[chanpos]->exten));
++ // strncpy(pri->pvts[chanpos]->context, ast_parking_con(), sizeof(pri->pvts[chanpos]->context));
++ pri->pvts[chanpos]->call = e->resume_req.call;
++ law = 1;
++ if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law);
++ // uhh ohh...what shall we do without the bearer cap???
++ law = ZT_LAW_ALAW;
++ res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++ if (!pri->pvts[chanpos]->digital) {
++ res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++ } else {
++ res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[chanpos]->law);
++ }
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++ /* Start PBX */
++ c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 1, SUB_REAL, law, PRI_TRANS_CAP_SPEECH);
++ if (c) {
++ pri->pvts[chanpos]->owner = c;
++ pri->pvts[chanpos]->call = e->resume_req.call;
++ zt_enable_ec(pri->pvts[chanpos]);
++ zt_train_ec(pri->pvts[chanpos]);
++ } else {
++ ast_log(LOG_ERROR, "unable to start pbx\n");
++ }
++
++ if (zpc) {
++ zpc->next = zpcl->next;
++ free(zpcl);
++ zpcl = zpc->next;
++ } else {
++ // remove head
++ pri->suspended_calls = zpcl->next;
++ free(zpcl);
++ zpcl = pri->suspended_calls;
++ zpc = NULL;
++ }
++ unparked = 1;
++ snprintf(temp, sizeof(temp), "Unparked %s", extenstr);
++ pri_resume_acknowledge(pri->pri, e->resume_req.call, chanpos + 1, temp);
++ break;
++ }
++ zpc = zpcl;
++ if (zpcl) zpcl = zpcl->next;
++ }
++ if (!unparked)
++ pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!");
++ } else {
++ pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!");
++ }
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ }
++ break;
++ case PRI_EVENT_HOLD_REQ:
++ if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++ pri_hold_reject(pri->pri, e->hold_req.call);
++ break;
++ }
++ chanpos = pri_find_principle(pri, e->hold_req.channel);
++ if (chanpos < 0) {
++ ast_log(LOG_WARNING, "Hold requested on unconfigured channel %d span %d\n", chanpos, pri->span);
++ chanpos = -1;
++ }
++ if (chanpos > -1) {
++ // ast_log(LOG_NOTICE, "Hold request for channel number %d span %d\n", chanpos, pri->span);
++ ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ if (pri->pvts[chanpos]->owner) {
++ struct zt_pvt *p = pri->pvts[chanpos];
++ struct zt_holded_call *zhc;
++ int holdacked=0;
++
++// ast_log(LOG_NOTICE,"HOLD request from channel %s tei %d\n",p->owner->name, e->hold_req.tei);
++ if (ast_bridged_channel(p->owner)) {
++ zhc = malloc(sizeof(struct zt_holded_call));
++ if (!zhc) {
++ ast_log(LOG_ERROR, "unable to malloc zt_holded_call\n");
++ break;
++ }
++ memset(zhc, 0, sizeof(zhc));
++ strncpy(zhc->msn, pri->pvts[chanpos]->cid_num, sizeof(zhc->msn));
++ strncpy(zhc->uniqueid, ast_bridged_channel(p->owner)->uniqueid, sizeof(zhc->uniqueid));
++ zhc->tei = e->hold_req.tei;
++ zhc->cref = e->hold_req.cref;
++ zhc->call = e->hold_req.call;
++ zhc->channel = p->owner;
++ zhc->alreadyhungup = 0;
++ zhc->bridge = ast_bridged_channel(p->owner);
++ zhc->next = pri->holded_calls;
++ pri->holded_calls = zhc;
++
++ /* put channel on hold */
++ ast_masq_hold_call(ast_bridged_channel(p->owner), p->owner);
++
++ pri_hold_acknowledge(pri->pri, e->hold_req.call);
++ holdacked = 1;
++ p->call = NULL; // free the bchannel withouth destroying the call
++ p->tei = -1;
++ } else {
++ // cant hold a non-bridge,...yet
++
++ // make a fake channel
++
++ // masquerade
++
++ // put on hold
++ pri_hold_reject(pri->pri, e->hold_req.call);
++ }
++ } else {
++ pri_hold_reject(pri->pri, e->hold_req.call);
++ }
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ } else {
++ pri_hold_reject(pri->pri, e->hold_req.call);
++ }
++ break;
++ case PRI_EVENT_RETRIEVE_REQ:
++ if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++ pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++ break;
++ }
++ chanpos = pri_find_empty_chan(pri, 1);
++ if (chanpos < 0) {
++ pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++ ast_log(LOG_WARNING, "Retrieve requested on odd channel number %d span %d\n", chanpos, pri->span);
++ chanpos = -1;
++ break;
++ } else if (!pri->pvts[chanpos]) {
++ ast_log(LOG_WARNING, "Retrieve requested on unconfigured channel number %d span %d\n", chanpos, pri->span);
++ pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++ chanpos = -1;
++ break;
++ }
++ if (chanpos > -1) {
++ struct zt_holded_call *onhold = NULL;
++ int retrieved = 0;
++ int res = -1;
++ struct app_tmp *tmp;
++ pthread_attr_t attr;
++ int law;
++
++ onhold = pri_get_callonhold(pri, e->retrieve_req.cref, e->retrieve_req.tei);
++
++ if (!onhold) {
++ pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++ break;
++ }
++ ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ // found a parked call
++ law = 1;
++ if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law);
++ // uhh ohh...what shall we do without the bearer cap???
++ law = ZT_LAW_ALAW;
++ res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++ res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++ /* Start PBX */
++ c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 0, SUB_REAL, law, PRI_TRANS_CAP_SPEECH);
++ if (c) {
++ pri->pvts[chanpos]->owner = c;
++ pri->pvts[chanpos]->outgoing = 1; /* for not sending proceedings... */
++ pri->pvts[chanpos]->call = e->retrieve_req.call;
++ pri->pvts[chanpos]->tei = e->retrieve_req.tei;
++ zt_enable_ec(pri->pvts[chanpos]);
++ zt_train_ec(pri->pvts[chanpos]);
++ } else {
++ ast_log(LOG_ERROR, "unable to start pbx\n");
++ }
++
++ retrieved = 1;
++ // ast_log(LOG_NOTICE, "sending RETRIEVE ACK on channel %d, span %d for tei %d cref %d\n",chanpos,pri->span, e->retrieve_req.tei, e->retrieve_req.cref);
++ pri_retrieve_acknowledge(pri->pri, e->retrieve_req.call, chanpos + 1);
++
++ // the magic begins here: ....
++ tmp = malloc(sizeof(struct app_tmp));
++ if (tmp) {
++ memset(tmp, 0, sizeof(struct app_tmp));
++ strncpy(tmp->app, "holdedcall", sizeof(tmp->app) - 1);
++ strncpy(tmp->data, onhold->uniqueid, sizeof(tmp->data) - 1);
++ tmp->chan = c;
++ }
++ pri_destroy_callonhold(pri, onhold);
++ onhold = NULL;
++
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ pthread_attr_init(&attr);
++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++ if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
++ ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", c->name, strerror(errno));
++ free(tmp);
++ ast_hangup(c);
++ retrieved = 0;
++ }
++
++ if (!retrieved) {
++ pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++ }
++ }
++ break;
++ case PRI_EVENT_DISPLAY_RECEIVED:
++ ast_log(LOG_NOTICE, "DISPLAY IE: [ %s ] received\n",e->display.text);
++ chanpos = pri_find_principle(pri, e->display.channel);
++ if (chanpos < 0) {
++ ast_log(LOG_WARNING, "odd channel number %d span %d\n", chanpos, pri->span);
++ chanpos = -1;
++ }
++ if (chanpos > -1) {
++ if (pri->pvts[chanpos]->owner) {
++ // ast_sendtext(pri->pvt[chanpos]->owner, e->display.text);
++ }
++ }
++ break;
+ case PRI_EVENT_ANSWER:
+ chanpos = pri_find_principle(pri, e->answer.channel);
+ if (chanpos < 0) {
+@@ -9030,6 +9887,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.
+@@ -9059,11 +9917,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
+@@ -9117,20 +9980,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 (!ast_strlen_zero(e->hangup.useruserinfo)) {
+@@ -9140,8 +10012,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;
+@@ -9151,15 +10035,23 @@ static void *pri_dchannel(void *vpri)
+ case PRI_EVENT_HANGUP_REQ:
+ chanpos = pri_find_principle(pri, e->hangup.channel);
+ if (chanpos < 0) {
+- ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
+- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+- } else {
++ if (pri->nodetype == BRI_NETWORK_PTMP) {
++ pri_hangup(pri->pri, e->hangup.call, e->hangup.cause, -1);
++ } else {
++ ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
++ PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++ }
++ } else if ((pri->pvts[chanpos]->priindication_oob != 2) || (!e->hangup.inband_progress) || (!pri->pvts[chanpos]->outgoing)) {
++ /* dont hang up if we want to hear inband call progress */
+ chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
+ if (chanpos > -1) {
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ if (pri->pvts[chanpos]->realcall)
+ pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
+ else if (pri->pvts[chanpos]->owner) {
++ char tmpstr[256];
++ snprintf(tmpstr, sizeof(tmpstr), "%d", e->hangup.cause);
++ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "PRI_CAUSE", tmpstr);
+ pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
+ if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
+ pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+@@ -9186,16 +10078,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
+@@ -9206,9 +10168,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");
++ }
++ 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);
+@@ -9220,6 +10212,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)
+@@ -9233,7 +10226,9 @@ static void *pri_dchannel(void *vpri)
+ #endif
+
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++ }
+ }
++ }
+ }
+ break;
+ case PRI_EVENT_CONFIG_ERR:
+@@ -9323,10 +10318,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;
+@@ -9334,6 +10341,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);
+ }
+@@ -9395,7 +10473,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;
+@@ -9463,39 +10541,77 @@ static char *complete_span_5(const char
+
+ static int handle_pri_set_debug_file(int fd, int argc, char **argv)
+ {
+- int myfd;
++ int myfd, x, d;
++ int span;
++
++ if (argc < 6)
++ return RESULT_SHOWUSAGE;
+
+ if (!strncasecmp(argv[1], "set", 3)) {
+- if (argc < 5)
++ if (argc < 7)
+ return RESULT_SHOWUSAGE;
+
+- if (ast_strlen_zero(argv[4]))
++ if (!argv[4] || ast_strlen_zero(argv[4]))
+ return RESULT_SHOWUSAGE;
+
++ if (!argv[5])
++ return RESULT_SHOWUSAGE;
++
++ if (!argv[6] || ast_strlen_zero(argv[6]))
++ return RESULT_SHOWUSAGE;
++
++ span = atoi(argv[6]);
++ if ((span < 1) && (span > NUM_SPANS)) {
++ return RESULT_SUCCESS;
++ }
++
++
+ myfd = open(argv[4], O_CREAT|O_WRONLY);
+ if (myfd < 0) {
+- ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
+- return RESULT_SUCCESS;
++ ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
++ return RESULT_SUCCESS;
+ }
+-
+- ast_mutex_lock(&pridebugfdlock);
+-
+- if (pridebugfd >= 0)
+- close(pridebugfd);
+-
+- pridebugfd = myfd;
+- ast_copy_string(pridebugfilename,argv[4],sizeof(pridebugfilename));
+-
+- ast_mutex_unlock(&pridebugfdlock);
+-
+- ast_cli(fd, "PRI debug output will be sent to '%s'\n", argv[4]);
++ for (x=0; x < NUM_SPANS; x++) {
++ ast_mutex_lock(&pris[x].lock);
++
++ if (pris[x].span == span) {
++ if (pris[x].debugfd >= 0)
++ close(pris[x].debugfd);
++ pris[x].debugfd = myfd;
++ for (d=0; d < NUM_DCHANS; d++) {
++ if (pris[x].dchans[d])
++ pri_set_debug_fd(pris[x].dchans[d], myfd);
++ }
++ }
++ ast_mutex_unlock(&pris[x].lock);
++ }
++
++ ast_cli(fd, "PRI debug output for span %d will be sent to '%s'\n", span, argv[4]);
+ } else {
++ if (!argv[5] || ast_strlen_zero(argv[5]))
++ return RESULT_SHOWUSAGE;
+ /* Assume it is unset */
+- ast_mutex_lock(&pridebugfdlock);
+- close(pridebugfd);
+- pridebugfd = -1;
+- ast_cli(fd, "PRI debug output to file disabled\n");
+- ast_mutex_unlock(&pridebugfdlock);
++ span = atoi(argv[5]);
++ if ((span < 1) && (span > NUM_SPANS)) {
++ return RESULT_SUCCESS;
++ }
++
++ for (x=0; x < NUM_SPANS; x++) {
++ ast_mutex_lock(&pris[x].lock);
++
++ if (pris[x].span == span) {
++ if (pris[x].debugfd >= 0)
++ close(pris[x].debugfd);
++ pris[x].debugfd = -1;
++ for (d=0; d < NUM_DCHANS; d++) {
++ if (pris[x].dchans[d])
++ pri_set_debug_fd(pris[x].dchans[d], -1);
++ }
++ }
++ ast_mutex_unlock(&pris[x].lock);
++ }
++
++ ast_cli(fd, "PRI debug output to file for span %d disabled\n", span);
+ }
+
+ return RESULT_SUCCESS;
+@@ -9529,6 +10645,7 @@ static int handle_pri_debug(int fd, int
+
+
+
++
+ static int handle_pri_no_debug(int fd, int argc, char *argv[])
+ {
+ int span;
+@@ -9678,10 +10795,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");
+@@ -9708,6 +10821,18 @@ static const char pri_show_spans_help[]
+ "Usage: pri show spans\n"
+ " Displays PRI Information\n";
+
++static char bri_debug_help[] =
++ "Usage: bri debug span <span>\n"
++ " Enables debugging on a given BRI span\n";
++
++static char bri_no_debug_help[] =
++ "Usage: bri no debug span <span>\n"
++ " Disables debugging on a given BRI span\n";
++
++static char bri_really_debug_help[] =
++ "Usage: bri intensive debug span <span>\n"
++ " Enables debugging down to the Q.921 level\n";
++
+ static struct ast_cli_entry zap_pri_cli[] = {
+ { { "pri", "debug", "span", NULL },
+ handle_pri_debug, "Enables PRI debugging on a span",
+@@ -9732,6 +10857,15 @@ static struct ast_cli_entry zap_pri_cli[
+ { { "pri", "show", "debug", NULL },
+ handle_pri_show_debug, "Displays current PRI debug settings" },
+
++ { { "bri", "debug", "span", NULL }, handle_pri_debug,
++ "Enables BRI debugging on a span", bri_debug_help, complete_span_4 },
++
++ { { "bri", "no", "debug", "span", NULL }, handle_pri_no_debug,
++ "Disables BRI debugging on a span", bri_no_debug_help, complete_span_5 },
++
++ { { "bri", "intense", "debug", "span", NULL }, handle_pri_really_debug,
++ "Enables REALLY INTENSE BRI debugging", bri_really_debug_help, complete_span_5 },
++
+ { { "pri", "set", "debug", "file", NULL },
+ handle_pri_set_debug_file, "Sends PRI debug output to the specified file" },
+
+@@ -9739,8 +10873,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";
++
++static int app_zapCD(struct ast_channel *chan, void *data)
++{
++ struct zt_pvt *p = chan->tech_pvt;
++
++ if((!p->pri) || (!p->pri->pri)) {
++ return -1;
++ }
++
++ if(!data) {
++ ast_log(LOG_WARNING, "zapCD wants a number to deflect to\n");
++ return -1;
++ }
++ return pri_deflect(p->pri->pri, p->call, data);
++}
++
++static char *zapInband_tdesc = "Inband Call Progress (pre-answer)";
++static char *zapInband_app = "zapInband";
++static char *zapInband_synopsis = "Inband Call Progress";
++
++static int app_zapInband(struct ast_channel *chan, void *data)
++{
++ struct zt_pvt *p = chan->tech_pvt;
++
++ return pri_acknowledge(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1);
++}
++
+ #endif /* HAVE_PRI */
+
++static int app_zapEC(struct ast_channel *chan, void *data)
++{
++ int res=-1;
++ struct zt_pvt *p = NULL;
++
++ if (!data) {
++ ast_log(LOG_WARNING, "zapEC requires one argument (on | off)\n");
++ }
++ if (chan && !strcasecmp("ZAP",chan->tech->type)) {
++ p = chan->tech_pvt;
++ if (!p) return res;
++ if (!strcasecmp("on",(char *)data)) {
++ zt_enable_ec(p);
++ res = 0;
++ if (option_verbose > 3) {
++ ast_verbose(VERBOSE_PREFIX_3 "Enabled echo cancelation on channel %s.\n", chan->name);
++ }
++ } else if (!strcasecmp("off",(char *)data)) {
++ zt_disable_ec(p);
++ res = 0;
++ if (option_verbose > 3) {
++ ast_verbose(VERBOSE_PREFIX_3 "Disabled echo cancelation on channel %s.\n", chan->name);
++ }
++ } else {
++ ast_log(LOG_WARNING, "Unknown argument %s to zapEC\n", (char *)data);
++ }
++ } else {
++ ast_log(LOG_WARNING, "zapNoEC only works on ZAP channels, check your extensions.conf!\n");
++ res = 0;
++ }
++
++ return res;
++}
++
++static char *zapEC_tdesc = "Enable/disable Echo cancelation";
++static char *zapEC_app = "zapEC";
++static char *zapEC_synopsis = "Enable/Disable Echo Cancelation on a Zap channel";
++
+ static int zap_destroy_channel(int fd, int argc, char **argv)
+ {
+ int channel;
+@@ -10320,8 +11522,11 @@ static int __unload_module(void)
+ }
+ ast_cli_unregister_multiple(zap_pri_cli, sizeof(zap_pri_cli) / sizeof(struct ast_cli_entry));
+ ast_unregister_application(zap_send_keypad_facility_app);
++ ast_unregister_application(zapCD_app);
++ ast_unregister_application(zapInband_app);
+ #endif
+ ast_cli_unregister_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
++ ast_unregister_application(zapEC_app);
+ ast_manager_unregister( "ZapDialOffhook" );
+ ast_manager_unregister( "ZapHangup" );
+ ast_manager_unregister( "ZapTransfer" );
+@@ -10823,6 +12028,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);
+@@ -10935,9 +12156,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")) {
+@@ -10950,6 +12183,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) - 1);
++ } else if (!strcasecmp(v->name, "withheldcid")) {
++ ast_copy_string(confp->pri.withheldcid, v->value, sizeof(confp->pri.withheldcid) - 1);
+ } else if (!strcasecmp(v->name, "resetinterval")) {
+ if (!strcasecmp(v->value, "never"))
+ confp->pri.resetinterval = -1;
+@@ -10966,6 +12203,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")) {
+@@ -11267,6 +12506,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);
+@@ -11314,7 +12554,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));
+@@ -11348,6 +12591,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");
+--- asterisk-1.4.8~dfsg.orig/configs/zapata.conf.sample
++++ asterisk-1.4.8~dfsg/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
+--- asterisk-1.4.8~dfsg.orig/main/channel.c
++++ asterisk-1.4.8~dfsg/main/channel.c
+@@ -4091,6 +4091,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) ||
Added: asterisk/branches/experimental/debian/patches/bristuff/zapata-gsm
===================================================================
--- asterisk/branches/experimental/debian/patches/bristuff/zapata-gsm (rev 0)
+++ asterisk/branches/experimental/debian/patches/bristuff/zapata-gsm 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,1030 @@
+--- asterisk-1.4.8~dfsg.orig/channels/chan_zap.c
++++ asterisk-1.4.8~dfsg/channels/chan_zap.c
+@@ -76,6 +76,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+ #ifdef HAVE_PRI
+ #include <libpri.h>
+ #endif
++#ifdef HAVE_GSMAT
++#include <libgsmat.h>
++#endif
+
+ #include "asterisk/lock.h"
+ #include "asterisk/channel.h"
+@@ -186,6 +189,7 @@ static const char config[] = "zapata.con
+ #define SIG_FXOGS ZT_SIG_FXOGS
+ #define SIG_FXOKS ZT_SIG_FXOKS
+ #define SIG_PRI ZT_SIG_CLEAR
++#define SIG_GSM (0x100000 | ZT_SIG_CLEAR)
+ #define SIG_SF ZT_SIG_SF
+ #define SIG_SFWINK (0x0100000 | ZT_SIG_SF)
+ #define SIG_SF_FEATD (0x0200000 | ZT_SIG_SF)
+@@ -212,6 +216,8 @@ static char defaultozz[64] = "";
+
+ static char nocid[256] = "No CID available";
+ static char withheldcid[256] = "CID withheld";
++static char gsm_modem_pin[20];
++static char gsm_modem_exten[AST_MAX_EXTENSION];
+
+ static char progzone[10] = "";
+
+@@ -253,7 +259,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);
+
+-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);
+
+
+ /*! \brief Avoid the silly zt_getevent which ignores a bunch of events */
+@@ -368,6 +374,19 @@ struct zt_pri {
+ int debugfd;
+ };
+
++#ifdef HAVE_GSMAT
++struct zt_gsm {
++ pthread_t master;
++ ast_mutex_t lock; /* Mutex */
++ int fd;
++ int span;
++ struct gsm_modul *modul;
++ char pin[256];
++ int available;
++ char exten[AST_MAX_EXTENSION]; /* Where to idle extra calls */
++ struct zt_pvt *pvt;
++};
++#endif
+
+ static struct zt_pri pris[NUM_SPANS];
+
+@@ -396,6 +415,7 @@ struct zt_pri;
+ #define POLARITY_REV 1
+
+
++
+ static struct zt_distRings drings;
+
+ struct distRingData {
+@@ -607,6 +627,9 @@ static struct zt_pvt {
+ int prioffset;
+ int logicalspan;
+ #endif
++#ifdef HAVE_GSMAT
++ struct zt_gsm gsm;
++#endif
+ int polarity;
+ int dsp_features;
+ char begindigit;
+@@ -711,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_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);
+@@ -1364,6 +1387,8 @@ static char *zap_sig2str(int sig)
+ return "GR-303 Signalling with FXOKS";
+ case SIG_GR303FXSKS:
+ return "GR-303 Signalling with FXSKS";
++ case SIG_GSM:
++ return "GSM Signalling";
+ case 0:
+ return "Pseudo Signalling";
+ default:
+@@ -1791,7 +1816,7 @@ static inline int zt_confmute(struct zt_
+ {
+ int x, y, res;
+ x = muted;
+- if (p->sig == SIG_PRI) {
++ if ((p->sig == SIG_PRI) || (p->sig == SIG_GSM)) {
+ y = 1;
+ res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &y);
+ if (res)
+@@ -2206,6 +2231,25 @@ static int zt_call(struct ast_channel *a
+ p->dialdest[0] = '\0';
+ disable_dtmf_detect(p);
+ break;
++ case SIG_GSM:
++#ifdef HAVE_GSMAT
++ if (p->gsm.modul) {
++ c = strchr(dest, '/');
++ if (c)
++ c++;
++ else
++ c = dest;
++ ast_mutex_lock(&p->gsm.lock);
++ if (gsm_dial(p->gsm.modul, p->use_callingpres ? ast->cid.cid_pres : 0, c)) {
++ ast_log(LOG_WARNING, "dialing failed on channel %d\n", p->channel);
++ ast_mutex_unlock(&p->gsm.lock);
++ ast_mutex_unlock(&p->lock);
++ return -1;
++ }
++ ast_mutex_unlock(&p->gsm.lock);
++ }
++#endif
++ break;
+ default:
+ ast_log(LOG_DEBUG, "not yet implemented\n");
+ ast_mutex_unlock(&p->lock);
+@@ -2844,7 +2888,13 @@ static int zt_hangup(struct ast_channel
+ }
+ }
+ #endif
+- if (p->sig && (p->sig != SIG_PRI))
++#ifdef HAVE_GSMAT
++ if (p->gsm.modul) {
++ if (!p->alreadyhungup)
++ gsm_hangup(p->gsm.modul);
++ }
++#endif
++ if (p->sig && (p->sig != SIG_PRI) && (p->sig != SIG_GSM))
+ res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_ONHOOK);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
+@@ -3021,6 +3071,13 @@ static int zt_answer(struct ast_channel
+ zt_train_ec(p);
+ break;
+ #endif
++#ifdef HAVE_GSMAT
++ case SIG_GSM:
++ if (p->gsm.modul) {
++ gsm_answer(p->gsm.modul);
++ }
++ break;
++#endif
+ case 0:
+ ast_mutex_unlock(&p->lock);
+ return 0;
+@@ -7365,6 +7422,10 @@ static int pri_create_spanmap(int span,
+
+ #endif
+
++#ifdef HAVE_GSMAT
++static void *gsm_dchannel(void *vgsm);
++#endif
++
+ static struct zt_pvt *mkintf(int channel, 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) */
+@@ -7593,6 +7654,37 @@ static struct zt_pvt *mkintf(int channel
+ tmp->prioffset = 0;
+ }
+ #endif
++#ifdef HAVE_GSMAT
++ if (chan_conf.signalling == SIG_GSM) {
++ struct zt_bufferinfo bi;
++ ast_mutex_init(&tmp->gsm.lock);
++ strncpy(tmp->gsm.pin, gsm_modem_pin, sizeof(tmp->gsm.pin) - 1);
++ strncpy(tmp->gsm.exten, gsm_modem_exten, sizeof(tmp->gsm.exten) - 1);
++ tmp->gsm.available = 0;
++ snprintf(fn, sizeof(fn), "%d", channel + 1);
++ /* Open non-blocking */
++ tmp->gsm.fd = zt_open(fn);
++ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
++ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
++ bi.numbufs = 16;
++ bi.bufsize = 1024;
++ if (ioctl(tmp->gsm.fd, ZT_SET_BUFINFO, &bi)) {
++ ast_log(LOG_ERROR, "Unable to set buffer info on channel '%s': %s\n", fn, strerror(errno));
++ return NULL;
++ }
++ tmp->gsm.pvt = tmp;
++ tmp->gsm.span = tmp->span;
++ tmp->gsm.modul = gsm_new(tmp->gsm.fd, 0, tmp->gsm.pin, tmp->span, tmp->channel);
++ if (ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, tmp->channel)) {
++ ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d: %s\n", tmp->channel, strerror(errno));
++ destroy_zt_pvt(&tmp);
++ return NULL;
++ }
++ if (ast_pthread_create(&tmp->gsm.master, NULL, gsm_dchannel, &tmp->gsm)) {
++ zt_close(tmp->gsm.fd);
++ }
++ }
++#endif
+ } else {
+ conf.chan.sig = tmp->sig;
+ conf.chan.radio = tmp->radio;
+@@ -7876,6 +7968,12 @@ static inline int available(struct zt_pv
+ return 1;
+ }
+ #endif
++#ifdef HAVE_GSMAT
++ if (p->gsm.modul) {
++ return gsm_available(p->gsm.modul);
++ }
++
++#endif
+ if (!(p->radio || (p->oprmode < 0)))
+ {
+ if (!p->sig || (p->sig == SIG_FXSLS))
+@@ -8230,6 +8328,235 @@ next:
+ return tmp;
+ }
+
++#ifdef HAVE_GSMAT
++static int zt_reset_span(int span, int sleep) {
++ int ctl;
++ int res;
++
++ ctl = open("/dev/zap/ctl", O_RDWR);
++ if (ctl < 0) {
++ ast_log(LOG_WARNING, "Unable to open /dev/zap/ctl: %s\n", strerror(errno));
++ return -1;
++ }
++ ast_verbose(VERBOSE_PREFIX_2 "Shutting down span %d. Please wait...\n", span);
++ res = ioctl(ctl, ZT_SHUTDOWN, &span);
++ if (res) {
++ ast_log(LOG_WARNING, "error shutting down span %d\n", span);
++ return -1;
++ }
++ usleep(sleep * 1000);
++ ast_verbose(VERBOSE_PREFIX_2 "Starting up span %d. Please wait...\n", span);
++ res = ioctl(ctl, ZT_STARTUP, &span);
++ if (res) {
++ ast_log(LOG_WARNING, "error starting up span %d\n", span);
++ return -1;
++ }
++ ast_verbose(VERBOSE_PREFIX_2 "Reset of span %d completed.\n", span);
++ return 0;
++}
++
++
++static void handle_gsm_event(struct zt_gsm *gsm, gsm_event *e)
++{
++ struct ast_channel *c = NULL;
++ int law = ZT_LAW_ALAW;
++ int res = 0;
++
++ switch(e->e) {
++ case GSM_EVENT_DCHAN_UP:
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "GSM Span %d registered to network!\n", gsm->span);
++ gsm->available = 1;
++ break;
++ case GSM_EVENT_DCHAN_DOWN:
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "GSM Span %d unregistered from network!\n", gsm->span);
++ gsm->available = 0;
++/* ast_mutex_lock(&gsm->pvt->lock);
++ gsm->pvt->alreadyhungup = 1;
++ if (gsm->pvt->owner) {
++ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ }
++ ast_mutex_unlock(&gsm->pvt->lock); */
++ break;
++ case GSM_EVENT_RING:
++ ast_mutex_lock(&gsm->pvt->lock);
++ if (!ast_strlen_zero(e->ring.callingnum)) {
++ strncpy(gsm->pvt->cid_num, e->ring.callingnum, sizeof(gsm->pvt->cid_num) - 1);
++ } else {
++ strncpy(gsm->pvt->cid_name, withheldcid, sizeof(gsm->pvt->cid_name));
++ }
++ if (!ast_strlen_zero(gsm->exten)) {
++ strncpy(gsm->pvt->exten, gsm->exten, sizeof(gsm->pvt->exten) - 1);
++ } else {
++ gsm->pvt->exten[0] = 's';
++ gsm->pvt->exten[1] = '\0';
++ }
++ c = zt_new(gsm->pvt, AST_STATE_RING, 1, SUB_REAL, ZT_LAW_ALAW, AST_TRANS_CAP_SPEECH);
++ if (c) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Ring on channel %d (from %s to %s)\n", e->ring.channel, e->ring.callingnum, gsm->exten);
++ gsm->pvt->owner = c;
++ if (ioctl(gsm->pvt->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", gsm->pvt->channel, law);
++ res = zt_setlaw(gsm->pvt->subs[SUB_REAL].zfd, law);
++ res = set_actual_gain(gsm->pvt->subs[SUB_REAL].zfd, 0, gsm->pvt->rxgain, gsm->pvt->txgain, law);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", gsm->pvt->channel);
++// } else {
++// ast_log(LOG_NOTICE, "tx gain %f rx gain %f law %d pvt->law %d\n", gsm->pvt->txgain, gsm->pvt->rxgain, law, gsm->pvt->law);
++ }
++ }
++ ast_mutex_unlock(&gsm->pvt->lock);
++ break;
++ case GSM_EVENT_HANGUP:
++ ast_verbose(VERBOSE_PREFIX_3 "Got hang up on channel %d\n", e->hangup.channel);
++ ast_mutex_lock(&gsm->pvt->lock);
++ gsm->pvt->alreadyhungup = 1;
++ if (gsm->pvt->owner) {
++ gsm->pvt->owner->hangupcause = e->hangup.cause;
++ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ }
++ ast_mutex_unlock(&gsm->pvt->lock);
++ break;
++ case GSM_EVENT_ERROR:
++ ast_log(LOG_WARNING, "Got error on channel\n");
++ ast_mutex_lock(&gsm->pvt->lock);
++ gsm->pvt->alreadyhungup = 1;
++ if (gsm->pvt->owner) {
++ gsm->pvt->owner->hangupcause = e->error.cause;
++ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ }
++ ast_mutex_unlock(&gsm->pvt->lock);
++ if (e->error.hard) {
++// gsm_poweroff(gsm->modul);
++ zt_reset_span(gsm->span, 8000);
++// gsm_restart(gsm->modul, 10000);
++ } else {
++// gsm_poweroff(gsm->modul);
++ zt_reset_span(gsm->span, 8000);
++// gsm_restart(gsm->modul, 10000);
++ }
++ break;
++ case GSM_EVENT_ALERTING:
++ ast_mutex_lock(&gsm->pvt->lock);
++ gsm->pvt->subs[SUB_REAL].needringing =1;
++ ast_mutex_unlock(&gsm->pvt->lock);
++ break;
++ case GSM_EVENT_ANSWER:
++ ast_mutex_lock(&gsm->pvt->lock);
++ gsm->pvt->dialing = 0;
++ gsm->pvt->subs[SUB_REAL].needanswer =1;
++ gsm->pvt->ignoredtmf = 0;
++ ast_mutex_unlock(&gsm->pvt->lock);
++ break;
++ case GSM_EVENT_PIN_REQUIRED:
++ gsm_send_pin(gsm->modul, gsm->pin);
++ break;
++ case GSM_EVENT_SM_RECEIVED:
++ ast_verbose(VERBOSE_PREFIX_3 "SMS from %s received on span %d. (Text: %s) (PDU: %s)\n", e->sm_received.sender, gsm->span, e->sm_received.text, e->sm_received.pdu);
++ manager_event(EVENT_FLAG_CALL, "Message received",
++ "Span: %d\r\n"
++ "Sender: %s\r\n"
++ "SMSC: %s\r\n"
++ "Length: %d\r\n"
++ "Text: %s\r\n"
++ "PDU: %s\r\n",
++ gsm->span,
++ e->sm_received.sender,
++ e->sm_received.smsc,
++ e->sm_received.len,
++ e->sm_received.text,
++ e->sm_received.pdu);
++ break;
++ default:
++ ast_log(LOG_WARNING,"!! Unknown GSM event %d !!\n", e->e);
++ }
++}
++
++static void *gsm_dchannel(void *vgsm)
++{
++ struct zt_gsm *gsm = vgsm;
++ gsm_event *e;
++ struct timeval tv = {0,0}, *next;
++ fd_set rfds, efds;
++ int res,x;
++
++ if (!gsm) return NULL;
++
++ if (!gsm->modul) {
++ fprintf(stderr, "No gsm_mod\n");
++ return NULL;
++ }
++ gsm_set_debug(gsm->modul, GSM_DEBUG_NONE);
++ for (;;) {
++
++ /* Run the D-Channel */
++ FD_ZERO(&rfds);
++ FD_ZERO(&efds);
++ FD_SET(gsm->fd, &rfds);
++ FD_SET(gsm->fd, &efds);
++
++ if ((next = gsm_schedule_next(gsm->modul))) {
++ gettimeofday(&tv, NULL);
++ tv.tv_sec = next->tv_sec - tv.tv_sec;
++ tv.tv_usec = next->tv_usec - tv.tv_usec;
++ if (tv.tv_usec < 0) {
++ tv.tv_usec += 1000000;
++ tv.tv_sec -= 1;
++ }
++ if (tv.tv_sec < 0) {
++ tv.tv_sec = 0;
++ tv.tv_usec = 0;
++ }
++ }
++ res = select(gsm->fd + 1, &rfds, NULL, &efds, next ? &tv : NULL);
++ e = NULL;
++
++ ast_mutex_lock(&gsm->lock);
++ if (!res) {
++ e = gsm_schedule_run(gsm->modul);
++ } else if (res > 0) {
++ e = gsm_check_event(gsm->modul, 1);
++ } else if (errno == ELAST) {
++ res = ioctl(gsm->fd, ZT_GETEVENT, &x);
++ printf("Got Zaptel event: %d\n", x);
++ } else if (errno != EINTR)
++ fprintf(stderr, "Error (%d) on select: %s\n", ELAST, strerror(errno));
++
++ if (!e) {
++ e = gsm_check_event(gsm->modul, 0);
++ }
++
++ if (e) {
++ handle_gsm_event(gsm, e);
++ }
++ ast_mutex_unlock(&gsm->lock);
++
++ res = ioctl(gsm->fd, ZT_GETEVENT, &x);
++
++ if (!res && x) {
++ switch (x) {
++ case ZT_EVENT_NOALARM:
++ ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", gsm->span);
++ usleep(1000);
++ gsm_restart(gsm->modul, 10000);
++ break;
++ case ZT_EVENT_ALARM:
++ ast_log(LOG_NOTICE, "Alarm detected on span %d\n", gsm->span);
++ break;
++ default:
++ fprintf(stderr, "Got event on GSM interface: %d\n", x);
++ }
++ }
++
++
++ }
++ return NULL;
++}
++
++#endif
++
+ #ifdef HAVE_PRI
+ static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv)
+ {
+@@ -8505,6 +8832,18 @@ static void zt_pri_error(char *s, int sp
+ ast_log(LOG_WARNING, "%d %s", span, s);
+ }
+
++#ifdef HAVE_GSMAT
++static void zt_gsm_message(char *s, int channel)
++{
++ ast_verbose("GSM %d: %s", channel, s);
++}
++
++static void zt_gsm_error(char *s, int channel)
++{
++ ast_log(LOG_WARNING, "GSM %d: %s", channel, s);
++}
++#endif
++
+ static int pri_check_restart(struct zt_pri *pri)
+ {
+ if ((pri->nodetype != PRI_NETWORK) && (pri->nodetype != PRI_CPE)) {
+@@ -10905,6 +11244,243 @@ static int app_zapInband(struct ast_chan
+
+ #endif /* HAVE_PRI */
+
++#ifdef HAVE_GSMAT
++static int handle_zap_reset_span(int fd, int argc, char *argv[])
++{
++ int span;
++ int sleep = 5000;
++ if (argc < 4)
++ return RESULT_SHOWUSAGE;
++ span = atoi(argv[3]);
++ if ((span < 1) || (span > NUM_SPANS)) {
++ ast_cli(fd, "Invalid span '%s'. Should be a number from %d to %d\n", argv[3], 1, NUM_SPANS);
++ return RESULT_SUCCESS;
++ }
++ if (zt_reset_span(span, sleep)) {
++ return RESULT_FAILURE;
++ }
++ return RESULT_SUCCESS;
++}
++
++static int handle_gsm_debug_helper(int fd, int channel, int debug)
++{
++/* gsm debug channel <channel> */
++ struct zt_pvt *pvt = NULL;
++ if (channel < 1) {
++ ast_cli(fd, "Invalid channel %d. Should be a number.\n", channel);
++ return RESULT_SUCCESS;
++ }
++ pvt = iflist;
++ while (pvt) {
++ if (pvt->channel == channel) {
++ ast_mutex_lock(&pvt->lock);
++ gsm_set_debug(pvt->gsm.modul, debug);
++ ast_mutex_unlock(&pvt->lock);
++ ast_cli(fd, "%s debugging on channel %d\n", debug ? "Enabled":"Disabled", channel);
++ return RESULT_SUCCESS;
++ }
++ pvt = pvt->next;
++ }
++
++ ast_cli(fd, "No GSM running on channel %d\n", channel);
++ return RESULT_SUCCESS;
++}
++
++
++
++static int handle_gsm_debug(int fd, int argc, char *argv[])
++{
++/* gsm debug channel <channel> */
++ int channel;
++ if (argc < 4) {
++ return RESULT_SHOWUSAGE;
++ }
++ channel = atoi(argv[3]);
++ return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_AT);
++}
++
++static int handle_gsm_no_debug(int fd, int argc, char *argv[])
++{
++/* gsm no debug channel <channel> */
++ int channel;
++ if (argc < 5) {
++ return RESULT_SHOWUSAGE;
++ }
++ channel = atoi(argv[4]);
++ return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_NONE);
++}
++
++static char zap_reset_help[] =
++ "Usage: zap reset span <span>\n"
++ " Reset/Restart a zaptel span\n";
++
++static char gsm_debug_help[] =
++ "Usage: gsm debug channel <channel>\n"
++ " Enables debugging on a given GSM channel\n";
++
++static char gsm_no_debug_help[] =
++ "Usage: gsm no debug channel <channel>\n"
++ " Disables debugging on a given GSM channel\n";
++
++static struct ast_cli_entry zap_gsm_cli[] = {
++ { { "zap", "reset", "span", NULL }, handle_zap_reset_span,
++ "Restart a zaptel span", zap_reset_help, complete_span_4 },
++ { { "gsm", "debug", "channel", NULL }, handle_gsm_debug,
++ "Enables GSM debugging on a channel", gsm_debug_help },
++ { { "gsm", "no", "debug", "channel", NULL }, handle_gsm_no_debug,
++ "Disables GSM debugging on a channel", gsm_no_debug_help},
++};
++
++
++
++static char gsm_send_pdu_help[] =
++ "Usage: gsm send pdu <channel> <pdu>\n"
++ " Sends a PDU on a GSM channel\n";
++
++
++
++static int handle_gsm_send_pdu(int fd, int argc, char *argv[])
++{
++/* gsm send sms <channel> <destination> <message> */
++ int channel;
++ struct zt_pvt *pvt = NULL;
++ if (argc < 5) {
++ return RESULT_SHOWUSAGE;
++ }
++ channel = atoi(argv[3]);
++ if (channel < 1) {
++ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]);
++ return RESULT_SUCCESS;
++ }
++ pvt = iflist;
++ while (pvt) {
++ if (pvt->channel == channel) {
++ if (pvt->owner) {
++ ast_cli(fd, "Channel in use.\n");
++ return RESULT_FAILURE;
++ } else {
++ ast_mutex_lock(&pvt->lock);
++ gsm_sms_send_pdu(pvt->gsm.modul, argv[4]);
++ ast_mutex_unlock(&pvt->lock);
++ return RESULT_SUCCESS;
++ }
++ }
++ pvt = pvt->next;
++ }
++
++ return RESULT_SUCCESS;
++}
++
++static struct ast_cli_entry gsm_send_pdu = {
++ { "gsm", "send", "pdu", NULL }, handle_gsm_send_pdu, "Sends a SM on a GSM channel", gsm_send_pdu_help, complete_span_4 };
++
++
++static char gsm_send_sms_help[] =
++ "Usage: gsm send sms <channel> <destination> <message>\n"
++ " Sends a SM on a GSM channel\n";
++
++
++static int handle_gsm_send_sms(int fd, int argc, char *argv[])
++{
++/* gsm send sms <channel> <destination> <message> */
++ int channel;
++ struct zt_pvt *pvt = NULL;
++ if (argc < 6) {
++ return RESULT_SHOWUSAGE;
++ }
++ channel = atoi(argv[3]);
++ if (channel < 1) {
++ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]);
++ return RESULT_SUCCESS;
++ }
++ pvt = iflist;
++ while (pvt) {
++ if (pvt->channel == channel) {
++ if (pvt->owner) {
++ ast_cli(fd, "Channel in use.\n");
++ return RESULT_FAILURE;
++ } else {
++ ast_mutex_lock(&pvt->lock);
++ gsm_sms_send_text(pvt->gsm.modul, argv[4], argv[5]);
++ ast_mutex_unlock(&pvt->lock);
++ return RESULT_SUCCESS;
++ }
++ }
++ pvt = pvt->next;
++ }
++
++ return RESULT_SUCCESS;
++}
++
++static int zt_gsm_sendtext(struct ast_channel *chan, const char * dest, const char *text, int ispdu) {
++ struct zt_pvt *pvt = NULL;
++ char *c = NULL;
++ pvt = chan->tech_pvt;
++
++ if (!pvt) return -1;
++
++ /* parse dialstring */
++ c = strrchr(dest, '/');
++ if (c)
++ c++;
++ else
++ c = (char *)dest;
++
++ ast_mutex_lock(&pvt->lock);
++ if (ispdu) {
++ gsm_sms_send_pdu(pvt->gsm.modul, (char *)text);
++ } else {
++ gsm_sms_send_text(pvt->gsm.modul, c, (char *)text);
++ }
++ ast_mutex_unlock(&pvt->lock);
++ gsm_wait(pvt->gsm.modul);
++ return 0;
++}
++
++static struct ast_cli_entry gsm_send_sms = {
++ { "gsm", "send", "sms", NULL }, handle_gsm_send_sms, "Sends a SM on a GSM channel", gsm_send_sms_help, complete_span_4 };
++
++static char gsm_show_status_help[] =
++ "Usage: gsm show status <channel>>\n"
++ " Displays status information about the GSM channel.\n";
++
++
++static int handle_gsm_show_status(int fd, int argc, char *argv[])
++{
++ int channel;
++ struct zt_pvt *pvt = NULL;
++ if (argc < 4) {
++ return RESULT_SHOWUSAGE;
++ }
++ channel = atoi(argv[3]);
++ if (channel < 1) {
++ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]);
++ return RESULT_SUCCESS;
++ }
++ pvt = iflist;
++ while (pvt) {
++ if (pvt->channel == channel) {
++ if (pvt->owner) {
++ ast_cli(fd, "Channel in use.\n");
++ return RESULT_FAILURE;
++ } else {
++ ast_mutex_lock(&pvt->lock);
++ gsm_request_status(pvt->gsm.modul);
++ ast_mutex_unlock(&pvt->lock);
++ return RESULT_SUCCESS;
++ }
++ }
++ pvt = pvt->next;
++ }
++
++ return RESULT_SUCCESS;
++}
++
++static struct ast_cli_entry gsm_show_status = {
++ { "gsm", "show", "status", NULL }, handle_gsm_show_status, "Displays status information about the GSM channel.", gsm_show_status_help, complete_span_4 };
++
++#endif /* HAVE_GSMAT */
++
+ static int app_zapEC(struct ast_channel *chan, void *data)
+ {
+ int res=-1;
+@@ -11525,6 +12101,12 @@ static int __unload_module(void)
+ ast_unregister_application(zapCD_app);
+ ast_unregister_application(zapInband_app);
+ #endif
++#ifdef HAVE_GSMAT
++ ast_cli_unregister_multiple(zap_gsm_cli, sizeof(zap_gsm_cli) / sizeof(zap_gsm_cli[0]));
++ ast_cli_unregister(&gsm_send_sms);
++ ast_cli_unregister(&gsm_send_pdu);
++ ast_cli_unregister(&gsm_show_status);
++#endif
+ ast_cli_unregister_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
+ ast_unregister_application(zapEC_app);
+ ast_manager_unregister( "ZapDialOffhook" );
+@@ -12045,6 +12627,11 @@ static int process_zap(struct zt_chan_co
+ confp->chan.radio = 0;
+ confp->pri.nodetype = BRI_CPE;
+ #endif
++#ifdef HAVE_GSMAT
++ } else if (!strcasecmp(v->value, "gsm")) {
++ confp->chan.sig = SIG_GSM;
++ confp->chan.radio = 0;
++#endif
+ } else {
+ ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value);
+ }
+@@ -12187,6 +12774,10 @@ static int process_zap(struct zt_chan_co
+ ast_copy_string(confp->pri.nocid, v->value, sizeof(confp->pri.nocid) - 1);
+ } else if (!strcasecmp(v->name, "withheldcid")) {
+ ast_copy_string(confp->pri.withheldcid, v->value, sizeof(confp->pri.withheldcid) - 1);
++ } else if (!strcasecmp(v->name, "pin")) {
++ ast_copy_string(gsm_modem_pin, v->value, sizeof(gsm_modem_pin) - 1);
++ } else if (!strcasecmp(v->name, "exten")) {
++ ast_copy_string(gsm_modem_exten, v->value, sizeof(gsm_modem_exten) - 1);
+ } else if (!strcasecmp(v->name, "resetinterval")) {
+ if (!strcasecmp(v->value, "never"))
+ confp->pri.resetinterval = -1;
+@@ -12541,6 +13132,10 @@ static int load_module(void)
+ ast_register_application(zap_send_keypad_facility_app, zap_send_keypad_facility_exec,
+ zap_send_keypad_facility_synopsis, zap_send_keypad_facility_descrip);
+ #endif
++#ifdef HAVE_GSMAT
++ gsm_set_error(zt_gsm_error);
++ gsm_set_message(zt_gsm_message);
++#endif
+ res = setup_zap(0);
+ /* Make sure we can register our Zap channel type */
+ if (res)
+@@ -12559,6 +13154,12 @@ static int load_module(void)
+ #endif
+ ast_register_application(zapEC_app, app_zapEC, zapEC_synopsis, zapEC_tdesc);
+ ast_cli_register_multiple(zap_cli, sizeof(zap_cli) / sizeof(struct ast_cli_entry));
++#ifdef HAVE_GSMAT
++ ast_cli_register(&gsm_send_sms);
++ ast_cli_register(&gsm_send_pdu);
++ ast_cli_register(&gsm_show_status);
++ ast_cli_register_multiple(zap_gsm_cli, sizeof(zap_gsm_cli) / sizeof(zap_gsm_cli[0]));
++#endif
+
+ memset(round_robin, 0, sizeof(round_robin));
+ ast_manager_register( "ZapTransfer", 0, action_transfer, "Transfer Zap Channel" );
+@@ -12572,7 +13173,48 @@ static int load_module(void)
+ return res;
+ }
+
+-static int zt_sendtext(struct ast_channel *c, const char *text)
++#ifdef HAVE_PRI
++static int zt_tdd_sendtext(struct ast_channel *c, const char *text);
++
++static int zt_pri_sendtext(struct ast_channel *c, const char *text) {
++ struct zt_pvt *p = c->tech_pvt;
++ if (!p) return -1;
++ if (!p->pri) return -1;
++ if (strlen(text)) {
++ if (p->pri) {
++ if (!pri_grab(p, p->pri)) {
++ // ast_log(LOG_NOTICE, "Sending Display IE '%s'\n", text);
++ pri_information_display(p->pri->pri,p->call,(char *)text);
++ pri_rel(p->pri);
++ } else ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
++ }
++ }
++ return 0;
++}
++#endif
++
++static int zt_sendtext(struct ast_channel *c, const char *dest, const char *text, int ispdu) {
++ struct zt_pvt *p = c->tech_pvt;
++ if (!p) return -1;
++ if (p->sig == SIG_PRI) {
++#ifdef HAVE_PRI
++ if (ispdu) {
++ ast_log(LOG_WARNING, "Dont know how to send PDU on ZAP ISDN channel\n");
++ return -1;
++ }
++ return zt_pri_sendtext(c, text);
++#endif
++ } else if (p->sig == SIG_GSM) {
++#ifdef HAVE_GSMAT
++ return zt_gsm_sendtext(c, dest, text, ispdu);
++#endif
++ } else {
++ return zt_tdd_sendtext(c, text);
++ }
++ return -1;
++}
++
++static int zt_tdd_sendtext(struct ast_channel *c, const char *text)
+ {
+ #define END_SILENCE_LEN 400
+ #define HEADER_MS 50
+--- asterisk-1.4.8~dfsg.orig/configure.ac
++++ asterisk-1.4.8~dfsg/configure.ac
+@@ -175,6 +175,7 @@ AST_EXT_LIB_SETUP([CURL], [cURL], [curl]
+ AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
+ AST_EXT_LIB_SETUP([GNUTLS], [GNU TLS support (used for iksemel only)], [gnutls])
+ AST_EXT_LIB_SETUP([GSM], [GSM], [gsm], [, or 'internal'])
++AST_EXT_LIB_SETUP([GSMAT], [GSMAT], [GSM AT command signalling], [gsmat])
+ AST_EXT_LIB_SETUP([IKSEMEL], [Iksemel Jabber Library], [iksemel])
+ AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap])
+ AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux Library], [isdnnet])
+--- asterisk-1.4.8~dfsg.orig/configure
++++ asterisk-1.4.8~dfsg/configure
+@@ -24642,6 +24642,188 @@ echo "$as_me: *** without explicitly spe
+ fi
+ fi
+
++{ echo "$as_me:$LINENO: checking for ${GSMAT_DIR}/include/libgsmat.h" >&5
++echo $ECHO_N "checking for ${GSMAT_DIR}/include/libgsmat.h... $ECHO_C" >&6; }
++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
++ echo $ECHO_N "(cached) $ECHO_C" >&6
++else
++ eval "$as_ac_Header=\$ac_header_preproc"
++fi
++ac_res=`eval echo '${'$as_ac_Header'}'`
++ { echo "$as_me:$LINENO: result: $ac_res" >&5
++echo "${ECHO_T}$ac_res" >&6; }
++
++if test `eval echo '${'$as_ac_Header'}'` = yes; then
++ GSMAT_HEADER_FOUND=1
++else
++ GSMAT_HEADER_FOUND=0
++fi
++
++
++
++ if test "${GSMAT_HEADER_FOUND}" = "yes"; then
++ GSMAT_LIB="-lgsmat "
++ GSMAT_HEADER_FOUND="1"
++ if test "x${GSMAT_DIR}" != "x"; then
++ GSMAT_LIB="${pbxlibdir} ${GSMAT_LIB}"
++ GSMAT_INCLUDE="-I${GSMAT_DIR}/include"
++ fi
++ CPPFLAGS="${saved_cppflags}"
++ else
++ if test "xlibgsmat.h" != "x" ; then
++ if test "${ac_cv_header_libpri_h+set}" = set; then
++ { echo "$as_me:$LINENO: checking for libgsmat.h" >&5
++echo $ECHO_N "checking for libgsmat.h... $ECHO_C" >&6; }
++if test "${ac_cv_header_libgsmat_h+set}" = set; then
++ echo $ECHO_N "(cached) $ECHO_C" >&6
++fi
++{ echo "$as_me:$LINENO: result: $ac_cv_header_libgsmat_h" >&5
++echo "${ECHO_T}$ac_cv_header_libgsmat_h" >&6; }
++else
++ # Is the header compilable?
++{ echo "$as_me:$LINENO: checking libgsmat.h usability" >&5
++echo $ECHO_N "checking libgsmat.h usability... $ECHO_C" >&6; }
++cat >conftest.$ac_ext <<_ACEOF
++/* confdefs.h. */
++_ACEOF
++cat confdefs.h >>conftest.$ac_ext
++cat >>conftest.$ac_ext <<_ACEOF
++/* end confdefs.h. */
++$ac_includes_default
++#include <libgsmat.h>
++_ACEOF
++rm -f conftest.$ac_objext
++if { (ac_try="$ac_compile"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
++ (eval "$ac_compile") 2>conftest.er1
++ ac_status=$?
++ grep -v '^ *+' conftest.er1 >conftest.err
++ rm -f conftest.er1
++ cat conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ (exit $ac_status); } && {
++ test -z "$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ } && test -s conftest.$ac_objext; then
++ ac_header_compiler=yes
++else
++ echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_header_compiler=no
++fi
++
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
++echo "${ECHO_T}$ac_header_compiler" >&6; }
++
++# Is the header present?
++{ echo "$as_me:$LINENO: checking libgsmat.h presence" >&5
++echo $ECHO_N "checking libgsmat.h presence... $ECHO_C" >&6; }
++cat >conftest.$ac_ext <<_ACEOF
++/* confdefs.h. */
++_ACEOF
++cat confdefs.h >>conftest.$ac_ext
++cat >>conftest.$ac_ext <<_ACEOF
++/* end confdefs.h. */
++#include <libgsmat.h>
++_ACEOF
++if { (ac_try="$ac_cpp conftest.$ac_ext"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
++ ac_status=$?
++ grep -v '^ *+' conftest.er1 >conftest.err
++ rm -f conftest.er1
++ cat conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ (exit $ac_status); } >/dev/null && {
++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ }; then
++ ac_header_preproc=yes
++else
++ echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_header_preproc=no
++fi
++
++rm -f conftest.err conftest.$ac_ext
++{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
++echo "${ECHO_T}$ac_header_preproc" >&6; }
++
++# So? What about this header?
++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
++ yes:no: )
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: accepted by the compiler, rejected by the preprocessor!" >&5
++echo "$as_me: WARNING: libgsmat.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: proceeding with the compiler's result" >&5
++echo "$as_me: WARNING: libgsmat.h: proceeding with the compiler's result" >&2;}
++ ac_header_preproc=yes
++ ;;
++ no:yes:* )
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: present but cannot be compiled" >&5
++echo "$as_me: WARNING: libgsmat.h: present but cannot be compiled" >&2;}
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: check for missing prerequisite headers?" >&5
++echo "$as_me: WARNING: libgsmat.h: check for missing prerequisite headers?" >&2;}
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: see the Autoconf documentation" >&5
++echo "$as_me: WARNING: libgsmat.h: see the Autoconf documentation" >&2;}
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: section \"Present But Cannot Be Compiled\"" >&5
++echo "$as_me: WARNING: libgsmat.h: section \"Present But Cannot Be Compiled\"" >&2;}
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: proceeding with the preprocessor's result" >&5
++echo "$as_me: WARNING: libgsmat.h: proceeding with the preprocessor's result" >&2;}
++ { echo "$as_me:$LINENO: WARNING: libgsmat.h: in the future, the compiler will take precedence" >&5
++echo "$as_me: WARNING: libgsmat.h: in the future, the compiler will take precedence" >&2;}
++
++ ;;
++esac
++{ echo "$as_me:$LINENO: checking for libgsmat.h" >&5
++echo $ECHO_N "checking for libgsmat.h... $ECHO_C" >&6; }
++if test "${ac_cv_header_libgsmat_h+set}" = set; then
++ echo $ECHO_N "(cached) $ECHO_C" >&6
++else
++ ac_cv_header_libgsmat_h=$ac_header_preproc
++fi
++{ echo "$as_me:$LINENO: result: $ac_cv_header_libgsmat_h" >&5
++echo "${ECHO_T}$ac_cv_header_libgsmat_h" >&6; }
++
++fi
++
++
++ fi
++ fi
++ if test "x${GSMAT_HEADER_FOUND}" = "x0" ; then
++ if test -n "${GSMAT_MANDATORY}" ;
++ then
++ { echo "$as_me:$LINENO: ***" >&5
++echo "$as_me: ***" >&6;}
++ { echo "$as_me:$LINENO: *** It appears that you do not have the GSMAT development package installed." >&5
++echo "$as_me: *** It appears that you do not have the GSMAT development package installed." >&6;}
++ { echo "$as_me:$LINENO: *** Please install it to include ${GSMAT_DESCRIP} support, or re-run configure" >&5
++echo "$as_me: *** Please install it to include ${GSMAT_DESCRIP} support, or re-run configure" >&6;}
++ { echo "$as_me:$LINENO: *** without explicitly specifying --with-${GSMAT_OPTION}" >&5
++echo "$as_me: *** without explicitly specifying --with-${GSMAT_OPTION}" >&6;}
++ exit 1
++ fi
++ GSMAT_LIB=""
++ GSMAT_INCLUDE=""
++ PBX_GSMAT=0
++ else
++ PBX_GSMAT=1
++
++cat >>confdefs.h <<_ACEOF
++#define HAVE_GSMAT 1
++_ACEOF
++
++fi
+
+ if test "${USE_PWLIB}" != "no"; then
+ if test -n "${PWLIB_DIR}"; then
Modified: asterisk/branches/experimental/debian/patches/series
===================================================================
--- asterisk/branches/experimental/debian/patches/series 2007-08-05 09:07:18 UTC (rev 3900)
+++ asterisk/branches/experimental/debian/patches/series 2007-08-05 09:48:15 UTC (rev 3901)
@@ -1,3 +1,4 @@
+#
astvarrundir
pubkey_jnctn
dbug433884
@@ -3,2 +4,62 @@
make-clean-fixes
bashism-safeasterisk
+
+### bristuff
+bristuff/bristuff-notice
+
+bristuff/configurable-AST_SYSTEM_NAME
+
+# standalone changes/applications
+# - they don't break the API
+# - they don't need other API changes
+bristuff/xagi
+bristuff/misc-app-segfault
+bristuff/misc-app-pickup
+bristuff/misc-app-devstate
+bristuff/misc-res-watchdog
+bristuff/misc-manager-dbdel
+bristuff/misc-res-esel
+
+# small non-API-breaking bug fixes
+bristuff/chan-iax2-hangup-cause
+bristuff/app-zapras-fix-audiomode
+bristuff/app-meetme-avoid-overflows
+bristuff/answer-before-say
+
+# app_dial adding of options
+bristuff/app-dial-priority-202
+bristuff/app-dial-etc
+bristuff/app-dial-R-noinband
+bristuff/app-dial-c-callback
+
+# and here goes our API :-)
+bristuff/ast-send-message
+bristuff/ast-send-message-users # XXX: merge this with above?
+
+# don't split these up!
+bristuff/ast_monitor_start-targetscript
+bristuff/ast-device-state-CID
+bristuff/uniqueid-01-use-pid-on-uniqueid-generation
+bristuff/uniqueid-10-channel-ops-uniqueid
+bristuff/uniqueid-20-monitor
+bristuff/uniqueid-30-app-chanspy
+bristuff/uniqueid-40-manager
+
+# euroISDN, BRI support
+# they depend on the uniqueid changes; the following are a set
+bristuff/feature-autoanswer
+bristuff/feature-holdedcalls
+bristuff/zapata-bri+euroisdn
+# GSM support; it needs the above patch applied first, unfortunately.
+bristuff/zapata-gsm
+
+# don't use chan_capi from bristuff
+# bristuff/chan-capi
+
+# misc pathes that are currently unused
+#bristuff/ast_channel_masquerade_locked
+#bristuff/find-feature
+#bristuff/feature-parking_con
+
+# use /usr/include/bristuffed/libpri.h - /usr/lib/libpri-bristuffed.so.1.0
+use-libpri-bristuffed
Added: asterisk/branches/experimental/debian/patches/use-libpri-bristuffed
===================================================================
--- asterisk/branches/experimental/debian/patches/use-libpri-bristuffed (rev 0)
+++ asterisk/branches/experimental/debian/patches/use-libpri-bristuffed 2007-08-05 09:48:15 UTC (rev 3901)
@@ -0,0 +1,137 @@
+--- asterisk-1.4.9~dfsg.orig/configure
++++ asterisk-1.4.9~dfsg/configure
+@@ -24323,18 +24323,18 @@ fi
+
+
+ if test "${AST_PRI_FOUND}" = "yes"; then
+- PRI_LIB="-lpri "
++ PRI_LIB="-lpri-bristuffed "
+ PRI_HEADER_FOUND="1"
+ if test "x${PRI_DIR}" != "x"; then
+ PRI_LIB="${pbxlibdir} ${PRI_LIB}"
+- PRI_INCLUDE="-I${PRI_DIR}/include"
++ PRI_INCLUDE="-I${PRI_DIR}/include/bristuffed"
+ saved_cppflags="${CPPFLAGS}"
+- CPPFLAGS="${CPPFLAGS} -I${PRI_DIR}/include"
++ CPPFLAGS="${CPPFLAGS} -I${PRI_DIR}/include/bristuffed"
+ if test "xlibpri.h" != "x" ; then
+- as_ac_Header=`echo "ac_cv_header_${PRI_DIR}/include/libpri.h" | $as_tr_sh`
++ as_ac_Header=`echo "ac_cv_header_${PRI_DIR}/include/bristuffed/libpri.h" | $as_tr_sh`
+ if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+- { echo "$as_me:$LINENO: checking for ${PRI_DIR}/include/libpri.h" >&5
+-echo $ECHO_N "checking for ${PRI_DIR}/include/libpri.h... $ECHO_C" >&6; }
++ { echo "$as_me:$LINENO: checking for ${PRI_DIR}/include/bristuffed/libpri.h" >&5
++echo $ECHO_N "checking for ${PRI_DIR}/include/bristuffed/libpri.h... $ECHO_C" >&6; }
+ if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+ fi
+@@ -24343,8 +24343,8 @@ ac_res=`eval echo '${'$as_ac_Header'}'`
+ echo "${ECHO_T}$ac_res" >&6; }
+ else
+ # Is the header compilable?
+-{ echo "$as_me:$LINENO: checking ${PRI_DIR}/include/libpri.h usability" >&5
+-echo $ECHO_N "checking ${PRI_DIR}/include/libpri.h usability... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking ${PRI_DIR}/include/bristuffed/libpri.h usability" >&5
++echo $ECHO_N "checking ${PRI_DIR}/include/bristuffed/libpri.h usability... $ECHO_C" >&6; }
+ cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h. */
+ _ACEOF
+@@ -24352,7 +24352,7 @@ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h. */
+ $ac_includes_default
+-#include <${PRI_DIR}/include/libpri.h>
++#include <${PRI_DIR}/include/bristuffed/libpri.h>
+ _ACEOF
+ rm -f conftest.$ac_objext
+ if { (ac_try="$ac_compile"
+@@ -24384,15 +24384,15 @@ rm -f core conftest.err conftest.$ac_obj
+ echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+ # Is the header present?
+-{ echo "$as_me:$LINENO: checking ${PRI_DIR}/include/libpri.h presence" >&5
+-echo $ECHO_N "checking ${PRI_DIR}/include/libpri.h presence... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking ${PRI_DIR}/include/bristuffed/libpri.h presence" >&5
++echo $ECHO_N "checking ${PRI_DIR}/include/bristuffed/libpri.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 <${PRI_DIR}/include/libpri.h>
++#include <${PRI_DIR}/include/bristuffed/libpri.h>
+ _ACEOF
+ if { (ac_try="$ac_cpp conftest.$ac_ext"
+ case "(($ac_try" in
+@@ -24425,30 +24425,30 @@ 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: ${PRI_DIR}/include/libpri.h: accepted by the compiler, rejected by the preprocessor!" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: proceeding with the compiler's result" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: proceeding with the compiler's result" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: accepted by the compiler, rejected by the preprocessor!" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: proceeding with the compiler's result" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: present but cannot be compiled" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: present but cannot be compiled" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: check for missing prerequisite headers?" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: check for missing prerequisite headers?" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: see the Autoconf documentation" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: see the Autoconf documentation" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: section \"Present But Cannot Be Compiled\"" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: section \"Present But Cannot Be Compiled\"" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: proceeding with the preprocessor's result" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: proceeding with the preprocessor's result" >&2;}
+- { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/libpri.h: in the future, the compiler will take precedence" >&5
+-echo "$as_me: WARNING: ${PRI_DIR}/include/libpri.h: in the future, the compiler will take precedence" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: present but cannot be compiled" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: present but cannot be compiled" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: check for missing prerequisite headers?" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: check for missing prerequisite headers?" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: see the Autoconf documentation" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: see the Autoconf documentation" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: section \"Present But Cannot Be Compiled\"" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: section \"Present But Cannot Be Compiled\"" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: proceeding with the preprocessor's result" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: proceeding with the preprocessor's result" >&2;}
++ { echo "$as_me:$LINENO: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: in the future, the compiler will take precedence" >&5
++echo "$as_me: WARNING: ${PRI_DIR}/include/bristuffed/libpri.h: in the future, the compiler will take precedence" >&2;}
+
+ ;;
+ esac
+-{ echo "$as_me:$LINENO: checking for ${PRI_DIR}/include/libpri.h" >&5
+-echo $ECHO_N "checking for ${PRI_DIR}/include/libpri.h... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: checking for ${PRI_DIR}/include/bristuffed/libpri.h" >&5
++echo $ECHO_N "checking for ${PRI_DIR}/include/bristuffed/libpri.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
+--- asterisk-1.4.9~dfsg.orig/configure.ac
++++ asterisk-1.4.9~dfsg/configure.ac
+@@ -795,7 +795,7 @@ fi
+
+ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
+
+-AST_EXT_LIB_CHECK([PRI], [pri], [pri_keypad_facility], [libpri.h])
++AST_EXT_LIB_CHECK([PRI], [pri-bristuffed], [pri_keypad_facility], [bristuffed/libpri.h])
+
+ if test "${USE_PWLIB}" != "no"; then
+ if test -n "${PWLIB_DIR}"; then
+--- asterisk-1.4.9~dfsg.orig/channels/chan_zap.c
++++ asterisk-1.4.9~dfsg/channels/chan_zap.c
+@@ -74,7 +74,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+ #include <zaptel/tonezone.h>
+
+ #ifdef HAVE_PRI
+-#include <libpri.h>
++#include <bristuffed/libpri.h>
+ #endif
+ #ifdef HAVE_GSMAT
+ #include <libgsmat.h>
Modified: asterisk/branches/experimental/debian/rules
===================================================================
--- asterisk/branches/experimental/debian/rules 2007-08-05 09:07:18 UTC (rev 3900)
+++ asterisk/branches/experimental/debian/rules 2007-08-05 09:48:15 UTC (rev 3901)
@@ -57,7 +57,6 @@
(echo "WARNING: non-free fpm sounds must be removed from sources before packaging." ; false )
touch $@
-BRISTUFF_DIR=debian/build/asterisk-bristuff
config.status: check-sounds patch
dh_testdir
More information about the Pkg-voip-commits
mailing list