- moved ECT to capicommand() (not working yet)

- added HOLD/RETRIEVE for Asterisk indications.
This commit is contained in:
MelwareDE 2005-08-21 10:28:43 +00:00
parent 0e85ce353d
commit ab3ff868aa
7 changed files with 253 additions and 364 deletions

View File

@ -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

11
README
View File

@ -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

View File

@ -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 <armin@melware.de>
*
* Reworked, but based on the work of
* Copyright (C) 2002-2005 Junghanns.NET GmbH
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License.
*/
#include "config.h"
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#ifndef CC_AST_HAVE_TECH_PVT
#include <asterisk/channel_pvt.h>
#endif
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/say.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <capi20.h>
#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;
}

View File

@ -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

View File

@ -49,8 +49,7 @@
#include <capi20.h>
#include <asterisk/dsp.h>
#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;

View File

@ -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;

View File

@ -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 <armin@melware.de>
*
* Reworked, but based on the work of
* Copyright (C) 2002-2005 Junghanns.NET GmbH
*
* Klaus-Peter Junghanns <kapejod@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 _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