Moved more utilities into own files.
This commit is contained in:
parent
76d0cae461
commit
cd18383e0e
279
chan_capi.c
279
chan_capi.c
|
@ -47,7 +47,6 @@
|
||||||
#define CAPI_APPLID_UNUSED 0xffffffff
|
#define CAPI_APPLID_UNUSED 0xffffffff
|
||||||
unsigned capi_ApplID = CAPI_APPLID_UNUSED;
|
unsigned capi_ApplID = CAPI_APPLID_UNUSED;
|
||||||
|
|
||||||
static _cword capi_MessageNumber;
|
|
||||||
static const char tdesc[] = "Common ISDN API Driver (" CC_VERSION ")";
|
static const char tdesc[] = "Common ISDN API Driver (" CC_VERSION ")";
|
||||||
static const char channeltype[] = "CAPI";
|
static const char channeltype[] = "CAPI";
|
||||||
static const struct ast_channel_tech capi_tech;
|
static const struct ast_channel_tech capi_tech;
|
||||||
|
@ -134,13 +133,10 @@ static int usecnt;
|
||||||
* this lock!
|
* this lock!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AST_MUTEX_DEFINE_STATIC(messagenumber_lock);
|
|
||||||
#ifndef CC_AST_HAS_VERSION_1_4
|
#ifndef CC_AST_HAS_VERSION_1_4
|
||||||
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
|
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
|
||||||
#endif
|
#endif
|
||||||
AST_MUTEX_DEFINE_STATIC(iflock);
|
AST_MUTEX_DEFINE_STATIC(iflock);
|
||||||
AST_MUTEX_DEFINE_STATIC(capi_put_lock);
|
|
||||||
AST_MUTEX_DEFINE_STATIC(verbose_lock);
|
|
||||||
|
|
||||||
static int capi_capability = AST_FORMAT_ALAW;
|
static int capi_capability = AST_FORMAT_ALAW;
|
||||||
|
|
||||||
|
@ -151,7 +147,6 @@ static struct cc_capi_controller *capi_controllers[CAPI_MAX_CONTROLLERS + 1];
|
||||||
static int capi_num_controllers = 0;
|
static int capi_num_controllers = 0;
|
||||||
static unsigned int capi_counter = 0;
|
static unsigned int capi_counter = 0;
|
||||||
static unsigned long capi_used_controllers = 0;
|
static unsigned long capi_used_controllers = 0;
|
||||||
static char *emptyid = "\0";
|
|
||||||
|
|
||||||
static struct ast_channel *chan_for_task;
|
static struct ast_channel *chan_for_task;
|
||||||
static int channel_task;
|
static int channel_task;
|
||||||
|
@ -166,8 +161,6 @@ static char capi_international_prefix[AST_MAX_EXTENSION];
|
||||||
|
|
||||||
static char default_language[MAX_LANGUAGE] = "";
|
static char default_language[MAX_LANGUAGE] = "";
|
||||||
|
|
||||||
static int capidebug = 0;
|
|
||||||
|
|
||||||
#ifdef CC_AST_HAS_VERSION_1_4
|
#ifdef CC_AST_HAS_VERSION_1_4
|
||||||
/* Global jitterbuffer configuration - by default, jb is disabled */
|
/* Global jitterbuffer configuration - by default, jb is disabled */
|
||||||
static struct ast_jb_conf default_jbconf =
|
static struct ast_jb_conf default_jbconf =
|
||||||
|
@ -188,27 +181,6 @@ static int pbx_capi_indicate(struct ast_channel *c, int condition, const void *d
|
||||||
static int pbx_capi_indicate(struct ast_channel *c, int condition);
|
static int pbx_capi_indicate(struct ast_channel *c, int condition);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* helper for <pbx>_verbose with different verbose settings
|
|
||||||
*/
|
|
||||||
void cc_verbose(int o_v, int c_d, char *text, ...)
|
|
||||||
{
|
|
||||||
char line[4096];
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, text);
|
|
||||||
vsnprintf(line, sizeof(line), text, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if ((o_v == 0) || (option_verbose > o_v)) {
|
|
||||||
if ((!c_d) || ((c_d) && (capidebug))) {
|
|
||||||
cc_mutex_lock(&verbose_lock);
|
|
||||||
cc_pbx_verbose(line);
|
|
||||||
cc_mutex_unlock(&verbose_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* B protocol settings
|
* B protocol settings
|
||||||
*/
|
*/
|
||||||
|
@ -299,64 +271,6 @@ static const char * capi_command_to_string(unsigned short wCmd)
|
||||||
return "UNDEFINED";
|
return "UNDEFINED";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get a new capi message number automically
|
|
||||||
*/
|
|
||||||
_cword get_capi_MessageNumber(void)
|
|
||||||
{
|
|
||||||
_cword mn;
|
|
||||||
|
|
||||||
cc_mutex_lock(&messagenumber_lock);
|
|
||||||
|
|
||||||
capi_MessageNumber++;
|
|
||||||
if (capi_MessageNumber == 0) {
|
|
||||||
/* avoid zero */
|
|
||||||
capi_MessageNumber = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mn = capi_MessageNumber;
|
|
||||||
|
|
||||||
cc_mutex_unlock(&messagenumber_lock);
|
|
||||||
|
|
||||||
return(mn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write a capi message to capi device
|
|
||||||
*/
|
|
||||||
MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
|
|
||||||
{
|
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
|
||||||
|
|
||||||
if (cc_mutex_lock(&capi_put_lock)) {
|
|
||||||
cc_log(LOG_WARNING, "Unable to lock capi put!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = capi20_put_cmsg(CMSG);
|
|
||||||
|
|
||||||
if (cc_mutex_unlock(&capi_put_lock)) {
|
|
||||||
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
|
||||||
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
|
||||||
error, capi_info_string((unsigned int)error));
|
|
||||||
} else {
|
|
||||||
unsigned short wCmd = HEADER_CMD(CMSG);
|
|
||||||
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
|
|
||||||
(wCmd == CAPI_P_RESP(DATA_B3))) {
|
|
||||||
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
|
|
||||||
} else {
|
|
||||||
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wait for a specific message
|
* wait for a specific message
|
||||||
*/
|
*/
|
||||||
|
@ -465,123 +379,6 @@ static int capi_tell_fax_finish(void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* wait some time for a new capi message
|
|
||||||
*/
|
|
||||||
static MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG)
|
|
||||||
{
|
|
||||||
MESSAGE_EXCHANGE_ERROR Info;
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
repeat:
|
|
||||||
Info = capi_get_cmsg(CMSG, capi_ApplID);
|
|
||||||
|
|
||||||
#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2)
|
|
||||||
/*
|
|
||||||
* For BSD allow controller 0:
|
|
||||||
*/
|
|
||||||
if ((HEADER_CID(CMSG) & 0xFF) == 0) {
|
|
||||||
HEADER_CID(CMSG) += capi_num_controllers;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* if queue is empty */
|
|
||||||
if (Info == 0x1104) {
|
|
||||||
/* try waiting a maximum of 0.100 seconds for a message */
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = 10000;
|
|
||||||
|
|
||||||
Info = capi20_waitformessage(capi_ApplID, &tv);
|
|
||||||
|
|
||||||
if (Info == 0x0000)
|
|
||||||
goto repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Info != 0x0000) && (Info != 0x1104)) {
|
|
||||||
if (capidebug) {
|
|
||||||
cc_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send Listen for supplementary to specified controller
|
|
||||||
*/
|
|
||||||
static void ListenOnSupplementary(unsigned controller)
|
|
||||||
{
|
|
||||||
_cmsg CMSG;
|
|
||||||
char fac[8];
|
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
|
||||||
int waitcount = 50;
|
|
||||||
|
|
||||||
fac[0] = 7; /* len */
|
|
||||||
fac[1] = 0x01; /* listen */
|
|
||||||
fac[2] = 0x00;
|
|
||||||
fac[3] = 4; /* len / sservice specific parameter , cstruct */
|
|
||||||
write_capi_dword(&(fac[4]), 0x0000079f);
|
|
||||||
|
|
||||||
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
|
||||||
FACILITY_REQ_CONTROLLER(&CMSG) = controller;
|
|
||||||
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY;
|
|
||||||
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac;
|
|
||||||
|
|
||||||
error = _capi_put_cmsg(&CMSG);
|
|
||||||
|
|
||||||
while (waitcount) {
|
|
||||||
error = capidev_check_wait_get_cmsg(&CMSG);
|
|
||||||
|
|
||||||
if (IS_FACILITY_CONF(&CMSG)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(30000);
|
|
||||||
waitcount--;
|
|
||||||
}
|
|
||||||
if (!waitcount) {
|
|
||||||
cc_log(LOG_ERROR,"Unable to supplementary-listen on contr%d (error=0x%x)\n",
|
|
||||||
controller, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send Listen to specified controller
|
|
||||||
*/
|
|
||||||
static unsigned ListenOnController(unsigned long CIPmask, unsigned controller)
|
|
||||||
{
|
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
|
||||||
_cmsg CMSG;
|
|
||||||
int waitcount = 50;
|
|
||||||
|
|
||||||
LISTEN_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), controller);
|
|
||||||
|
|
||||||
LISTEN_REQ_INFOMASK(&CMSG) = 0xffff; /* lots of info ;) + early B3 connect */
|
|
||||||
/* 0x00ff if no early B3 should be done */
|
|
||||||
|
|
||||||
LISTEN_REQ_CIPMASK(&CMSG) = CIPmask;
|
|
||||||
error = _capi_put_cmsg(&CMSG);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
while (waitcount) {
|
|
||||||
error = capidev_check_wait_get_cmsg(&CMSG);
|
|
||||||
|
|
||||||
if (IS_LISTEN_CONF(&CMSG)) {
|
|
||||||
error = LISTEN_CONF_INFO(&CMSG);
|
|
||||||
ListenOnSupplementary(controller);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(30000);
|
|
||||||
waitcount--;
|
|
||||||
}
|
|
||||||
if (!waitcount)
|
|
||||||
error = 0x100F;
|
|
||||||
|
|
||||||
done:
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TCAP -> CIP Translation Table (TransferCapability->CommonIsdnProfile)
|
* TCAP -> CIP Translation Table (TransferCapability->CommonIsdnProfile)
|
||||||
*/
|
*/
|
||||||
|
@ -1318,82 +1115,6 @@ static int pbx_capi_hangup(struct ast_channel *c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* convert a number
|
|
||||||
*/
|
|
||||||
static char *capi_number_func(unsigned char *data, unsigned int strip, char *buf)
|
|
||||||
{
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
if (data[0] == 0xff) {
|
|
||||||
len = read_capi_word(&data[1]);
|
|
||||||
data += 2;
|
|
||||||
} else {
|
|
||||||
len = data[0];
|
|
||||||
data += 1;
|
|
||||||
}
|
|
||||||
if (len > (AST_MAX_EXTENSION - 1))
|
|
||||||
len = (AST_MAX_EXTENSION - 1);
|
|
||||||
|
|
||||||
/* convert a capi struct to a \0 terminated string */
|
|
||||||
if ((!len) || (len < strip))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
len = len - strip;
|
|
||||||
data += strip;
|
|
||||||
|
|
||||||
memcpy(buf, data, len);
|
|
||||||
buf[len] = '\0';
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
#define capi_number(data, strip) \
|
|
||||||
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* parse the dialstring
|
|
||||||
*/
|
|
||||||
static void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid)
|
|
||||||
{
|
|
||||||
int cp = 0;
|
|
||||||
char *buffer_p = buffer;
|
|
||||||
char *oc;
|
|
||||||
|
|
||||||
/* interface is the first part of the string */
|
|
||||||
*interface = buffer;
|
|
||||||
|
|
||||||
*dest = emptyid;
|
|
||||||
*param = emptyid;
|
|
||||||
*ocid = NULL;
|
|
||||||
|
|
||||||
while (*buffer_p) {
|
|
||||||
if (*buffer_p == '/') {
|
|
||||||
*buffer_p = 0;
|
|
||||||
buffer_p++;
|
|
||||||
if (cp == 0) {
|
|
||||||
*dest = buffer_p;
|
|
||||||
cp++;
|
|
||||||
} else if (cp == 1) {
|
|
||||||
*param = buffer_p;
|
|
||||||
cp++;
|
|
||||||
} else {
|
|
||||||
cc_log(LOG_WARNING, "Too many parts in dialstring '%s'\n",
|
|
||||||
buffer);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
buffer_p++;
|
|
||||||
}
|
|
||||||
if ((oc = strchr(*dest, ':')) != NULL) {
|
|
||||||
*ocid = *dest;
|
|
||||||
*oc = '\0';
|
|
||||||
*dest = oc + 1;
|
|
||||||
}
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_4 "parsed dialstring: '%s' '%s' '%s' '%s'\n",
|
|
||||||
*interface, (*ocid) ? *ocid : "NULL", *dest, *param);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PBX tells us to make a call
|
* PBX tells us to make a call
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -558,9 +558,6 @@ struct cc_capi_controller {
|
||||||
* prototypes
|
* prototypes
|
||||||
*/
|
*/
|
||||||
extern unsigned capi_ApplID;
|
extern unsigned capi_ApplID;
|
||||||
extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG);
|
|
||||||
extern _cword get_capi_MessageNumber(void);
|
|
||||||
extern void cc_verbose(int o_v, int c_d, char *text, ...);
|
|
||||||
extern void cc_start_b3(struct capi_pvt *i);
|
extern void cc_start_b3(struct capi_pvt *i);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <asterisk/options.h>
|
#include <asterisk/options.h>
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
|
#include "chan_capi_utils.h"
|
||||||
#include "chan_capi_qsig.h"
|
#include "chan_capi_qsig.h"
|
||||||
#include "chan_capi_qsig_asn197no.h"
|
#include "chan_capi_qsig_asn197no.h"
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <asterisk/pbx.h>
|
#include <asterisk/pbx.h>
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
|
#include "chan_capi_utils.h"
|
||||||
#include "chan_capi_qsig.h"
|
#include "chan_capi_qsig.h"
|
||||||
#include "chan_capi_qsig_asn197ade.h"
|
#include "chan_capi_qsig_asn197ade.h"
|
||||||
#include "chan_capi_qsig_asn197no.h"
|
#include "chan_capi_qsig_asn197no.h"
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <asterisk/pbx.h>
|
#include <asterisk/pbx.h>
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
|
#include "chan_capi_utils.h"
|
||||||
#include "chan_capi_qsig.h"
|
#include "chan_capi_qsig.h"
|
||||||
#include "chan_capi_qsig_asn197ade.h"
|
#include "chan_capi_qsig_asn197ade.h"
|
||||||
#include "chan_capi_qsig_asn197no.h"
|
#include "chan_capi_qsig_asn197no.h"
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_rtp.h"
|
#include "chan_capi_rtp.h"
|
||||||
|
#include "chan_capi_utils.h"
|
||||||
|
|
||||||
/* RTP settings / NCPI RTP struct */
|
/* RTP settings / NCPI RTP struct */
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,45 @@
|
||||||
#include "chan_capi_supplementary.h"
|
#include "chan_capi_supplementary.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send Listen for supplementary to specified controller
|
||||||
|
*/
|
||||||
|
void ListenOnSupplementary(unsigned controller)
|
||||||
|
{
|
||||||
|
_cmsg CMSG;
|
||||||
|
char fac[8];
|
||||||
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
|
int waitcount = 50;
|
||||||
|
|
||||||
|
fac[0] = 7; /* len */
|
||||||
|
fac[1] = 0x01; /* listen */
|
||||||
|
fac[2] = 0x00;
|
||||||
|
fac[3] = 4; /* len / sservice specific parameter , cstruct */
|
||||||
|
write_capi_dword(&(fac[4]), 0x0000079f);
|
||||||
|
|
||||||
|
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||||
|
FACILITY_REQ_CONTROLLER(&CMSG) = controller;
|
||||||
|
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY;
|
||||||
|
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac;
|
||||||
|
|
||||||
|
error = _capi_put_cmsg(&CMSG);
|
||||||
|
|
||||||
|
while (waitcount) {
|
||||||
|
error = capidev_check_wait_get_cmsg(&CMSG);
|
||||||
|
|
||||||
|
if (IS_FACILITY_CONF(&CMSG)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(30000);
|
||||||
|
waitcount--;
|
||||||
|
}
|
||||||
|
if (!waitcount) {
|
||||||
|
cc_log(LOG_ERROR,"Unable to supplementary-listen on contr%d (error=0x%x)\n",
|
||||||
|
controller, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CAPI FACILITY_IND supplementary services
|
* CAPI FACILITY_IND supplementary services
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
/*
|
/*
|
||||||
* prototypes
|
* prototypes
|
||||||
*/
|
*/
|
||||||
|
extern void ListenOnSupplementary(unsigned controller);
|
||||||
extern void handle_facility_indication_supplementary(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i);
|
extern void handle_facility_indication_supplementary(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,136 @@
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
#include "chan_capi_supplementary.h"
|
||||||
|
|
||||||
|
int capidebug = 0;
|
||||||
|
char *emptyid = "\0";
|
||||||
|
|
||||||
|
AST_MUTEX_DEFINE_STATIC(verbose_lock);
|
||||||
|
AST_MUTEX_DEFINE_STATIC(messagenumber_lock);
|
||||||
|
AST_MUTEX_DEFINE_STATIC(capi_put_lock);
|
||||||
|
|
||||||
|
static _cword capi_MessageNumber;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper for <pbx>_verbose with different verbose settings
|
||||||
|
*/
|
||||||
|
void cc_verbose(int o_v, int c_d, char *text, ...)
|
||||||
|
{
|
||||||
|
char line[4096];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, text);
|
||||||
|
vsnprintf(line, sizeof(line), text, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if ((o_v == 0) || (option_verbose > o_v)) {
|
||||||
|
if ((!c_d) || ((c_d) && (capidebug))) {
|
||||||
|
cc_mutex_lock(&verbose_lock);
|
||||||
|
cc_pbx_verbose(line);
|
||||||
|
cc_mutex_unlock(&verbose_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a new capi message number automically
|
||||||
|
*/
|
||||||
|
_cword get_capi_MessageNumber(void)
|
||||||
|
{
|
||||||
|
_cword mn;
|
||||||
|
|
||||||
|
cc_mutex_lock(&messagenumber_lock);
|
||||||
|
|
||||||
|
capi_MessageNumber++;
|
||||||
|
if (capi_MessageNumber == 0) {
|
||||||
|
/* avoid zero */
|
||||||
|
capi_MessageNumber = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mn = capi_MessageNumber;
|
||||||
|
|
||||||
|
cc_mutex_unlock(&messagenumber_lock);
|
||||||
|
|
||||||
|
return(mn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* write a capi message to capi device
|
||||||
|
*/
|
||||||
|
MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
|
||||||
|
{
|
||||||
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
|
|
||||||
|
if (cc_mutex_lock(&capi_put_lock)) {
|
||||||
|
cc_log(LOG_WARNING, "Unable to lock capi put!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = capi20_put_cmsg(CMSG);
|
||||||
|
|
||||||
|
if (cc_mutex_unlock(&capi_put_lock)) {
|
||||||
|
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
||||||
|
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
||||||
|
error, capi_info_string((unsigned int)error));
|
||||||
|
} else {
|
||||||
|
unsigned short wCmd = HEADER_CMD(CMSG);
|
||||||
|
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
|
||||||
|
(wCmd == CAPI_P_RESP(DATA_B3))) {
|
||||||
|
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
|
||||||
|
} else {
|
||||||
|
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait some time for a new capi message
|
||||||
|
*/
|
||||||
|
MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG)
|
||||||
|
{
|
||||||
|
MESSAGE_EXCHANGE_ERROR Info;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
repeat:
|
||||||
|
Info = capi_get_cmsg(CMSG, capi_ApplID);
|
||||||
|
|
||||||
|
#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2)
|
||||||
|
/*
|
||||||
|
* For BSD allow controller 0:
|
||||||
|
*/
|
||||||
|
if ((HEADER_CID(CMSG) & 0xFF) == 0) {
|
||||||
|
HEADER_CID(CMSG) += capi_num_controllers;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* if queue is empty */
|
||||||
|
if (Info == 0x1104) {
|
||||||
|
/* try waiting a maximum of 0.100 seconds for a message */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 10000;
|
||||||
|
|
||||||
|
Info = capi20_waitformessage(capi_ApplID, &tv);
|
||||||
|
|
||||||
|
if (Info == 0x0000)
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Info != 0x0000) && (Info != 0x1104)) {
|
||||||
|
if (capidebug) {
|
||||||
|
cc_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Info;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* decode capi 2.0 info word
|
* decode capi 2.0 info word
|
||||||
|
@ -375,3 +505,115 @@ void show_capi_info(struct capi_pvt *i, _cword info)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send Listen to specified controller
|
||||||
|
*/
|
||||||
|
unsigned ListenOnController(unsigned long CIPmask, unsigned controller)
|
||||||
|
{
|
||||||
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
|
_cmsg CMSG;
|
||||||
|
int waitcount = 50;
|
||||||
|
|
||||||
|
LISTEN_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), controller);
|
||||||
|
|
||||||
|
LISTEN_REQ_INFOMASK(&CMSG) = 0xffff; /* lots of info ;) + early B3 connect */
|
||||||
|
/* 0x00ff if no early B3 should be done */
|
||||||
|
|
||||||
|
LISTEN_REQ_CIPMASK(&CMSG) = CIPmask;
|
||||||
|
error = _capi_put_cmsg(&CMSG);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
while (waitcount) {
|
||||||
|
error = capidev_check_wait_get_cmsg(&CMSG);
|
||||||
|
|
||||||
|
if (IS_LISTEN_CONF(&CMSG)) {
|
||||||
|
error = LISTEN_CONF_INFO(&CMSG);
|
||||||
|
ListenOnSupplementary(controller);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(30000);
|
||||||
|
waitcount--;
|
||||||
|
}
|
||||||
|
if (!waitcount)
|
||||||
|
error = 0x100F;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert a number
|
||||||
|
*/
|
||||||
|
char *capi_number_func(unsigned char *data, unsigned int strip, char *buf)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
if (data[0] == 0xff) {
|
||||||
|
len = read_capi_word(&data[1]);
|
||||||
|
data += 2;
|
||||||
|
} else {
|
||||||
|
len = data[0];
|
||||||
|
data += 1;
|
||||||
|
}
|
||||||
|
if (len > (AST_MAX_EXTENSION - 1))
|
||||||
|
len = (AST_MAX_EXTENSION - 1);
|
||||||
|
|
||||||
|
/* convert a capi struct to a \0 terminated string */
|
||||||
|
if ((!len) || (len < strip))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = len - strip;
|
||||||
|
data += strip;
|
||||||
|
|
||||||
|
memcpy(buf, data, len);
|
||||||
|
buf[len] = '\0';
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse the dialstring
|
||||||
|
*/
|
||||||
|
void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid)
|
||||||
|
{
|
||||||
|
int cp = 0;
|
||||||
|
char *buffer_p = buffer;
|
||||||
|
char *oc;
|
||||||
|
|
||||||
|
/* interface is the first part of the string */
|
||||||
|
*interface = buffer;
|
||||||
|
|
||||||
|
*dest = emptyid;
|
||||||
|
*param = emptyid;
|
||||||
|
*ocid = NULL;
|
||||||
|
|
||||||
|
while (*buffer_p) {
|
||||||
|
if (*buffer_p == '/') {
|
||||||
|
*buffer_p = 0;
|
||||||
|
buffer_p++;
|
||||||
|
if (cp == 0) {
|
||||||
|
*dest = buffer_p;
|
||||||
|
cp++;
|
||||||
|
} else if (cp == 1) {
|
||||||
|
*param = buffer_p;
|
||||||
|
cp++;
|
||||||
|
} else {
|
||||||
|
cc_log(LOG_WARNING, "Too many parts in dialstring '%s'\n",
|
||||||
|
buffer);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer_p++;
|
||||||
|
}
|
||||||
|
if ((oc = strchr(*dest, ':')) != NULL) {
|
||||||
|
*ocid = *dest;
|
||||||
|
*oc = '\0';
|
||||||
|
*dest = oc + 1;
|
||||||
|
}
|
||||||
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "parsed dialstring: '%s' '%s' '%s' '%s'\n",
|
||||||
|
*interface, (*ocid) ? *ocid : "NULL", *dest, *param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,20 @@
|
||||||
/*
|
/*
|
||||||
* prototypes
|
* prototypes
|
||||||
*/
|
*/
|
||||||
|
extern int capidebug;
|
||||||
|
extern char *emptyid;
|
||||||
|
|
||||||
|
extern void cc_verbose(int o_v, int c_d, char *text, ...);
|
||||||
|
extern _cword get_capi_MessageNumber(void);
|
||||||
|
extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG);
|
||||||
|
extern MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG);
|
||||||
extern char *capi_info_string(unsigned int info);
|
extern char *capi_info_string(unsigned int info);
|
||||||
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
||||||
|
extern unsigned ListenOnController(unsigned long CIPmask, unsigned controller);
|
||||||
|
extern void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid);
|
||||||
|
extern char *capi_number_func(unsigned char *data, unsigned int strip, char *buf);
|
||||||
|
|
||||||
|
#define capi_number(data, strip) \
|
||||||
|
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue