diff --git a/README b/README index c759fe2..5c85dd4 100644 --- a/README +++ b/README @@ -202,6 +202,11 @@ ECT: exten => s,1,capicommand(hold) exten => s,2,Dial(CAPI/contr1/1234,,M(capi3pty)) +Peer link creation: + Create a reference for chan-capi to know who is the calling channel on Dial(). + This is needed if you want to use CCBS/CCNR afterwards. + Example: + exten => s,1,capicommand(peerlink) Using CLIR ========== @@ -362,7 +367,10 @@ CALLINGSUBADDRESS CALLEDSUBADDRESS If set on dial(), the called subaddress will be set to the content. - + +CCLINKAGEID + If a Call-Linkage-Id is received for CCBS/CCNR, this variable contains this Id. + CONNECTEDNUMBER Can be set before answering and if set, the content is used for IE 'Connected Number' on answering. diff --git a/chan_capi.c b/chan_capi.c index 82484a5..d1dd434 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -1210,6 +1210,8 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) dsa = calledsubaddress; } + i->peer = cc_get_peer_link_id(pbx_builtin_getvar_helper(c, "CAPIPEERLINKID")); + i->MessageNumber = get_capi_MessageNumber(); CONNECT_REQ_HEADER(&CMSG, capi_ApplID, i->MessageNumber, i->controller); CONNECT_REQ_CONTROLLER(&CMSG) = i->controller; @@ -4050,6 +4052,24 @@ static int pbx_capi_call_deflect(struct ast_channel *c, char *param) return(res); } +/* + * store the peer for future actions + */ +static int pbx_capi_peer_link(struct ast_channel *c, char *param) +{ + char buffer[32]; + int id; + + id = cc_add_peer_link_id(c); + + if (id >= 0) { + snprintf(buffer, sizeof(buffer) - 1, "%d", id); + pbx_builtin_setvar_helper(c, "_CAPIPEERLINKID", buffer); + } + + return 0; +} + /* * retrieve a hold on call */ @@ -4621,6 +4641,7 @@ static struct capicommands_s { int (*cmd)(struct ast_channel *, char *); int capionly; } capicommands[] = { + { "peerlink", pbx_capi_peer_link, 0 }, { "progress", pbx_capi_signal_progress, 1 }, { "deflect", pbx_capi_call_deflect, 1 }, { "receivefax", pbx_capi_receive_fax, 1 }, @@ -4634,7 +4655,7 @@ static struct capicommands_s { { "ect", pbx_capi_ect, 1 }, { "3pty_begin", pbx_capi_3pty_begin, 1 }, { "qsig_ssct", pbx_capi_qsig_ssct, 1 }, - { "qsig_ct", pbx_capi_qsig_ct, 1 }, + { "qsig_ct", pbx_capi_qsig_ct, 1 }, { "qsig_callmark",pbx_capi_qsig_callmark, 1 }, { "qsig_getplci", pbx_capi_qsig_getplci, 1 }, { NULL, NULL, 0 } diff --git a/chan_capi.h b/chan_capi.h index e4f01fd..9a753c5 100644 --- a/chan_capi.h +++ b/chan_capi.h @@ -291,6 +291,9 @@ struct capi_pvt { /*! Channel we belong to, possibly NULL */ struct ast_channel *owner; + /*! Channel who called us, possibly NULL */ + struct ast_channel *peer; + /* capi message number */ _cword MessageNumber; unsigned int NCCI; diff --git a/chan_capi_supplementary.c b/chan_capi_supplementary.c index 41d3e59..ab0c507 100644 --- a/chan_capi_supplementary.c +++ b/chan_capi_supplementary.c @@ -20,6 +20,53 @@ #include "chan_capi_supplementary.h" #include "chan_capi_utils.h" +#define CCBSNR_MAX_LIST_ENTRIES 32 +static struct ccbsnr_s ccbsnr_list[CCBSNR_MAX_LIST_ENTRIES]; + +/* + * a new CCBS/CCNR id was received + */ +static void new_ccbsnr_id(ccbsnrtype_t type, unsigned int plci, + _cword id, struct capi_pvt *i) +{ + int a; + char buffer[CAPI_MAX_STRING]; + + for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) { + if (ccbsnr_list[a].type == CCBSNR_TYPE_NULL) { + ccbsnr_list[a].type = type; + ccbsnr_list[a].id = id; + ccbsnr_list[a].plci = plci; + ccbsnr_list[a].state = CCBSNR_AVAILABLE; + + if (i->peer) { + snprintf(buffer, CAPI_MAX_STRING-1, "%d", (id | ((plci & 0xff) << 16))); + pbx_builtin_setvar_helper(i->peer, "CCLINKAGEID", buffer); + } + break; + } + } + if (a == CCBSNR_MAX_LIST_ENTRIES) { + cc_log(LOG_ERROR, "No free entry for new CCBS/CCNR ID\n"); + } +} + +/* + * a CCBS/CCNR id was removed + */ +static void del_ccbsnr_id(unsigned int plci, _cword id) +{ + int a; + + for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) { + if (((ccbsnr_list[a].plci & 0xff) == (plci & 0xff)) && + (ccbsnr_list[a].id == id)) { + ccbsnr_list[a].type = CCBSNR_TYPE_NULL; + ccbsnr_list[a].state = 0; + break; + } + } +} /* * send Listen for supplementary to specified controller @@ -81,6 +128,7 @@ void handle_facility_indication_supplementary( case 0x800d: /* CCBS erase call linkage ID */ cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS/CCNR erase id=0x%04x\n", PLCI & 0xff, PLCI, infoword); + del_ccbsnr_id(PLCI, infoword); break; } @@ -134,10 +182,12 @@ void handle_facility_indication_supplementary( case 0x8013: /* CCBS info retain */ cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x CCBS unique id=0x%04x\n", i->vname, PLCI, infoword); + new_ccbsnr_id(CCBSNR_TYPE_CCBS, PLCI, infoword, i); break; case 0x8015: /* CCNR info retain */ cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x CCNR unique id=0x%04x\n", i->vname, PLCI, infoword); + new_ccbsnr_id(CCBSNR_TYPE_CCNR, PLCI, infoword, i); break; case 0x800d: /* CCBS erase call linkage ID */ /* handled above */ diff --git a/chan_capi_supplementary.h b/chan_capi_supplementary.h index a355f4f..7e98273 100644 --- a/chan_capi_supplementary.h +++ b/chan_capi_supplementary.h @@ -20,4 +20,22 @@ extern void ListenOnSupplementary(unsigned controller); extern void handle_facility_indication_supplementary(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i); +typedef enum { + CCBSNR_TYPE_NULL = 0, + CCBSNR_TYPE_CCBS, + CCBSNR_TYPE_CCNR +} ccbsnrtype_t; + +#define CCBSNR_AVAILABLE 1 + +struct ccbsnr_s { + ccbsnrtype_t type; + _cword id; + unsigned int plci; + unsigned int state; + char context[AST_MAX_CONTEXT]; + char exten[AST_MAX_EXTENSION]; + int priority; +}; + #endif diff --git a/chan_capi_utils.c b/chan_capi_utils.c index 598d9b0..c813843 100644 --- a/chan_capi_utils.c +++ b/chan_capi_utils.c @@ -12,6 +12,7 @@ */ #include +#include #include "chan_capi20.h" #include "chan_capi.h" #include "chan_capi_utils.h" @@ -26,6 +27,9 @@ AST_MUTEX_DEFINE_STATIC(capi_put_lock); static _cword capi_MessageNumber; +#define CAPI_MAX_PEERLINKCHANNELS 32 +static struct ast_channel *peerlinkchannel[CAPI_MAX_PEERLINKCHANNELS]; + /* * helper for _verbose with different verbose settings */ @@ -617,3 +621,41 @@ void parse_dialstring(char *buffer, char **interface, char **dest, char **param, return; } +/* + * Add a new peer link id + */ +int cc_add_peer_link_id(struct ast_channel *c) +{ + int a; + + for (a = 0; a < CAPI_MAX_PEERLINKCHANNELS; a++) { + if (peerlinkchannel[a] == NULL) { + peerlinkchannel[a] = c; + break; + } + } + if (a == CAPI_MAX_PEERLINKCHANNELS) { + return -1; + } + return a; +} + +/* + * Get and remove peer link id + */ +struct ast_channel *cc_get_peer_link_id(const char *p) +{ + int id = -1; + struct ast_channel *chan = NULL; + + if (p) { + id = (int)strtoul(p, NULL, 0); + } + + if ((id >= 0) && (id < CAPI_MAX_PEERLINKCHANNELS)) { + chan = peerlinkchannel[id]; + peerlinkchannel[id] = NULL; + } + return chan; +} + diff --git a/chan_capi_utils.h b/chan_capi_utils.h index cb00d3d..689c95b 100644 --- a/chan_capi_utils.h +++ b/chan_capi_utils.h @@ -29,6 +29,8 @@ 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); +extern int cc_add_peer_link_id(struct ast_channel *c); +extern struct ast_channel *cc_get_peer_link_id(const char *p); #define capi_number(data, strip) \ capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))