- moved ECT to capicommand() (not working yet)
- added HOLD/RETRIEVE for Asterisk indications.V0_6
parent
0e85ce353d
commit
ab3ff868aa
2
Makefile
2
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
|
||||
|
||||
|
|
11
README
11
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
|
||||
|
|
215
app_capiECT.c
215
app_capiECT.c
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
312
chan_capi.c
312
chan_capi.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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
|
Loading…
Reference in New Issue