- added variable REDIRECTREASON

- use stack memory for capi_number()
- use struct for capicommand() commands
- capicommand(RETRIEVE) can now be called from other channels
- start PBX on SETUP only.
This commit is contained in:
MelwareDE 2005-08-28 14:14:23 +00:00
parent 7ee382db9e
commit 398aa1b09f
2 changed files with 160 additions and 75 deletions

4
README
View File

@ -276,4 +276,8 @@ REDIRECTINGNUMBER
On incoming call, if the call was redirected to you by someone, the On incoming call, if the call was redirected to you by someone, the
number of the redirecting party is saved in this variable. number of the redirecting party is saved in this variable.
REDIRECTREASON
If the incoming call was redirected to you, this variable is set
with the reason value.

View File

@ -686,20 +686,33 @@ static int capi_hangup(struct ast_channel *c)
/* /*
* convert a number * convert a number
*/ */
static char *capi_number(char *data, int strip) static char *capi_number_func(unsigned char *data, unsigned int strip, char *buf)
{ {
unsigned len = *data; 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)
len = AST_MAX_EXTENSION;
/* XXX fix me */
/* convert a capi struct to a \0 terminated string */ /* convert a capi struct to a \0 terminated string */
if ((!len) || (len < (unsigned int) strip)) if ((!len) || (len < strip))
return NULL; return NULL;
len = len - strip; len = len - strip;
data = (char *)(data + 1 + strip); data += strip;
return strndup((char *)data, len); 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 * parse the dialstring
@ -750,6 +763,11 @@ static int capi_call(struct ast_channel *c, char *idest, int timeout)
char bchaninfo[3]; char bchaninfo[3];
int CLIR; int CLIR;
int callernplan = 0; int callernplan = 0;
char *ton, *p;
char *osa = NULL;
char *dsa = NULL;
char callingsubaddress[AST_MAX_EXTENSION];
char calledsubaddress[AST_MAX_EXTENSION];
_cmsg CMSG; _cmsg CMSG;
MESSAGE_EXCHANGE_ERROR error; MESSAGE_EXCHANGE_ERROR error;
@ -797,15 +815,31 @@ static int capi_call(struct ast_channel *c, char *idest, int timeout)
#else #else
CLIR = c->callingpres; CLIR = c->callingpres;
#endif #endif
cc_ast_verbose(1, 1, VERBOSE_PREFIX_2 "%s: Call %s %s%s (pres=0x%02x)\n", if ((ton = pbx_builtin_getvar_helper(c, "CALLERTON"))) {
callernplan = atoi(ton) & 0x7f;
}
cc_ast_verbose(1, 1, VERBOSE_PREFIX_2 "%s: Call %s %s%s (pres=0x%02x, ton=0x%02x)\n",
i->name, c->name, i->doB3 ? "with B3 ":" ", i->name, c->name, i->doB3 ? "with B3 ":" ",
i->doOverlap ? "overlap":"", CLIR); i->doOverlap ? "overlap":"", CLIR, callernplan);
/* set FD for Asterisk*/ /* set FD for Asterisk*/
c->fds[0] = i->fd; c->fds[0] = i->fd;
i->outgoing = 1; i->outgoing = 1;
if ((p = pbx_builtin_getvar_helper(c, "CALLINGSUBADDRESS"))) {
callingsubaddress[0] = strlen(p) + 1;
callingsubaddress[1] = 0x80;
strncpy(&callingsubaddress[2], p, sizeof(callingsubaddress) - 3);
osa = callingsubaddress;
}
if ((p = pbx_builtin_getvar_helper(c, "CALLEDSUBADDRESS"))) {
calledsubaddress[0] = strlen(p) + 1;
calledsubaddress[1] = 0x80;
strncpy(&calledsubaddress[2], p, sizeof(calledsubaddress) - 3);
dsa = calledsubaddress;
}
i->MessageNumber = get_ast_capi_MessageNumber(); i->MessageNumber = get_ast_capi_MessageNumber();
CONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, i->controller); CONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, i->controller);
CONNECT_REQ_CONTROLLER(&CMSG) = i->controller; CONNECT_REQ_CONTROLLER(&CMSG) = i->controller;
@ -823,7 +857,7 @@ static int capi_call(struct ast_channel *c, char *idest, int timeout)
called[1] = 0x80; called[1] = 0x80;
strncpy(&called[2], dest, sizeof(called) - 3); strncpy(&called[2], dest, sizeof(called) - 3);
CONNECT_REQ_CALLEDPARTYNUMBER(&CMSG) = called; CONNECT_REQ_CALLEDPARTYNUMBER(&CMSG) = called;
CONNECT_REQ_CALLEDPARTYSUBADDRESS(&CMSG) = NULL; CONNECT_REQ_CALLEDPARTYSUBADDRESS(&CMSG) = dsa;
#ifdef CC_AST_CHANNEL_HAS_CID #ifdef CC_AST_CHANNEL_HAS_CID
if (c->cid.cid_num) if (c->cid.cid_num)
@ -841,7 +875,7 @@ static int capi_call(struct ast_channel *c, char *idest, int timeout)
strncpy(&calling[3], callerid, sizeof(calling) - 4); strncpy(&calling[3], callerid, sizeof(calling) - 4);
CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = calling; CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = calling;
CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = NULL; CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = osa;
CONNECT_REQ_B1PROTOCOL(&CMSG) = 1; CONNECT_REQ_B1PROTOCOL(&CMSG) = 1;
CONNECT_REQ_B2PROTOCOL(&CMSG) = 1; CONNECT_REQ_B2PROTOCOL(&CMSG) = 1;
@ -1227,19 +1261,6 @@ static struct ast_channel *capi_new(struct ast_capi_pvt *i, int state)
ast_setstate(tmp, state); ast_setstate(tmp, state);
if (state == AST_STATE_RING) {
if (ast_pbx_start(tmp)) {
ast_log(LOG_ERROR, "%s: Unable to start pbx on channel!\n",
i->name);
ast_hangup(tmp);
ast_channel_free(tmp);
i->owner = NULL;
tmp = NULL;
} else {
cc_ast_verbose(2, 0, VERBOSE_PREFIX_2 "%s: started pbx on channel (callgroup=%d)!\n",
i->name, tmp->callgroup);
}
}
return tmp; return tmp;
} }
@ -1887,6 +1908,25 @@ static void handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsigned int
i->name); i->name);
} }
/*
* incoming call SETUP
*/
static void handle_setup_element(_cmsg *CMSG, unsigned int PLCI, struct ast_capi_pvt *i)
{
if (!i->owner) {
ast_log(LOG_ERROR, "No channel for interface!\n");
return;
}
if (i->isdnmode == AST_CAPI_ISDNMODE_DID) {
if (!strlen(i->dnid) && (i->immediate)) {
start_pbx_on_match(i, PLCI, CMSG->Messagenumber);
}
} else {
start_pbx_on_match(i, PLCI, CMSG->Messagenumber);
}
}
/* /*
* CAPI INFO_IND * CAPI INFO_IND
*/ */
@ -1894,7 +1934,8 @@ static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned
{ {
_cmsg CMSG2; _cmsg CMSG2;
struct ast_frame fr; struct ast_frame fr;
char *p; char *p = NULL;
int val = 0;
memset(&CMSG2, 0, sizeof(_cmsg)); memset(&CMSG2, 0, sizeof(_cmsg));
INFO_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, PLCI); INFO_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, PLCI);
@ -1942,8 +1983,8 @@ static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned
break; break;
} }
} }
cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element NOTIFICATION INDICATOR '%s'\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element NOTIFICATION INDICATOR '%s' (0x%02x)\n",
i->name, desc); i->name, desc, INFO_IND_INFOELEMENT(CMSG)[1]);
break; break;
} }
case 0x0028: /* DSP */ case 0x0028: /* DSP */
@ -1970,10 +2011,16 @@ static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned
break; break;
case 0x0074: /* Redirecting Number */ case 0x0074: /* Redirecting Number */
p = capi_number(INFO_IND_INFOELEMENT(CMSG), 3); p = capi_number(INFO_IND_INFOELEMENT(CMSG), 3);
if (INFO_IND_INFOELEMENT(CMSG)[0] > 2) {
val = INFO_IND_INFOELEMENT(CMSG)[3] & 0x0f;
}
cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element REDIRECTING NUMBER '%s' Reason=0x%02x\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element REDIRECTING NUMBER '%s' Reason=0x%02x\n",
i->name, p, (INFO_IND_INFOELEMENT(CMSG)[0] > 2) ? (INFO_IND_INFOELEMENT(CMSG)[3] & 0x0f) : 0xff); i->name, p, val);
if (i->owner) { if (i->owner) {
char reasonbuf[16];
snprintf(reasonbuf, sizeof(reasonbuf) - 1, "%d", val);
pbx_builtin_setvar_helper(i->owner, "REDIRECTINGNUMBER", p); pbx_builtin_setvar_helper(i->owner, "REDIRECTINGNUMBER", p);
pbx_builtin_setvar_helper(i->owner, "REDIRECTREASON", reasonbuf);
} }
break; break;
case 0x4000: /* CHARGE in UNITS */ case 0x4000: /* CHARGE in UNITS */
@ -2013,10 +2060,13 @@ static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned
* related to the call setup; then, we could always abort if we * related to the call setup; then, we could always abort if we
* get a PROGRESS with a hangupcause set (safer?) * get a PROGRESS with a hangupcause set (safer?)
*/ */
if (i->owner && i->owner->hangupcause == AST_CAUSE_USER_BUSY) { if (i->doB3 == AST_CAPI_B3_DONT) {
if ((i->owner) &&
(i->owner->hangupcause == AST_CAUSE_USER_BUSY)) {
pipe_cause_control(i, 1); pipe_cause_control(i, 1);
break; break;
} }
}
fr.frametype = AST_FRAME_CONTROL; fr.frametype = AST_FRAME_CONTROL;
fr.subclass = AST_CONTROL_PROGRESS; fr.subclass = AST_CONTROL_PROGRESS;
pipe_frame(i, &fr); pipe_frame(i, &fr);
@ -2024,6 +2074,7 @@ static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned
case 0x8005: /* SETUP */ case 0x8005: /* SETUP */
cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element SETUP\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element SETUP\n",
i->name); i->name);
handle_setup_element(CMSG, PLCI, i);
break; break;
case 0x8007: /* CONNECT */ case 0x8007: /* CONNECT */
cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CONNECT\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CONNECT\n",
@ -2728,14 +2779,10 @@ static void capi_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsig
i->MessageNumber = CMSG->Messagenumber; i->MessageNumber = CMSG->Messagenumber;
i->cid_ton = callernplan; i->cid_ton = callernplan;
if (i->isdnmode == AST_CAPI_ISDNMODE_DID) {
capi_new(i, AST_STATE_DOWN); capi_new(i, AST_STATE_DOWN);
if (i->isdnmode == AST_CAPI_ISDNMODE_DID) {
i->state = CAPI_STATE_DID; i->state = CAPI_STATE_DID;
if (!strlen(i->dnid) && (i->immediate) && (i->owner)) {
start_pbx_on_match(i, PLCI, CMSG->Messagenumber);
}
} else { } else {
capi_new(i, AST_STATE_RING);
i->state = CAPI_STATE_INCALL; i->state = CAPI_STATE_INCALL;
} }
@ -2760,12 +2807,16 @@ static void capi_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsig
i->name, i->cid, i->dnid); i->name, i->cid, i->dnid);
sprintf(buffer, "%d", callednplan); sprintf(buffer, "%d", callednplan);
pbx_builtin_setvar_helper(i->owner, "CALLEDTON", buffer); pbx_builtin_setvar_helper(i->owner, "CALLEDTON", buffer);
#warning TODO set some variables on incoming call /*
/* TODO pbx_builtin_setvar_helper(i->owner, "CALLINGSUBADDRESS",
pbx_builtin_setvar_helper(i->owner, "USERUSERINFO", buffer); CONNECT_IND_CALLINGPARTYSUBADDRESS(CMSG));
pbx_builtin_setvar_helper(i->owner, "CALLINGSUBADDR", buffer); pbx_builtin_setvar_helper(i->owner, "CALLEDSUBADDRESS",
pbx_builtin_setvar_helper(i->owner, "CALLEDSUBADDR", buffer); CONNECT_IND_CALLEDPARTYSUBADDRESS(CMSG));
pbx_builtin_setvar_helper(i->owner, "PRIREDIRECTREASON", buffer); pbx_builtin_setvar_helper(i->owner, "USERUSERINFO",
CONNECT_IND_USERUSERDATA(CMSG));
*/
/* TODO : set some more variables on incoming call */
/*
pbx_builtin_setvar_helper(i->owner, "ANI2", buffer); pbx_builtin_setvar_helper(i->owner, "ANI2", buffer);
pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer); pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer);
*/ */
@ -3011,10 +3062,15 @@ static void capi_handle_msg(_cmsg *CMSG)
*/ */
static int capi_retrieve(struct ast_channel *c, char *param) static int capi_retrieve(struct ast_channel *c, char *param)
{ {
struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); struct ast_capi_pvt *i = NULL;
_cmsg CMSG; _cmsg CMSG;
char fac[4]; char fac[4];
unsigned int plci = i->onholdPLCI; unsigned int plci = 0;
if (!(strcmp(c->type, "CAPI"))) {
i = CC_AST_CHANNEL_PVT(c);
plci = i->onholdPLCI;
}
if (param) { if (param) {
plci = (unsigned int)strtoul(param, NULL, 0); plci = (unsigned int)strtoul(param, NULL, 0);
@ -3029,6 +3085,12 @@ static int capi_retrieve(struct ast_channel *c, char *param)
} }
} }
if (!i) {
ast_log(LOG_WARNING, "%s is not valid or not on capi hold to retrieve!\n",
c->name);
return 0;
}
if ((i->state != CAPI_STATE_ONHOLD) && if ((i->state != CAPI_STATE_ONHOLD) &&
(i->isdnstate & CAPI_ISDN_STATE_HOLD)) { (i->isdnstate & CAPI_ISDN_STATE_HOLD)) {
int waitcount = 200; int waitcount = 200;
@ -3175,7 +3237,8 @@ static int capi_hold(struct ast_channel *c, char *param)
char buffer[16]; char buffer[16];
char fac[4]; char fac[4];
#warning TODO: support holdtype notify /* TODO: support holdtype notify */
if (i->isdnstate & CAPI_ISDN_STATE_HOLD) { if (i->isdnstate & CAPI_ISDN_STATE_HOLD) {
ast_log(LOG_NOTICE,"%s: %s already on hold.\n", ast_log(LOG_NOTICE,"%s: %s already on hold.\n",
i->name, c->name); i->name, c->name);
@ -3185,12 +3248,12 @@ static int capi_hold(struct ast_channel *c, char *param)
if (i->state != CAPI_STATE_BCONNECTED) { if (i->state != CAPI_STATE_BCONNECTED) {
ast_log(LOG_NOTICE,"%s: Cannot put on hold %s while not connected.\n", ast_log(LOG_NOTICE,"%s: Cannot put on hold %s while not connected.\n",
i->name, c->name); i->name, c->name);
return -1; return 0;
} }
if (!(capi_controllers[i->controller]->holdretrieve)) { if (!(capi_controllers[i->controller]->holdretrieve)) {
ast_log(LOG_NOTICE,"%s: HOLD for %s not supported by controller.\n", ast_log(LOG_NOTICE,"%s: HOLD for %s not supported by controller.\n",
i->name, c->name); i->name, c->name);
return -1; return 0;
} }
fac[0] = 3; /* len */ fac[0] = 3; /* len */
@ -3302,6 +3365,7 @@ static int capi_holdtype(struct ast_channel *c, char *param)
return 0; return 0;
} }
#if 0
/* /*
* set early-B3 for incoming connections * set early-B3 for incoming connections
* (only for NT mode) * (only for NT mode)
@ -3347,6 +3411,27 @@ static int capi_set_earlyb3(struct ast_channel *c, char *param)
return 0; return 0;
} }
#endif
/*
* struct of capi commands
*/
static struct capicommands_s {
char *cmdname;
int (*cmd)(struct ast_channel *, char *);
int capionly;
} capicommands[] = {
/* { "earlyb3", capi_set_earlyb3, 1 }, */
{ "deflect", capi_call_deflect, 1 },
{ "receivefax", capi_receive_fax, 1 },
{ "echosquelch", capi_echosquelch, 1 },
{ "malicious", capi_malicious, 1 },
{ "hold", capi_hold, 1 },
{ "holdtype", capi_holdtype, 1 },
{ "retrieve", capi_retrieve, 0 },
{ "ect", capi_ect, 1 },
{ NULL, NULL, 0 }
};
/* /*
* capi command interface * capi command interface
@ -3358,15 +3443,15 @@ static int capicommand_exec(struct ast_channel *chan, void *data)
char *s; char *s;
char *stringp; char *stringp;
char *command, *params; char *command, *params;
struct capicommands_s *capicmd = &capicommands[0];
if (!data) { if (!data) {
ast_log(LOG_WARNING, "capiCommand requires arguments\n"); ast_log(LOG_WARNING, "capiCommand requires arguments\n");
return -1; return -1;
} }
if (strcmp(chan->type, "CAPI")) {
ast_log(LOG_WARNING, "capiCommand works on CAPI channels only, check your extensions.conf!\n"); LOCAL_USER_ADD(u);
return -1;
}
s = ast_strdupa(data); s = ast_strdupa(data);
stringp = s; stringp = s;
command = strsep(&stringp, "|"); command = strsep(&stringp, "|");
@ -3374,31 +3459,26 @@ static int capicommand_exec(struct ast_channel *chan, void *data)
cc_ast_verbose(2, 1, VERBOSE_PREFIX_3 "capiCommand: '%s' '%s'\n", cc_ast_verbose(2, 1, VERBOSE_PREFIX_3 "capiCommand: '%s' '%s'\n",
command, params); command, params);
LOCAL_USER_ADD(u); while(capicmd->cmd) {
if (!strcasecmp(command, "earlyb3")) { if (!strcasecmp(capicmd->cmdname, command))
res = capi_set_earlyb3(chan, params); break;
} else if (!strcasecmp(command, "deflect")) { capicmd++;
res = capi_call_deflect(chan, params); }
} else if (!strcasecmp(command, "receivefax")) { if (!capicmd->cmd) {
res = capi_receive_fax(chan, params); LOCAL_USER_REMOVE(u);
} else if (!strcasecmp(command, "echosquelch")) {
res = capi_echosquelch(chan, params);
} else if (!strcasecmp(command, "malicious")) {
res = capi_malicious(chan, params);
} else if (!strcasecmp(command, "hold")) {
res = capi_hold(chan, params);
} else if (!strcasecmp(command, "holdtype")) {
res = capi_holdtype(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", ast_log(LOG_WARNING, "Unknown command '%s' for capiCommand\n",
command); command);
return -1;
} }
if ((capicmd->capionly) && (strcmp(chan->type, "CAPI"))) {
LOCAL_USER_REMOVE(u);
ast_log(LOG_WARNING, "capiCommand works on CAPI channels only, check your extensions.conf!\n");
return -1;
}
res = (capicmd->cmd)(chan, params);
LOCAL_USER_REMOVE(u); LOCAL_USER_REMOVE(u);
return(res); return(res);
} }
@ -3420,9 +3500,9 @@ static int capi_indicate(struct ast_channel *c, int condition)
case AST_CONTROL_RINGING: case AST_CONTROL_RINGING:
cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested RINGING-Indication for %s\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested RINGING-Indication for %s\n",
i->name, c->name); i->name, c->name);
#warning TODO somehow enable unhold on ringing, but when wanted only /* TODO somehow enable unhold on ringing, but when wanted only */
/* if (i->isdnstate & CAPI_ISDN_STATE_HOLD) */ if (i->isdnstate & CAPI_ISDN_STATE_HOLD)
/* capi_retrieve(c, NULL); */ capi_retrieve(c, NULL);
ret = capi_alert(c); ret = capi_alert(c);
break; break;
case AST_CONTROL_BUSY: case AST_CONTROL_BUSY:
@ -3456,11 +3536,12 @@ static int capi_indicate(struct ast_channel *c, int condition)
case AST_CONTROL_PROGRESS: case AST_CONTROL_PROGRESS:
cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROGRESS-Indication for %s\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROGRESS-Indication for %s\n",
i->name, c->name); i->name, c->name);
#warning TODO: in NT-mode we should send progress for early b3 to phone /* TODO: in NT-mode we should send progress for early b3 to phone */
break; break;
case AST_CONTROL_PROCEEDING: case AST_CONTROL_PROCEEDING:
cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROCEEDING-Indication for %s\n", cc_ast_verbose(3, 1, VERBOSE_PREFIX_2 "%s: Requested PROCEEDING-Indication for %s\n",
i->name, c->name); i->name, c->name);
/* TODO: in NT-mode we should send progress for early b3 to phone */
break; break;
#ifdef CC_AST_CONTROL_HOLD #ifdef CC_AST_CONTROL_HOLD
case AST_CONTROL_HOLD: case AST_CONTROL_HOLD: