From ab3ff868aa455b0f495a9c43474e4ae8f7d1dbd8 Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Sun, 21 Aug 2005 10:28:43 +0000 Subject: [PATCH] - moved ECT to capicommand() (not working yet) - added HOLD/RETRIEVE for Asterisk indications. --- Makefile | 2 +- README | 11 +- app_capiECT.c | 215 ----------------------- capi.conf | 1 + chan_capi.c | 312 +++++++++++++++++++++++---------- chan_capi_pvt.h => chan_capi.h | 25 +++ chan_capi_app.h | 51 ------ 7 files changed, 253 insertions(+), 364 deletions(-) delete mode 100644 app_capiECT.c rename chan_capi_pvt.h => chan_capi.h (93%) delete mode 100644 chan_capi_app.h diff --git a/Makefile b/Makefile index d2f4737..93bde76 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ LIBS=-ldl -lpthread -lm CC=gcc INSTALL=install -SHAREDOS=chan_capi.so app_capiECT.so +SHAREDOS=chan_capi.so CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations diff --git a/README b/README index 21c9c57..7f027ea 100644 --- a/README +++ b/README @@ -48,7 +48,6 @@ This chan_capi version includes: - Call deflection on circuit busy (deflect=12345678) - (Inter)national dialing prefix (for callerid) configurable in capi.conf - CLI command "capi info" shows B channel status of chan_capi -- CapiECT will announce the callerID since it gets lost on most isdn pbxes The called party can press # to drop the call - Catch all MSN (incomingmsn=*) - Some configuration enhancements (msn=123,124,125 and controller=1,2,3,4) @@ -123,14 +122,20 @@ Malicious Call Identification: Hold: 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! + An optional parameter is the name of the variable which shall be set with + the reference ID of the call on hold. Example: exten => s,1,capicommand(hold) + or + exten => s,1,capicommand(hold|MYHOLDVAR) Retrieve: - Gets back the holded call + Gets back the holded call. An optional parameter is the reference ID of the call + on hold. Example: exten => s,1,capicommand(retrieve) + or + exten => s,1,capicommand(retrieve|${MYHOLDVAR}) Helper applications diff --git a/app_capiECT.c b/app_capiECT.c deleted file mode 100644 index 4ce99a4..0000000 --- a/app_capiECT.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * (CAPI*) - * - * An implementation of Common ISDN API 2.0 for Asterisk - * - * ECT transfer the held call - * - * Copyright (C) 2005 Cytronics & Melware - * - * Armin Schindler - * - * Reworked, but based on the work of - * Copyright (C) 2002-2005 Junghanns.NET GmbH - * - * Klaus-Peter Junghanns - * - * This program is free software and may be modified and - * distributed under the terms of the GNU Public License. - */ - -#include "config.h" - -#include -#include -#include -#ifndef CC_AST_HAVE_TECH_PVT -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "chan_capi_pvt.h" -#include "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 = CC_AST_CHANNEL_PVT(chan); - MESSAGE_EXCHANGE_ERROR Info; - _cmsg CMSG; - 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; - } - - if (i->onholdPLCI <= 0) { - ast_log(LOG_WARNING, "no call on hold that could be transfered\n"); - return -1; - } - - LOCAL_USER_ADD(u); - - /* Do our thing here */ - - 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("capi RETRIEVE",chan); */ - - DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG) = i->onholdPLCI; - - if ((Info = _capi_put_cmsg(&CMSG)) == 0) { - ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n", - i->onholdPLCI); - } - - /* then the destination */ - - DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); - DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; - - if ((Info = _capi_put_cmsg(&CMSG)) == 0) { - 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, get_ast_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; - - if ((Info = _capi_put_cmsg(&CMSG)) == 0) { - 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, get_ast_capi_MessageNumber(), 0); - DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; - - if ((Info = _capi_put_cmsg(&CMSG)) == 0) { - 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, get_ast_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; - - if ((Info = _capi_put_cmsg(&CMSG)) == 0) { - 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, get_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) = (char *)&fac; - - if ((Info = _capi_put_cmsg(&CMSG)) != 0) { - res = (int)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; -} - diff --git a/capi.conf b/capi.conf index 2f8c66f..b5e9db5 100644 --- a/capi.conf +++ b/capi.conf @@ -26,6 +26,7 @@ softdtmf=on ;enable/disable software dtmf detection, recommended for AVM ca relaxdtmf=on ;in addition to softdtmf, you can use relaxed dtmf detection accountcode= ;Asterisk accountcode to use in CDRs context=capi-in ;context for incoming calls +hold=yes ;on hold, ISDN HOLD shall be used ;immediate=yes ;immediate start of pbx with extension 's' if no digits were ;received on incoming call (no destination number yet) ;echosquelch=1 ;_VERY_PRIMITIVE_ echo suppression diff --git a/chan_capi.c b/chan_capi.c index 9a7d24c..cf85405 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -49,8 +49,7 @@ #include #include #include "xlaw.h" -#include "chan_capi_app.h" -#include "chan_capi_pvt.h" +#include "chan_capi.h" /* #define CC_VERSION "cm-x.y.z" */ #define CC_VERSION "$Revision$" @@ -58,7 +57,7 @@ /* * personal stuff */ -unsigned ast_capi_ApplID = 0; +static unsigned ast_capi_ApplID = 0; static _cword ast_capi_MessageNumber = 1; static char *desc = "Common ISDN API for Asterisk"; @@ -84,7 +83,7 @@ AST_MUTEX_DEFINE_STATIC(usecnt_lock); AST_MUTEX_DEFINE_STATIC(iflock); AST_MUTEX_DEFINE_STATIC(contrlock); AST_MUTEX_DEFINE_STATIC(capi_put_lock); -AST_MUTEX_DEFINE_EXPORTED(verbose_lock); +AST_MUTEX_DEFINE_STATIC(verbose_lock); static int capi_capability = AST_FORMAT_ALAW; @@ -97,10 +96,13 @@ static unsigned int capi_counter = 0; static unsigned long capi_used_controllers = 0; static char *emptyid = "\0"; -char capi_national_prefix[AST_MAX_EXTENSION]; -char capi_international_prefix[AST_MAX_EXTENSION]; +static char capi_national_prefix[AST_MAX_EXTENSION]; +static char capi_international_prefix[AST_MAX_EXTENSION]; -int capidebug = 0; +static int capidebug = 0; + +/* local prototypes */ +static int capi_indicate(struct ast_channel *c, int condition); /* */ #define return_on_no_interface(x) \ @@ -112,7 +114,7 @@ int capidebug = 0; /* * get a new capi message number atomically */ -_cword get_ast_capi_MessageNumber(void) +static _cword get_ast_capi_MessageNumber(void) { _cword mn; @@ -127,7 +129,7 @@ _cword get_ast_capi_MessageNumber(void) /* * write a capi message to capi device */ -MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG) +static MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG) { MESSAGE_EXCHANGE_ERROR error; @@ -160,7 +162,7 @@ MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG) /* * wait some time for a new capi message */ -MESSAGE_EXCHANGE_ERROR check_wait_get_cmsg(_cmsg *CMSG) +static MESSAGE_EXCHANGE_ERROR check_wait_get_cmsg(_cmsg *CMSG) { MESSAGE_EXCHANGE_ERROR Info; struct timeval tv; @@ -354,7 +356,7 @@ static void capi_echo_canceller(struct ast_channel *c, int function) /* * turn on/off DTMF detection */ -int capi_detect_dtmf(struct ast_channel *c, int flag) +static int capi_detect_dtmf(struct ast_channel *c, int flag) { struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); MESSAGE_EXCHANGE_ERROR error; @@ -731,7 +733,7 @@ static void parse_dialstring(char *buffer, char **interface, char **dest, char * /* * Asterisk tells us to make a call */ -int capi_call(struct ast_channel *c, char *idest, int timeout) +static int capi_call(struct ast_channel *c, char *idest, int timeout) { struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); char *dest, *interface, *param; @@ -1087,86 +1089,13 @@ static int capi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(newchan); - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: fixup now %s\n", - i->name, newchan->name); + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: %s fixup now %s\n", + i->name, oldchan->name, newchan->name); i->owner = newchan; return 0; } -/* - * we don't support own indications - */ -static int capi_indicate(struct ast_channel *c, int condition) -{ - struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); - _cmsg CMSG; - int ret = -1; - - if (i == NULL) { - return -1; - } - - switch (condition) { - case AST_CONTROL_RINGING: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested RINGING-Indication for %s\n", - i->name, c->name); - ret = capi_alert(c); - break; - case AST_CONTROL_BUSY: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested BUSY-Indication for %s\n", - i->name, c->name); - if ((i->state == CAPI_STATE_ALERTING) || - (i->state == CAPI_STATE_DID) || (i->state == CAPI_STATE_INCALL)) { - CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG) = i->PLCI; - CONNECT_RESP_REJECT(&CMSG) = 3; - _capi_put_cmsg(&CMSG); - ret = 0; - } - break; - case AST_CONTROL_CONGESTION: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested CONGESTION-Indication for %s\n", - i->name, c->name); - if ((i->state == CAPI_STATE_ALERTING) || - (i->state == CAPI_STATE_DID) || (i->state == CAPI_STATE_INCALL)) { - CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG) = i->PLCI; - CONNECT_RESP_REJECT(&CMSG) = 4; - _capi_put_cmsg(&CMSG); - ret = 0; - } - break; - case AST_CONTROL_PROGRESS: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROGRESS-Indication for %s\n", - i->name, c->name); - break; - case AST_CONTROL_PROCEEDING: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROCEEDING-Indication for %s\n", - i->name, c->name); - break; -#ifdef CC_AST_CONTROL_HOLD - case AST_CONTROL_HOLD: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested HOLD-Indication for %s\n", - i->name, c->name); - break; - case AST_CONTROL_UNHOLD: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested UNHOLD-Indication for %s\n", - i->name, c->name); - break; -#endif - case -1: /* stop indications */ - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested Indication-STOP for %s\n", - i->name, c->name); - break; - default: - cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested unknown Indication %d for %s\n", - i->name, condition, c->name); - break; - } - return(ret); -} - /* * a new channel is needed */ @@ -1325,6 +1254,9 @@ struct ast_channel *capi_request(char *type, int format, void *data) if ((!interface) || (!dest)) { ast_log(LOG_ERROR, "Syntax error in dialstring. Read the docs!\n"); +#ifdef CC_AST_HAVE_TECH_PVT + *cause = AST_CAUSE_INVALID_NUMBER_FORMAT; +#endif return NULL; } @@ -1401,6 +1333,9 @@ struct ast_channel *capi_request(char *type, int format, void *data) ast_mutex_unlock(&iflock); cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "didn't find capi device for interface '%s'\n", interface); +#ifdef CC_AST_HAVE_TECH_PVT + *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; +#endif return NULL; } @@ -2180,7 +2115,7 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) || (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) { - ast_log(LOG_WARNING, "%s: unable to retrieve PLCI=%#x, REASON = %#x%#x\n", + ast_log(LOG_WARNING, "%s: unable to retrieve PLCI=%#x, REASON = 0x%02x%02x\n", i->name, PLCI, FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); @@ -2791,6 +2726,7 @@ static void capi_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsig i->name, i->cid, i->dnid); sprintf(buffer, "%d", callednplan); pbx_builtin_setvar_helper(i->owner, "CALLEDTON", buffer); +#warning TODO set some variables on incoming call /* TODO pbx_builtin_setvar_helper(i->owner, "USERUSERINFO", buffer); pbx_builtin_setvar_helper(i->owner, "CALLINGSUBADDR", buffer); @@ -3044,12 +2980,37 @@ static int capi_retrieve(struct ast_channel *c, char *param) struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); _cmsg CMSG; char fac[4]; + unsigned int plci = i->onholdPLCI; - if (i->onholdPLCI == 0) { - ast_log(LOG_WARNING, "%s: %s is not on hold to retrieve!\n", - i->name, c->name); + if (param) { + plci = (unsigned int)strtoul(param, NULL, 0); + ast_mutex_lock(&iflock); + for (i = iflist; i; i = i->next) { + if (i->onholdPLCI == plci) + break; + } + ast_mutex_unlock(&iflock); + if (!i) { + plci = 0; + } + } + + if ((i->state != CAPI_STATE_ONHOLD) && + (i->isdnstate & CAPI_ISDN_STATE_HOLD)) { + int waitcount = 200; + while ((waitcount > 0) && (i->state != CAPI_STATE_ONHOLD)) { + usleep(10000); + } + } + + if ((!plci) || (i->state != CAPI_STATE_ONHOLD)) { + ast_log(LOG_WARNING, "%s: 0x%x is not valid or not on hold to retrieve!\n", + i->name, plci); return -1; } + cc_ast_verbose(2, 1, VERBOSE_PREFIX_4 "%s: using PLCI=%#x for retrieve\n", + i->name, plci); + if (!(capi_controllers[i->controller]->holdretrieve)) { ast_log(LOG_NOTICE,"%s: RETRIEVE for %s not supported by controller.\n", i->name, c->name); @@ -3062,13 +3023,73 @@ static int capi_retrieve(struct ast_channel *c, char *param) fac[3] = 0; FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI; + FACILITY_REQ_PLCI(&CMSG) = plci; FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; _capi_put_cmsg(&CMSG); cc_ast_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent RETRIEVE for PLCI=%#x\n", - i->name, i->PLCI); + i->name, plci); + + i->isdnstate &= ~CAPI_ISDN_STATE_HOLD; + return 0; +} + +/* + * explicit transfer a held call + */ +static int capi_ect(struct ast_channel *c, char *param) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + struct ast_capi_pvt *ii = NULL; + _cmsg CMSG; + char fac[8]; + unsigned int plci; + + return -1; + + if ((!param) || (!strlen(param))) { + ast_log(LOG_WARNING, "capi ECT requires an argument (held call ID)\n"); + return -1; + } + + plci = (unsigned int)strtoul(param, NULL, 0); + ast_mutex_lock(&iflock); + for (ii = iflist; ii; ii = ii->next) { + if (ii->onholdPLCI == plci) + break; + } + ast_mutex_unlock(&iflock); + if (!ii) { + ast_log(LOG_WARNING, "%s: 0x%x is not on hold !\n", + i->name, plci); + return -1; + } + + cc_ast_verbose(2, 1, VERBOSE_PREFIX_4 "%s: using PLCI=%#x for ECT\n", + i->name, plci); + + if (!(capi_controllers[i->controller]->ECT)) { + ast_log(LOG_NOTICE,"%s: ECT for %s not supported by controller.\n", + i->name, c->name); + return -1; + } + + fac[0] = 7; /* len */ + fac[1] = 0x06; /* ECT (function) */ + fac[2] = 0x00; + fac[3] = 4; /* len / sservice specific parameter , cstruct */ + write_capi_dword(&(fac[4]), plci); + + FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + FACILITY_REQ_CONTROLLER(&CMSG) = i->controller; + FACILITY_REQ_PLCI(&CMSG) = i->PLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + _capi_put_cmsg(&CMSG); + cc_ast_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent ECT for PLCI=%#x to PLCI=%#x\n", + i->name, plci, i->PLCI); return 0; } @@ -3108,6 +3129,13 @@ static int capi_hold(struct ast_channel *c, char *param) i->name, i->PLCI); i->onholdPLCI= i->PLCI; + i->isdnstate |= CAPI_ISDN_STATE_HOLD; + + if (param) { + char buffer[16]; + snprintf(buffer, sizeof(buffer) - 1, "%d", i->PLCI); + pbx_builtin_setvar_helper(i->owner, param, buffer); + } return 0; } @@ -3256,6 +3284,8 @@ static int capicommand_exec(struct ast_channel *chan, void *data) res = capi_hold(chan, params); } else if (!strcasecmp(command, "retrieve")) { res = capi_retrieve(chan, params); + } else if (!strcasecmp(command, "ect")) { + res = capi_ect(chan, params); } else { res = -1; ast_log(LOG_WARNING, "Unknown command '%s' for capiCommand\n", @@ -3266,6 +3296,93 @@ static int capicommand_exec(struct ast_channel *chan, void *data) return(res); } +/* + * we don't support own indications + */ +static int capi_indicate(struct ast_channel *c, int condition) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + int ret = -1; + + if (i == NULL) { + return -1; + } + + switch (condition) { + case AST_CONTROL_RINGING: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested RINGING-Indication for %s\n", + i->name, c->name); +/* if (i->isdnstate & CAPI_ISDN_STATE_HOLD) */ +/* capi_retrieve(c, NULL); */ + ret = capi_alert(c); + break; + case AST_CONTROL_BUSY: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested BUSY-Indication for %s\n", + i->name, c->name); + if ((i->state == CAPI_STATE_ALERTING) || + (i->state == CAPI_STATE_DID) || (i->state == CAPI_STATE_INCALL)) { + CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); + CONNECT_RESP_PLCI(&CMSG) = i->PLCI; + CONNECT_RESP_REJECT(&CMSG) = 3; + _capi_put_cmsg(&CMSG); + ret = 0; + } + if (i->isdnstate & CAPI_ISDN_STATE_HOLD) + capi_retrieve(c, NULL); + break; + case AST_CONTROL_CONGESTION: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested CONGESTION-Indication for %s\n", + i->name, c->name); + if ((i->state == CAPI_STATE_ALERTING) || + (i->state == CAPI_STATE_DID) || (i->state == CAPI_STATE_INCALL)) { + CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); + CONNECT_RESP_PLCI(&CMSG) = i->PLCI; + CONNECT_RESP_REJECT(&CMSG) = 4; + _capi_put_cmsg(&CMSG); + ret = 0; + } + if (i->isdnstate & CAPI_ISDN_STATE_HOLD) + capi_retrieve(c, NULL); + break; + case AST_CONTROL_PROGRESS: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROGRESS-Indication for %s\n", + i->name, c->name); + break; + case AST_CONTROL_PROCEEDING: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROCEEDING-Indication for %s\n", + i->name, c->name); + break; +#ifdef CC_AST_CONTROL_HOLD + case AST_CONTROL_HOLD: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested HOLD-Indication for %s\n", + i->name, c->name); + if (i->hold) { + ret = capi_hold(c, NULL); + } + break; + case AST_CONTROL_UNHOLD: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested UNHOLD-Indication for %s\n", + i->name, c->name); + if (i->hold) { + ret = capi_retrieve(c, NULL); + } + break; +#endif + case -1: /* stop indications */ + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested Indication-STOP for %s\n", + i->name, c->name); + if (i->isdnstate & CAPI_ISDN_STATE_HOLD) + capi_retrieve(c, NULL); + break; + default: + cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested unknown Indication %d for %s\n", + i->name, condition, c->name); + break; + } + return(ret); +} + /* * do the bridge */ @@ -3460,6 +3577,7 @@ int mkif(struct ast_capi_conf *conf) tmp->callgroup = conf->callgroup; tmp->group = conf->group; tmp->immediate = conf->immediate; + tmp->hold = conf->hold; tmp->smoother = ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE); @@ -3676,7 +3794,7 @@ static const struct ast_channel_tech capi_tech = { .fixup = capi_fixup, .setoption = NULL, }; -#endif +#endif /* * init capi stuff @@ -3829,6 +3947,12 @@ static int conf_interface(struct ast_capi_conf *conf, struct ast_variable *v) } continue; } + if (!strcasecmp(v->name, "hold")) { + if (ast_true(v->value)) { + conf->hold = 1; + } + continue; + } if (!strcasecmp(v->name, "relaxdtmf")) { if (ast_true(v->value)) { conf->softdtmf = 2; diff --git a/chan_capi_pvt.h b/chan_capi.h similarity index 93% rename from chan_capi_pvt.h rename to chan_capi.h index 3924957..6628b48 100644 --- a/chan_capi_pvt.h +++ b/chan_capi.h @@ -36,6 +36,20 @@ #define AST_CAPI_ISDNMODE_PTMP 0 #define AST_CAPI_ISDNMODE_PTP 1 +/* + * helper for ast_verbose with different verbose settings + */ +#define cc_ast_verbose(o_v, c_d, text...) \ + do { \ + if ((o_v == 0) || (option_verbose > o_v)) { \ + if ((!c_d) || ((c_d) && (capidebug))) { \ + ast_mutex_lock(&verbose_lock); \ + ast_verbose(text); \ + ast_mutex_unlock(&verbose_lock); \ + } \ + } \ + } while(0) + /* some helper functions */ static inline void write_capi_word(void *m, unsigned short val) { @@ -49,6 +63,13 @@ static inline unsigned short read_capi_word(void *m) val = ((unsigned char *)m)[0] | (((unsigned char *)m)[1] << 8); return (val); } +static inline void write_capi_dword(void *m, unsigned int val) +{ + ((unsigned char *)m)[0] = val & 0xff; + ((unsigned char *)m)[1] = (val >> 8) & 0xff; + ((unsigned char *)m)[2] = (val >> 16) & 0xff; + ((unsigned char *)m)[3] = (val >> 24) & 0xff; +} static inline unsigned short read_capi_dword(void *m) { unsigned int val; @@ -142,6 +163,7 @@ struct ast_capi_gains { }; #define CAPI_ISDN_STATE_SETUP_ACK 0x01 +#define CAPI_ISDN_STATE_HOLD 0x02 /* ! Private data for a capi device */ struct ast_capi_pvt { @@ -223,6 +245,8 @@ struct ast_capi_pvt { int isdnmode; /* Answer before getting digits? */ int immediate; + /* Use ISDN HOLD */ + int hold; /* Common ISDN Profile (CIP) */ int cip; @@ -293,6 +317,7 @@ struct ast_capi_conf { int ectail; int isdnmode; int immediate; + int hold; int es; unsigned int callgroup; unsigned int group; diff --git a/chan_capi_app.h b/chan_capi_app.h deleted file mode 100644 index d753ead..0000000 --- a/chan_capi_app.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * (CAPI*) - * - * An implementation of Common ISDN API 2.0 for Asterisk - * - * include file for helper applications - * - * Copyright (C) 2005 Cytronics & Melware - * - * Armin Schindler - * - * Reworked, but based on the work of - * Copyright (C) 2002-2005 Junghanns.NET GmbH - * - * Klaus-Peter Junghanns - * - * 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 _cword get_ast_capi_MessageNumber(void); -extern int capidebug; -extern ast_mutex_t verbose_lock; - -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); - -/* - * helper for ast_verbose with different verbose settings - */ -#define cc_ast_verbose(o_v, c_d, text...) \ - do { \ - if ((o_v == 0) || (option_verbose > o_v)) { \ - if ((!c_d) || ((c_d) && (capidebug))) { \ - ast_mutex_lock(&verbose_lock); \ - ast_verbose(text); \ - ast_mutex_unlock(&verbose_lock); \ - } \ - } \ - } while(0) - - -#endif