diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_agent.c | 3 | ||||
-rw-r--r-- | channels/chan_dahdi.c | 32 | ||||
-rw-r--r-- | channels/chan_h323.c | 12 | ||||
-rw-r--r-- | channels/chan_iax2.c | 108 | ||||
-rw-r--r-- | channels/chan_local.c | 75 | ||||
-rw-r--r-- | channels/chan_mgcp.c | 2 | ||||
-rw-r--r-- | channels/chan_misdn.c | 1553 | ||||
-rw-r--r-- | channels/chan_phone.c | 8 | ||||
-rw-r--r-- | channels/chan_sip.c | 1111 | ||||
-rw-r--r-- | channels/chan_skinny.c | 54 | ||||
-rw-r--r-- | channels/chan_unistim.c | 12 | ||||
-rw-r--r-- | channels/misdn/chan_misdn_config.h | 10 | ||||
-rw-r--r-- | channels/misdn/isdn_lib.c | 196 | ||||
-rw-r--r-- | channels/misdn/isdn_lib.h | 202 | ||||
-rw-r--r-- | channels/misdn/isdn_lib_intern.h | 1 | ||||
-rw-r--r-- | channels/misdn/isdn_msg_parser.c | 395 | ||||
-rw-r--r-- | channels/misdn_config.c | 113 |
17 files changed, 2813 insertions, 1074 deletions
diff --git a/channels/chan_agent.c b/channels/chan_agent.c index b15f7a04e..818f61935 100644 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -757,8 +757,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout) time(&p->start); /* Call on this agent */ ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); - ast_set_callerid(p->chan, - ast->cid.cid_num, ast->cid.cid_name, NULL); + ast_channel_set_connected_line(p->chan, &ast->connected); ast_channel_inherit_variables(ast, p->chan); res = ast_call(p->chan, p->loginchan, 0); CLEANUP(ast,p); diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index f520e32f7..f6d3fb9ad 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -3156,7 +3156,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) } p->callwaitcas = 0; if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) { - p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p)); + p->cidlen = ast_callerid_generate(p->cidspill, ast->connected.id.name, ast->connected.id.number, AST_LAW(p)); p->cidpos = 0; send_callerid(p); } @@ -3197,12 +3197,12 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) } else { /* Call waiting call */ p->callwaitrings = 0; - if (ast->cid.cid_num) - ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num)); + if (ast->connected.id.number) + ast_copy_string(p->callwait_num, ast->connected.id.number, sizeof(p->callwait_num)); else p->callwait_num[0] = '\0'; - if (ast->cid.cid_name) - ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name)); + if (ast->connected.id.name) + ast_copy_string(p->callwait_name, ast->connected.id.name, sizeof(p->callwait_name)); else p->callwait_name[0] = '\0'; /* Call waiting tone instead */ @@ -3214,8 +3214,8 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE)) ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name); } - n = ast->cid.cid_name; - l = ast->cid.cid_num; + n = ast->connected.id.name; + l = ast->connected.id.number; if (l) ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num)); else @@ -3281,14 +3281,14 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) switch (mysig) { case SIG_FEATD: - l = ast->cid.cid_num; + l = ast->connected.id.number; if (l) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c); else snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c); break; case SIG_FEATDMF: - l = ast->cid.cid_num; + l = ast->connected.id.number; if (l) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c); else @@ -3423,7 +3423,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) } if (!p->hidecallerid) { - l = ast->cid.cid_num; + l = ast->connected.id.number; } else { l = NULL; } @@ -3472,10 +3472,10 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) } } isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai, - p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED), - p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED ); + p->use_callingpres ? cid_pres2ss7pres(ast->connected.id.number_presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED), + p->use_callingpres ? cid_pres2ss7screen(ast->connected.id.number_presentation) : SS7_SCREENING_USER_PROVIDED ); - isup_set_oli(p->ss7call, ast->cid.cid_ani2); + isup_set_oli(p->ss7call, ast->connected.ani2); isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc); ast_channel_lock(ast); @@ -3587,9 +3587,9 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) l = NULL; n = NULL; if (!p->hidecallerid) { - l = ast->cid.cid_num; + l = ast->connected.id.number; if (!p->hidecalleridname) { - n = ast->cid.cid_name; + n = ast->connected.id.name; } } @@ -3803,7 +3803,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) } } pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan, - p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE)); + p->use_callingpres ? ast->connected.id.number_presentation : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE)); if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) { if (!strcasecmp(rr_str, "UNKNOWN")) redirect_reason = 0; diff --git a/channels/chan_h323.c b/channels/chan_h323.c index c3e074d14..0445497b4 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -606,18 +606,18 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout) /* make sure null terminated */ called_addr[sizeof(called_addr) - 1] = '\0'; - if (c->cid.cid_num) - ast_copy_string(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num)); + if (c->connected.id.number) + ast_copy_string(pvt->options.cid_num, c->connected.id.number, sizeof(pvt->options.cid_num)); - if (c->cid.cid_name) - ast_copy_string(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name)); + if (c->connected.id.name) + ast_copy_string(pvt->options.cid_name, c->connected.id.name, sizeof(pvt->options.cid_name)); if (c->cid.cid_rdnis) { ast_copy_string(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis)); } - pvt->options.presentation = c->cid.cid_pres; - pvt->options.type_of_number = c->cid.cid_ton; + pvt->options.presentation = c->connected.id.number_presentation; + pvt->options.type_of_number = c->connected.id.number_type; if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) { if (!strcasecmp(addr, "UNKNOWN")) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 860e1d614..d594498f6 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -380,7 +380,9 @@ enum iax2_flags { them before sending voice or anything else*/ IAX_ALLOWFWDOWNLOAD = (1 << 26), /*!< Allow the FWDOWNL command? */ IAX_IMMEDIATE = (1 << 27), /*!< Allow immediate off-hook to extension s */ - IAX_FORCE_ENCRYPT = (1 << 28), /*!< Forces call encryption, if encryption not possible hangup */ + IAX_SENDCONNECTEDLINE = (1 << 28), /*!< Allow sending of connected line updates */ + IAX_RECVCONNECTEDLINE = (1 << 29), /*!< Allow receiving of connected line updates */ + IAX_FORCE_ENCRYPT = (1 << 30), /*!< Forces call encryption, if encryption not possible hangup */ }; static int global_rtautoclear = 120; @@ -1976,7 +1978,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x); iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x); iaxs[x]->amaflags = amaflags; - ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT); + ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); ast_string_field_set(iaxs[x], accountcode, accountcode); ast_string_field_set(iaxs[x], mohinterpret, mohinterpret); ast_string_field_set(iaxs[x], mohsuggest, mohsuggest); @@ -3601,6 +3603,8 @@ struct create_addr_info { char outkey[80]; char timezone[80]; char prefs[32]; + char cid_num[80]; + char cid_name[80]; char context[AST_MAX_CONTEXT]; char peercontext[AST_MAX_CONTEXT]; char mohinterpret[MAX_MUSICCLASS]; @@ -3644,7 +3648,7 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0))) goto return_unref; - ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT); + ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); cai->maxtime = peer->maxms; cai->capability = peer->capability; cai->encmethods = peer->encmethods; @@ -3662,6 +3666,8 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka ast_copy_string(cai->username, peer->username, sizeof(cai->username)); ast_copy_string(cai->timezone, peer->zonetag, sizeof(cai->timezone)); ast_copy_string(cai->outkey, peer->outkey, sizeof(cai->outkey)); + ast_copy_string(cai->cid_num, peer->cid_num, sizeof(cai->cid_num)); + ast_copy_string(cai->cid_name, peer->cid_name, sizeof(cai->cid_name)); ast_copy_string(cai->mohinterpret, peer->mohinterpret, sizeof(cai->mohinterpret)); ast_copy_string(cai->mohsuggest, peer->mohsuggest, sizeof(cai->mohsuggest)); if (ast_strlen_zero(peer->dbsecret)) { @@ -3870,8 +3876,8 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout) if (pds.port) sin.sin_port = htons(atoi(pds.port)); - l = c->cid.cid_num; - n = c->cid.cid_name; + l = c->connected.id.number; + n = c->connected.id.name; /* Now build request */ memset(&ied, 0, sizeof(ied)); @@ -3888,21 +3894,21 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout) if (l) { iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l); - iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); + iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->connected.id.number_presentation); } else { if (n) - iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); + iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->connected.id.number_presentation); else iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE); } - iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->cid.cid_ton); + iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->connected.id.number_type); iax_ie_append_short(&ied, IAX_IE_CALLINGTNS, c->cid.cid_tns); if (n) iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, n); - if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->cid.cid_ani) - iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->cid.cid_ani); + if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->connected.ani) + iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->connected.ani); if (!ast_strlen_zero(c->language)) iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language); @@ -4398,6 +4404,11 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data, ast_moh_stop(c); goto done; } + break; + case AST_CONTROL_CONNECTED_LINE: + if (!ast_test_flag(pvt, IAX_SENDCONNECTEDLINE)) + goto done; + break; } res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1); @@ -6381,7 +6392,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies iaxs[callno]->amaflags = user->amaflags; if (!ast_strlen_zero(user->language)) ast_string_field_set(iaxs[callno], language, user->language); - ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); /* Keep this check last */ if (!ast_strlen_zero(user->dbsecret)) { char *family, *key=NULL; @@ -9954,6 +9965,31 @@ immediatedial: ast_mutex_unlock(&iaxsl[fr->callno]); return 1; } + /* Don't allow connected line updates unless we are configured to */ + if (f.frametype == AST_FRAME_CONTROL && f.subclass == AST_CONTROL_CONNECTED_LINE) { + struct ast_party_connected_line connected; + + if (!ast_test_flag(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) { + ast_mutex_unlock(&iaxsl[fr->callno]); + return 1; + } + + /* Initialize defaults */ + ast_party_connected_line_init(&connected); + connected.id.number_presentation = iaxs[fr->callno]->calling_pres; + + if (!ast_connected_line_parse_data(f.data.ptr, f.datalen, &connected)) { + ast_string_field_set(iaxs[fr->callno], cid_num, connected.id.number); + ast_string_field_set(iaxs[fr->callno], cid_name, connected.id.name); + iaxs[fr->callno]->calling_pres = connected.id.number_presentation; + + if (iaxs[fr->callno]->owner) { + ast_set_callerid(iaxs[fr->callno]->owner, S_OR(connected.id.number, ""), S_OR(connected.id.name, ""), NULL); + iaxs[fr->callno]->owner->cid.cid_pres = connected.id.number_presentation; + } + } + ast_party_connected_line_free(&connected); + } /* Common things */ f.src = "IAX2"; f.mallocd = 0; @@ -10449,7 +10485,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data memset(&cai, 0, sizeof(cai)); cai.capability = iax2_capability; - ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); /* Populate our address from the given */ if (create_addr(pds.peer, NULL, &sin, &cai)) { @@ -10468,7 +10504,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data } /* If this is a trunk, update it now */ - ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); if (ast_test_flag(&cai, IAX_TRUNK)) { int new_callno; if ((new_callno = make_trunk(callno, 1)) != -1) @@ -10731,7 +10767,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st if (peer) { if (firstpass) { - ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT); + ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); peer->encmethods = iax2_encryption; peer->adsi = adsi; ast_string_field_set(peer,secret,""); @@ -10904,6 +10940,18 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st ast_string_field_set(peer, zonetag, v->value); } else if (!strcasecmp(v->name, "adsi")) { peer->adsi = ast_true(v->value); + } else if (!strcasecmp(v->name, "connectedline")) { + if (ast_true(v->value)) { + ast_set_flag(peer, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); + } else if (!strcasecmp(v->value, "send")) { + ast_clear_flag(peer, IAX_RECVCONNECTEDLINE); + ast_set_flag(peer, IAX_SENDCONNECTEDLINE); + } else if (!strcasecmp(v->value, "receive")) { + ast_clear_flag(peer, IAX_SENDCONNECTEDLINE); + ast_set_flag(peer, IAX_RECVCONNECTEDLINE); + } else { + ast_clear_flag(peer, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); + } }/* else if (strcasecmp(v->name,"type")) */ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ v = v->next; @@ -11002,7 +11050,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st user->adsi = adsi; ast_string_field_set(user, name, name); ast_string_field_set(user, language, language); - ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_FORCE_ENCRYPT); + ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); ast_clear_flag(user, IAX_HASCALLERID); ast_string_field_set(user, cid_name, ""); ast_string_field_set(user, cid_num, ""); @@ -11147,6 +11195,18 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st user->maxauthreq = 0; } else if (!strcasecmp(v->name, "adsi")) { user->adsi = ast_true(v->value); + } else if (!strcasecmp(v->name, "connectedline")) { + if (ast_true(v->value)) { + ast_set_flag(user, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); + } else if (!strcasecmp(v->value, "send")) { + ast_clear_flag(user, IAX_RECVCONNECTEDLINE); + ast_set_flag(user, IAX_SENDCONNECTEDLINE); + } else if (!strcasecmp(v->value, "receive")) { + ast_clear_flag(user, IAX_SENDCONNECTEDLINE); + ast_set_flag(user, IAX_RECVCONNECTEDLINE); + } else { + ast_clear_flag(user, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); + } }/* else if (strcasecmp(v->name,"type")) */ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ v = v->next; @@ -11262,10 +11322,8 @@ static void set_config_destroy(void) trunkmaxsize = MAX_TRUNKDATA; amaflags = 0; delayreject = 0; - ast_clear_flag((&globalflags), IAX_NOTRANSFER); - ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA); - ast_clear_flag((&globalflags), IAX_USEJITTERBUF); - ast_clear_flag((&globalflags), IAX_FORCEJITTERBUF); + ast_clear_flag((&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | + IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); delete_users(); } @@ -11569,6 +11627,18 @@ static int set_config(char *config_file, int reload) adsi = ast_true(v->value); } else if (!strcasecmp(v->name, "srvlookup")) { srvlookup = ast_true(v->value); + } else if (!strcasecmp(v->name, "connectedline")) { + if (ast_true(v->value)) { + ast_set_flag((&globalflags), IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); + } else if (!strcasecmp(v->value, "send")) { + ast_clear_flag((&globalflags), IAX_RECVCONNECTEDLINE); + ast_set_flag((&globalflags), IAX_SENDCONNECTEDLINE); + } else if (!strcasecmp(v->value, "receive")) { + ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE); + ast_set_flag((&globalflags), IAX_RECVCONNECTEDLINE); + } else { + ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); + } } /*else if (strcasecmp(v->name,"type")) */ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ v = v->next; diff --git a/channels/chan_local.c b/channels/chan_local.c index e426e10fa..509e69b10 100644 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -406,6 +406,37 @@ static int local_indicate(struct ast_channel *ast, int condition, const void *da ast_moh_start(ast, data, NULL); } else if (condition == AST_CONTROL_UNHOLD) { ast_moh_stop(ast); + } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { + struct ast_channel *this_channel; + struct ast_channel *the_other_channel; + /* A connected line update frame may only contain a partial amount of data, such + * as just a source, or just a ton, and not the full amount of information. However, + * the collected information is all stored in the outgoing channel's connectedline + * structure, so when receiving a connected line update on an outgoing local channel, + * we need to transmit the collected connected line information instead of whatever + * happens to be in this control frame. The same applies for redirecting information, which + * is why it is handled here as well.*/ + isoutbound = IS_OUTBOUND(ast, p); + if (isoutbound) { + this_channel = p->chan; + the_other_channel = p->owner; + } else { + this_channel = p->owner; + the_other_channel = p->chan; + } + if (the_other_channel) { + unsigned char frame_data[1024]; + if (condition == AST_CONTROL_CONNECTED_LINE) { + f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected); + } else { + f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting); + } + f.subclass = condition; + f.data.ptr = frame_data; + if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) { + ast_mutex_unlock(&p->lock); + } + } } else { /* Queue up a frame representing the indication as a control frame */ ast_mutex_lock(&p->lock); @@ -509,22 +540,45 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout) if (!p) return -1; - - ast_mutex_lock(&p->lock); + + /* If you value your sanity, please don't look at this code */ +start_over: + while (ast_channel_trylock(p->chan)) { + ast_channel_unlock(p->owner); + usleep(1); + ast_channel_lock(p->owner); + } + + /* p->owner and p->chan are locked now. Let's get p locked */ + if (ast_mutex_trylock(&p->lock)) { + /* @#$&$@ */ + ast_channel_unlock(p->chan); + ast_channel_unlock(p->owner); + usleep(1); + ast_channel_lock(p->owner); + goto start_over; + } /* * Note that cid_num and cid_name aren't passed in the ast_channel_alloc * call, so it's done here instead. + * + * All these failure points just return -1. The individual strings will + * be cleared when we destroy the channel. */ - p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); - p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); - p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); - p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); - p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); - p->chan->cid.cid_pres = p->owner->cid.cid_pres; - p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; - p->chan->cid.cid_ton = p->owner->cid.cid_ton; + if (!(p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis))) { + return -1; + } + ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting); + + if (!(p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid))) { + return -1; + } p->chan->cid.cid_tns = p->owner->cid.cid_tns; + + ast_connected_line_copy_to_caller(&p->chan->cid, &p->owner->connected); + ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->cid); + ast_string_field_set(p->chan, language, p->owner->language); ast_string_field_set(p->chan, accountcode, p->owner->accountcode); ast_string_field_set(p->chan, musicclass, p->owner->musicclass); @@ -560,6 +614,7 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout) ast_set_flag(p, LOCAL_LAUNCHED_PBX); ast_mutex_unlock(&p->lock); + ast_channel_unlock(p->chan); return res; } diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index cad9d9497..83a2e61b4 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -915,7 +915,7 @@ static int mgcp_call(struct ast_channel *ast, char *dest, int timeout) transmit_modify_request(sub->next); } - transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name); + transmit_notify_request_with_callerid(sub, tone, ast->connected.id.number, ast->connected.id.name); ast_setstate(ast, AST_STATE_RINGING); if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 599bcef82..52b8f1d9f 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <signal.h> #include <sys/file.h> #include <semaphore.h> +#include <ctype.h> #include "asterisk/channel.h" #include "asterisk/config.h" @@ -88,8 +89,6 @@ struct misdn_jb{ ast_mutex_t mutexjb; }; - - /*! \brief allocates the jb-structure and initialize the elements */ struct misdn_jb *misdn_jb_init(int size, int upper_threshold); @@ -340,10 +339,6 @@ struct chan_list { */ char mohinterpret[MAX_MUSICCLASS]; -#if 0 - int zero_read_cnt; /* Not used */ -#endif - /*! * \brief Number of outgoing audio frames dropped since last debug gripe message. */ @@ -401,18 +396,10 @@ struct chan_list { */ struct timeval overlap_tv; -#if 0 - struct chan_list *peer; /* Not used */ -#endif - /*! * \brief Next channel call record in the list. */ struct chan_list *next; -#if 0 - struct chan_list *prev; /* Not used */ - struct chan_list *first; /* Not used */ -#endif }; @@ -423,13 +410,14 @@ void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_ void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch); static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame); -static struct robin_list { +struct robin_list { char *group; int port; int channel; struct robin_list *next; struct robin_list *prev; -} *robin = NULL; +}; +static struct robin_list *robin = NULL; static inline void free_robin_list_r(struct robin_list *r) @@ -538,7 +526,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data); int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len); -void debug_numplan(int port, int numplan, char *type); +void debug_numtype(int port, int numtype, char *type); int add_out_calls(int port); int add_in_calls(int port); @@ -580,6 +568,534 @@ static struct chan_list * get_chan_by_ast_name(char *name) return NULL; } +/*! + * \internal + * \brief Convert the mISDN type of number code to a string + * + * \param number_type mISDN type of number code. + * + * \return The mISDN type of number code as a string + */ +static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type) +{ + const char *str; + + switch (number_type) { + default: + case NUMTYPE_UNKNOWN: + str = "Unknown"; + break; + + case NUMTYPE_INTERNATIONAL: + str = "International"; + break; + + case NUMTYPE_NATIONAL: + str = "National"; + break; + + case NUMTYPE_NETWORK_SPECIFIC: + str = "Network Specific"; + break; + + case NUMTYPE_SUBSCRIBER: + str = "Subscriber"; + break; + + case NUMTYPE_ABBREVIATED: + str = "Abbreviated"; + break; + } + + return str; +} + +/*! + * \internal + * \brief Convert the mISDN type of number code to Asterisk type of number code + * + * \param number_type mISDN type of number code. + * + * \return Asterisk type of number code + */ +static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type) +{ + int ast_number_type; + + switch (number_type) { + default: + case NUMTYPE_UNKNOWN: + ast_number_type = NUMTYPE_UNKNOWN << 4; + break; + + case NUMTYPE_INTERNATIONAL: + ast_number_type = NUMTYPE_INTERNATIONAL << 4; + break; + + case NUMTYPE_NATIONAL: + ast_number_type = NUMTYPE_NATIONAL << 4; + break; + + case NUMTYPE_NETWORK_SPECIFIC: + ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4; + break; + + case NUMTYPE_SUBSCRIBER: + ast_number_type = NUMTYPE_SUBSCRIBER << 4; + break; + + case NUMTYPE_ABBREVIATED: + ast_number_type = NUMTYPE_ABBREVIATED << 4; + break; + } + + return ast_number_type; +} + +/*! + * \internal + * \brief Convert the Asterisk type of number code to mISDN type of number code + * + * \param ast_number_type Asterisk type of number code. + * + * \return mISDN type of number code + */ +static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type) +{ + enum mISDN_NUMBER_TYPE number_type; + + switch ((ast_number_type >> 4) & 0x07) { + default: + case NUMTYPE_UNKNOWN: + number_type = NUMTYPE_UNKNOWN; + break; + + case NUMTYPE_INTERNATIONAL: + number_type = NUMTYPE_INTERNATIONAL; + break; + + case NUMTYPE_NATIONAL: + number_type = NUMTYPE_NATIONAL; + break; + + case NUMTYPE_NETWORK_SPECIFIC: + number_type = NUMTYPE_NETWORK_SPECIFIC; + break; + + case NUMTYPE_SUBSCRIBER: + number_type = NUMTYPE_SUBSCRIBER; + break; + + case NUMTYPE_ABBREVIATED: + number_type = NUMTYPE_ABBREVIATED; + break; + } + + return number_type; +} + +/*! + * \internal + * \brief Convert the mISDN numbering plan code to a string + * + * \param number_plan mISDN numbering plan code. + * + * \return The mISDN numbering plan code as a string + */ +static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan) +{ + const char *str; + + switch (number_plan) { + default: + case NUMPLAN_UNKNOWN: + str = "Unknown"; + break; + + case NUMPLAN_ISDN: + str = "ISDN"; + break; + + case NUMPLAN_DATA: + str = "Data"; + break; + + case NUMPLAN_TELEX: + str = "Telex"; + break; + + case NUMPLAN_NATIONAL: + str = "National"; + break; + + case NUMPLAN_PRIVATE: + str = "Private"; + break; + } + + return str; +} + +/*! + * \internal + * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code + * + * \param number_plan mISDN numbering plan code. + * + * \return Asterisk numbering plan code + */ +static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan) +{ + int ast_number_plan; + + switch (number_plan) { + default: + case NUMPLAN_UNKNOWN: + ast_number_plan = NUMPLAN_UNKNOWN; + break; + + case NUMPLAN_ISDN: + ast_number_plan = NUMPLAN_ISDN; + break; + + case NUMPLAN_DATA: + ast_number_plan = NUMPLAN_DATA; + break; + + case NUMPLAN_TELEX: + ast_number_plan = NUMPLAN_TELEX; + break; + + case NUMPLAN_NATIONAL: + ast_number_plan = NUMPLAN_NATIONAL; + break; + + case NUMPLAN_PRIVATE: + ast_number_plan = NUMPLAN_PRIVATE; + break; + } + + return ast_number_plan; +} + +/*! + * \internal + * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code + * + * \param ast_number_plan Asterisk numbering plan code. + * + * \return mISDN numbering plan code + */ +static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan) +{ + enum mISDN_NUMBER_PLAN number_plan; + + switch (ast_number_plan & 0x0F) { + default: + case NUMPLAN_UNKNOWN: + number_plan = NUMPLAN_UNKNOWN; + break; + + case NUMPLAN_ISDN: + number_plan = NUMPLAN_ISDN; + break; + + case NUMPLAN_DATA: + number_plan = NUMPLAN_DATA; + break; + + case NUMPLAN_TELEX: + number_plan = NUMPLAN_TELEX; + break; + + case NUMPLAN_NATIONAL: + number_plan = NUMPLAN_NATIONAL; + break; + + case NUMPLAN_PRIVATE: + number_plan = NUMPLAN_PRIVATE; + break; + } + + return number_plan; +} + +/*! + * \internal + * \brief Convert the mISDN presentation code to a string + * + * \param presentation mISDN number presentation restriction code. + * + * \return The mISDN presentation code as a string + */ +static const char *misdn_to_str_pres(int presentation) +{ + const char *str; + + switch (presentation) { + case 0: + str = "Allowed"; + break; + + case 1: + str = "Restricted"; + break; + + case 2: + str = "Unavailable"; + break; + + default: + str = "Unknown"; + break; + } + + return str; +} + +/*! + * \internal + * \brief Convert the mISDN presentation code to Asterisk presentation code + * + * \param presentation mISDN number presentation restriction code. + * + * \return Asterisk presentation code + */ +static int misdn_to_ast_pres(int presentation) +{ + switch (presentation) { + default: + case 0: + presentation = AST_PRES_ALLOWED; + break; + + case 1: + presentation = AST_PRES_RESTRICTED; + break; + + case 2: + presentation = AST_PRES_UNAVAILABLE; + break; + } + + return presentation; +} + +/*! + * \internal + * \brief Convert the Asterisk presentation code to mISDN presentation code + * + * \param presentation Asterisk number presentation restriction code. + * + * \return mISDN presentation code + */ +static int ast_to_misdn_pres(int presentation) +{ + switch (presentation & AST_PRES_RESTRICTION) { + default: + case AST_PRES_ALLOWED: + presentation = 0; + break; + + case AST_PRES_RESTRICTED: + presentation = 1; + break; + + case AST_PRES_UNAVAILABLE: + presentation = 2; + break; + } + + return presentation; +} + +/*! + * \internal + * \brief Convert the mISDN screening code to a string + * + * \param screening mISDN number screening code. + * + * \return The mISDN screening code as a string + */ +static const char *misdn_to_str_screen(int screening) +{ + const char *str; + + switch (screening) { + case 0: + str = "Unscreened"; + break; + + case 1: + str = "Passed Screen"; + break; + + case 2: + str = "Failed Screen"; + break; + + case 3: + str = "Network Number"; + break; + + default: + str = "Unknown"; + break; + } + + return str; +} + +/*! + * \internal + * \brief Convert the mISDN screening code to Asterisk screening code + * + * \param screening mISDN number screening code. + * + * \return Asterisk screening code + */ +static int misdn_to_ast_screen(int screening) +{ + switch (screening) { + default: + case 0: + screening = AST_PRES_USER_NUMBER_UNSCREENED; + break; + + case 1: + screening = AST_PRES_USER_NUMBER_PASSED_SCREEN; + break; + + case 2: + screening = AST_PRES_USER_NUMBER_FAILED_SCREEN; + break; + + case 3: + screening = AST_PRES_NETWORK_NUMBER; + break; + } + + return screening; +} + +/*! + * \internal + * \brief Convert the Asterisk screening code to mISDN screening code + * + * \param screening Asterisk number screening code. + * + * \return mISDN screening code + */ +static int ast_to_misdn_screen(int screening) +{ + switch (screening & AST_PRES_NUMBER_TYPE) { + default: + case AST_PRES_USER_NUMBER_UNSCREENED: + screening = 0; + break; + + case AST_PRES_USER_NUMBER_PASSED_SCREEN: + screening = 1; + break; + + case AST_PRES_USER_NUMBER_FAILED_SCREEN: + screening = 2; + break; + + case AST_PRES_NETWORK_NUMBER: + screening = 3; + break; + } + + return screening; +} + +/*! + * \internal + * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code. + * + * \param ast Asterisk redirecting reason code. + * + * \return mISDN reason code + */ +static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast) +{ + unsigned index; + + static const struct misdn_reasons { + enum AST_REDIRECTING_REASON ast; + enum mISDN_REDIRECTING_REASON q931; + } misdn_reason_table[] = { + /* *INDENT-OFF* */ + { AST_REDIRECTING_REASON_UNKNOWN, mISDN_REDIRECTING_REASON_UNKNOWN }, + { AST_REDIRECTING_REASON_USER_BUSY, mISDN_REDIRECTING_REASON_CALL_FWD_BUSY }, + { AST_REDIRECTING_REASON_NO_ANSWER, mISDN_REDIRECTING_REASON_NO_REPLY }, + { AST_REDIRECTING_REASON_UNAVAILABLE, mISDN_REDIRECTING_REASON_NO_REPLY }, + { AST_REDIRECTING_REASON_UNCONDITIONAL, mISDN_REDIRECTING_REASON_CALL_FWD }, + { AST_REDIRECTING_REASON_TIME_OF_DAY, mISDN_REDIRECTING_REASON_UNKNOWN }, + { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN }, + { AST_REDIRECTING_REASON_DEFLECTION, mISDN_REDIRECTING_REASON_DEFLECTION }, + { AST_REDIRECTING_REASON_FOLLOW_ME, mISDN_REDIRECTING_REASON_UNKNOWN }, + { AST_REDIRECTING_REASON_OUT_OF_ORDER, mISDN_REDIRECTING_REASON_OUT_OF_ORDER }, + { AST_REDIRECTING_REASON_AWAY, mISDN_REDIRECTING_REASON_UNKNOWN }, + { AST_REDIRECTING_REASON_CALL_FWD_DTE, mISDN_REDIRECTING_REASON_CALL_FWD_DTE } + /* *INDENT-ON* */ + }; + + for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) { + if (misdn_reason_table[index].ast == ast) { + return misdn_reason_table[index].q931; + } + } + return mISDN_REDIRECTING_REASON_UNKNOWN; +} + +/*! + * \internal + * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code + * + * \param q931 mISDN redirecting reason code. + * + * \return Asterisk redirecting reason code + */ +static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931) +{ + enum AST_REDIRECTING_REASON ast; + + switch (q931) { + default: + case mISDN_REDIRECTING_REASON_UNKNOWN: + ast = AST_REDIRECTING_REASON_UNKNOWN; + break; + + case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY: + ast = AST_REDIRECTING_REASON_USER_BUSY; + break; + + case mISDN_REDIRECTING_REASON_NO_REPLY: + ast = AST_REDIRECTING_REASON_NO_ANSWER; + break; + + case mISDN_REDIRECTING_REASON_DEFLECTION: + ast = AST_REDIRECTING_REASON_DEFLECTION; + break; + + case mISDN_REDIRECTING_REASON_OUT_OF_ORDER: + ast = AST_REDIRECTING_REASON_OUT_OF_ORDER; + break; + + case mISDN_REDIRECTING_REASON_CALL_FWD_DTE: + ast = AST_REDIRECTING_REASON_CALL_FWD_DTE; + break; + + case mISDN_REDIRECTING_REASON_CALL_FWD: + ast = AST_REDIRECTING_REASON_UNCONDITIONAL; + break; + } + + return ast; +} + struct allowed_bearers { @@ -590,7 +1106,7 @@ struct allowed_bearers { }; /* *INDENT-OFF* */ -static const struct allowed_bearers allowed_bearers_array[]= { +static const struct allowed_bearers allowed_bearers_array[] = { /* Name, Displayable Name Bearer Capability, Deprecated */ { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 }, { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 }, @@ -609,7 +1125,7 @@ static const char *bearer2str(int cap) if (allowed_bearers_array[index].cap == cap) { return allowed_bearers_array[index].display; } - } /* end for */ + } return "Unknown Bearer"; } @@ -682,6 +1198,95 @@ static void print_bearer(struct misdn_bchannel *bc) } } +/*! + * \internal + * \brief Prefix a string to another string in place. + * + * \param str_prefix String to prefix to the main string. + * \param str_main String to get the prefix added to it. + * \param size Buffer size of the main string (Includes null terminator). + * + * \note The str_main buffer size must be greater than one. + * + * \return Nothing + */ +static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size) +{ + size_t len_over; + size_t len_total; + size_t len_main; + size_t len_prefix; + + len_prefix = strlen(str_prefix); + if (!len_prefix) { + /* There is no prefix to prepend. */ + return; + } + len_main = strlen(str_main); + len_total = len_prefix + len_main; + if (size <= len_total) { + /* We need to truncate since the buffer is too small. */ + len_over = len_total + 1 - size; + if (len_over <= len_main) { + len_main -= len_over; + } else { + len_over -= len_main; + len_main = 0; + len_prefix -= len_over; + } + } + if (len_main) { + memmove(str_main + len_prefix, str_main, len_main); + } + memcpy(str_main, str_prefix, len_prefix); + str_main[len_prefix + len_main] = '\0'; +} + +/*! + * \internal + * \brief Add a configured prefix to the given number. + * + * \param port Logical port number + * \param number_type Type-of-number passed in. + * \param number Given number string to add prefix + * \param size Buffer size number string occupies. + * + * \return Nothing + */ +static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size) +{ + enum misdn_cfg_elements type_prefix; + char num_prefix[MISDN_MAX_NUMBER_LEN]; + + /* Get prefix string. */ + switch (number_type) { + case NUMTYPE_UNKNOWN: + type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN; + break; + case NUMTYPE_INTERNATIONAL: + type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL; + break; + case NUMTYPE_NATIONAL: + type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL; + break; + case NUMTYPE_NETWORK_SPECIFIC: + type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC; + break; + case NUMTYPE_SUBSCRIBER: + type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER; + break; + case NUMTYPE_ABBREVIATED: + type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED; + break; + default: + /* Type-of-number does not have a prefix that can be added. */ + return; + } + misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix)); + + misdn_prefix_string(num_prefix, number, size); +} + static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc) { char buf[128]; @@ -691,7 +1296,8 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd } if (originator == ORG_AST) { - if (!(ast = ast_bridged_channel(ast))) { + ast = ast_bridged_channel(ast); + if (!ast) { return; } } @@ -745,7 +1351,8 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd /*************** Helpers END *************/ static void sighandler(int sig) -{} +{ +} static void *misdn_tasks_thread_func(void *data) { @@ -840,6 +1447,7 @@ static void misdn_tasks_remove(int task_id) static int misdn_l1_task(const void *vdata) { const int *data = vdata; + misdn_lib_isdn_l1watcher(*data); chan_misdn_log(5, *data, "L1watcher timeout\n"); return 1; @@ -866,21 +1474,22 @@ static int misdn_overlap_dial_task(const void *data) tv_end.tv_sec += ch->overlap_dial; tv_now = ast_tvnow(); - if ((diff = ast_tvdiff_ms(tv_end, tv_now)) > 100) { + diff = ast_tvdiff_ms(tv_end, tv_now); + if (100 < diff) { return diff; } /* if we are 100ms near the timeout, we are satisfied.. */ stop_indicate(ch); - if (ast_strlen_zero(ch->bc->dad)) { + if (ast_strlen_zero(ch->bc->dialed.number)) { dad = "s"; - ast_copy_string(ch->ast->exten, "s", sizeof(ch->ast->exten)); + strcpy(ch->ast->exten, dad); } else { - dad = ch->bc->dad; + dad = ch->bc->dialed.number; } - if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) { ch->state = MISDN_DIALING; if (pbx_start_chan(ch) < 0) { chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n"); @@ -957,8 +1566,10 @@ static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct level = 1; } else if (!strcasecmp(a->argv[3], "off")) { level = 0; - } else { + } else if (isdigit(a->argv[3][0])) { level = atoi(a->argv[3]); + } else { + return CLI_SHOWUSAGE; } switch (a->argc) { @@ -1293,27 +1904,29 @@ struct state_struct { }; static struct state_struct state_array[] = { +/* *INDENT-OFF* */ { MISDN_NOTHING, "NOTHING" }, /* at beginning */ - { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */ - { MISDN_EXTCANTMATCH, "EXTCANTMATCH" }, /* when asterisk couldn't match our ext */ - { MISDN_INCOMING_SETUP, "INCOMING SETUP" }, /* when pbx_start */ - { MISDN_DIALING, "DIALING" }, /* when pbx_start */ - { MISDN_PROGRESS, "PROGRESS" }, /* when pbx_start */ - { MISDN_PROCEEDING, "PROCEEDING" }, /* when pbx_start */ - { MISDN_CALLING, "CALLING" }, /* when misdn_call is called */ - { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */ - { MISDN_ALERTING, "ALERTING" }, /* when Alerting */ - { MISDN_BUSY, "BUSY" }, /* when BUSY */ - { MISDN_CONNECTED, "CONNECTED" }, /* when connected */ - { MISDN_PRECONNECTED, "PRECONNECTED" }, /* when connected */ - { MISDN_DISCONNECTED, "DISCONNECTED" }, /* when connected */ - { MISDN_RELEASED, "RELEASED" }, /* when connected */ - { MISDN_BRIDGED, "BRIDGED" }, /* when bridged */ + { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */ + { MISDN_EXTCANTMATCH, "EXTCANTMATCH" }, /* when asterisk couldn't match our ext */ + { MISDN_INCOMING_SETUP, "INCOMING SETUP" }, /* when pbx_start */ + { MISDN_DIALING, "DIALING" }, /* when pbx_start */ + { MISDN_PROGRESS, "PROGRESS" }, /* when pbx_start */ + { MISDN_PROCEEDING, "PROCEEDING" }, /* when pbx_start */ + { MISDN_CALLING, "CALLING" }, /* when misdn_call is called */ + { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */ + { MISDN_ALERTING, "ALERTING" }, /* when Alerting */ + { MISDN_BUSY, "BUSY" }, /* when BUSY */ + { MISDN_CONNECTED, "CONNECTED" }, /* when connected */ + { MISDN_PRECONNECTED, "PRECONNECTED" }, /* when connected */ + { MISDN_DISCONNECTED, "DISCONNECTED" }, /* when connected */ + { MISDN_RELEASED, "RELEASED" }, /* when connected */ + { MISDN_BRIDGED, "BRIDGED" }, /* when bridged */ { MISDN_CLEANING, "CLEANING" }, /* when hangup from * but we were connected before */ - { MISDN_HUNGUP_FROM_MISDN, "HUNGUP_FROM_MISDN" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ - { MISDN_HOLDED, "HOLDED" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ - { MISDN_HOLD_DISCONNECT, "HOLD_DISCONNECT" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ + { MISDN_HUNGUP_FROM_MISDN, "HUNGUP_FROM_MISDN" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ + { MISDN_HOLDED, "HOLDED" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ + { MISDN_HOLD_DISCONNECT, "HOLD_DISCONNECT" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ { MISDN_HUNGUP_FROM_AST, "HUNGUP_FROM_AST" }, /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */ +/* *INDENT-ON* */ }; static const char *misdn_get_ch_state(struct chan_list *p) @@ -1384,18 +1997,24 @@ static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct as static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc) { struct ast_channel *ast = help->ast; - ast_cli(fd, - "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n", - bc->pid, bc->port, bc->channel, + ast_cli(fd, + "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n" + " --> caller:\"%s\" <%s>\n" + " --> redirecting:\"%s\" <%s>\n" + " --> context:%s state:%s\n", + bc->pid, + bc->port, + bc->channel, bc->nt ? "NT" : "TE", help->originator == ORG_AST ? "*" : "I", - ast ? ast->exten : NULL, - ast ? ast->cid.cid_num : NULL, - bc->rad, - ast ? ast->context : NULL, - misdn_get_ch_state(help) - ); + ast ? ast->exten : "", + (ast && ast->cid.cid_name) ? ast->cid.cid_name : "", + (ast && ast->cid.cid_num) ? ast->cid.cid_num : "", + bc->redirecting.from.name, + bc->redirecting.from.number, + ast ? ast->context : "", + misdn_get_ch_state(help)); if (misdn_debug[bc->port] > 0) { ast_cli(fd, " --> astname: %s\n" @@ -1418,21 +2037,18 @@ static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel help->l3id, help->addr, bc->addr, - bc ? bc->l3_id : -1, + bc->l3_id, bc->display, - bc->active, bc_state2str(bc->bc_state), bearer2str(bc->capability), #ifdef MISDN_1_2 bc->pipeline, #else - bc->ec_enable, + bc->ec_enable, #endif - help->norxtone, help->notxtone, - bc->holded - ); + bc->holded); } } @@ -1480,15 +2096,17 @@ static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, st if (help->state == MISDN_HOLDED) { ast_cli(a->fd, "ITS A HOLDED BC:\n"); ast_cli(a->fd, " --> l3_id: %x\n" - " --> dad:%s oad:%s\n" - " --> hold_port: %d\n" - " --> hold_channel: %d\n", - help->l3id, - ast->exten, - ast->cid.cid_num, - help->hold_info.port, - help->hold_info.channel - ); + " --> dialed:%s\n" + " --> caller:\"%s\" <%s>\n" + " --> hold_port: %d\n" + " --> hold_channel: %d\n", + help->l3id, + ast->exten, + ast->cid.cid_name ? ast->cid.cid_name : "", + ast->cid.cid_num ? ast->cid.cid_num : "", + help->hold_info.port, + help->hold_info.channel + ); } else { ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num); } @@ -1693,7 +2311,7 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st return 0; } tmp->bc->fac_out.Function = Fac_CD; - ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber)); + ast_copy_string((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber)); misdn_lib_send_event(tmp->bc, EVENT_FACILITY); } else if (strstr(a->argv[3], "CFActivate")) { if (a->argc < 7) { @@ -1718,7 +2336,7 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st } else if (strstr(a->argv[3], "CFDeactivate")) { if (a->argc < 6) { - ast_verbose("CFActivate requires 1 arg: FromNumber\n\n"); + ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n"); return 0; } port = atoi(a->argv[4]); @@ -1728,10 +2346,10 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr); bc->fac_out.Function = Fac_CFDeactivate; - bc->fac_out.u.CFDeactivate.BasicService = 0; //All Services - bc->fac_out.u.CFDeactivate.Procedure = 0; //Unconditional + bc->fac_out.u.CFDeactivate.BasicService = 0; /* All Services */ + bc->fac_out.u.CFDeactivate.Procedure = 0; /* Unconditional */ + ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber)); - ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber)); misdn_lib_send_event(bc, EVENT_FACILITY); } @@ -2009,23 +2627,25 @@ static struct ast_cli_entry chan_misdn_clis[] = { }; /*! \brief Updates caller ID information from config */ -static int update_config(struct chan_list *ch, int orig) +static void update_config(struct chan_list *ch) { struct ast_channel *ast; struct misdn_bchannel *bc; - int port, hdlc = 0; - int pres, screen; + int port; + int hdlc = 0; + int pres; + int screen; if (!ch) { ast_log(LOG_WARNING, "Cannot configure without chanlist\n"); - return -1; + return; } ast = ch->ast; bc = ch->bc; if (! ast || ! bc) { ast_log(LOG_WARNING, "Cannot configure without ast || bc\n"); - return -1; + return; } port = bc->port; @@ -2033,7 +2653,6 @@ static int update_config(struct chan_list *ch, int orig) chan_misdn_log(7, port, "update_config: Getting Config\n"); misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); - if (hdlc) { switch (bc->capability) { case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: @@ -2050,48 +2669,17 @@ static int update_config(struct chan_list *ch, int orig) chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen); if (pres < 0 || screen < 0) { - chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres); + chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number_presentation); - switch (ast->cid.cid_pres & 0x60) { - case AST_PRES_RESTRICTED: - bc->pres = 1; - chan_misdn_log(2, port, " --> PRES: Restricted (1)\n"); - break; - case AST_PRES_UNAVAILABLE: - bc->pres = 2; - chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n"); - break; - default: - bc->pres = 0; - chan_misdn_log(2, port, " --> PRES: Allowed (0)\n"); - break; - } + bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation); + chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation); - switch (ast->cid.cid_pres & 0x3) { - default: - case AST_PRES_USER_NUMBER_UNSCREENED: - bc->screen = 0; - chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n"); - break; - case AST_PRES_USER_NUMBER_PASSED_SCREEN: - bc->screen = 1; - chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n"); - break; - case AST_PRES_USER_NUMBER_FAILED_SCREEN: - bc->screen = 2; - chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n"); - break; - case AST_PRES_NETWORK_NUMBER: - bc->screen = 3; - chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n"); - break; - } + bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation); + chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening); } else { - bc->screen = screen; - bc->pres = pres; + bc->caller.screening = screen; + bc->caller.presentation = pres; } - - return 0; } @@ -2130,20 +2718,26 @@ static void config_jitterbuffer(struct chan_list *ch) } -void debug_numplan(int port, int numplan, char *type) +void debug_numtype(int port, int numtype, char *type) { - switch (numplan) { - case NUMPLAN_INTERNATIONAL: + switch (numtype) { + case NUMTYPE_UNKNOWN: + chan_misdn_log(2, port, " --> %s: Unknown\n", type); + break; + case NUMTYPE_INTERNATIONAL: chan_misdn_log(2, port, " --> %s: International\n", type); break; - case NUMPLAN_NATIONAL: + case NUMTYPE_NATIONAL: chan_misdn_log(2, port, " --> %s: National\n", type); break; - case NUMPLAN_SUBSCRIBER: + case NUMTYPE_NETWORK_SPECIFIC: + chan_misdn_log(2, port, " --> %s: Network Specific\n", type); + break; + case NUMTYPE_SUBSCRIBER: chan_misdn_log(2, port, " --> %s: Subscriber\n", type); break; - case NUMPLAN_UNKNOWN: - chan_misdn_log(2, port, " --> %s: Unknown\n", type); + case NUMTYPE_ABBREVIATED: + chan_misdn_log(2, port, " --> %s: Abbreviated\n", type); break; /* Maybe we should cut off the prefix if present ? */ default: @@ -2193,7 +2787,7 @@ static int update_ec_config(struct misdn_bchannel *bc) #endif -static int read_config(struct chan_list *ch, int orig) +static int read_config(struct chan_list *ch) { struct ast_channel *ast; struct misdn_bchannel *bc; @@ -2234,7 +2828,6 @@ static int read_config(struct chan_list *ch, int orig) misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf)); misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int)); - if (ch->ast_dsp) { ch->ignore_dtmf = 1; } @@ -2251,7 +2844,6 @@ static int read_config(struct chan_list *ch, int orig) misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect)); misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc)); - if (hdlc) { switch (bc->capability) { case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: @@ -2280,14 +2872,16 @@ static int read_config(struct chan_list *ch, int orig) misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect)); + misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected)); + misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup)); + misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); - chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg)); ast->pickupgroup = pg; ast->callgroup = cg; - if (orig == ORG_AST) { + if (ch->originator == ORG_AST) { char callerid[BUFFERSIZE + 1]; /* ORIGINATOR Asterisk (outgoing call) */ @@ -2300,80 +2894,46 @@ static int read_config(struct chan_list *ch, int orig) misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid)); if (!ast_strlen_zero(callerid)) { - chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid); - ast_copy_string(bc->oad, callerid, sizeof(bc->oad)); + char *cid_name = NULL; + char *cid_num = NULL; + + ast_callerid_parse(callerid, &cid_name, &cid_num); + if (cid_name) { + ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name)); + } else { + bc->caller.name[0] = '\0'; + } + if (cid_num) { + ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number)); + } else { + bc->caller.number[0] = '\0'; + } + chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number); } - misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(bc->dnumplan)); - misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(bc->onumplan)); - misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan)); - debug_numplan(port, bc->dnumplan, "TON"); - debug_numplan(port, bc->onumplan, "LTON"); - debug_numplan(port, bc->cpnnumplan, "CTON"); + misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type)); + bc->dialed.number_plan = NUMPLAN_ISDN; + debug_numtype(port, bc->dialed.number_type, "TON"); ch->overlap_dial = 0; } else { /* ORIGINATOR MISDN (incoming call) */ - char prefix[BUFFERSIZE + 1] = ""; if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) { ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1; } - misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan)); - debug_numplan(port, bc->cpnnumplan, "CTON"); - - switch (bc->onumplan) { - case NUMPLAN_INTERNATIONAL: - misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix)); - break; + /* Add configured prefix to caller.number */ + misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number)); - case NUMPLAN_NATIONAL: - misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix)); - break; - default: - break; - } - - ast_copy_string(buf, bc->oad, sizeof(buf)); - snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf); - - if (!ast_strlen_zero(bc->dad)) { - ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad)); + if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) { + ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number)); } - if (ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) { - ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad)); - } + /* Add configured prefix to dialed.number */ + misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number)); - prefix[0] = 0; - - switch (bc->dnumplan) { - case NUMPLAN_INTERNATIONAL: - misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix)); - break; - case NUMPLAN_NATIONAL: - misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix)); - break; - default: - break; - } - - ast_copy_string(buf, bc->dad, sizeof(buf)); - snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf); - - if (strcmp(bc->dad, ast->exten)) { - ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten)); - } - - ast_set_callerid(ast, bc->oad, NULL, bc->oad); - - if ( !ast_strlen_zero(bc->rad) ) { - if (ast->cid.cid_rdnis) { - ast_free(ast->cid.cid_rdnis); - } - ast->cid.cid_rdnis = ast_strdup(bc->rad); - } + ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten)); misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial)); ast_mutex_init(&ch->overlap_tv_lock); @@ -2400,6 +2960,79 @@ static int read_config(struct chan_list *ch, int orig) return 0; } +/*! + * \internal + * \brief Notify peer that the connected line has changed. + * + * \param ast Current Asterisk channel + * \param bc Associated B channel + * \param originator Who originally created this channel. ORG_AST or ORG_MISDN + * + * \return Nothing + */ +static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator) +{ + int number_type; + + if (originator == ORG_MISDN) { + /* ORIGINATOR MISDN (incoming call) */ + + ast_copy_string(bc->connected.name, S_OR(ast->connected.id.name, ""), sizeof(bc->connected.name)); + ast_copy_string(bc->connected.number, S_OR(ast->connected.id.number, ""), sizeof(bc->connected.number)); + bc->connected.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation); + bc->connected.screening = ast_to_misdn_screen(ast->connected.id.number_presentation); + + misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type)); + if (number_type < 0) { + bc->connected.number_type = ast_to_misdn_ton(ast->connected.id.number_type); + bc->connected.number_plan = ast_to_misdn_plan(ast->connected.id.number_type); + } else { + /* Force us to send in CONNECT message */ + bc->connected.number_type = number_type; + bc->connected.number_plan = NUMPLAN_ISDN; + } + debug_numtype(bc->port, bc->connected.number_type, "CTON"); + } else { + /* ORIGINATOR Asterisk (outgoing call) */ + + ast_copy_string(bc->caller.name, S_OR(ast->connected.id.name, ""), sizeof(bc->caller.name)); + ast_copy_string(bc->caller.number, S_OR(ast->connected.id.number, ""), sizeof(bc->caller.number)); + bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation); + bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation); + + misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type)); + if (number_type < 0) { + bc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type); + bc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type); + } else { + /* Force us to send in SETUP message */ + bc->caller.number_type = number_type; + bc->caller.number_plan = NUMPLAN_ISDN; + } + debug_numtype(bc->port, bc->caller.number_type, "LTON"); + } +} + +/*! + * \internal + * \brief Copy the redirecting info out of the Asterisk channel + * + * \param bc Associated B channel + * \param ast Current Asterisk channel + * + * \return Nothing + */ +static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast) +{ + ast_copy_string(bc->redirecting.from.name, S_OR(ast->redirecting.from.name, ""), sizeof(bc->redirecting.from.name)); + ast_copy_string(bc->redirecting.from.number, S_OR(ast->cid.cid_rdnis, ""), sizeof(bc->redirecting.from.number)); + bc->redirecting.from.presentation = ast_to_misdn_pres(ast->redirecting.from.number_presentation); + bc->redirecting.from.screening = ast_to_misdn_screen(ast->redirecting.from.number_presentation); + bc->redirecting.from.number_type = ast_to_misdn_ton(ast->redirecting.from.number_type); + bc->redirecting.from.number_plan = ast_to_misdn_plan(ast->redirecting.from.number_type); + bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason); +} + /*****************************/ /*** AST Indications Start ***/ @@ -2411,22 +3044,17 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) int r; int exceed; int bridging; - struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(ast); + int number_type; + struct chan_list *ch; struct misdn_bchannel *newbc; - char *dest_cp = ast_strdupa(dest); + char *dest_cp; + AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(type); - AST_APP_ARG(ext); - AST_APP_ARG(opts); + AST_APP_ARG(intf); /* The interface token is discarded. */ + AST_APP_ARG(ext); /* extension token */ + AST_APP_ARG(opts); /* options token */ ); - AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/'); - - if (ast_strlen_zero(args.ext)) { - chan_misdn_log(0, 0, "misdn_call: No Extension given!\n"); - return -1; - } - if (!ast) { ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n"); return -1; @@ -2439,47 +3067,74 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) return -1; } + ch = MISDN_ASTERISK_TECH_PVT(ast); if (!ch) { - ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); + ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast->name); ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; ast_setstate(ast, AST_STATE_DOWN); return -1; } newbc = ch->bc; - if (!newbc) { - ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); + ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast->name); ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; ast_setstate(ast, AST_STATE_DOWN); return -1; } + /* + * dest is ---v + * Dial(mISDN/g:group_name[/extension[/options]]) + * Dial(mISDN/port[:preselected_channel][/extension[/options]]) + * + * The dial extension could be empty if you are using MISDN_KEYPAD + * to control ISDN provider features. + */ + dest_cp = ast_strdupa(dest); + AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/'); + if (!args.ext) { + args.ext = ""; + } + port = newbc->port; - if ((exceed = add_out_calls(port))) { + exceed = add_out_calls(port); + if (exceed != 0) { char tmp[16]; snprintf(tmp, sizeof(tmp), "%d", exceed); pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp); + ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; + ast_setstate(ast, AST_STATE_DOWN); return -1; } chan_misdn_log(1, port, "* CALL: %s\n", dest); - chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context); + chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context); - chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten); - if (ast->exten) { - ast_copy_string(ast->exten, args.ext, sizeof(ast->exten)); - ast_copy_string(newbc->dad, args.ext, sizeof(newbc->dad)); - } + ast_copy_string(ast->exten, args.ext, sizeof(ast->exten)); + ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number)); - ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad)); + if (ast_strlen_zero(newbc->caller.name) && !ast_strlen_zero(ast->connected.id.name)) { + ast_copy_string(newbc->caller.name, ast->connected.id.name, sizeof(newbc->caller.name)); + chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number); + } + if (ast_strlen_zero(newbc->caller.number) && !ast_strlen_zero(ast->connected.id.number)) { + ast_copy_string(newbc->caller.number, ast->connected.id.number, sizeof(newbc->caller.number)); + chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number); + } - chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num); - if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) { - ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad)); + misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type)); + if (number_type < 0) { + newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type); + newbc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type); + } else { + /* Force us to send in SETUP message */ + newbc->caller.number_type = number_type; + newbc->caller.number_plan = NUMPLAN_ISDN; } + debug_numtype(port, newbc->caller.number_type, "LTON"); newbc->capability = ast->transfercapability; pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability)); @@ -2487,10 +3142,10 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) chan_misdn_log(2, port, " --> * Call with flag Digital\n"); } - /* update screening and presentation */ - update_config(ch, ORG_AST); + /* update caller screening and presentation */ + update_config(ch); - /* fill in some ies from channel vary */ + /* fill in some ies from channel dialplan variables */ import_ch(ast, newbc, ch); /* Finally The Options Override Everything */ @@ -2499,6 +3154,11 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) } else { chan_misdn_log(2, port, "NO OPTS GIVEN\n"); } + if (newbc->set_presentation) { + newbc->caller.presentation = newbc->presentation; + } + + misdn_copy_redirecting_from_ast(newbc, ast); /*check for bridging*/ misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging)); @@ -2519,7 +3179,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) /** we should have l3id after sending setup **/ ch->l3id = newbc->l3_id; - if (r == -ENOCHAN ) { + if (r == -ENOCHAN) { chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n"); chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1); ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; @@ -2585,9 +3245,19 @@ static int misdn_answer(struct ast_channel *ast) p->state = MISDN_CONNECTED; stop_indicate(p); - if ( ast_strlen_zero(p->bc->cad) ) { - chan_misdn_log(2, p->bc->port, " --> empty cad using dad\n"); - ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad)); + if (ast_strlen_zero(p->bc->connected.number)) { + chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n"); + ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number)); + + /* + * Use the misdn_set_opt() application to set the presentation + * before we answer or you can use the CONECTEDLINE() function + * to set everything before using the Answer() application. + */ + p->bc->connected.presentation = p->bc->presentation; + p->bc->connected.screening = 0; /* unscreened */ + p->bc->connected.number_type = p->bc->dialed.number_type; + p->bc->connected.number_plan = p->bc->dialed.number_plan; } misdn_lib_send_event(p->bc, EVENT_CONNECT); @@ -2628,15 +3298,15 @@ static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int dur break; case MISDN_CALLING_ACKNOWLEDGE: ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad)); - if (strlen(bc->dad) < sizeof(bc->dad) - 1) { - strncat(bc->dad, buf, sizeof(bc->dad) - strlen(bc->dad) - 1); + if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) { + strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); } - ast_copy_string(p->ast->exten, bc->dad, sizeof(p->ast->exten)); + ast_copy_string(p->ast->exten, bc->dialed.number, sizeof(p->ast->exten)); misdn_lib_send_event(bc, EVENT_INFORMATION); break; default: /* Do not send Digits in CONNECTED State, when - * the other side is too mISDN. */ + * the other side is also mISDN. */ if (p->other_ch) { return 0; } @@ -2687,7 +3357,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data, switch (cond) { case AST_CONTROL_BUSY: - chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid); ast_setstate(ast, AST_STATE_BUSY); p->bc->out_cause = AST_CAUSE_USER_BUSY; @@ -2699,20 +3369,20 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data, } return -1; case AST_CONTROL_RING: - chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc->pid); return -1; case AST_CONTROL_RINGING: - chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc->pid); switch (p->state) { case MISDN_ALERTING: - chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc->pid); break; case MISDN_CONNECTED: - chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1); + chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc->pid); return -1; default: p->state = MISDN_ALERTING; - chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc->pid); misdn_lib_send_event( p->bc, EVENT_ALERTING); if (p->other_ch && p->other_ch->bc) { @@ -2727,7 +3397,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data, } } - chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc->pid); ast_setstate(ast, AST_STATE_RING); if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) { @@ -2738,28 +3408,28 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data, } break; case AST_CONTROL_ANSWER: - chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc->pid); start_bc_tones(p); break; case AST_CONTROL_TAKEOFFHOOK: - chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc->pid); return -1; case AST_CONTROL_OFFHOOK: - chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc->pid); return -1; case AST_CONTROL_FLASH: - chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc->pid); break; case AST_CONTROL_PROGRESS: - chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc->pid); misdn_lib_send_event( p->bc, EVENT_PROGRESS); break; case AST_CONTROL_PROCEEDING: - chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc->pid); misdn_lib_send_event( p->bc, EVENT_PROCEEDING); break; case AST_CONTROL_CONGESTION: - chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid); p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION; start_bc_tones(p); @@ -2770,7 +3440,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data, } break; case -1 : - chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid); stop_indicate(p); @@ -2780,14 +3450,23 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data, break; case AST_CONTROL_HOLD: ast_moh_start(ast, data, p->mohinterpret); - chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid); break; case AST_CONTROL_UNHOLD: ast_moh_stop(ast); - chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid); + break; + case AST_CONTROL_CONNECTED_LINE: + chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid); + misdn_update_connected_line(ast, p->bc, p->originator); + break; + case AST_CONTROL_REDIRECTING: + chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid); + misdn_copy_redirecting_from_ast(p->bc, ast); break; default: - chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1); + chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid); + break; } return 0; @@ -2814,8 +3493,10 @@ static int misdn_hangup(struct ast_channel *ast) if (bc) { const char *tmp; + ast_channel_lock(ast); - if ((tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER"))) { + tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER"); + if (tmp) { ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp); strcpy(bc->uu, tmp); bc->uulen = strlen(bc->uu); @@ -2875,11 +3556,17 @@ static int misdn_hangup(struct ast_channel *ast) } ast_channel_unlock(ast); - chan_misdn_log(1, bc->port, "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n", p->bc ? p->bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(p)); + chan_misdn_log(1, bc->port, + "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n", + p->bc ? p->bc->pid : -1, + ast->context, + ast->exten, + ast->cid.cid_name ? ast->cid.cid_name : "", + ast->cid.cid_num ? ast->cid.cid_num : "", + misdn_get_ch_state(p)); chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id); chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause); chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause); - chan_misdn_log(2, bc->port, " --> state:%s\n", misdn_get_ch_state(p)); switch (p->state) { case MISDN_INCOMING_SETUP: @@ -3034,7 +3721,7 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context); } } else { - ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten); + ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten); } } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); @@ -3081,7 +3768,8 @@ static struct ast_frame *misdn_read(struct ast_channel *ast) FD_ZERO(&rrfs); FD_SET(tmp->pipe[0], &rrfs); - if (!(t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv))) { + t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv); + if (!t) { chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n"); len = 160; } @@ -3249,15 +3937,11 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } - - - -static enum ast_bridge_result misdn_bridge (struct ast_channel *c0, - struct ast_channel *c1, int flags, - struct ast_frame **fo, - struct ast_channel **rc, - int timeoutms) - +static enum ast_bridge_result misdn_bridge(struct ast_channel *c0, + struct ast_channel *c1, int flags, + struct ast_frame **fo, + struct ast_channel **rc, + int timeoutms) { struct chan_list *ch1, *ch2; struct ast_channel *carr[2], *who; @@ -3293,7 +3977,11 @@ static enum ast_bridge_result misdn_bridge (struct ast_channel *c0, ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name); - chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad); + chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n", + ch1->bc->caller.name, + ch1->bc->caller.number, + ch2->bc->caller.name, + ch2->bc->caller.number); if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) { ch1->ignore_dtmf = 1; @@ -3342,7 +4030,7 @@ static enum ast_bridge_result misdn_bridge (struct ast_channel *c0, } #endif - ast_write(who == c0 ? c1 : c0, f); + ast_write((who == c0) ? c1 : c0, f); } chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1); @@ -3437,7 +4125,8 @@ static struct chan_list *init_chan_list(int orig) { struct chan_list *cl; - if (!(cl = ast_calloc(1, sizeof(*cl)))) { + cl = ast_calloc(1, sizeof(*cl)); + if (!cl) { chan_misdn_log(-1, 0, "misdn_request: malloc failed!"); return NULL; } @@ -3455,38 +4144,54 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat { struct ast_channel *tmp = NULL; char group[BUFFERSIZE + 1] = ""; - char buf[128]; - char *buf2 = ast_strdupa(data), *ext = NULL, *port_str; - char *tokb = NULL, *p = NULL; - int channel = 0, port = 0; + char dial_str[128]; + char *dest_cp; + char *p = NULL; + int channel = 0; + int port = 0; struct misdn_bchannel *newbc = NULL; int dec = 0; + struct chan_list *cl; - struct chan_list *cl = init_chan_list(ORG_AST); - - snprintf(buf, sizeof(buf), "%s/%s", misdn_type, (char*)data); + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(intf); /* interface token */ + AST_APP_ARG(ext); /* extension token */ + AST_APP_ARG(opts); /* options token */ + ); - port_str = strtok_r(buf2, "/", &tokb); + snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data); - ext = strtok_r(NULL, "/", &tokb); + /* + * data is ---v + * Dial(mISDN/g:group_name[/extension[/options]]) + * Dial(mISDN/port[:preselected_channel][/extension[/options]]) + * + * The dial extension could be empty if you are using MISDN_KEYPAD + * to control ISDN provider features. + */ + dest_cp = ast_strdupa(data); + AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/'); + if (!args.ext) { + args.ext = ""; + } - if (port_str) { - if (port_str[0] == 'g' && port_str[1] == ':' ) { + if (!ast_strlen_zero(args.intf)) { + if (args.intf[0] == 'g' && args.intf[1] == ':' ) { /* We make a group call lets checkout which ports are in my group */ - port_str += 2; - ast_copy_string(group, port_str, sizeof(group)); + args.intf += 2; + ast_copy_string(group, args.intf, sizeof(group)); chan_misdn_log(2, 0, " --> Group Call group: %s\n", group); - } else if ((p = strchr(port_str, ':'))) { + } else if ((p = strchr(args.intf, ':'))) { /* we have a preselected channel */ - *p = 0; - channel = atoi(++p); - port = atoi(port_str); + *p++ = 0; + channel = atoi(p); + port = atoi(args.intf); chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel); } else { - port = atoi(port_str); + port = atoi(args.intf); } } else { - ast_log(LOG_WARNING, " --> ! IND : CALL dad:%s WITHOUT PORT/Group, check extensions.conf\n", ext); + ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str); return NULL; } @@ -3579,7 +4284,8 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat chan_misdn_log(4, port, "portup:%d\n", port_up); if (port_up > 0) { - if ((newbc = misdn_lib_get_free_bc(port, 0, 0, dec))) { + newbc = misdn_lib_get_free_bc(port, 0, 0, dec); + if (newbc) { break; } } @@ -3602,18 +4308,22 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel); } newbc = misdn_lib_get_free_bc(port, channel, 0, dec); - if (!newbc) { - ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext); + ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str); return NULL; } } /* create ast_channel and link all the objects together */ + cl = init_chan_list(ORG_AST); + if (!cl) { + ast_log(LOG_WARNING, "Could not create Asterisk channel for Dial(%s)\n", dial_str); + return NULL; + } cl->bc = newbc; - tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel); + tmp = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, port, channel); if (!tmp) { ast_log(LOG_ERROR, "Could not create Asterisk object\n"); return NULL; @@ -3625,7 +4335,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat cl_queue_chan(&cl_te, cl); /* fill in the config into the objects */ - read_config(cl, ORG_AST); + read_config(cl); /* important */ cl->need_hangup = 0; @@ -3736,7 +4446,7 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++); if (tmp) { - chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid); + chan_misdn_log(2, 0, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid); tmp->nativeformats = prefformat; @@ -3791,7 +4501,11 @@ static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bc } } - chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad); + chan_misdn_log(6, bc->port, + "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n", + bc->dialed.number, + bc->caller.name, + bc->caller.number); return NULL; } @@ -3805,7 +4519,7 @@ static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid) } } - chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid); + chan_misdn_log(6, 0, "$$$ find_chan_by_pid: No channel found for pid:%d\n", pid); return NULL; } @@ -3818,7 +4532,11 @@ static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchann return NULL; } - chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad); + chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d dialed:%s caller:\"%s\" <%s>\n", + bc->channel, + bc->dialed.number, + bc->caller.name, + bc->caller.number); for (; help; help = help->next) { chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state == MISDN_HOLDED, help->hold_info.channel); if ((help->state == MISDN_HOLDED) && @@ -3826,7 +4544,11 @@ static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchann return help; } } - chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad); + chan_misdn_log(6, bc->port, + "$$$ find_holded: No channel found for dialed:%s caller:\"%s\" <%s>\n", + bc->dialed.number, + bc->caller.name, + bc->caller.number); return NULL; } @@ -3947,12 +4669,14 @@ static void hangup_chan(struct chan_list *ch) } /** Isdn asks us to release channel, pendant to misdn_hangup **/ -static void release_chan(struct misdn_bchannel *bc) { +static void release_chan(struct misdn_bchannel *bc) +{ struct ast_channel *ast = NULL; struct chan_list *ch; ast_mutex_lock(&release_lock); - if (!(ch = find_chan_by_bc(cl_te, bc))) { + ch = find_chan_by_bc(cl_te, bc); + if (!ch) { chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n"); ast_mutex_unlock(&release_lock); return; @@ -3965,7 +4689,7 @@ static void release_chan(struct misdn_bchannel *bc) { chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id); /* releasing jitterbuffer */ - if (ch->jb ) { + if (ch->jb) { misdn_jb_destroy(ch->jb); ch->jb = NULL; } else { @@ -3993,7 +4717,14 @@ static void release_chan(struct misdn_bchannel *bc) { close(ch->pipe[1]); if (ast && MISDN_ASTERISK_TECH_PVT(ast)) { - chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n", bc ? bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(ch)); + chan_misdn_log(1, bc->port, + "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s> state: %s\n", + bc->pid, + ast->context, + ast->exten, + ast->cid.cid_name ? ast->cid.cid_name : "", + ast->cid.cid_num ? ast->cid.cid_num : "", + misdn_get_ch_state(ch)); chan_misdn_log(3, bc->port, " --> * State Down\n"); MISDN_ASTERISK_TECH_PVT(ast) = NULL; @@ -4053,9 +4784,14 @@ static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch, ch->state = MISDN_INCOMING_SETUP; } - chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num); + chan_misdn_log(1, bc->port, + "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n", + ast->context, + ast->exten, + ast->cid.cid_name ? ast->cid.cid_name : "", + ast->cid.cid_num ? ast->cid.cid_num : ""); - strncpy(ast->exten, "s", 2); + strcpy(ast->exten, "s"); if (pbx_start_chan(ch) < 0) { ast = NULL; @@ -4183,6 +4919,7 @@ void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_ void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) { char tmp[32]; + chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid); snprintf(tmp, sizeof(tmp), "%d", bc->pid); pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp); @@ -4237,7 +4974,8 @@ int add_out_calls(int port) return 0; } -static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) { +static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) +{ if (pbx_start_chan(ch) < 0) { hangup_chan(ch); chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n"); @@ -4250,10 +4988,11 @@ static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct as } } -static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) { +static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) +{ ch->state = MISDN_WAITING4DIGS; misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); - if (bc->nt && !bc->dad[0]) { + if (bc->nt && !bc->dialed.number[0]) { dialtone_indicate(ch); } } @@ -4273,7 +5012,14 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) debuglevel = 5; } - chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none"); + chan_misdn_log(debuglevel, bc->port, + "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n", + manager_isdn_get_info(event), + bc->caller.name, + bc->caller.number, + bc->dialed.number, + bc->pid, + ch ? misdn_get_ch_state(ch) : "none"); if (debuglevel == 1) { misdn_lib_log_ies(bc); chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state)); @@ -4407,25 +5153,23 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad)); } - strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1); - ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten)); + strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); + ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten)); /* Check for Pickup Request first */ if (!strcmp(ch->ast->exten, ast_pickup_ext())) { if (ast_pickup_call(ch->ast)) { hangup_chan(ch); } else { - struct ast_channel *chan = ch->ast; ch->state = MISDN_CALLING_ACKNOWLEDGE; - ast_setstate(chan, AST_STATE_DOWN); hangup_chan(ch); ch->ast = NULL; break; } } - if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { - if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) { + if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { + if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) { ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port); strcpy(ch->ast->exten, "i"); @@ -4459,7 +5203,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) break; } - if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { ch->state = MISDN_DIALING; start_pbx(ch, bc, ch->ast); } @@ -4482,8 +5226,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits)); if (ch->state != MISDN_CONNECTED ) { if (digits) { - strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1); - ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten)); + strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); + ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten)); ast_cdr_update(ch->ast); } @@ -4494,10 +5238,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) case EVENT_SETUP: { struct chan_list *ch = find_chan_by_bc(cl_te, bc); - int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad); + int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dialed.number); struct ast_channel *chan; int exceed; - int pres, screen; int ai; int im; @@ -4537,10 +5280,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ch->bc = bc; ch->l3id = bc->l3_id; ch->addr = bc->addr; - ch->originator = ORG_MISDN; - - chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel); + chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, bc->port, bc->channel); if (!chan) { misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n"); @@ -4555,49 +5296,44 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp); } - read_config(ch, ORG_MISDN); + read_config(ch); export_ch(chan, bc, ch); ch->ast->rings = 1; ast_setstate(ch->ast, AST_STATE_RINGING); - switch (bc->pres) { - case 1: - pres = AST_PRES_RESTRICTED; - chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n"); - break; - case 2: - pres = AST_PRES_UNAVAILABLE; - chan_misdn_log(2, bc->port, " --> PRES: Unavailable (2)\n"); - break; - default: - pres = AST_PRES_ALLOWED; - chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres); - break; - } + /* Update asterisk channel caller information */ + chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type); + chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan); + chan->cid.cid_ton = misdn_to_ast_ton(bc->caller.number_type) + | misdn_to_ast_plan(bc->caller.number_plan); - switch (bc->screen) { - default: - case 0: - screen = AST_PRES_USER_NUMBER_UNSCREENED; - chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen); - break; - case 1: - screen = AST_PRES_USER_NUMBER_PASSED_SCREEN; - chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n"); - break; - case 2: - screen = AST_PRES_USER_NUMBER_FAILED_SCREEN; - chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n"); - break; - case 3: - screen = AST_PRES_NETWORK_NUMBER; - chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n"); - break; - } + chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation); + chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening); + chan->cid.cid_pres = misdn_to_ast_pres(bc->caller.presentation) + | misdn_to_ast_screen(bc->caller.screening); + + ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number); + + if (!ast_strlen_zero(bc->redirecting.from.number)) { + struct ast_party_redirecting redirecting; - chan->cid.cid_pres = pres | screen; + /* Add configured prefix to redirecting.from.number */ + misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number)); + + /* Update asterisk channel redirecting information */ + ast_party_redirecting_set_init(&redirecting, &chan->redirecting); + redirecting.from.number = bc->redirecting.from.number; + redirecting.from.number_type = + misdn_to_ast_ton(bc->redirecting.from.number_type) + | misdn_to_ast_plan(bc->redirecting.from.number_plan); + redirecting.from.number_presentation = + misdn_to_ast_pres(bc->redirecting.from.presentation) + | misdn_to_ast_screen(bc->redirecting.from.screening); + redirecting.reason = misdn_to_ast_reason(bc->redirecting.reason); + ast_channel_set_redirecting(chan, &redirecting); + } pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability)); chan->transfercapability = bc->capability; @@ -4627,7 +5363,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) break; } } - } /* end for */ + } if (i == ARRAY_LEN(allowed_bearers_array)) { /* We did not find the bearer capability */ chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n", @@ -4652,7 +5388,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) hangup_chan(ch); } else { ch->state = MISDN_CALLING_ACKNOWLEDGE; - ast_setstate(chan, AST_STATE_DOWN); hangup_chan(ch); ch->ast = NULL; break; @@ -4669,16 +5404,16 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) break; } - /* check if we should jump into s when we have no dad */ + /* check if we should jump into s when we have no dialed.number */ misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im)); - if (im && ast_strlen_zero(bc->dad)) { + if (im && ast_strlen_zero(bc->dialed.number)) { do_immediate_setup(bc, ch, chan); break; } chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context); - if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { - if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) { + if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { + if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) { ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port); strcpy(ch->ast->exten, "i"); misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE); @@ -4722,7 +5457,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) * the number is empty, we wait for the ISDN timeout * instead of our own timer. */ - if (ch->overlap_dial && bc->nt && !bc->dad[0] ) { + if (ch->overlap_dial && bc->nt && !bc->dialed.number[0] ) { wait_for_digits(ch, bc, chan); break; } @@ -4747,7 +5482,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) /* If the extension does not exist and we're not TE_PTMP we wait for more digits * without interdigit timeout. * */ - if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { wait_for_digits(ch, bc, chan); break; } @@ -4755,29 +5490,30 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) /* * If the extension exists let's just jump into it. * */ - if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING); ch->state = MISDN_DIALING; start_pbx(ch, bc, chan); break; } - } break; + } case EVENT_SETUP_ACKNOWLEDGE: ch->state = MISDN_CALLING_ACKNOWLEDGE; - if (bc->channel) + if (bc->channel) { update_name(ch->ast,bc->port,bc->channel); + } if (!ast_strlen_zero(bc->infos_pending)) { /* TX Pending Infos */ - strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1); + strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); if (!ch->ast) { break; } - ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten)); + ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten)); ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad)); ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending)); @@ -4842,29 +5578,31 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } break; case EVENT_CONNECT: - { - struct ast_channel *bridged; + { + struct ast_party_connected_line connected; - /*we answer when we've got our very new L3 ID from the NT stack */ - misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE); + /* we answer when we've got our very new L3 ID from the NT stack */ + misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE); - if (!ch->ast) { - break; - } + if (!ch->ast) { + break; + } - bridged = ast_bridged_channel(ch->ast); - stop_indicate(ch); + stop_indicate(ch); - if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) { - struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged); + /* Add configured prefix to connected.number */ + misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number)); + + /* Update the connected line information on the other channel */ + ast_party_connected_line_init(&connected); + connected.id.number = bc->connected.number; + connected.id.number_type = misdn_to_ast_ton(bc->connected.number_type) + | misdn_to_ast_plan(bc->connected.number_plan); + connected.id.number_presentation = misdn_to_ast_pres(bc->connected.presentation) + | misdn_to_ast_screen(bc->connected.screening); + connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + ast_channel_queue_connected_line_update(ch->ast, &connected); - chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad); - if (bridged_ch) { - bridged_ch->bc->cpnnumplan = bc->cpnnumplan; - ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad)); - } - } - } ch->l3id = bc->l3_id; ch->addr = bc->addr; @@ -4874,6 +5612,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ast_queue_control(ch->ast, AST_CONTROL_ANSWER); break; + } case EVENT_CONNECT_ACKNOWLEDGE: ch->l3id = bc->l3_id; ch->addr = bc->addr; @@ -4947,8 +5686,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) stop_bc_tones(ch); hangup_chan(ch); - if (ch) + if (ch) { ch->state = MISDN_CLEANING; + } release_chan(bc); break; @@ -5003,16 +5743,16 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } else { bc->tone_cnt = 0; } - } break; - + } case EVENT_BCHAN_DATA: if (ch->bc->AOCD_need_export) { export_aoc_vars(ch->originator, ch->ast, ch->bc); } if (!misdn_cap_is_speech(ch->bc->capability)) { struct ast_frame frame; - /*In Data Modes we queue frames*/ + + /* In Data Modes we queue frames */ frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */ frame.subclass = AST_FORMAT_ALAW; frame.datalen = bc->bframe_len; @@ -5023,8 +5763,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) frame.src = NULL; frame.data.ptr = bc->bframe; - if (ch->ast) + if (ch->ast) { ast_queue_frame(ch->ast, &frame); + } } else { fd_set wrfs; struct timeval tv = { 0, 0 }; @@ -5099,6 +5840,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) break; default: misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE); + break; } break; @@ -5137,8 +5879,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n"); misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT); } - } break; + } case EVENT_HOLD: { int hold_allowed; @@ -5171,8 +5913,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) misdn_lib_send_event(bc, EVENT_HOLD_REJECT); chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n"); } - } break; + } case EVENT_FACILITY: print_facility(&(bc->fac_in), bc); @@ -5189,7 +5931,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ch_br = MISDN_ASTERISK_TECH_PVT(bridged); /*ch->state = MISDN_FACILITY_DEFLECTED;*/ if (ch_br->bc) { - if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) { + if (ast_exists_extension(bridged, ch->context, (char *) bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->caller.number)) { ch_br->state = MISDN_DIALING; if (pbx_start_chan(ch_br) < 0) { chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n"); @@ -5461,6 +6203,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data) { struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan); char *parse; + AST_DECLARE_APP_ARGS(args, AST_APP_ARG(facility_type); AST_APP_ARG(arg)[99]; @@ -5473,7 +6216,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data) return -1; } - if (ast_strlen_zero((char *)data)) { + if (ast_strlen_zero((char *) data)) { ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n"); return -1; } @@ -5492,7 +6235,9 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data) } if (strlen(args.arg[0]) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) { - ast_log(LOG_WARNING, "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n", (int)sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)); + ast_log(LOG_WARNING, + "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n", + (int) sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)); return 0; } ch->bc->fac_out.Function = Fac_CD; @@ -5516,11 +6261,11 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data) int port_up; AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(grouppar); - AST_APP_ARG(timeout); + AST_APP_ARG(grouppar); + AST_APP_ARG(timeout); ); - if (ast_strlen_zero((char *)data)) { + if (ast_strlen_zero((char *) data)) { ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n"); return -1; } @@ -5543,7 +6288,7 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data) ast_copy_string(group, port_str, sizeof(group)); chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group); - for ( port = misdn_cfg_get_next_port(port); + for (port = misdn_cfg_get_next_port(port); port > 0; port = misdn_cfg_get_next_port(port)) { char cfg_group[BUFFERSIZE + 1]; @@ -5554,7 +6299,6 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data) if (!strcasecmp(cfg_group, group)) { port_up = misdn_lib_port_up(port, 1); - if (!port_up) { chan_misdn_log(2, 0, " --> port '%d'\n", port); misdn_lib_get_port_up(port); @@ -5752,12 +6496,15 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]); /* CRICH: callingpres!!! */ if (strstr(tok, "allowed")) { - ch->bc->pres = 0; + ch->bc->presentation = 0; + ch->bc->set_presentation = 1; } else if (strstr(tok, "restricted")) { - ch->bc->pres = 1; + ch->bc->presentation = 1; + ch->bc->set_presentation = 1; } else if (strstr(tok, "not_screened")) { chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n"); - ch->bc->pres = 1; + ch->bc->presentation = 1; + ch->bc->set_presentation = 1; } break; case 'i' : @@ -5975,16 +6722,10 @@ int misdn_jb_empty(struct misdn_jb *jb, char *data, int len) return read; } - - - /*******************************************************/ /*************** JITTERBUFFER END *********************/ /*******************************************************/ - - - static void chan_misdn_log(int level, int port, char *tmpl, ...) { va_list ap; @@ -6005,7 +6746,6 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...) if (level == -1) { ast_log(LOG_WARNING, "%s", buf); - } else if (misdn_debug_only[port] ? (level == 1 && misdn_debug[port]) || (level == misdn_debug[port]) : level <= misdn_debug[port]) { @@ -6021,7 +6761,8 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...) FILE *fp = fopen(global_tracefile, "a+"); - if ((p = strchr(tmp, '\n'))) { + p = strchr(tmp, '\n'); + if (p) { *p = ':'; } diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 82a37cc36..dd1578cb8 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -303,13 +303,13 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout) snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min); } /* the standard format of ast->callerid is: "name" <number>, but not always complete */ - if (ast_strlen_zero(ast->cid.cid_name)) + if (ast_strlen_zero(ast->connected.id.name)) strcpy(cid.name, DEFAULT_CALLER_ID); else - ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name)); + ast_copy_string(cid.name, ast->connected.id.name, sizeof(cid.name)); - if (ast->cid.cid_num) - ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number)); + if (ast->connected.id.number) + ast_copy_string(cid.number, ast->connected.id.number, sizeof(cid.number)); p = ast->tech_pvt; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4fb164f9c..10883c5f3 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -942,6 +942,54 @@ static const struct cfsip_options { { SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED, "tdialog" }, }; +/*! \brief Diversion header reasons + * + * The core defines a bunch of constants used to define + * redirecting reasons. This provides a translation table + * between those and the strings which may be present in + * a SIP Diversion header + */ +static const struct sip_reasons { + enum AST_REDIRECTING_REASON code; + char * const text; +} sip_reason_table[] = { + { AST_REDIRECTING_REASON_UNKNOWN, "unknown" }, + { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" }, + { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" }, + { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" }, + { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" }, + { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" }, + { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" }, + { AST_REDIRECTING_REASON_DEFLECTION, "deflection" }, + { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" }, + { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" }, + { AST_REDIRECTING_REASON_AWAY, "away" }, + { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"} +}; + +static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text) +{ + enum AST_REDIRECTING_REASON ast = AST_REDIRECTING_REASON_UNKNOWN; + int i; + + for (i = 0; i < ARRAY_LEN(sip_reason_table); ++i) { + if (!strcasecmp(text, sip_reason_table[i].text)) { + ast = sip_reason_table[i].code; + break; + } + } + + return ast; +} + +static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code) +{ + if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) { + return sip_reason_table[code].text; + } + + return "unknown"; +} /*! \brief SIP Methods we support \todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have @@ -1354,7 +1402,10 @@ struct sip_auth { #define SIP_PROG_INBAND_NO (1 << 25) #define SIP_PROG_INBAND_YES (2 << 25) -#define SIP_SENDRPID (1 << 29) /*!< DP: Remote Party-ID Support */ +#define SIP_SENDRPID (3 << 29) /*!< DP: Remote Party-ID Support */ +#define SIP_SENDRPID_NO (0 << 29) +#define SIP_SENDRPID_PAI (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */ +#define SIP_SENDRPID_RPID (2 << 29) /*!< Use "Remote-Party-ID" for rpid */ #define SIP_G726_NONSTANDARD (1 << 31) /*!< DP: Use non-standard packing for G726-32 data */ /*! \brief Flags to copy from peer/user to dialog */ @@ -1373,6 +1424,9 @@ struct sip_auth { /* Space for addition of other realtime flags in the future */ #define SIP_PAGE2_STATECHANGEQUEUE (1 << 9) /*!< D: Unsent state pending change exists */ +#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 10) +#define SIP_PAGE2_RPID_IMMEDIATE (1 << 11) + #define SIP_PAGE2_PREFERRED_CODEC (1 << 13) /*!< GDP: Only respond with single most preferred joint codec */ #define SIP_PAGE2_VIDEOSUPPORT (1 << 14) /*!< DP: Video supported if offered? */ #define SIP_PAGE2_TEXTSUPPORT (1 << 15) /*!< GDP: Global text enable */ @@ -1403,7 +1457,8 @@ struct sip_auth { (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \ SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | \ SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \ - SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC) + SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \ + SIP_PAGE2_RPID_IMMEDIATE) /*@}*/ @@ -1611,8 +1666,6 @@ struct sip_pvt { AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */ /* we only store the part in <brackets> in this field. */ AST_STRING_FIELD(our_contact); /*!< Our contact header */ - AST_STRING_FIELD(rpid); /*!< Our RPID header */ - AST_STRING_FIELD(rpid_from); /*!< Our RPID From header */ AST_STRING_FIELD(url); /*!< URL to be sent with next message to peer */ AST_STRING_FIELD(parkinglot); /*!< Parkinglot */ AST_STRING_FIELD(engine); /*!< RTP engine to use */ @@ -2237,7 +2290,7 @@ static int transmit_response_using_temp(ast_string_field callid, struct sockaddr static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req); static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req); static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req); -static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp); +static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid); static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported); static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale); static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); @@ -2258,7 +2311,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno); static void copy_request(struct sip_request *dst, const struct sip_request *src); static void receive_message(struct sip_pvt *p, struct sip_request *req); -static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req); +static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward); static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only); /*--- Dialog management */ @@ -2506,11 +2559,14 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req); static int set_address_from_contact(struct sip_pvt *pvt); static void check_via(struct sip_pvt *p, struct sip_request *req); static char *get_calleridname(const char *input, char *output, size_t outputsize); -static int get_rpid_num(const char *input, char *output, int maxlen); -static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq); +static int get_rpid(struct sip_pvt *p, struct sip_request *oreq); +static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason); static int get_destination(struct sip_pvt *p, struct sip_request *oreq); static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline); static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout); +static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen); +static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen); +static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward); /*-- TCP connection handling ---*/ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session); @@ -2537,6 +2593,7 @@ static int add_header_contentLength(struct sip_request *req, int len); static int add_line(struct sip_request *req, const char *line); static int add_text(struct sip_request *req, const char *text); static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode); +static int add_rpid(struct sip_request *req, struct sip_pvt *p); static int add_vidupdate(struct sip_request *req); static void add_route(struct sip_request *req, struct sip_route *route); static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field); @@ -2545,7 +2602,6 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st static void set_destination(struct sip_pvt *p, char *uri); static void append_date(struct sip_request *req); static void build_contact(struct sip_pvt *p); -static void build_rpid(struct sip_pvt *p); /*------Request handling functions */ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock); @@ -4808,6 +4864,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) ast_string_field_set(dialog, tohost, peer->tohost); ast_string_field_set(dialog, fullcontact, peer->fullcontact); ast_string_field_set(dialog, context, peer->context); + ast_string_field_set(dialog, cid_num, peer->cid_num); + ast_string_field_set(dialog, cid_name, peer->cid_name); ast_string_field_set(dialog, parkinglot, peer->parkinglot); ast_string_field_set(dialog, engine, peer->engine); ref_proxy(dialog, obproxy_get(dialog, peer)); @@ -5072,11 +5130,13 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout) p->t38.jointcapability = p->t38.capability; ast_debug(2, "Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability); + sip_pvt_lock(p); xmitres = transmit_invite(p, SIP_INVITE, 1, 2); + sip_pvt_unlock(p); if (xmitres == XMIT_ERROR) return -1; p->invitestate = INV_CALLING; - + /* Initialize auto-congest time */ AST_SCHED_REPLACE_UNREF(p->initid, sched, p->timer_b, auto_congest, p, dialog_unref(_data, "dialog ptr dec when SCHED_REPLACE del op succeeded"), @@ -5810,7 +5870,7 @@ static int sip_answer(struct ast_channel *ast) change_t38_state(p, T38_ENABLED); } ast_rtp_instance_new_source(p->rtp); - res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE); + res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE, TRUE); ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); } sip_pvt_unlock(p); @@ -5846,8 +5906,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { ast_rtp_instance_new_source(p->rtp); p->invitestate = INV_EARLY_MEDIA; - transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); + transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); + ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); } else if (p->t38.state == T38_ENABLED && !p->t38.direct) { change_t38_state(p, T38_DISABLED); transmit_reinvite_with_sdp(p, FALSE, FALSE); @@ -5868,8 +5928,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { p->invitestate = INV_EARLY_MEDIA; - transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); + transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); + ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); } p->lastrtptx = time(NULL); res = ast_rtp_instance_write(p->vrtp, frame); @@ -5889,8 +5949,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { p->invitestate = INV_EARLY_MEDIA; - transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); + transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); + ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); } p->lastrtptx = time(NULL); res = ast_rtp_instance_write(p->trtp, frame); @@ -6109,8 +6169,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { p->invitestate = INV_EARLY_MEDIA; - transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); + transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); + ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); break; } res = -1; @@ -6168,6 +6228,12 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data case AST_CONTROL_SRCUPDATE: ast_rtp_instance_new_source(p->rtp); break; + case AST_CONTROL_CONNECTED_LINE: + update_connectedline(p, data, datalen); + break; + case AST_CONTROL_REDIRECTING: + update_redirecting(p, data, datalen); + break; case -1: res = -1; break; @@ -8709,9 +8775,6 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in if (!ast_strlen_zero(global_useragent)) add_header(req, "User-Agent", global_useragent); - if (!ast_strlen_zero(p->rpid)) - add_header(req, "Remote-Party-ID", p->rpid); - if (!ast_strlen_zero(p->url)) { add_header(req, "Access-URL", p->url); ast_string_field_set(p, url, NULL); @@ -8749,6 +8812,14 @@ static int __transmit_response(struct sip_pvt *p, const char *msg, const struct return -1; } respprep(&resp, p, msg, req); + + if (ast_test_flag(&p->flags[0], SIP_SENDRPID) + && ast_test_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND) + && (!strncmp(msg, "180", 3) || !strncmp(msg, "183", 3))) { + ast_clear_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND); + add_rpid(&resp, p); + } + add_header_contentLength(&resp, 0); /* If we are cancelling an incoming invite for some reason, add information about the reason why we are doing this in clear text */ @@ -8968,6 +9039,89 @@ static int add_digit(struct sip_request *req, char digit, unsigned int duration, return 0; } +/*! + * \pre if p->owner exists, it must be locked + * \brief Add Remote-Party-ID header to SIP message + */ +static int add_rpid(struct sip_request *req, struct sip_pvt *p) +{ + struct ast_str *tmp = ast_str_alloca(256); + char *lid_num = NULL; + char *lid_name = NULL; + int lid_pres; + const char *fromdomain; + const char *privacy = NULL; + const char *screen = NULL; + const char *anonymous_string = "\"Anonymous\" <anonymous@anonymous.invalid>"; + + if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) { + return 0; + } + + if (p->owner && p->owner->connected.id.number) + lid_num = p->owner->connected.id.number; + if (p->owner && p->owner->connected.id.name) + lid_name = p->owner->connected.id.name; + lid_pres = (p->owner) ? p->owner->connected.id.number_presentation : AST_PRES_NUMBER_NOT_AVAILABLE; + + if (ast_strlen_zero(lid_num)) + return 0; + if (ast_strlen_zero(lid_name)) + lid_name = lid_num; + fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); + + if (ast_test_flag(&p->flags[0], SIP_SENDRPID_PAI)) { + if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) { + ast_str_set(&tmp, -1, "%s", anonymous_string); + } else { + ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>", lid_name, lid_num, fromdomain); + } + add_header(req, "P-Asserted-Identity", ast_str_buffer(tmp)); + } else { + ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>;party=%s", lid_name, lid_num, fromdomain, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "calling" : "called"); + + switch (lid_pres) { + case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: + case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: + privacy = "off"; + screen = "no"; + break; + case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: + case AST_PRES_ALLOWED_NETWORK_NUMBER: + privacy = "off"; + screen = "yes"; + break; + case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: + case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: + privacy = "full"; + screen = "no"; + break; + case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: + case AST_PRES_PROHIB_NETWORK_NUMBER: + privacy = "full"; + screen = "yes"; + break; + case AST_PRES_NUMBER_NOT_AVAILABLE: + break; + default: + if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) { + privacy = "full"; + } + else + privacy = "off"; + screen = "no"; + break; + } + + if (!ast_strlen_zero(privacy) && !ast_strlen_zero(screen)) { + ast_str_append(&tmp, -1, ";privacy=%s;screen=%s", privacy, screen); + } + + add_header(req, "Remote-Party-ID", ast_str_buffer(tmp)); + } + return 0; +} + /*! \brief add XML encoded media control with update \note XML: The only way to turn 0 bits of information into a few hundred. (markster) */ static int add_vidupdate(struct sip_request *req) @@ -9581,7 +9735,7 @@ static void copy_request(struct sip_request *dst, const struct sip_request *src) /*! \brief Used for 200 OK and 183 early media \return Will return XMIT_ERROR for network errors. */ -static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp) +static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid) { struct sip_request resp; int seqno; @@ -9590,6 +9744,9 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const return -1; } respprep(&resp, p, msg, req); + if (rpid == TRUE) { + add_rpid(&resp, p); + } if (p->rtp) { if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { ast_debug(1, "Setting framing from config on incoming call\n"); @@ -9739,85 +9896,6 @@ static void build_contact(struct sip_pvt *p) } } -/*! \brief Build the Remote Party-ID & From using callingpres options */ -static void build_rpid(struct sip_pvt *p) -{ - int send_pres_tags = TRUE; - const char *privacy=NULL; - const char *screen=NULL; - char buf[256]; - const char *clid = default_callerid; - const char *clin = NULL; - const char *fromdomain; - - if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from)) - return; - - if (p->owner && p->owner->cid.cid_num) - clid = p->owner->cid.cid_num; - if (p->owner && p->owner->cid.cid_name) - clin = p->owner->cid.cid_name; - if (ast_strlen_zero(clin)) - clin = clid; - - switch (p->callingpres) { - case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: - privacy = "off"; - screen = "no"; - break; - case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: - privacy = "off"; - screen = "yes"; - break; - case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: - privacy = "off"; - screen = "no"; - break; - case AST_PRES_ALLOWED_NETWORK_NUMBER: - privacy = "off"; - screen = "yes"; - break; - case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: - privacy = "full"; - screen = "no"; - break; - case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: - privacy = "full"; - screen = "yes"; - break; - case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: - privacy = "full"; - screen = "no"; - break; - case AST_PRES_PROHIB_NETWORK_NUMBER: - privacy = "full"; - screen = "yes"; - break; - case AST_PRES_NUMBER_NOT_AVAILABLE: - send_pres_tags = FALSE; - break; - default: - ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres); - if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) - privacy = "full"; - else - privacy = "off"; - screen = "no"; - break; - } - - fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); - - snprintf(buf, sizeof(buf), "\"%s\" <sip:%s@%s>", clin, clid, fromdomain); - if (send_pres_tags) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen); - ast_string_field_set(p, rpid, buf); - - ast_string_field_build(p, rpid_from, "\"%s\" <sip:%s@%s>;tag=%s", clin, - S_OR(p->fromuser, clid), - fromdomain, p->tag); -} - /*! \brief Initiate new SIP request to peer/user */ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod) { @@ -9853,15 +9931,9 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text); - if (p->owner) { - l = p->owner->cid.cid_num; - n = p->owner->cid.cid_name; - } - /* if we are not sending RPID and user wants his callerid restricted */ - if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) && - ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) { - l = CALLERID_UNKNOWN; - n = l; + if (p->owner && (p->owner->connected.id.number_presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) { + l = p->owner->connected.id.number; + n = p->owner->connected.id.name; } if (ast_strlen_zero(l)) l = default_callerid; @@ -9950,12 +10022,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho /* SLD: FIXME?: do Route: here too? I think not cos this is the first request. * OTOH, then we won't have anything in p->route anyway */ - /* Build Remote Party-ID and From */ - if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) { - build_rpid(p); - add_header(req, "From", p->rpid_from); - } else - add_header(req, "From", from); + add_header(req, "From", from); add_header(req, "To", to); ast_string_field_set(p, exten, l); build_contact(p); @@ -9964,8 +10031,44 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho add_header(req, "CSeq", tmp_n); if (!ast_strlen_zero(global_useragent)) add_header(req, "User-Agent", global_useragent); - if (!ast_strlen_zero(p->rpid)) - add_header(req, "Remote-Party-ID", p->rpid); +} + +/*! \brief Add "Diversion" header to outgoing message + * + * We need to add a Diversion header if the owner channel of + * this dialog has redirecting information associated with it. + * + * \param req The request/response to which we will add the header + * \param pvt The sip_pvt which represents the call-leg + * \param apr Redirecting data used to make the diversion header + */ +static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt) +{ + const char *diverting_number; + const char *diverting_name; + const char *reason; + char header_text[256]; + + if (!pvt->owner) { + return; + } + + diverting_number = pvt->owner->cid.cid_rdnis; + diverting_name = pvt->owner->redirecting.from.name; + reason = sip_reason_code_to_str(pvt->owner->redirecting.reason); + + if (ast_strlen_zero(diverting_number)) { + return; + } + + /* We at least have a number to place in the Diversion header, which is enough */ + if (ast_strlen_zero(diverting_name)) { + snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason); + } else { + snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s", diverting_name, diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason); + } + + add_header(req, "Diversion", header_text); } /*! \brief Build REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it @@ -10086,6 +10189,11 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init) ast_channel_unlock(chan); } + if ((sipmethod == SIP_INVITE || sipmethod == SIP_UPDATE) && ast_test_flag(&p->flags[0], SIP_SENDRPID)) + add_rpid(&req, p); + if (sipmethod == SIP_INVITE) { + add_diversion_header(&req, p); + } if (sdp) { if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) { ast_udptl_offered_from_local(p->udptl, 1); @@ -10568,6 +10676,80 @@ static char mandescr_sipnotify[] = " *Variable: <name>=<value> At least one variable pair must be specified.\n" " ActionID: <id> Action ID for this transaction. Will be returned.\n"; +/*! \brief Send a provisional response indicating that a call was redirected + */ +static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen) +{ + struct sip_request resp; + + if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) { + return; + } + + if (!ast_strlen_zero(p->owner->redirecting.to.number)) { + ast_string_field_set(p, exten, p->owner->redirecting.to.number); + build_contact(p); + } + respprep(&resp, p, "181 Call is being forwarded", &p->initreq); + add_diversion_header(&resp, p); + send_response(p, &resp, XMIT_UNRELIABLE, 0); +} + +/*! \brief Notify peer that the connected line has changed */ +static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen) +{ + + if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) + return; + if (ast_strlen_zero(p->owner->connected.id.number)) + return; + + append_history(p, "ConnectedLine", "%s party is now %s <%s>", ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "Calling" : "Called", p->owner->connected.id.name, p->owner->connected.id.number); + + if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) { + struct sip_request req; + + if (p->invitestate == INV_CONFIRMED || p->invitestate == INV_TERMINATED) { + reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1); + + add_header(&req, "Allow", ALLOWED_METHODS); + add_header(&req, "Supported", SUPPORTED_EXTENSIONS); + add_rpid(&req, p); + add_sdp(&req, p, FALSE, TRUE, FALSE); + + initialize_initreq(p, &req); + p->lastinvite = p->ocseq; + ast_set_flag(&p->flags[0], SIP_OUTGOING); + send_request(p, &req, XMIT_CRITICAL, p->ocseq); + } else { + reqprep(&req, p, SIP_UPDATE, 0, 1); + add_rpid(&req, p); + add_header_contentLength(&req, 0); + send_request(p, &req, XMIT_CRITICAL, p->ocseq); + } + } else { + if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPID_IMMEDIATE)) { + struct sip_request resp; + + if ((p->owner->_state == AST_STATE_RING) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT)) { + respprep(&resp, p, "180 Ringing", &p->initreq); + add_rpid(&resp, p); + send_response(p, &resp, XMIT_UNRELIABLE, 0); + ast_set_flag(&p->flags[0], SIP_RINGING); + } else if (p->owner->_state == AST_STATE_RINGING) { + respprep(&resp, p, "183 Session Progress", &p->initreq); + add_rpid(&resp, p); + send_response(p, &resp, XMIT_UNRELIABLE, 0); + ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); + } else { + ast_log(LOG_DEBUG, "Unable able to send update to '%s' in state '%s'\n", p->owner->name, ast_state2str(p->owner->_state)); + } + } else { + ast_set_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND); + } + } +} + static const struct _map_x_s regstatestrings[] = { { REG_STATE_FAILED, "Failed" }, { REG_STATE_UNREGISTERED, "Unregistered"}, @@ -10595,7 +10777,7 @@ static const char *regstate2str(enum sipregistrystate regstate) static int sip_reregister(const void *data) { /* if we are here, we know that we need to reregister. */ - struct sip_registry *r= (struct sip_registry *) data; + struct sip_registry *r = (struct sip_registry *) data; /* if we couldn't get a reference to the registry object, punt */ if (!r) @@ -12260,23 +12442,199 @@ static void sip_set_redirstr(struct sip_pvt *p, char *reason) { } } +/*! \brief Parse the parts of the P-Asserted-Identity header + * on an incoming packet. Returns 1 if a valid header is found + * and it is different from the current caller id. + */ +static int get_pai(struct sip_pvt *p, struct sip_request *req) +{ + char pai[256]; + char privacy[64]; + char *cid_num = ""; + char *cid_name = ""; + int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + char *start = NULL, *end = NULL; + + ast_copy_string(pai, get_header(req, "P-Asserted-Identity"), sizeof(pai)); + + if (ast_strlen_zero(pai)) { + return 0; + } + + start = pai; + if (*start == '"') { + *start++ = '\0'; + end = strchr(start, '"'); + if (!end) + return 0; + *end++ = '\0'; + cid_name = start; + start = ast_skip_blanks(end); + } + + if (*start != '<') + return 0; + *start++ = '\0'; + end = strchr(start, '@'); + if (!end) + return 0; + *end++ = '\0'; + if (!strncasecmp(start, "anonymous@anonymous.invalid", 27)) { + callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + /*XXX Assume no change in cid_num. Perhaps it should be + * blanked? + */ + cid_num = (char *)p->cid_num; + } else if (!strncasecmp(start, "sip:", 4)) { + cid_num = start + 4; + if (ast_is_shrinkable_phonenumber(cid_num)) + ast_shrink_phone_number(cid_num); + start = end; + + end = strchr(start, '>'); + if (!end) + return 0; + *end = '\0'; + } else { + return 0; + } + + ast_copy_string(privacy, get_header(req, "Privacy"), sizeof(privacy)); + if (!ast_strlen_zero(privacy) && strncmp(privacy, "id", 2)) { + callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + } + + /* Only return true if the supplied caller id is different */ + if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres) + return 0; + + ast_string_field_set(p, cid_num, cid_num); + ast_string_field_set(p, cid_name, cid_name); + p->callingpres = callingpres; + + if (p->owner) { + ast_set_callerid(p->owner, cid_num, cid_name, NULL); + p->owner->cid.cid_pres = callingpres; + } + + return 1; +} + +/*! \brief Get name, number and presentation from remote party id header, + * returns true if a valid header was found and it was different from the + * current caller id. + */ +static int get_rpid(struct sip_pvt *p, struct sip_request *oreq) +{ + char tmp[256]; + struct sip_request *req; + char *cid_num = ""; + char *cid_name = ""; + int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + char *privacy = ""; + char *screen = ""; + char *start, *end; + + if (!ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) + return 0; + req = oreq; + if (!req) + req = &p->initreq; + ast_copy_string(tmp, get_header(req, "Remote-Party-ID"), sizeof(tmp)); + if (ast_strlen_zero(tmp)) { + return get_pai(p, req); + } + + start = tmp; + if (*start == '"') { + *start++ = '\0'; + end = strchr(start, '"'); + if (!end) + return 0; + *end++ = '\0'; + cid_name = start; + start = ast_skip_blanks(end); + } + + if (*start != '<') + return 0; + *start++ = '\0'; + end = strchr(start, '@'); + if (!end) + return 0; + *end++ = '\0'; + if (strncasecmp(start, "sip:", 4)) + return 0; + cid_num = start + 4; + if (ast_is_shrinkable_phonenumber(cid_num)) + ast_shrink_phone_number(cid_num); + start = end; + + end = strchr(start, '>'); + if (!end) + return 0; + *end++ = '\0'; + if (*end) { + start = end; + if (*start != ';') + return 0; + *start++ = '\0'; + while (!ast_strlen_zero(start)) { + end = strchr(start, ';'); + if (end) + *end++ = '\0'; + if (!strncasecmp(start, "privacy=", 8)) + privacy = start + 8; + else if (!strncasecmp(start, "screen=", 7)) + screen = start + 7; + start = end; + } + + if (!strcasecmp(privacy, "full")) { + if (!strcasecmp(screen, "yes")) + callingpres = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; + else if (!strcasecmp(screen, "no")) + callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + } else { + if (!strcasecmp(screen, "yes")) + callingpres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; + else if (!strcasecmp(screen, "no")) + callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + } + } + + /* Only return true if the supplied caller id is different */ + if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres) + return 0; + + ast_string_field_set(p, cid_num, cid_num); + ast_string_field_set(p, cid_name, cid_name); + p->callingpres = callingpres; + + if (p->owner) { + ast_set_callerid(p->owner, cid_num, cid_name, NULL); + p->owner->cid.cid_pres = callingpres; + } + + return 1; +} + /*! \brief Get referring dnis */ -static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq) +static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason) { - char tmp[256], *exten, *rexten, *rdomain; - char *params, *reason = NULL; + char tmp[256], *exten, *rexten, *rdomain, *rname = NULL; + char *params, *reason_param = NULL; struct sip_request *req; - + req = oreq ? oreq : &p->initreq; ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp)); if (ast_strlen_zero(tmp)) - return 0; + return -1; - /*! \todo This function does not take user-parameters into consideration. - First look for @, then start looking for ; to find uri-parameters. - */ - params = strchr(tmp, ';'); + if ((params = strchr(tmp, '>'))) { + params = strchr(params, ';'); + } exten = get_in_brackets(tmp); if (!strncasecmp(exten, "sip:", 4)) { @@ -12295,16 +12653,16 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq) while (*params == ';' || *params == ' ') params++; /* Check if we have a reason parameter */ - if ((reason = strcasestr(params, "reason="))) { - reason+=7; + if ((reason_param = strcasestr(params, "reason="))) { + reason_param+=7; /* Remove enclosing double-quotes */ - if (*reason == '"') - ast_strip_quoted(reason, "\"", "\""); - if (!ast_strlen_zero(reason)) { - sip_set_redirstr(p, reason); + if (*reason_param == '"') + ast_strip_quoted(reason_param, "\"", "\""); + if (!ast_strlen_zero(reason_param)) { + sip_set_redirstr(p, reason_param); if (p->owner) { pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause); - pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason); + pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param); } } } @@ -12312,13 +12670,32 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq) rdomain = exten; rexten = strsep(&rdomain, "@"); /* trim anything after @ */ - if (p->owner) + if (p->owner) pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain); if (sip_debug_test_pvt(p)) - ast_verbose("RDNIS for this call is is %s (reason %s)\n", exten, reason ? reason : ""); + ast_verbose("RDNIS for this call is %s (reason %s)\n", exten, reason ? reason_param : ""); + + /*ast_string_field_set(p, rdnis, rexten);*/ + + if (*tmp == '\"') { + char *end_quote; + rname = tmp + 1; + end_quote = strchr(rname, '\"'); + *end_quote = '\0'; + } - ast_string_field_set(p, rdnis, rexten); + if (number) { + *number = ast_strdup(rexten); + } + + if (name && rname) { + *name = ast_strdup(rname); + } + + if (reason && !ast_strlen_zero(reason_param)) { + *reason = sip_reason_str_to_code(reason_param); + } return 0; } @@ -12931,58 +13308,12 @@ static char *get_calleridname(const char *input, char *output, size_t outputsize return output; } -/*! \brief Get caller id number from Remote-Party-ID header field - * Returns true if number should be restricted (privacy setting found) - * output is set to NULL if no number found - */ -static int get_rpid_num(const char *input, char *output, int maxlen) -{ - char *start; - char *end; - - start = strchr(input, ':'); - if (!start) { - output[0] = '\0'; - return 0; - } - start++; - - /* we found "number" */ - ast_copy_string(output, start, maxlen); - output[maxlen-1] = '\0'; - - end = strchr(output, '@'); - if (end) - *end = '\0'; - else - output[0] = '\0'; - if (strstr(input, "privacy=full") || strstr(input, "privacy=uri")) - return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; - - return 0; -} - - -/*! \brief helper function for check_{user|peer}_ok() */ -static void replace_cid(struct sip_pvt *p, const char *rpid_num, const char *calleridname) -{ - /* replace callerid if rpid found, and not restricted */ - if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) { - char *tmp = ast_strdupa(rpid_num); /* XXX the copy can be done later */ - if (!ast_strlen_zero(calleridname)) - ast_string_field_set(p, cid_name, calleridname); - if (ast_is_shrinkable_phonenumber(tmp)) - ast_shrink_phone_number(tmp); - ast_string_field_set(p, cid_num, tmp); - } -} /*! \brief Validate device authentication */ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, struct sip_request *req, int sipmethod, struct sockaddr_in *sin, struct sip_peer **authpeer, - enum xmittype reliable, - char *rpid_num, char *calleridname, char *uri2) + enum xmittype reliable, char *calleridname, char *uri2) { enum check_auth_result res; int debug=sip_debug_test_addr(sin); @@ -13030,7 +13361,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, if (p->sipoptions) peer->sipoptions = p->sipoptions; - replace_cid(p, rpid_num, calleridname); do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE)); ast_string_field_set(p, peersecret, peer->secret); @@ -13083,14 +13413,18 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, /* XXX this takes the name from the caller... can we override ? */ ast_string_field_set(p, authname, peer->username); } - if (!ast_strlen_zero(peer->cid_num)) { - char *tmp = ast_strdupa(peer->cid_num); - if (ast_is_shrinkable_phonenumber(tmp)) - ast_shrink_phone_number(tmp); - ast_string_field_set(p, cid_num, tmp); + if (!get_rpid(p, req)) { + if (!ast_strlen_zero(peer->cid_num)) { + char *tmp = ast_strdupa(peer->cid_num); + if (ast_is_shrinkable_phonenumber(tmp)) + ast_shrink_phone_number(tmp); + ast_string_field_set(p, cid_num, tmp); + } + if (!ast_strlen_zero(peer->cid_name)) + ast_string_field_set(p, cid_name, peer->cid_name); + if (peer->callingpres) + p->callingpres = peer->callingpres; } - if (!ast_strlen_zero(peer->cid_name)) - ast_string_field_set(p, cid_name, peer->cid_name); ast_string_field_set(p, fullcontact, peer->fullcontact); if (!ast_strlen_zero(peer->context)) ast_string_field_set(p, context, peer->context); @@ -13140,8 +13474,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ char *dummy; /* dummy return value for parse_uri */ char *domain; /* dummy return value for parse_uri */ char *of, *of2; - char rpid_num[50]; - const char *rpid; enum check_auth_result res; char calleridname[50]; char *uri2 = ast_strdupa(uri); @@ -13157,11 +13489,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ if (calleridname[0]) ast_string_field_set(p, cid_name, calleridname); - rpid = get_header(req, "Remote-Party-ID"); - memset(rpid_num, 0, sizeof(rpid_num)); - if (!ast_strlen_zero(rpid)) - p->callingpres = get_rpid_num(rpid, rpid_num, sizeof(rpid_num)); - of = get_in_brackets(from); if (ast_strlen_zero(p->exten)) { char *t = uri2; @@ -13235,13 +13562,13 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ } res = check_peer_ok(p, of, req, sipmethod, sin, - authpeer, reliable, rpid_num, calleridname, uri2); + authpeer, reliable, calleridname, uri2); if (res != AUTH_DONT_KNOW) return res; /* Finally, apply the guest policy */ if (sip_cfg.allowguest) { - replace_cid(p, rpid_num, calleridname); + get_rpid(p, req); if (!dialog_initialize_rtp(p)) { res = AUTH_SUCCESSFUL; } else { @@ -16483,29 +16810,150 @@ static struct ast_custom_function sipchaninfo_function = { .read = function_sipchaninfo_read, }; +static int read_to_parts(struct sip_pvt *p, struct sip_request *req, char **name, char **number) +{ + + char to_header[256]; + char *to_name = NULL; + char *to_number = NULL; + char *separator; + + ast_copy_string(to_header, get_header(req, "To"), sizeof(to_header)); + + /* Let's get that number first! */ + to_number = get_in_brackets(to_header); + + if (!strncasecmp(to_number, "sip:", 4)) { + to_number += 4; + } else if (!strncasecmp(to_number, "sips:", 5)) { + to_number += 5; + } else { + ast_log(LOG_WARNING, "Not a SIP URI? (%s)!\n", to_number); + return -1; + } + + /* Remove the host and such since we just want the number */ + if ((separator = strchr(to_number, '@'))) { + *separator = '\0'; + } + + /* We have the number. Let's get the name now. */ + + if (*to_header == '\"') { + to_name = to_header + 1; + if (!(separator = (char *)find_closing_quote(to_name, NULL))) { + ast_log(LOG_NOTICE, "No closing quote in name section of To: header (%s)\n", to_header); + return -1; + } + *separator = '\0'; + } + + if (number) { + *number = ast_strdup(to_number); + } + if (name && !ast_strlen_zero(to_name)) { + *name = ast_strdup(to_name); + } + + return 0; +} + +/*! \brief update redirecting information for a channel based on headers + * + */ +static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward) +{ + char *redirecting_from_name = NULL; + char *redirecting_from_number = NULL; + char *redirecting_to_name = NULL; + char *redirecting_to_number = NULL; + int reason = AST_REDIRECTING_REASON_UNCONDITIONAL; + int is_response = req->method == SIP_RESPONSE; + int res = 0; + + res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason); + if (res == -1) { + if (is_response) { + read_to_parts(p, req, &redirecting_from_name, &redirecting_from_number); + } else { + return; + } + } + + /* At this point, all redirecting "from" info should be filled in appropriately + * on to the "to" info + */ + + if (is_response) { + parse_moved_contact(p, req, &redirecting_to_name, &redirecting_to_number, set_call_forward); + } else { + read_to_parts(p, req, &redirecting_to_name, &redirecting_to_number); + } + + if (!ast_strlen_zero(redirecting_from_number)) { + if (redirecting->from.number) { + ast_free(redirecting->from.number); + } + ast_debug(3, "Got redirecting from number %s\n", redirecting_from_number); + redirecting->from.number = redirecting_from_number; + } + if (!ast_strlen_zero(redirecting_from_name)) { + if (redirecting->from.name) { + ast_free(redirecting->from.name); + } + ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name); + redirecting->from.name = redirecting_from_name; + } + if (!ast_strlen_zero(redirecting_to_number)) { + if (redirecting->to.number) { + ast_free(redirecting->to.number); + } + ast_debug(3, "Got redirecting to number %s\n", redirecting_to_number); + redirecting->to.number = redirecting_to_number; + } + if (!ast_strlen_zero(redirecting_to_name)) { + if (redirecting->to.name) { + ast_free(redirecting->to.name); + } + ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number); + redirecting->to.name = redirecting_to_name; + } + redirecting->reason = reason; +} + /*! \brief Parse 302 Moved temporalily response \todo XXX Doesn't redirect over TLS on sips: uri's. If we get a redirect to a SIPS: uri, this needs to be going back to the dialplan (this is a request for a secure signalling path). Note that transport=tls is deprecated, but we need to support it on incoming requests. */ -static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req) +static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward) { - char tmp[SIPBUFSIZE]; - char *s, *e, *t, *trans; + char contact[SIPBUFSIZE]; + char *contact_name = NULL; + char *contact_number = NULL; + char *separator, *trans; char *domain; enum sip_transport transport = SIP_TRANSPORT_UDP; - ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp)); - if ((t = strchr(tmp, ','))) - *t = '\0'; + ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); + if ((separator = strchr(contact, ','))) + *separator = '\0'; - s = get_in_brackets(tmp); - if ((trans = strcasestr(s, ";transport="))) do { + /* ooh, a name */ + if (*contact == '"') { + contact_name = contact + 1; + if ((separator = strchr(contact_name, '"'))) { + *separator++ = '\0'; + } + } + + contact_number = get_in_brackets(contact); + if ((trans = strcasestr(contact_number, ";transport="))) { trans += 11; - if ((e = strchr(trans, ';'))) - *e = '\0'; + if ((separator = strchr(trans, ';'))) + *separator = '\0'; if (!strncasecmp(trans, "tcp", 3)) transport = SIP_TRANSPORT_TCP; @@ -16513,12 +16961,12 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req) transport = SIP_TRANSPORT_TLS; else { if (strncasecmp(trans, "udp", 3)) - ast_debug(1, "received contact with an invalid transport, '%s'\n", s); + ast_debug(1, "received contact with an invalid transport, '%s'\n", contact_number); /* This will assume UDP for all unknown transports */ transport = SIP_TRANSPORT_UDP; } - } while(0); - s = remove_uri_parameters(s); + } + contact_number = remove_uri_parameters(contact_number); if (p->socket.tcptls_session) { ao2_ref(p->socket.tcptls_session, -1); @@ -16528,51 +16976,70 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req) p->socket.fd = -1; p->socket.type = transport; - if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) { + if (set_call_forward && ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) { char *host = NULL; - if (!strncasecmp(s, "sip:", 4)) - s += 4; - else if (!strncasecmp(s, "sips:", 5)) - s += 5; - e = strchr(s, '/'); - if (e) - *e = '\0'; - if ((host = strchr(s, '@'))) { + if (!strncasecmp(contact_number, "sip:", 4)) + contact_number += 4; + else if (!strncasecmp(contact_number, "sips:", 5)) + contact_number += 5; + separator = strchr(contact_number, '/'); + if (separator) + *separator = '\0'; + if ((host = strchr(contact_number, '@'))) { *host++ = '\0'; - ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", s, get_transport(transport), host); + ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", contact_number, get_transport(transport), host); if (p->owner) - ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", s, get_transport(transport), host); + ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", contact_number, get_transport(transport), host); } else { - ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), s); + ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), contact_number); if (p->owner) - ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), s); + ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), contact_number); } } else { - e = strchr(tmp, '@'); - if (e) { - *e++ = '\0'; - domain = e; + separator = strchr(contact, '@'); + if (separator) { + *separator++ = '\0'; + domain = separator; } else { /* No username part */ - domain = tmp; - } - e = strchr(tmp, '/'); /* WHEN do we hae a forward slash in the URI? */ - if (e) - *e = '\0'; - - if (!strncasecmp(s, "sip:", 4)) - s += 4; - else if (!strncasecmp(s, "sips:", 5)) - s += 5; - e = strchr(s, ';'); /* And username ; parameters? */ - if (e) - *e = '\0'; - ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", s, domain); - if (p->owner) { - pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain); - ast_string_field_set(p->owner, call_forward, s); + domain = contact; + } + separator = strchr(contact, '/'); /* WHEN do we hae a forward slash in the URI? */ + if (separator) + *separator = '\0'; + + if (!strncasecmp(contact_number, "sip:", 4)) + contact_number += 4; + else if (!strncasecmp(contact_number, "sips:", 5)) + contact_number += 5; + separator = strchr(contact_number, ';'); /* And username ; parameters? */ + if (separator) + *separator = '\0'; + if (set_call_forward) { + ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", contact_number, domain); + if (p->owner) { + pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain); + ast_string_field_set(p->owner, call_forward, contact_number); + } } } + + /* We've gotten the number for the contact, now get the name */ + + if (*contact == '\"') { + contact_name = contact + 1; + if (!(separator = (char *)find_closing_quote(contact_name, NULL))) { + ast_log(LOG_NOTICE, "No closing quote on name in Contact header? %s\n", contact); + } + *separator = '\0'; + } + + if (name && !ast_strlen_zero(contact_name)) { + *name = ast_strdup(contact_name); + } + if (number) { + *number = ast_strdup(contact_number); + } } /*! \brief Check pending actions on SIP call */ @@ -16635,6 +17102,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru int reinvite = (p->owner && p->owner->_state == AST_STATE_UP); char *p_hdrval; int rtn; + struct ast_party_connected_line connected; if (reinvite) ast_debug(4, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid); @@ -16653,7 +17121,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru /* RFC3261 says we must treat every 1xx response (but not 100) that we don't recognize as if it was 183. */ - if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 182 && resp != 183) + if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 181 && resp != 182 && resp != 183) resp = 183; /* Any response between 100 and 199 is PROCEEDING */ @@ -16681,6 +17149,14 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p)) ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); if (!req->ignore && p->owner) { + if (get_rpid(p, req)) { + ast_party_connected_line_init(&connected); + connected.id.number = (char *) p->cid_num; + connected.id.name = (char *) p->cid_name; + connected.id.number_presentation = p->callingpres; + connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + ast_channel_queue_connected_line_update(p->owner, &connected); + } ast_queue_control(p->owner, AST_CONTROL_RINGING); if (p->owner->_state != AST_STATE_UP) { ast_setstate(p->owner, AST_STATE_RINGING); @@ -16698,10 +17174,32 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru check_pendings(p); break; + case 181: /* Call Is Being Forwarded */ + if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) + ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore && p->owner) { + struct ast_party_redirecting redirecting = {{0,},}; + change_redirecting_information(p, req, &redirecting, FALSE); + ast_channel_queue_redirecting_update(p->owner, &redirecting); + } + check_pendings(p); + break; + case 183: /* Session progress */ if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); /* Ignore 183 Session progress without SDP */ + if (!req->ignore && p->owner) { + if (get_rpid(p, req)) { + /* Queue a connected line update */ + ast_party_connected_line_init(&connected); + connected.id.number = (char *) p->cid_num; + connected.id.name = (char *) p->cid_name; + connected.id.number_presentation = p->callingpres; + connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + ast_channel_queue_connected_line_update(p->owner, &connected); + } + } if (find_sdp(req)) { if (p->invitestate != INV_CANCELLED) p->invitestate = INV_EARLY_MEDIA; @@ -16723,7 +17221,17 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if (!reinvite) /* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */ /* For re-invites, we try to recover */ - ast_set_flag(&p->flags[0], SIP_PENDINGBYE); + ast_set_flag(&p->flags[0], SIP_PENDINGBYE); + } + + if (!req->ignore && p->owner && get_rpid(p, req)) { + /* Queue a connected line update */ + ast_party_connected_line_init(&connected); + connected.id.number = (char *) p->cid_num; + connected.id.name = (char *) p->cid_name; + connected.id.number_presentation = p->callingpres; + connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + ast_channel_queue_connected_line_update(p->owner, &connected); } /* Parse contact header for continued conversation */ @@ -16747,6 +17255,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if (!req->ignore && p->owner) { if (!reinvite) { + struct ast_party_connected_line connected; + ast_party_connected_line_collect_caller(&connected, &p->owner->cid); + ast_channel_queue_connected_line_update(p->owner, &connected); ast_queue_control(p->owner, AST_CONTROL_ANSWER); if (sip_cfg.callevents) manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", @@ -17402,6 +17913,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_ case 183: /* 183 Session Progress */ case 180: /* 180 Ringing */ case 182: /* 182 Queued */ + case 181: /* 181 Call Is Being Forwarded */ if (sipmethod == SIP_INVITE) handle_response_invite(p, resp, rest, req, seqno); break; @@ -17569,7 +18081,11 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_ case 301: /* Moved permanently */ case 302: /* Moved temporarily */ case 305: /* Use Proxy */ - parse_moved_contact(p, req); + { + struct ast_party_redirecting redirecting = {{0,},}; + change_redirecting_information(p, req, &redirecting, TRUE); + ast_channel_set_redirecting(p->owner, &redirecting); + } /* Fall through */ case 486: /* Busy here */ case 600: /* Busy everywhere */ @@ -18265,7 +18781,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in /* We should answer something here. If we are here, the call we are replacing exists, so an accepted can't harm */ - transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE); + transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE); /* Do something more clever here */ ast_channel_unlock(c); sip_pvt_unlock(p->refer->refer_call); @@ -18299,7 +18815,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in Targetcall is not touched by the masq */ /* Answer the incoming call and set channel to UP state */ - transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE); + transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE); ast_setstate(c, AST_STATE_UP); @@ -18699,10 +19215,11 @@ static int sip_t38_abort(const void *data) return 0; } -/*! \brief Handle incoming INVITE request -\note If the INVITE has a Replaces header, it is part of an +/*! + * \brief Handle incoming INVITE request + * \note If the INVITE has a Replaces header, it is part of an * attended transfer. If so, we do not go through the dial - * plan but tries to find the active call and masquerade + * plan but try to find the active call and masquerade * into it */ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock) @@ -18973,6 +19490,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int parse_ok_contact(p, req); } else { /* Re-invite on existing call */ ast_clear_flag(&p->flags[0], SIP_OUTGOING); /* This is now an inbound dialog */ + if (get_rpid(p, req)) { + struct ast_party_connected_line connected; + + ast_party_connected_line_init(&connected); + connected.id.number = (char *) p->cid_num; + connected.id.name = (char *) p->cid_name; + connected.id.number_presentation = p->callingpres; + connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + ast_channel_queue_connected_line_update(p->owner, &connected); + } /* Handle SDP here if we already have an owner */ if (find_sdp(req)) { if (process_sdp(p, req, SDP_T38_INITIATE)) { @@ -18995,6 +19522,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int if (!p->lastinvite && !req->ignore && !p->owner) { /* This is a new invite */ /* Handle authentication if this is our first invite */ + struct ast_party_redirecting redirecting = {{0,},}; res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin); if (res == AUTH_CHALLENGE_SENT) { p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */ @@ -19052,7 +19580,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int return 0; } gotdest = get_destination(p, NULL); /* Get destination right away */ - get_rdnis(p, NULL); /* Get redirect information */ + change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */ extract_uri(p, req); /* Get the Contact URI */ build_contact(p); /* Build our contact header */ @@ -19096,9 +19624,11 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int if (c) { /* Pre-lock the call */ ast_channel_lock(c); + ast_channel_set_redirecting(c, &redirecting); } } } else { + struct ast_party_redirecting redirecting = {{0,},}; if (sipdebug) { if (!req->ignore) ast_debug(2, "Got a SIP re-invite for call %s\n", p->callid); @@ -19108,6 +19638,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int if (!req->ignore) reinvite = 1; c = p->owner; + change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */ + if (c) { + ast_channel_set_redirecting(c, &redirecting); + } } /* Session-Timers */ @@ -19318,7 +19852,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int c->hangupcause = AST_CAUSE_CALL_REJECTED; } else { sip_pvt_unlock(p); - ast_setstate(c, AST_STATE_DOWN); c->hangupcause = AST_CAUSE_NORMAL_CLEARING; } p->invitestate = INV_COMPLETED; @@ -19348,7 +19881,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int } else if (p->t38.state == T38_DISABLED) { /* If this is not a re-invite or something to ignore - it's critical */ ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); - transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE); + transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE : TRUE, FALSE); } p->invitestate = INV_TERMINATED; @@ -19466,6 +19999,8 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * else ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER); } else { + struct ast_party_connected_line connected_caller; + /* Transfer succeeded! */ const char *xfersound = pbx_builtin_getvar_helper(target.chan1, "ATTENDED_TRANSFER_COMPLETE_SOUND"); @@ -19480,6 +20015,45 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name); ast_channel_unlock(targetcall_pvt->owner); } + + if (target.chan2) { + if (current->chan2) { + /* Tell each of the other channels to whom they are now connected */ + ast_channel_lock(current->chan2); + ast_connected_line_copy_from_caller(&connected_caller, ¤t->chan2->cid); + ast_channel_unlock(current->chan2); + connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + ast_channel_update_connected_line(target.chan2, &connected_caller); + ast_channel_lock(target.chan2); + ast_connected_line_copy_from_caller(&connected_caller, &target.chan2->cid); + ast_channel_unlock(target.chan2); + connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + ast_channel_update_connected_line(current->chan2, &connected_caller); + ast_party_connected_line_free(&connected_caller); + } + } else { + /* Notify the first other party that they are connected to someone else assuming that target.chan1 + has progressed far enough through the dialplan to have it's called party information set. */ + if (current->chan2) { + ast_channel_lock(target.chan1); + ast_party_connected_line_copy(&connected_caller, &target.chan1->connected); + ast_channel_unlock(target.chan1); + connected_caller = target.chan1->connected; + connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + ast_channel_update_connected_line(current->chan2, &connected_caller); + ast_party_connected_line_free(&connected_caller); + } + + /* We can't indicate to the called channel directly so we force the masquerade to complete + and queue and update to be read and passed-through */ + ast_channel_lock(target.chan1); + ast_do_masquerade(target.chan1); + ast_channel_unlock(target.chan1); + + ast_party_connected_line_collect_caller(&connected_caller, &target.chan1->cid); + connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + ast_channel_queue_connected_line_update(target.chan1, &connected_caller); + } } if (targetcall_pvt) ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt"); @@ -20553,10 +21127,10 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so */ int ret = 0; - if (p->ocseq < seqno && seqno != p->lastnoninvite) { + if (p->ocseq < seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) { ast_debug(1, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq); ret = -1; - } else if (p->ocseq != seqno && seqno != p->lastnoninvite) { + } else if (p->ocseq != seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) { /* ignore means "don't do anything with it" but still have to * respond appropriately. * But in this case this is a response already, so we really @@ -22130,7 +22704,16 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID); } else if (!strcasecmp(v->name, "sendrpid")) { ast_set_flag(&mask[0], SIP_SENDRPID); - ast_set2_flag(&flags[0], ast_true(v->value), SIP_SENDRPID); + if (!strcasecmp(v->value, "pai")) { + ast_set_flag(&flags[0], SIP_SENDRPID_PAI); + } else if (!strcasecmp(v->value, "rpid")) { + ast_set_flag(&flags[0], SIP_SENDRPID_RPID); + } else if (ast_true(v->value)) { + ast_set_flag(&flags[0], SIP_SENDRPID_RPID); + } + } else if (!strcasecmp(v->name, "rpid_immediate")) { + ast_set_flag(&mask[1], SIP_PAGE2_RPID_IMMEDIATE); + ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RPID_IMMEDIATE); } else if (!strcasecmp(v->name, "g726nonstandard")) { ast_set_flag(&mask[0], SIP_G726_NONSTANDARD); ast_set2_flag(&flags[0], ast_true(v->value), SIP_G726_NONSTANDARD); diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index f4104a89e..588680e3c 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -2516,6 +2516,43 @@ static int skinny_extensionstate_cb(char *context, char *exten, int state, void return 0; } +static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen) +{ + struct ast_channel *c = sub->owner; + struct skinny_line *l = sub->parent; + struct skinny_device *d = l->device; + + if (ast_strlen_zero(c->cid.cid_num) || ast_strlen_zero(c->connected.id.number)) + return; + + if (sub->owner->_state == AST_STATE_UP) { + transmit_callstate(d, l->instance, SKINNY_CONNECTED, sub->callid); + transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid); + if (sub->outgoing) + transmit_callinfo(d, c->connected.id.name, c->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1); + else + transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2); + } else { + if (sub->outgoing) { + transmit_callstate(d, l->instance, SKINNY_RINGIN, sub->callid); + transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid); + transmit_callinfo(d, c->connected.id.name, c->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1); + } else { + if (!sub->ringing) { + transmit_callstate(d, l->instance, SKINNY_RINGOUT, sub->callid); + transmit_displaypromptstatus(d, "Ring-Out", 0, l->instance, sub->callid); + sub->ringing = 1; + } else { + transmit_callstate(d, l->instance, SKINNY_PROGRESS, sub->callid); + transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid); + sub->progress = 1; + } + + transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2); + } + } +} + static void mwi_event_cb(const struct ast_event *event, void *userdata) { struct skinny_line *l = userdata; @@ -3610,6 +3647,8 @@ static void *skinny_newcall(void *data) l->hidecallerid ? "" : l->cid_num, l->hidecallerid ? "" : l->cid_name, c->cid.cid_ani ? NULL : l->cid_num); + c->connected.id.number = ast_strdup(c->exten); + c->connected.id.name = NULL; ast_setstate(c, AST_STATE_RING); if (!sub->rtp) { start_rtp(sub); @@ -3773,7 +3812,7 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout) transmit_callstateonly(d, sub, SKINNY_RINGIN); transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN); transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid); - transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); + transmit_callinfo(d, ast->connected.id.name, ast->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1); transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); transmit_ringer_mode(d, SKINNY_RING_INSIDE); @@ -3900,7 +3939,7 @@ static int skinny_answer(struct ast_channel *ast) /* order matters here... for some reason, transmit_callinfo must be before transmit_callstate, or you won't get keypad messages in some situations. */ - transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); + transmit_callinfo(d, ast->connected.id.name, ast->connected.id.number, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); transmit_callstateonly(d, sub, SKINNY_CONNECTED); transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED); transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid); @@ -4095,6 +4134,10 @@ static char *control2str(int ind) { return "Unhold"; case AST_CONTROL_SRCUPDATE: return "Media Source Update"; + case AST_CONTROL_CONNECTED_LINE: + return "Connected Line"; + case AST_CONTROL_REDIRECTING: + return "Redirecting"; case -1: return "Stop tone"; default: @@ -4202,7 +4245,7 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s transmit_callstateonly(d, sub, SKINNY_RINGOUT); transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid); transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid); - transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ + transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->connected.id.name, l->lastnumberdialed), S_OR(ast->connected.id.number, l->lastnumberdialed), l->instance, sub->callid, 2); /* 2 = outgoing from phone */ sub->ringing = 1; if (!d->earlyrtp) { break; @@ -4243,7 +4286,7 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s } transmit_callstateonly(d, sub, SKINNY_PROGRESS); transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid); - transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ + transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->connected.id.name, l->lastnumberdialed), S_OR(ast->connected.id.number, l->lastnumberdialed), l->instance, sub->callid, 2); /* 2 = outgoing from phone */ sub->progress = 1; if (!d->earlyrtp) { break; @@ -4264,6 +4307,9 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s case AST_CONTROL_SRCUPDATE: ast_rtp_instance_new_source(sub->rtp); break; + case AST_CONTROL_CONNECTED_LINE: + update_connectedline(sub, data, datalen); + break; default: ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); return -1; /* Tell asterisk to provide inband signalling */ diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 1cd94e02f..e4588b368 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -3671,16 +3671,16 @@ static int unistim_call(struct ast_channel *ast, char *dest, int timeout) Sendicon(TEXT_LINE0, FAV_ICON_NONE, session); if (sub->owner) { - if (sub->owner->cid.cid_num) { - send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->cid.cid_num); - change_callerid(session, 0, sub->owner->cid.cid_num); + if (sub->owner->connected.id.number) { + send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->connected.id.number); + change_callerid(session, 0, sub->owner->connected.id.number); } else { send_text(TEXT_LINE1, TEXT_NORMAL, session, DEFAULTCALLERID); change_callerid(session, 0, DEFAULTCALLERID); } - if (sub->owner->cid.cid_name) { - send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->cid.cid_name); - change_callerid(session, 1, sub->owner->cid.cid_name); + if (sub->owner->connected.id.name) { + send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->connected.id.name); + change_callerid(session, 1, sub->owner->connected.id.name); } else { send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERNAME); change_callerid(session, 1, DEFAULTCALLERNAME); diff --git a/channels/misdn/chan_misdn_config.h b/channels/misdn/chan_misdn_config.h index c00db864b..d64b8c860 100644 --- a/channels/misdn/chan_misdn_config.h +++ b/channels/misdn/chan_misdn_config.h @@ -46,10 +46,16 @@ enum misdn_cfg_elements { MISDN_CFG_DIALPLAN, /* int */ MISDN_CFG_LOCALDIALPLAN, /* int */ MISDN_CFG_CPNDIALPLAN, /* int */ - MISDN_CFG_NATPREFIX, /* char[] */ - MISDN_CFG_INTERNATPREFIX, /* char[] */ + MISDN_CFG_TON_PREFIX_UNKNOWN, /* char[] */ + MISDN_CFG_TON_PREFIX_INTERNATIONAL, /* char[] */ + MISDN_CFG_TON_PREFIX_NATIONAL, /* char[] */ + MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC,/* char[] */ + MISDN_CFG_TON_PREFIX_SUBSCRIBER, /* char[] */ + MISDN_CFG_TON_PREFIX_ABBREVIATED, /* char[] */ MISDN_CFG_PRES, /* int */ MISDN_CFG_SCREEN, /* int */ + MISDN_CFG_DISPLAY_CONNECTED, /* int */ + MISDN_CFG_DISPLAY_SETUP, /* int */ MISDN_CFG_ALWAYS_IMMEDIATE, /* int (bool) */ MISDN_CFG_NODIALTONE, /* int (bool) */ MISDN_CFG_IMMEDIATE, /* int (bool) */ diff --git a/channels/misdn/isdn_lib.c b/channels/misdn/isdn_lib.c index 071f756eb..d8cf6171a 100644 --- a/channels/misdn/isdn_lib.c +++ b/channels/misdn/isdn_lib.c @@ -171,19 +171,24 @@ struct misdn_stack *get_stack_by_bc(struct misdn_bchannel *bc) void get_show_stack_details(int port, char *buf) { - struct misdn_stack *stack=get_misdn_stack(); + struct misdn_stack *stack = get_misdn_stack(); - for ( ; stack; stack=stack->next) { - if (stack->port == port) break; + for (; stack; stack = stack->next) { + if (stack->port == port) { + break; + } } if (stack) { - sprintf(buf, "* Port %d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d", - stack->port, stack->nt ? "NT" : "TE", stack->ptp ? "PTP" : "PMP", - stack->l2link ? "UP" : "DOWN", stack->l1link ? "UP" : "DOWN", + sprintf(buf, "* Port %2d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d", + stack->port, + stack->nt ? "NT" : "TE", + stack->ptp ? "PTP" : "PMP", + stack->l2link ? "UP " : "DOWN", + stack->l1link ? "UP " : "DOWN", stack->blocked); } else { - buf[0]=0; + buf[0] = 0; } } @@ -644,6 +649,29 @@ static void bc_next_state_change(struct misdn_bchannel *bc, enum bchannel_state static void empty_bc(struct misdn_bchannel *bc) { + bc->caller.presentation = 0; /* allowed */ + bc->caller.number_plan = NUMPLAN_ISDN; + bc->caller.number_type = NUMTYPE_UNKNOWN; + bc->caller.name[0] = 0; + bc->caller.number[0] = 0; + bc->caller.subaddress[0] = 0; + + bc->connected.presentation = 0; /* allowed */ + bc->connected.number_plan = NUMPLAN_ISDN; + bc->connected.number_type = NUMTYPE_UNKNOWN; + bc->connected.name[0] = 0; + bc->connected.number[0] = 0; + bc->connected.subaddress[0] = 0; + + bc->redirecting.from.presentation = 0; /* allowed */ + bc->redirecting.from.number_plan = NUMPLAN_ISDN; + bc->redirecting.from.number_type = NUMTYPE_UNKNOWN; + bc->redirecting.from.name[0] = 0; + bc->redirecting.from.number[0] = 0; + bc->redirecting.from.subaddress[0] = 0; + + bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN; + bc->dummy=0; bc->bframe_len=0; @@ -678,12 +706,6 @@ static void empty_bc(struct misdn_bchannel *bc) bc->generate_tone=0; bc->tone_cnt=0; - bc->dnumplan=NUMPLAN_UNKNOWN; - bc->onumplan=NUMPLAN_UNKNOWN; - bc->rnumplan=NUMPLAN_UNKNOWN; - bc->cpnnumplan=NUMPLAN_UNKNOWN; - - bc->active = 0; bc->early_bconnect = 1; @@ -701,7 +723,12 @@ static void empty_bc(struct misdn_bchannel *bc) bc->cause = AST_CAUSE_NORMAL_CLEARING; bc->out_cause = AST_CAUSE_NORMAL_CLEARING; - bc->pres = 0; /* allowed */ + + bc->display_connected = 0; /* none */ + bc->display_setup = 0; /* none */ + + bc->presentation = 0; /* allowed */ + bc->set_presentation = 0; bc->evq=EVENT_NOTHING; @@ -719,15 +746,14 @@ static void empty_bc(struct misdn_bchannel *bc) bc->hdlc=0; + bc->dialed.number_plan = NUMPLAN_ISDN; + bc->dialed.number_type = NUMTYPE_UNKNOWN; + bc->dialed.number[0] = 0; + bc->dialed.subaddress[0] = 0; bc->info_dad[0] = 0; bc->display[0] = 0; bc->infos_pending[0] = 0; - bc->cad[0] = 0; - bc->oad[0] = 0; - bc->dad[0] = 0; - bc->rad[0] = 0; - bc->orig_dad[0] = 0; bc->uu[0]=0; bc->uulen=0; @@ -929,7 +955,7 @@ static int create_process(int midev, struct misdn_bchannel *bc) if (stack->procids[proc_id] == 0) { break; } - } /* end for */ + } if (proc_id == MAXPROCS) { cb_log(0, stack->port, "Couldn't Create New ProcId.\n"); return -1; @@ -1560,7 +1586,14 @@ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_ setup_bc(bc); if ( *bc->crypt_key ) { - cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + cb_log(4, stack->port, + "ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n", + bc->channel, + bc->caller.number_type, + bc->caller.name, + bc->caller.number, + bc->dialed.number_type, + bc->dialed.number); manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); } @@ -1582,7 +1615,14 @@ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_ case EVENT_CONNECT: if ( *bc->crypt_key ) { - cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + cb_log(4, stack->port, + "ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n", + bc->channel, + bc->caller.number_type, + bc->caller.name, + bc->caller.number, + bc->dialed.number_type, + bc->dialed.number); manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); } case EVENT_ALERTING: @@ -2454,7 +2494,14 @@ static int handle_bchan(msg_t *msg) { unsigned int *cont = (unsigned int *) &frm->data.p; - cb_log(4, stack->port, "PH_CONTROL: channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + cb_log(4, stack->port, + "PH_CONTROL: channel:%d caller%d:\"%s\" <%s> dialed%d:%s \n", + bc->channel, + bc->caller.number_type, + bc->caller.name, + bc->caller.number, + bc->dialed.number_type, + bc->dialed.number); if ((*cont & ~DTMF_TONE_MASK) == DTMF_TONE_VAL) { int dtmf = *cont & DTMF_TONE_MASK; @@ -3268,10 +3315,6 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i return NULL; } - - - -/* ******************************************************************* */ /*! * \internal * \brief Convert the facility function enum value into a string. @@ -3286,14 +3329,8 @@ static const char *fac2str(enum FacFunction facility) } arr[] = { /* *INDENT-OFF* */ { Fac_None, "Fac_None" }, - { Fac_GetSupportedServices, "Fac_GetSupportedServices" }, - { Fac_Listen, "Fac_Listen" }, - { Fac_Suspend, "Fac_Suspend" }, - { Fac_Resume, "Fac_Resume" }, { Fac_CFActivate, "Fac_CFActivate" }, { Fac_CFDeactivate, "Fac_CFDeactivate" }, - { Fac_CFInterrogateParameters, "Fac_CFInterrogateParameters" }, - { Fac_CFInterrogateNumbers, "Fac_CFInterrogateNumbers" }, { Fac_CD, "Fac_CD" }, { Fac_AOCDCurrency, "Fac_AOCDCurrency" }, { Fac_AOCDChargingUnit, "Fac_AOCDChargingUnit" }, @@ -3306,10 +3343,10 @@ static const char *fac2str(enum FacFunction facility) if (arr[index].facility == facility) { return arr[index].name; } - } /* end for */ + } return "unknown"; -} /* end fac2str() */ +} void misdn_lib_log_ies(struct misdn_bchannel *bc) { @@ -3321,20 +3358,50 @@ void misdn_lib_log_ies(struct misdn_bchannel *bc) if (!stack) return; - cb_log(2, stack->port, " --> channel:%d mode:%s cause:%d ocause:%d rad:%s cad:%s\n", bc->channel, stack->nt?"NT":"TE", bc->cause, bc->out_cause, bc->rad, bc->cad); + cb_log(2, stack->port, + " --> channel:%d mode:%s cause:%d ocause:%d\n", + bc->channel, + stack->nt ? "NT" : "TE", + bc->cause, + bc->out_cause); + + cb_log(2, stack->port, + " --> info_dad:%s dialed numtype:%d plan:%d\n", + bc->info_dad, + bc->dialed.number_type, + bc->dialed.number_plan); + + cb_log(2, stack->port, + " --> caller:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n", + bc->caller.name, + bc->caller.number, + bc->caller.number_type, + bc->caller.number_plan, + bc->caller.presentation, + bc->caller.screening); + + cb_log(2, stack->port, + " --> redirecting:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d reason:%d\n", + bc->redirecting.from.name, + bc->redirecting.from.number, + bc->redirecting.from.number_type, + bc->redirecting.from.number_plan, + bc->redirecting.from.presentation, + bc->redirecting.from.screening, + bc->redirecting.reason); cb_log(2, stack->port, - " --> info_dad:%s onumplan:%c dnumplan:%c rnumplan:%c cpnnumplan:%c\n", - bc->info_dad, - bc->onumplan>=0?'0'+bc->onumplan:' ', - bc->dnumplan>=0?'0'+bc->dnumplan:' ', - bc->rnumplan>=0?'0'+bc->rnumplan:' ', - bc->cpnnumplan>=0?'0'+bc->cpnnumplan:' ' - ); + " --> connected:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n", + bc->connected.name, + bc->connected.number, + bc->connected.number_type, + bc->connected.number_plan, + bc->connected.presentation, + bc->connected.screening); cb_log(3, stack->port, " --> caps:%s pi:%x keypad:%s sending_complete:%d\n", bearer2str(bc->capability),bc->progress_indicator, bc->keypad, bc->sending_complete); - cb_log(4, stack->port, " --> screen:%d --> pres:%d\n", - bc->screen, bc->pres); + + cb_log(4, stack->port, " --> set_pres:%d pres:%d\n", bc->set_presentation, bc->presentation); cb_log(4, stack->port, " --> addr:%x l3id:%x b_stid:%x layer_id:%x\n", bc->addr, bc->l3_id, bc->b_stid, bc->layer_id); @@ -3373,7 +3440,12 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) stack = get_stack_by_bc(bc); if (!stack) { - cb_log(0,bc->port,"SENDEVENT: no Stack for event:%s oad:%s dad:%s \n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad); + cb_log(0,bc->port, + "SENDEVENT: no Stack for event:%s caller:\"%s\" <%s> dialed:%s \n", + isdn_get_info(msgs_g, event, 0), + bc->caller.name, + bc->caller.number, + bc->dialed.number); RETURN(-1,OUT); } @@ -3390,7 +3462,13 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) RETURN(0,OUT); } - cb_log(1, stack->port, "I SEND:%s oad:%s dad:%s pid:%d\n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad, bc->pid); + cb_log(1, stack->port, + "I SEND:%s caller:\"%s\" <%s> dialed:%s pid:%d\n", + isdn_get_info(msgs_g, event, 0), + bc->caller.name, + bc->caller.number, + bc->dialed.number, + bc->pid); cb_log(4, stack->port, " --> bc_state:%s\n",bc_state2str(bc->bc_state)); misdn_lib_log_ies(bc); @@ -3431,7 +3509,14 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) if (misdn_cap_is_speech(bc->capability)) { if ((event==EVENT_CONNECT)||(event==EVENT_RETRIEVE_ACKNOWLEDGE)) { if ( *bc->crypt_key ) { - cb_log(4, stack->port, " --> ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + cb_log(4, stack->port, + " --> ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n", + bc->channel, + bc->caller.number_type, + bc->caller.name, + bc->caller.number, + bc->dialed.number_type, + bc->dialed.number); manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); } @@ -3571,8 +3656,19 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) /* Later we should think about sending bchannel data directly to misdn. */ msg = isdn_msg_build_event(msgs_g, bc, event, stack->nt); - msg_queue_tail(&stack->downqueue, msg); - sem_post(&glob_mgr->new_msg); + if (!msg) { + /* + * The message was not built. + * + * NOTE: The only time that the message will fail to build + * is because the requested FACILITY message is not supported. + * A failed malloc() results in exit() being called. + */ + RETURN(-1, OUT); + } else { + msg_queue_tail(&stack->downqueue, msg); + sem_post(&glob_mgr->new_msg); + } OUT: misdn_send_unlock(bc); diff --git a/channels/misdn/isdn_lib.h b/channels/misdn/isdn_lib.h index 638df8a74..ff098c18b 100644 --- a/channels/misdn/isdn_lib.h +++ b/channels/misdn/isdn_lib.h @@ -96,15 +96,23 @@ enum misdn_err_e { ENOCHAN=1 }; - enum mISDN_NUMBER_PLAN { - NUMPLAN_UNINITIALIZED=-1, - NUMPLAN_INTERNATIONAL=0x1, - NUMPLAN_NATIONAL=0x2, - NUMPLAN_SUBSCRIBER=0x4, - NUMPLAN_UNKNOWN=0x0 + NUMPLAN_UNKNOWN = 0x0, + NUMPLAN_ISDN = 0x1, /* ISDN/Telephony numbering plan E.164 */ + NUMPLAN_DATA = 0x3, /* Data numbering plan X.121 */ + NUMPLAN_TELEX = 0x4, /* Telex numbering plan F.69 */ + NUMPLAN_NATIONAL = 0x8, + NUMPLAN_PRIVATE = 0x9 }; +enum mISDN_NUMBER_TYPE { + NUMTYPE_UNKNOWN = 0x0, + NUMTYPE_INTERNATIONAL = 0x1, + NUMTYPE_NATIONAL = 0x2, + NUMTYPE_NETWORK_SPECIFIC = 0x3, + NUMTYPE_SUBSCRIBER = 0x4, + NUMTYPE_ABBREVIATED = 0x5 +}; enum event_response_e { RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE, @@ -189,6 +197,19 @@ enum { /* progress indicators */ INFO_PI_INTERWORKING_NO_RELEASE_POST_ANSWER =0x13 }; +/*! + * \brief Q.931 encoded redirecting reason + */ +enum mISDN_REDIRECTING_REASON { + mISDN_REDIRECTING_REASON_UNKNOWN = 0x0, + mISDN_REDIRECTING_REASON_CALL_FWD_BUSY = 0x1, /* Call forwarding busy or called DTE busy */ + mISDN_REDIRECTING_REASON_NO_REPLY = 0x2, /* Call forwarding no reply */ + mISDN_REDIRECTING_REASON_DEFLECTION = 0x4, /* Call deflection */ + mISDN_REDIRECTING_REASON_OUT_OF_ORDER = 0x9, /* Called DTE out of order */ + mISDN_REDIRECTING_REASON_CALL_FWD_DTE = 0xA, /* Call forwarding by the called DTE */ + mISDN_REDIRECTING_REASON_CALL_FWD = 0xF /* Call forwarding unconditional or systematic call redirection */ +}; + enum { /*CODECS*/ INFO_CODEC_ULAW=2, INFO_CODEC_ALAW=3 @@ -202,12 +223,81 @@ enum layer_e { UNKNOWN }; +/* Maximum phone number (address) length plus null terminator */ +#define MISDN_MAX_NUMBER_LEN (31 + 1) + +/* Maximum name length plus null terminator (From ECMA-164) */ +#define MISDN_MAX_NAME_LEN (50 + 1) + +/* Maximum subaddress length plus null terminator */ +#define MISDN_MAX_SUBADDRESS_LEN (23 + 1) + +/* Maximum keypad facility content length plus null terminator */ +#define MISDN_MAX_KEYPAD_LEN (31 + 1) + +/*! \brief Connected-Line/Calling/Redirecting ID info struct */ +struct misdn_party_id { + /*! \brief Number presentation restriction code + * 0=Allowed, 1=Restricted, 2=Unavailable + */ + int presentation; + + /*! \brief Number screening code + * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number + */ + int screening; + + /*! \brief Type-of-number in ISDN terms for the number */ + enum mISDN_NUMBER_TYPE number_type; + + /*! \brief Type-of-number numbering plan. */ + enum mISDN_NUMBER_PLAN number_plan; + + /*! \brief Subscriber Name + * \note The name is currently obtained from Asterisk for + * potential use in display ie's since basic ISDN does + * not support names directly. + */ + char name[MISDN_MAX_NAME_LEN]; + + /*! \brief Phone number (Address) */ + char number[MISDN_MAX_NUMBER_LEN]; + + /*! \brief Subaddress number */ + char subaddress[MISDN_MAX_SUBADDRESS_LEN]; +}; + +/*! \brief Redirecting information struct */ +struct misdn_party_redirecting { + /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */ + struct misdn_party_id from; + + /*! \brief Reason a call is being redirected (Q.931 field value) */ + enum mISDN_REDIRECTING_REASON reason; +}; +/*! \brief B channel control structure */ struct misdn_bchannel { /*! \brief B channel send locking structure */ struct send_lock *send_lock; + /*! \brief Originating/Caller ID information struct + * \note The number_type element is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls + * \note The number element can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls + */ + struct misdn_party_id caller; + + /*! \brief Connected-Party/Connected-Line ID information struct + * \note The number_type element is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls + */ + struct misdn_party_id connected; + + /*! \brief Redirecting information struct (Where a call diversion or transfer was invoked) + * \note The redirecting subaddress is not defined in Q.931 so it is not used. + */ + struct misdn_party_redirecting redirecting; + /*! \brief TRUE if this is a dummy BC record */ int dummy; @@ -326,26 +416,6 @@ struct misdn_bchannel { /*! \brief TRUE if we will not use the jitter buffer system */ int nojitter; - /*! \brief Type-of-number in ISDN terms for the dialed/called number - * \note This value is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls - */ - enum mISDN_NUMBER_PLAN dnumplan; - - /*! \brief Type-of-number in ISDN terms for the redirecting number which a call diversion or transfer was invoked. - * \note Collected from the incoming SETUP message but not used. - */ - enum mISDN_NUMBER_PLAN rnumplan; - - /*! \brief Type-of-number in ISDN terms for the originating/calling number (Caller-ID) - * \note This value is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls - */ - enum mISDN_NUMBER_PLAN onumplan; - - /*! \brief Type-of-number in ISDN terms for the connected party number - * \note This value is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls - */ - enum mISDN_NUMBER_PLAN cpnnumplan; - /*! \brief Progress Indicator IE coding standard field. * \note Collected from the incoming messages but not used. */ @@ -421,16 +491,38 @@ struct misdn_bchannel { */ int stack_holder; - /*! \brief Caller ID presentation restriction code + /*! + * \brief Put a display ie in the CONNECT message + * \details + * Put a display ie in the CONNECT message containing the following + * information if it is available (nt port only): + * 0 - Do not put the connected line information in the display ie. + * 1 - Put the available connected line name in the display ie. + * 2 - Put the available connected line number in the display ie. + * 3 - Put the available connected line name and number in the display ie. + */ + int display_connected; + + /*! + * \brief Put a display ie in the SETUP message + * \details + * Put a display ie in the SETUP message containing the following + * information if it is available (nt port only): + * 0 - Do not put the caller information in the display ie. + * 1 - Put the available caller name in the display ie. + * 2 - Put the available caller number in the display ie. + * 3 - Put the available caller name and number in the display ie. + */ + int display_setup; + + /*! \brief User set presentation restriction code * 0=Allowed, 1=Restricted, 2=Unavailable * \note It is settable by the misdn_set_opt() application. */ - int pres; + int presentation; - /*! \brief Caller ID screening code - * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number - */ - int screen; + /*! \brief TRUE if the user set the presentation restriction code */ + int set_presentation; /*! \brief SETUP message bearer capability field code value */ int capability; @@ -462,6 +554,23 @@ struct misdn_bchannel { int hdlc; /* V110 */ + /*! \brief Dialed/Called information struct */ + struct { + /*! \brief Type-of-number in ISDN terms for the dialed/called number + * \note This value is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls + */ + enum mISDN_NUMBER_TYPE number_type; + + /*! \brief Type-of-number numbering plan. */ + enum mISDN_NUMBER_PLAN number_plan; + + /*! \brief Dialed/Called Phone Number (Address) */ + char number[MISDN_MAX_NUMBER_LEN]; + + /*! \brief Dialed/Called Subaddress number */ + char subaddress[MISDN_MAX_SUBADDRESS_LEN]; + } dialed; + /*! \brief Display message that can be displayed by the user phone. * \note Maximum displayable length is 34 or 82 octets. * It is also settable by the misdn_set_opt() application. @@ -469,39 +578,20 @@ struct misdn_bchannel { char display[84]; /*! \brief Not used. Contents are setup but not used. */ - char msn[32]; - - /*! \brief Originating/Calling Phone Number (Address) - * \note This value can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls - */ - char oad[32]; - - /*! \brief Redirecting Phone Number (Address) where a call diversion or transfer was invoked */ - char rad[32]; - - /*! \brief Dialed/Called Phone Number (Address) */ - char dad[32]; - - /*! \brief Connected Party/Line Phone Number (Address) */ - char cad[32]; - - /*! \brief Original Dialed/Called Phone Number (Address) before national/international dialing prefix added. - * \note Not used. Contents are setup but not used. - */ - char orig_dad[32]; + char msn[MISDN_MAX_NUMBER_LEN]; /*! \brief Q.931 Keypad Facility IE contents * \note Contents exported and imported to Asterisk variable MISDN_KEYPAD */ - char keypad[32]; + char keypad[MISDN_MAX_KEYPAD_LEN]; /*! \brief Current overlap dialing digits to/from INFORMATION messages */ - char info_dad[64]; + char info_dad[MISDN_MAX_NUMBER_LEN]; /*! \brief Collected digits to go into info_dad[] while waiting for a SETUP_ACKNOWLEDGE to come in. */ - char infos_pending[64]; + char infos_pending[MISDN_MAX_NUMBER_LEN]; -/* unsigned char info_keypad[32]; */ +/* unsigned char info_keypad[MISDN_MAX_KEYPAD_LEN]; */ /* unsigned char clisub[24]; */ /* unsigned char cldsub[24]; */ diff --git a/channels/misdn/isdn_lib_intern.h b/channels/misdn/isdn_lib_intern.h index a4ddc7a49..3347fe335 100644 --- a/channels/misdn/isdn_lib_intern.h +++ b/channels/misdn/isdn_lib_intern.h @@ -41,7 +41,6 @@ struct send_lock { struct isdn_msg { unsigned long misdn_msg; - enum layer_e layer; enum event_e event; void (*msg_parser)(struct isdn_msg *msgs, msg_t *msg, struct misdn_bchannel *bc, int nt); diff --git a/channels/misdn/isdn_msg_parser.c b/channels/misdn/isdn_msg_parser.c index 6c4272ea0..01c084ff7 100644 --- a/channels/misdn/isdn_msg_parser.c +++ b/channels/misdn/isdn_msg_parser.c @@ -25,6 +25,42 @@ #include "ie.c" +/*! + * \internal + * \brief Build the name, number, name/number display message string + * + * \param display Display buffer to fill in + * \param display_length Length of the display buffer to fill in + * \param display_format Display format enumeration + * \param name Name string to use + * \param number Number string to use + * + * \return Nothing + */ +static void build_display_str(char *display, size_t display_length, int display_format, const char *name, const char *number) +{ + display[0] = 0; + switch (display_format) { + default: + case 0: /* none */ + break; + + case 1: /* name */ + snprintf(display, display_length, "%s", name); + break; + + case 2: /* number */ + snprintf(display, display_length, "%s", number); + break; + + case 3: /* both */ + if (name[0] || number[0]) { + snprintf(display, display_length, "\"%s\" <%s>", name, number); + } + break; + } +} + static void set_channel(struct misdn_bchannel *bc, int channel) { @@ -161,62 +197,74 @@ static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchann int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; SETUP_t *setup= (SETUP_t*)((unsigned long)msg->data+HEADER_LEN); Q931_info_t *qi=(Q931_info_t*)((unsigned long)msg->data+HEADER_LEN); + int type; + int plan; + int present; + int screen; + int reason; #ifdef DEBUG printf("Parsing SETUP Msg\n"); #endif - { - int type,plan,present, screen; - char id[32]; - dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, id, sizeof(id)-1, nt,bc); - - bc->onumplan=type; - strcpy(bc->oad, id); - switch (present) { - case 0: - bc->pres=0; /* screened */ - break; - case 1: - bc->pres=1; /* not screened */ - break; - default: - bc->pres=0; - } - switch (screen) { - case 0: - break; - default: - ; - } - } - { - int type, plan; - char number[32]; - dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)setup, &type, &plan, number, sizeof(number)-1, nt,bc); - strcpy(bc->dad, number); - bc->dnumplan=type; + + dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, bc->caller.number, sizeof(bc->caller.number) - 1, nt, bc); + bc->caller.number_type = type; + bc->caller.number_plan = plan; + switch (present) { + default: + case 0: + bc->caller.presentation = 0; /* presentation allowed */ + break; + case 1: + bc->caller.presentation = 1; /* presentation restricted */ + break; + case 2: + bc->caller.presentation = 2; /* Number not available */ + break; } - { - char keypad[32]; - dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, keypad, sizeof(keypad)-1, nt,bc); - strcpy(bc->keypad, keypad); + if (0 <= screen) { + bc->caller.screening = screen; + } else { + bc->caller.screening = 0; /* Unscreened */ } - { - dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &bc->sending_complete, nt,bc); - + dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *) setup, &type, &plan, bc->dialed.number, sizeof(bc->dialed.number) - 1, nt, bc); + bc->dialed.number_type = type; + bc->dialed.number_plan = plan; + + dec_ie_keypad(setup->KEYPAD, (Q931_info_t *) setup, bc->keypad, sizeof(bc->keypad) - 1, nt, bc); + + dec_ie_complete(setup->COMPLETE, (Q931_info_t *) setup, &bc->sending_complete, nt, bc); + + dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *) setup, &type, &plan, &present, &screen, &reason, bc->redirecting.from.number, sizeof(bc->redirecting.from.number) - 1, nt, bc); + bc->redirecting.from.number_type = type; + bc->redirecting.from.number_plan = plan; + switch (present) { + default: + case 0: + bc->redirecting.from.presentation = 0; /* presentation allowed */ + break; + case 1: + bc->redirecting.from.presentation = 1; /* presentation restricted */ + break; + case 2: + bc->redirecting.from.presentation = 2; /* Number not available */ + break; } - - { - int type, plan, present, screen, reason; - char id[32]; - dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)setup, &type, &plan, &present, &screen, &reason, id, sizeof(id)-1, nt,bc); - - strcpy(bc->rad, id); - bc->rnumplan=type; + if (0 <= screen) { + bc->redirecting.from.screening = screen; + } else { + bc->redirecting.from.screening = 0; /* Unscreened */ + } + if (0 <= reason) { + bc->redirecting.reason = reason; + } else { + bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN; } + { int coding, capability, mode, rate, multi, user, async, urate, stopbits, dbits, parity; + dec_ie_bearer(setup->BEARER, (Q931_info_t *)setup, &coding, &capability, &mode, &rate, &multi, &user, &async, &urate, &stopbits, &dbits, &parity, nt,bc); switch (capability) { case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; @@ -271,7 +319,7 @@ static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchann } -#define ANY_CHANNEL 0xff /* IE attribut for 'any channel' */ +#define ANY_CHANNEL 0xff /* IE attribute for 'any channel' */ static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -286,35 +334,43 @@ static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, in enc_ie_channel_id(&setup->CHANNEL_ID, msg, 1, bc->channel, nt,bc); - { - int type=bc->onumplan,plan=1,present=bc->pres,screen=bc->screen; - enc_ie_calling_pn(&setup->CALLING_PN, msg, type, plan, present, - screen, bc->oad, nt, bc); - } + enc_ie_calling_pn(&setup->CALLING_PN, msg, bc->caller.number_type, bc->caller.number_plan, + bc->caller.presentation, bc->caller.screening, bc->caller.number, nt, bc); - { - if (bc->dad[0]) - enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, nt,bc); + if (bc->dialed.number[0]) { + enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dialed.number_type, bc->dialed.number_plan, bc->dialed.number, nt, bc); } - { - if (bc->rad[0]) - enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, nt,bc); + if (bc->redirecting.from.number[0]) { + enc_ie_redir_nr(&setup->REDIR_NR, msg, bc->redirecting.from.number_type, bc->redirecting.from.number_plan, + bc->redirecting.from.presentation, bc->redirecting.from.screening, bc->redirecting.reason, + bc->redirecting.from.number, nt, bc); } - { - if (bc->keypad[0]) - enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc); + if (bc->keypad[0]) { + enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc); } + if (*bc->display) { - enc_ie_display(&setup->DISPLAY, msg, bc->display, nt,bc); + enc_ie_display(&setup->DISPLAY, msg, bc->display, nt, bc); + } else if (nt && bc->caller.presentation == 0) { + char display[sizeof(bc->display)]; + + /* Presentation is allowed */ + build_display_str(display, sizeof(display), bc->display_setup, bc->caller.name, bc->caller.number); + if (display[0]) { + enc_ie_display(&setup->DISPLAY, msg, display, nt, bc); + } } { - int coding=0, capability, mode=0 /* 2 for packet ! */ - ,user, rate=0x10; + int coding = 0; + int capability; + int mode = 0; /* 2 for packet! */ + int user; + int rate = 0x10; switch (bc->law) { case INFO_CODEC_ULAW: user=2; @@ -340,8 +396,6 @@ static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, in capability=bc->capability; } - - enc_ie_bearer(&setup->BEARER, msg, coding, capability, mode, rate, -1, user, nt,bc); } @@ -365,15 +419,36 @@ static void parse_connect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bcha { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; CONNECT_t *connect=(CONNECT_t*)((unsigned long)(msg->data+HEADER_LEN)); + int type; + int plan; + int pres; + int screen; - int plan,pres,screen; - - bc->ces = connect->ces; bc->ces = connect->ces; dec_ie_progress(connect->PROGRESS, (Q931_info_t *)connect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc); - dec_ie_connected_pn(connect->CONNECT_PN,(Q931_info_t *)connect, &bc->cpnnumplan, &plan, &pres, &screen, bc->cad, 31, nt, bc); + dec_ie_connected_pn(connect->CONNECT_PN, (Q931_info_t *) connect, &type, &plan, + &pres, &screen, bc->connected.number, sizeof(bc->connected.number) - 1, nt, bc); + bc->connected.number_type = type; + bc->connected.number_plan = plan; + switch (pres) { + default: + case 0: + bc->connected.presentation = 0; /* presentation allowed */ + break; + case 1: + bc->connected.presentation = 1; /* presentation restricted */ + break; + case 2: + bc->connected.presentation = 2; /* Number not available */ + break; + } + if (0 <= screen) { + bc->connected.screening = screen; + } else { + bc->connected.screening = 0; /* Unscreened */ + } /* cb_log(1,bc->port,"CONNETED PN: %s cpn_dialplan:%d\n", connected_pn, type); @@ -400,9 +475,17 @@ static msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, enc_ie_date(&connect->DATE, msg, now, nt,bc); } - { - int type=bc->cpnnumplan, plan=1, present=2, screen=0; - enc_ie_connected_pn(&connect->CONNECT_PN, msg, type,plan, present, screen, bc->cad, nt , bc); + enc_ie_connected_pn(&connect->CONNECT_PN, msg, bc->connected.number_type, bc->connected.number_plan, + bc->connected.presentation, bc->connected.screening, bc->connected.number, nt, bc); + + if (nt && bc->connected.presentation == 0) { + char display[sizeof(bc->display)]; + + /* Presentation is allowed */ + build_display_str(display, sizeof(display), bc->display_connected, bc->connected.name, bc->connected.number); + if (display[0]) { + enc_ie_display(&connect->DISPLAY, msg, display, nt, bc); + } } #ifdef DEBUG @@ -982,12 +1065,12 @@ static void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bch static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { - int len, - HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN; - unsigned char *ie_fac, - fac_tmp[256]; - msg_t *msg =(msg_t*)create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc?bc->l3_id:-1, sizeof(FACILITY_t) ,nt); - FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN); + int len; + int HEADER_LEN; + unsigned char *ie_fac; + unsigned char fac_tmp[256]; + msg_t *msg; + FACILITY_t *facility; Q931_info_t *qi; #ifdef DEBUG @@ -995,8 +1078,14 @@ static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, #endif len = encodeFac(fac_tmp, &(bc->fac_out)); - if (len <= 0) + if (len <= 0) { + /* mISDN does not know how to build the requested facility structure */ return NULL; + } + + msg = (msg_t *) create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc ? bc->l3_id : -1, sizeof(FACILITY_t), nt); + HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN; + facility = (FACILITY_t *) (msg->data + HEADER_LEN); ie_fac = msg_put(msg, len); if (bc->nt) { @@ -1009,7 +1098,9 @@ static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, memcpy(ie_fac, fac_tmp, len); if (*bc->display) { +#ifdef DEBUG printf("Sending %s as Display\n", bc->display); +#endif enc_ie_display(&facility->DISPLAY, msg, bc->display, nt,bc); } @@ -1062,15 +1153,11 @@ static void parse_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_ { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; INFORMATION_t *information=(INFORMATION_t*)((unsigned long)(msg->data+HEADER_LEN)); - { - int type, plan; - char number[32]; - char keypad[32]; - dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *)information, &type, &plan, number, sizeof(number)-1, nt, bc); - dec_ie_keypad(information->KEYPAD, (Q931_info_t *)information, keypad, sizeof(keypad)-1, nt, bc); - strcpy(bc->info_dad, number); - strcpy(bc->keypad,keypad); - } + int type, plan; + + dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *) information, &type, &plan, bc->info_dad, sizeof(bc->info_dad) - 1, nt, bc); + dec_ie_keypad(information->KEYPAD, (Q931_info_t *) information, bc->keypad, sizeof(bc->keypad) - 1, nt, bc); + #ifdef DEBUG printf("Parsing INFORMATION Msg\n"); #endif @@ -1084,13 +1171,13 @@ static msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel * information=(INFORMATION_t*)((msg->data+HEADER_LEN)); - { - enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc); - } + enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc); { if (*bc->display) { +#ifdef DEBUG printf("Sending %s as Display\n", bc->display); +#endif enc_ie_display(&information->DISPLAY, msg, bc->display, nt,bc); } } @@ -1110,7 +1197,6 @@ static void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchan dec_ie_cause(status->CAUSE, (Q931_info_t *)(status), &location, &cause, nt,bc); if (cause>0) bc->cause=cause; - ; #ifdef DEBUG printf("Parsing STATUS Msg\n"); @@ -1161,97 +1247,40 @@ static msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc, /** Msg Array **/ struct isdn_msg msgs_g[] = { - {CC_PROCEEDING,L3,EVENT_PROCEEDING, - parse_proceeding,build_proceeding, - "PROCEEDING"}, - {CC_ALERTING,L3,EVENT_ALERTING, - parse_alerting,build_alerting, - "ALERTING"}, - {CC_PROGRESS,L3,EVENT_PROGRESS, - parse_progress,build_progress, - "PROGRESS"}, - {CC_SETUP,L3,EVENT_SETUP, - parse_setup,build_setup, - "SETUP"}, - {CC_CONNECT,L3,EVENT_CONNECT, - parse_connect,build_connect, - "CONNECT"}, - {CC_SETUP_ACKNOWLEDGE,L3,EVENT_SETUP_ACKNOWLEDGE, - parse_setup_acknowledge,build_setup_acknowledge, - "SETUP_ACKNOWLEDGE"}, - {CC_CONNECT_ACKNOWLEDGE ,L3,EVENT_CONNECT_ACKNOWLEDGE , - parse_connect_acknowledge ,build_connect_acknowledge, - "CONNECT_ACKNOWLEDGE "}, - {CC_USER_INFORMATION,L3,EVENT_USER_INFORMATION, - parse_user_information,build_user_information, - "USER_INFORMATION"}, - {CC_SUSPEND_REJECT,L3,EVENT_SUSPEND_REJECT, - parse_suspend_reject,build_suspend_reject, - "SUSPEND_REJECT"}, - {CC_RESUME_REJECT,L3,EVENT_RESUME_REJECT, - parse_resume_reject,build_resume_reject, - "RESUME_REJECT"}, - {CC_HOLD,L3,EVENT_HOLD, - parse_hold,build_hold, - "HOLD"}, - {CC_SUSPEND,L3,EVENT_SUSPEND, - parse_suspend,build_suspend, - "SUSPEND"}, - {CC_RESUME,L3,EVENT_RESUME, - parse_resume,build_resume, - "RESUME"}, - {CC_HOLD_ACKNOWLEDGE,L3,EVENT_HOLD_ACKNOWLEDGE, - parse_hold_acknowledge,build_hold_acknowledge, - "HOLD_ACKNOWLEDGE"}, - {CC_SUSPEND_ACKNOWLEDGE,L3,EVENT_SUSPEND_ACKNOWLEDGE, - parse_suspend_acknowledge,build_suspend_acknowledge, - "SUSPEND_ACKNOWLEDGE"}, - {CC_RESUME_ACKNOWLEDGE,L3,EVENT_RESUME_ACKNOWLEDGE, - parse_resume_acknowledge,build_resume_acknowledge, - "RESUME_ACKNOWLEDGE"}, - {CC_HOLD_REJECT,L3,EVENT_HOLD_REJECT, - parse_hold_reject,build_hold_reject, - "HOLD_REJECT"}, - {CC_RETRIEVE,L3,EVENT_RETRIEVE, - parse_retrieve,build_retrieve, - "RETRIEVE"}, - {CC_RETRIEVE_ACKNOWLEDGE,L3,EVENT_RETRIEVE_ACKNOWLEDGE, - parse_retrieve_acknowledge,build_retrieve_acknowledge, - "RETRIEVE_ACKNOWLEDGE"}, - {CC_RETRIEVE_REJECT,L3,EVENT_RETRIEVE_REJECT, - parse_retrieve_reject,build_retrieve_reject, - "RETRIEVE_REJECT"}, - {CC_DISCONNECT,L3,EVENT_DISCONNECT, - parse_disconnect,build_disconnect, - "DISCONNECT"}, - {CC_RESTART,L3,EVENT_RESTART, - parse_restart,build_restart, - "RESTART"}, - {CC_RELEASE,L3,EVENT_RELEASE, - parse_release,build_release, - "RELEASE"}, - {CC_RELEASE_COMPLETE,L3,EVENT_RELEASE_COMPLETE, - parse_release_complete,build_release_complete, - "RELEASE_COMPLETE"}, - {CC_FACILITY,L3,EVENT_FACILITY, - parse_facility,build_facility, - "FACILITY"}, - {CC_NOTIFY,L3,EVENT_NOTIFY, - parse_notify,build_notify, - "NOTIFY"}, - {CC_STATUS_ENQUIRY,L3,EVENT_STATUS_ENQUIRY, - parse_status_enquiry,build_status_enquiry, - "STATUS_ENQUIRY"}, - {CC_INFORMATION,L3,EVENT_INFORMATION, - parse_information,build_information, - "INFORMATION"}, - {CC_STATUS,L3,EVENT_STATUS, - parse_status,build_status, - "STATUS"}, - {CC_TIMEOUT,L3,EVENT_TIMEOUT, - parse_timeout,build_timeout, - "TIMEOUT"}, - {0,0,0,NULL,NULL,NULL} +/* *INDENT-OFF* */ + /* misdn_msg, event, msg_parser, msg_builder, info */ + { CC_PROCEEDING, EVENT_PROCEEDING, parse_proceeding, build_proceeding, "PROCEEDING" }, + { CC_ALERTING, EVENT_ALERTING, parse_alerting, build_alerting, "ALERTING" }, + { CC_PROGRESS, EVENT_PROGRESS, parse_progress, build_progress, "PROGRESS" }, + { CC_SETUP, EVENT_SETUP, parse_setup, build_setup, "SETUP" }, + { CC_CONNECT, EVENT_CONNECT, parse_connect, build_connect, "CONNECT" }, + { CC_SETUP_ACKNOWLEDGE, EVENT_SETUP_ACKNOWLEDGE, parse_setup_acknowledge, build_setup_acknowledge, "SETUP_ACKNOWLEDGE" }, + { CC_CONNECT_ACKNOWLEDGE, EVENT_CONNECT_ACKNOWLEDGE, parse_connect_acknowledge, build_connect_acknowledge, "CONNECT_ACKNOWLEDGE " }, + { CC_USER_INFORMATION, EVENT_USER_INFORMATION, parse_user_information, build_user_information, "USER_INFORMATION" }, + { CC_SUSPEND_REJECT, EVENT_SUSPEND_REJECT, parse_suspend_reject, build_suspend_reject, "SUSPEND_REJECT" }, + { CC_RESUME_REJECT, EVENT_RESUME_REJECT, parse_resume_reject, build_resume_reject, "RESUME_REJECT" }, + { CC_HOLD, EVENT_HOLD, parse_hold, build_hold, "HOLD" }, + { CC_SUSPEND, EVENT_SUSPEND, parse_suspend, build_suspend, "SUSPEND" }, + { CC_RESUME, EVENT_RESUME, parse_resume, build_resume, "RESUME" }, + { CC_HOLD_ACKNOWLEDGE, EVENT_HOLD_ACKNOWLEDGE, parse_hold_acknowledge, build_hold_acknowledge, "HOLD_ACKNOWLEDGE" }, + { CC_SUSPEND_ACKNOWLEDGE, EVENT_SUSPEND_ACKNOWLEDGE, parse_suspend_acknowledge, build_suspend_acknowledge, "SUSPEND_ACKNOWLEDGE" }, + { CC_RESUME_ACKNOWLEDGE, EVENT_RESUME_ACKNOWLEDGE, parse_resume_acknowledge, build_resume_acknowledge, "RESUME_ACKNOWLEDGE" }, + { CC_HOLD_REJECT, EVENT_HOLD_REJECT, parse_hold_reject, build_hold_reject, "HOLD_REJECT" }, + { CC_RETRIEVE, EVENT_RETRIEVE, parse_retrieve, build_retrieve, "RETRIEVE" }, + { CC_RETRIEVE_ACKNOWLEDGE, EVENT_RETRIEVE_ACKNOWLEDGE, parse_retrieve_acknowledge, build_retrieve_acknowledge, "RETRIEVE_ACKNOWLEDGE" }, + { CC_RETRIEVE_REJECT, EVENT_RETRIEVE_REJECT, parse_retrieve_reject, build_retrieve_reject, "RETRIEVE_REJECT" }, + { CC_DISCONNECT, EVENT_DISCONNECT, parse_disconnect, build_disconnect, "DISCONNECT" }, + { CC_RESTART, EVENT_RESTART, parse_restart, build_restart, "RESTART" }, + { CC_RELEASE, EVENT_RELEASE, parse_release, build_release, "RELEASE" }, + { CC_RELEASE_COMPLETE, EVENT_RELEASE_COMPLETE, parse_release_complete, build_release_complete, "RELEASE_COMPLETE" }, + { CC_FACILITY, EVENT_FACILITY, parse_facility, build_facility, "FACILITY" }, + { CC_NOTIFY, EVENT_NOTIFY, parse_notify, build_notify, "NOTIFY" }, + { CC_STATUS_ENQUIRY, EVENT_STATUS_ENQUIRY, parse_status_enquiry, build_status_enquiry, "STATUS_ENQUIRY" }, + { CC_INFORMATION, EVENT_INFORMATION, parse_information, build_information, "INFORMATION" }, + { CC_STATUS, EVENT_STATUS, parse_status, build_status, "STATUS" }, + { CC_TIMEOUT, EVENT_TIMEOUT, parse_timeout, build_timeout, "TIMEOUT" }, + { 0, 0, NULL, NULL, NULL } +/* *INDENT-ON* */ }; #define msgs_max (sizeof(msgs_g)/sizeof(struct isdn_msg)) diff --git a/channels/misdn_config.c b/channels/misdn_config.c index f447c5c21..444b939f2 100644 --- a/channels/misdn_config.c +++ b/channels/misdn_config.c @@ -132,7 +132,7 @@ static const struct misdn_cfg_spec port_spec[] = { { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE, "Sets the musiconhold class." }, { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE, - "Sets the caller ID." }, + "Set the outgoing caller id to the value." }, { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE, "Set the method to use for channel selection:\n" "\t standard - Use the first free channel starting from the lowest number.\n" @@ -140,62 +140,71 @@ static const struct misdn_cfg_spec port_spec[] = { "\t round_robin - Use the round robin algorithm to select a channel. Use this\n" "\t if you want to balance your load." }, { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE, - "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n" - "\n" + "Dialplan means Type Of Number in ISDN Terms\n" "\tThere are different types of the dialplan:\n" "\n" - "\tdialplan -> outgoing Number\n" - "\tlocaldialplan -> callerid\n" - "\tcpndialplan -> connected party number\n" + "\tdialplan -> for outgoing call's dialed number\n" + "\tlocaldialplan -> for outgoing call's callerid\n" + "\t (if -1 is set use the value from the asterisk channel)\n" + "\tcpndialplan -> for incoming call's connected party number sent to caller\n" + "\t (if -1 is set use the value from the asterisk channel)\n" "\n" "\tdialplan options:\n" "\n" "\t0 - unknown\n" "\t1 - International\n" "\t2 - National\n" - "\t4 - Subscriber\n" - "\n" - "\tThis setting is used for outgoing calls." }, + "\t4 - Subscriber" }, { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE, - "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n" - "\n" + "Dialplan means Type Of Number in ISDN Terms\n" "\tThere are different types of the dialplan:\n" "\n" - "\tdialplan -> outgoing Number\n" - "\tlocaldialplan -> callerid\n" - "\tcpndialplan -> connected party number\n" + "\tdialplan -> for outgoing call's dialed number\n" + "\tlocaldialplan -> for outgoing call's callerid\n" + "\t (if -1 is set use the value from the asterisk channel)\n" + "\tcpndialplan -> for incoming call's connected party number sent to caller\n" + "\t (if -1 is set use the value from the asterisk channel)\n" "\n" "\tdialplan options:\n" "\n" "\t0 - unknown\n" "\t1 - International\n" "\t2 - National\n" - "\t4 - Subscriber\n" - "\n" - "\tThis setting is used for outgoing calls." }, + "\t4 - Subscriber" }, { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE, - "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n" - "\n" + "Dialplan means Type Of Number in ISDN Terms\n" "\tThere are different types of the dialplan:\n" "\n" - "\tdialplan -> outgoing Number\n" - "\tlocaldialplan -> callerid\n" - "\tcpndialplan -> connected party number\n" + "\tdialplan -> for outgoing call's dialed number\n" + "\tlocaldialplan -> for outgoing call's callerid\n" + "\t (if -1 is set use the value from the asterisk channel)\n" + "\tcpndialplan -> for incoming call's connected party number sent to caller\n" + "\t (if -1 is set use the value from the asterisk channel)\n" "\n" "\tdialplan options:\n" "\n" "\t0 - unknown\n" "\t1 - International\n" "\t2 - National\n" - "\t4 - Subscriber\n" - "\n" - "\tThis setting is used for outgoing calls." }, - { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE, - "Prefix for national, this is put before the\n" - "\toad if an according dialplan is set by the other end." }, - { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE, - "Prefix for international, this is put before the\n" - "\toad if an according dialplan is set by the other end." }, + "\t4 - Subscriber" }, + { "unknownprefix", MISDN_CFG_TON_PREFIX_UNKNOWN, MISDN_CTYPE_STR, "", NONE, + "Prefix for unknown numbers, this is put before an incoming number\n" + "\tif its type-of-number is unknown." }, + { "internationalprefix", MISDN_CFG_TON_PREFIX_INTERNATIONAL, MISDN_CTYPE_STR, "00", NONE, + "Prefix for international numbers, this is put before an incoming number\n" + "\tif its type-of-number is international." }, + { "nationalprefix", MISDN_CFG_TON_PREFIX_NATIONAL, MISDN_CTYPE_STR, "0", NONE, + "Prefix for national numbers, this is put before an incoming number\n" + "\tif its type-of-number is national." }, + { "netspecificprefix", MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC, MISDN_CTYPE_STR, "", NONE, + "Prefix for network-specific numbers, this is put before an incoming number\n" + "\tif its type-of-number is network-specific." }, + { "subscriberprefix", MISDN_CFG_TON_PREFIX_SUBSCRIBER, MISDN_CTYPE_STR, "", NONE, + "Prefix for subscriber numbers, this is put before an incoming number\n" + "\tif its type-of-number is subscriber." }, + { "abbreviatedprefix", MISDN_CFG_TON_PREFIX_ABBREVIATED, MISDN_CTYPE_STR, "", NONE, + "Prefix for abbreviated numbers, this is put before an incoming number\n" + "\tif its type-of-number is abbreviated." }, { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE, "These (presentation and screen) are the exact isdn screening and presentation\n" "\tindicators.\n" @@ -212,6 +221,22 @@ static const struct misdn_cfg_spec port_spec[] = { "\n" "\tscreen=0, presentation=0 -> callerid presented\n" "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" }, + { "display_connected", MISDN_CFG_DISPLAY_CONNECTED, MISDN_CTYPE_INT, "0", NONE, + "Put a display ie in the CONNECT message containing the following\n" + "\tinformation if it is available (nt port only):\n" + "\n" + "\t0 - Do not put the connected line information in the display ie.\n" + "\t1 - Put the available connected line name in the display ie.\n" + "\t2 - Put the available connected line number in the display ie.\n" + "\t3 - Put the available connected line name and number in the display ie." }, + { "display_setup", MISDN_CFG_DISPLAY_SETUP, MISDN_CTYPE_INT, "0", NONE, + "Put a display ie in the SETUP message containing the following\n" + "\tinformation if it is available (nt port only):\n" + "\n" + "\t0 - Do not put the caller information in the display ie.\n" + "\t1 - Put the available caller name in the display ie.\n" + "\t2 - Put the available caller number in the display ie.\n" + "\t3 - Put the available caller name and number in the display ie." }, { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE, "Enable this to get into the s dialplan-extension.\n" "\tThere you can use DigitTimeout if you can't or don't want to use\n" @@ -220,7 +245,7 @@ static const struct misdn_cfg_spec port_spec[] = { { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE, "Enable this to prevent chan_misdn to generate the dialtone\n" "\tThis makes only sense together with the always_immediate=yes option\n" - "\tto generate your own dialtone with Playtones or so."}, + "\tto generate your own dialtone with Playtones or so." }, { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE, "Enable this if you want callers which called exactly the base\n" "\tnumber (so no extension is set) to jump into the s extension.\n" @@ -257,17 +282,17 @@ static const struct misdn_cfg_spec port_spec[] = { #endif #ifdef WITH_BEROEC { "bnechocancel", MISDN_CFG_BNECHOCANCEL, MISDN_CTYPE_BOOLINT, "yes", 64, - "echotail in ms (1-200)\n"}, + "echotail in ms (1-200)" }, { "bnec_antihowl", MISDN_CFG_BNEC_ANTIHOWL, MISDN_CTYPE_INT, "0", NONE, - "Use antihowl\n"}, + "Use antihowl" }, { "bnec_nlp", MISDN_CFG_BNEC_NLP, MISDN_CTYPE_BOOL, "yes", NONE, - "Nonlinear Processing (much faster adaption)"}, + "Nonlinear Processing (much faster adaption)" }, { "bnec_zerocoeff", MISDN_CFG_BNEC_ZEROCOEFF, MISDN_CTYPE_BOOL, "no", NONE, - "ZeroCoeffeciens\n"}, + "ZeroCoeffeciens" }, { "bnec_tonedisabler", MISDN_CFG_BNEC_TD, MISDN_CTYPE_BOOL, "no", NONE, - "Disable Tone\n"}, + "Disable Tone" }, { "bnec_adaption", MISDN_CFG_BNEC_ADAPT, MISDN_CTYPE_INT, "1", NONE, - "Adaption mode (0=no,1=full,2=fast)\n"}, + "Adaption mode (0=no,1=full,2=fast)" }, #endif { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE, "Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n" @@ -311,13 +336,13 @@ static const struct misdn_cfg_spec port_spec[] = { { "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE, "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." }, { "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4, - "Watches the layer 1. If the layer 1 is down, it tries to\n" - "\tget it up. The timeout is given in seconds. with 0 as value it\n" - "\tdoes not watch the l1 at all\n" + "Monitors L1 of the port. If L1 is down it tries\n" + "\tto bring it up. The polling timeout is given in seconds.\n" + "\tSetting the value to 0 disables monitoring L1 of the port.\n" "\n" - "\tThis option is only read at loading time of chan_misdn, which\n" - "\tmeans you need to unload and load chan_misdn to change the value,\n" - "\tan Asterisk restart should do the trick." }, + "\tThis option is only read at chan_misdn loading time.\n" + "\tYou need to unload and load chan_misdn to change the\n" + "\tvalue. An asterisk restart will also do the trick." }, { "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4, "Enables overlap dial for the given amount of seconds.\n" "\tPossible values are positive integers or:\n" |