Index: channels/chan_dahdi.c =================================================================== --- a/channels/chan_dahdi.c (.../trunk) (revision 186562) +++ b/channels/chan_dahdi.c (.../team/group/issue14068) (revision 186562) @@ -3096,6 +3096,196 @@ } #endif /* defined(HAVE_SS7) */ +#if defined(HAVE_PRI) +static enum AST_REDIRECTING_REASON pri_to_ast_reason(int pri_reason) +{ + enum AST_REDIRECTING_REASON ast_reason; + + switch (pri_reason) { + case PRI_REDIR_FORWARD_ON_BUSY: + ast_reason = AST_REDIRECTING_REASON_USER_BUSY; + break; + case PRI_REDIR_FORWARD_ON_NO_REPLY: + ast_reason = AST_REDIRECTING_REASON_NO_ANSWER; + break; + case PRI_REDIR_DEFLECTION: + ast_reason = AST_REDIRECTING_REASON_DEFLECTION; + break; + case PRI_REDIR_UNCONDITIONAL: + ast_reason = AST_REDIRECTING_REASON_UNCONDITIONAL; + break; + case PRI_REDIR_UNKNOWN: + default: + ast_reason = AST_REDIRECTING_REASON_UNKNOWN; + break; + } /* end switch */ + + return ast_reason; +} +#endif /* defined(HAVE_PRI) */ + +#if defined(HAVE_PRI) +static int ast_to_pri_reason(enum AST_REDIRECTING_REASON ast_reason) +{ + int pri_reason; + + switch (ast_reason) { + case AST_REDIRECTING_REASON_USER_BUSY: + pri_reason = PRI_REDIR_FORWARD_ON_BUSY; + break; + case AST_REDIRECTING_REASON_NO_ANSWER: + pri_reason = PRI_REDIR_FORWARD_ON_NO_REPLY; + break; + case AST_REDIRECTING_REASON_UNCONDITIONAL: + pri_reason = PRI_REDIR_UNCONDITIONAL; + break; + case AST_REDIRECTING_REASON_DEFLECTION: + pri_reason = PRI_REDIR_DEFLECTION; + break; + case AST_REDIRECTING_REASON_UNKNOWN: + default: + pri_reason = PRI_REDIR_UNKNOWN; + break; + } /* end switch */ + + return pri_reason; +} +#endif /* defined(HAVE_PRI) */ + +#if defined(HAVE_PRI) +static int pri_to_ast_presentation(int pri_presentation) +{ + int ast_presentation; + + switch (pri_presentation) { + case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: + ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + break; + case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: + ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; + break; + case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: + ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN; + break; + case PRES_ALLOWED_NETWORK_NUMBER: + ast_presentation = AST_PRES_ALLOWED_NETWORK_NUMBER; + break; + case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: + ast_presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + break; + case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: + ast_presentation = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; + break; + case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: + ast_presentation = AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN; + break; + case PRES_PROHIB_NETWORK_NUMBER: + ast_presentation = AST_PRES_PROHIB_NETWORK_NUMBER; + break; + case PRES_NUMBER_NOT_AVAILABLE: + ast_presentation = AST_PRES_NUMBER_NOT_AVAILABLE; + break; + default: + ast_presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; /* ?? */ + break; + } /* end switch */ + + return ast_presentation; +} +#endif /* defined(HAVE_PRI) */ + +#if defined(HAVE_PRI) +static int ast_to_pri_presentation(int ast_presentation) +{ + int pri_presentation; + + switch (ast_presentation) { + case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: + pri_presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + break; + case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: + pri_presentation = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; + break; + case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: + pri_presentation = PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN; + break; + case AST_PRES_ALLOWED_NETWORK_NUMBER: + pri_presentation = PRES_ALLOWED_NETWORK_NUMBER; + break; + case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: + pri_presentation = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + break; + case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: + pri_presentation = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; + break; + case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: + pri_presentation = PRES_PROHIB_USER_NUMBER_FAILED_SCREEN; + break; + case AST_PRES_PROHIB_NETWORK_NUMBER: + pri_presentation = PRES_PROHIB_NETWORK_NUMBER; + break; + case AST_PRES_NUMBER_NOT_AVAILABLE: + pri_presentation = PRES_NUMBER_NOT_AVAILABLE; + break; + default: + pri_presentation = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; /* ?? */ + break; + } /* end switch */ + + return pri_presentation; +} +#endif /* defined(HAVE_PRI) */ + +#if defined(HAVE_PRI) +static enum AST_CONNECTED_LINE_UPDATE_SOURCE pri_to_ast_connected_line_update_source(enum PRI_CONNECTED_LINE_UPDATE_SOURCE pri_source) +{ + enum AST_CONNECTED_LINE_UPDATE_SOURCE ast_source; + + switch (pri_source) { + case PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER: + ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + break; + case PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER: + ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + break; + case PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING: + ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING; + break; + case PRI_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN: + default: + ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN; + break; + } /* end switch */ + + return ast_source; +} +#endif /* defined(HAVE_PRI) */ + +#if defined(HAVE_PRI) +static enum PRI_CONNECTED_LINE_UPDATE_SOURCE ast_to_pri_connected_line_update_source(enum AST_CONNECTED_LINE_UPDATE_SOURCE ast_source) +{ + enum PRI_CONNECTED_LINE_UPDATE_SOURCE pri_source; + + switch (ast_source) { + case AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER: + pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + break; + case AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER: + pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; + break; + case AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING: + pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING; + break; + case AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN: + default: + pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN; + break; + } /* end switch */ + + return pri_source; +} +#endif /* defined(HAVE_PRI) */ + static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) { struct dahdi_pvt *p = ast->tech_pvt; @@ -3391,7 +3581,8 @@ ast_mutex_unlock(&p->lock); return -1; } -#ifdef HAVE_SS7 + +#if defined(HAVE_SS7) if (p->ss7) { char ss7_called_nai; int called_nai_strip; @@ -3528,7 +3719,8 @@ ast_setstate(ast, AST_STATE_DIALING); ss7_rel(p->ss7); } -#endif /* HAVE_SS7 */ +#endif /* defined(HAVE_SS7) */ + #ifdef HAVE_OPENR2 if (p->mfcr2) { openr2_calling_party_category_t chancat; @@ -3563,7 +3755,8 @@ ast_setstate(ast, AST_STATE_DIALING); } #endif /* HAVE_OPENR2 */ -#ifdef HAVE_PRI + +#if defined(HAVE_PRI) if (p->pri) { struct pri_sr *sr; #ifdef SUPPORT_USERUSER @@ -3574,8 +3767,6 @@ int prilocaldialplan; int ldp_strip; int exclusive; - const char *rr_str; - int redirect_reason; c = strchr(dest, '/'); if (c) { @@ -3804,20 +3995,10 @@ } pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan, 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; - else if (!strcasecmp(rr_str, "BUSY")) - redirect_reason = 1; - else if (!strcasecmp(rr_str, "NO_REPLY")) - redirect_reason = 2; - else if (!strcasecmp(rr_str, "UNCONDITIONAL")) - redirect_reason = 15; - else - redirect_reason = PRI_REDIR_UNCONDITIONAL; - } else - redirect_reason = PRI_REDIR_UNCONDITIONAL; - pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason); + pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, ast->redirecting.from.number_type, + ast->redirecting.from.number_presentation, + ast_to_pri_reason(ast->redirecting.reason)); + pri_sr_set_redirecting_name(sr, ast->redirecting.from.name); #ifdef SUPPORT_USERUSER /* User-user info */ @@ -3838,7 +4019,8 @@ ast_setstate(ast, AST_STATE_DIALING); pri_rel(p->pri); } -#endif +#endif /* defined(HAVE_PRI) */ + ast_mutex_unlock(&p->lock); return 0; } @@ -7111,6 +7293,7 @@ int res=-1; int idx; int func = DAHDI_FLASH; + ast_mutex_lock(&p->lock); idx = dahdi_get_index(chan, p, 0); ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name); @@ -7345,6 +7528,65 @@ case -1: res = tone_zone_play_tone(p->subs[idx].dfd, -1); break; + case AST_CONTROL_CONNECTED_LINE: + ast_debug(1, "Received AST_CONTROL_CONNECTED_LINE on %s\n", chan->name); +#if defined(HAVE_PRI) + if (p->pri) { + struct pri_party_connected_line connected; + + if (chan->connected.id.number) { + ast_copy_string(connected.id.number, chan->connected.id.number, sizeof(connected.id.number)); + } else { + connected.id.number[0] = '\0'; + } + if (chan->connected.id.name) { + ast_copy_string(connected.id.name, chan->connected.id.name, sizeof(connected.id.name)); + } else { + connected.id.name[0] = '\0'; + } + connected.id.number_type = chan->connected.id.number_type; + connected.id.number_presentation = ast_to_pri_presentation(chan->connected.id.number_presentation); + connected.source = ast_to_pri_connected_line_update_source(chan->connected.source); + pri_connected_line_update(p->pri->pri, p->call, &connected); + } +#endif /* defined(HAVE_PRI) */ + break; + case AST_CONTROL_REDIRECTING: + ast_debug(1, "Received AST_CONTROL_REDIRECTING on %s\n", chan->name); +#if defined(HAVE_PRI) + if (p->pri) { + struct pri_party_redirecting redirecting; + + if (chan->cid.cid_rdnis) { + ast_copy_string(redirecting.from.number, chan->cid.cid_rdnis, sizeof(redirecting.from.number)); + } else { + redirecting.from.number[0] = '\0'; + } + if (chan->redirecting.from.name) { + ast_copy_string(redirecting.from.name, chan->redirecting.from.name, sizeof(redirecting.from.name)); + } else { + redirecting.from.name[0] = '\0'; + } + redirecting.from.number_type = chan->redirecting.from.number_type; + redirecting.from.number_presentation = ast_to_pri_presentation(chan->redirecting.from.number_presentation); + if (chan->redirecting.to.number) { + ast_copy_string(redirecting.to.number, chan->redirecting.to.number, sizeof(redirecting.to.number)); + } else { + redirecting.to.number[0] = '\0'; + } + if (chan->redirecting.to.name) { + ast_copy_string(redirecting.to.name, chan->redirecting.to.name, sizeof(redirecting.to.name)); + } else { + redirecting.to.name[0] = '\0'; + } + redirecting.to.number_type = chan->redirecting.to.number_type; + redirecting.to.number_presentation = ast_to_pri_presentation(chan->redirecting.to.number_presentation); + redirecting.count = chan->redirecting.count; + redirecting.reason = ast_to_pri_reason(chan->redirecting.reason); + pri_redirecting_update(p->pri->pri, p->call, &redirecting); + } +#endif /* defined(HAVE_PRI) */ + break; } } else res = 0; @@ -12607,17 +12849,17 @@ if (chanpos > -1) { ast_mutex_lock(&pri->pvts[chanpos]->lock); /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */ - if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) { + if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) + && pri->pvts[chanpos]->call == e->digit.call + && pri->pvts[chanpos]->owner) { /* how to do that */ int digitlen = strlen(e->digit.digits); - char digit; int i; + for (i = 0; i < digitlen; i++) { - digit = e->digit.digits[i]; - { - struct ast_frame f = { AST_FRAME_DTMF, digit, }; - dahdi_queue_frame(pri->pvts[chanpos], &f, pri); - } + struct ast_frame f = { AST_FRAME_DTMF, e->digit.digits[i], }; + + dahdi_queue_frame(pri->pvts[chanpos], &f, pri); } } ast_mutex_unlock(&pri->pvts[chanpos]->lock); @@ -12635,17 +12877,40 @@ if (chanpos > -1) { ast_mutex_lock(&pri->pvts[chanpos]->lock); /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */ - if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) { + if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) + && pri->pvts[chanpos]->call == e->ring.call + && pri->pvts[chanpos]->owner) { /* how to do that */ int digitlen = strlen(e->ring.callednum); - char digit; int i; + for (i = 0; i < digitlen; i++) { - digit = e->ring.callednum[i]; - { - struct ast_frame f = { AST_FRAME_DTMF, digit, }; - dahdi_queue_frame(pri->pvts[chanpos], &f, pri); + struct ast_frame f = { AST_FRAME_DTMF, e->ring.callednum[i], }; + + dahdi_queue_frame(pri->pvts[chanpos], &f, pri); + } + if (pri->pvts[chanpos]->owner) { + char dnid[AST_MAX_EXTENSION]; + + /* + * Append the received info digits to the end of + * the exten and dnid strings + */ + strncat(pri->pvts[chanpos]->owner->exten, + e->ring.callednum, + sizeof(pri->pvts[chanpos]->owner->exten) - 1 + - strlen(pri->pvts[chanpos]->owner->exten)); + if (pri->pvts[chanpos]->owner->cid.cid_dnid) { + ast_copy_string(dnid, + pri->pvts[chanpos]->owner->cid.cid_dnid, + sizeof(dnid)); + ast_free(pri->pvts[chanpos]->owner->cid.cid_dnid); + } else { + dnid[0] = 0; } + strncat(dnid, e->ring.callednum, + sizeof(dnid) - 1 - strlen(dnid)); + pri->pvts[chanpos]->owner->cid.cid_dnid = ast_strdup(dnid); } } ast_mutex_unlock(&pri->pvts[chanpos]->lock); @@ -12683,6 +12948,7 @@ if ((chanpos < 0) && (e->ring.flexible)) chanpos = pri_find_empty_chan(pri, 1); if (chanpos > -1) { + struct ast_party_redirecting redirecting = {{0,},}; ast_mutex_lock(&pri->pvts[chanpos]->lock); if (pri->switchtype == PRI_SWITCH_GR303_TMC) { /* Should be safe to lock CRV AFAIK while bearer is still locked */ @@ -12704,6 +12970,17 @@ break; } } + if (e->ring.redirectingnum[0] || e->ring.redirectingname[0]) { + redirecting.to.number = e->ring.callednum; + redirecting.to.number_type = e->ring.calledplan; + redirecting.to.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + redirecting.from.name = e->ring.redirectingname; + redirecting.from.number = e->ring.redirectingnum; + redirecting.from.number_presentation = e->ring.redirectingpres; + redirecting.from.number_type = e->ring.callingplanrdnis; + redirecting.reason = pri_to_ast_reason(e->ring.redirectingreason); + redirecting.count = e->ring.redirectingcount; + } pri->pvts[chanpos]->call = e->ring.call; apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan); if (pri->pvts[chanpos]->use_callerid) { @@ -12789,7 +13066,9 @@ pri->pvts[chanpos]->callingpres = e->ring.callingpres; /* Start PBX */ - if (!e->ring.complete && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) { + if (!e->ring.complete + && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) + && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) { /* Release the PRI lock while we create the channel */ ast_mutex_unlock(&pri->lock); if (crv) { @@ -12804,6 +13083,9 @@ ast_mutex_unlock(&pri->pvts[chanpos]->lock); + if (c && (redirecting.from.number || redirecting.from.name)) { + ast_channel_update_redirecting(c, &redirecting); + } if (!ast_strlen_zero(e->ring.callingsubaddr)) { pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr); } @@ -12821,8 +13103,10 @@ snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan); pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr); - if (e->ring.redirectingreason >= 0) + if (e->ring.redirectingreason >= 0) { + /* This is now just a status variable. Use REDIRECTING() dialplan function. */ pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason)); + } ast_mutex_lock(&pri->pvts[chanpos]->lock); ast_mutex_lock(&pri->lock); @@ -12849,6 +13133,9 @@ ast_mutex_unlock(&pri->pvts[chanpos]->lock); + if (redirecting.from.number || redirecting.from.name) { + ast_channel_update_redirecting(c, &redirecting); + } if (e->ring.ani2 >= 0) { snprintf(ani2str, 5, "%d", e->ring.ani2); pbx_builtin_setvar_helper(c, "ANI2", ani2str); @@ -12861,8 +13148,10 @@ } #endif - if (e->ring.redirectingreason >= 0) + if (e->ring.redirectingreason >= 0) { + /* This is now just a status variable. Use REDIRECTING() dialplan function. */ pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason)); + } snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan); pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr); @@ -12946,6 +13235,19 @@ } #endif + if ((e->ringing.calledname[0] || e->ringing.callednum[0]) && pri->pvts[chanpos]->owner) { + struct ast_party_connected_line connected; + + /* Update the connected line information on the other channel */ + ast_party_connected_line_init(&connected); + connected.id.name = e->ringing.calledname; + connected.id.number = e->ringing.callednum; + connected.id.number_type = e->ringing.calledplan; + connected.id.number_presentation = pri_to_ast_presentation(e->ringing.calledpres); + connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + ast_channel_queue_connected_line_update(pri->pvts[chanpos]->owner, &connected); + } + ast_mutex_unlock(&pri->pvts[chanpos]->lock); } } @@ -13050,12 +13352,85 @@ ast_mutex_lock(&pri->pvts[chanpos]->lock); ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num)); ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name)); - pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1; + pri->pvts[chanpos]->subs[SUB_REAL].needcallerid = 1; dahdi_enable_ec(pri->pvts[chanpos]); ast_mutex_unlock(&pri->pvts[chanpos]->lock); } } break; + case PRI_EVENT_FACILITY: + chanpos = pri_find_principle(pri, e->facility.channel); + if (chanpos < 0) { + ast_log(LOG_WARNING, "Facility requested on unconfigured channel %d/%d span %d\n", + PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span); + } else { + chanpos = pri_fixup_principle(pri, chanpos, e->facility.call); + if (chanpos < 0) { + ast_log(LOG_WARNING, "Facility requested on channel %d/%d not in use on span %d\n", + PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span); + } else { + int i; + + ast_mutex_lock(&pri->pvts[chanpos]->lock); + for (i = 0; i < e->facility.subcmds.counter_subcmd; i++) { + struct subcommand *subcmd = &e->facility.subcmds.subcmd[i]; + struct ast_channel *owner; + + switch (subcmd->cmd) { + case CMD_CONNECTEDLINE: + owner = pri->pvts[chanpos]->owner; + if (owner) { + struct ast_party_connected_line connected; + struct cmd_connectedline *cmdcl; + + /* Update the connected line information on the other channel */ + ast_party_connected_line_init(&connected); + cmdcl = &subcmd->connectedline; + connected.id.number = cmdcl->connected.id.number; + connected.id.name = cmdcl->connected.id.name; + connected.id.number_type = cmdcl->connected.id.number_type; + connected.id.number_presentation = pri_to_ast_presentation(cmdcl->connected.id.number_presentation); + connected.source = pri_to_ast_connected_line_update_source(cmdcl->connected.source); + ast_channel_queue_connected_line_update(owner, &connected); + + ast_copy_string(pri->pvts[chanpos]->lastcid_num, cmdcl->connected.id.number, sizeof(pri->pvts[chanpos]->lastcid_num)); + ast_copy_string(pri->pvts[chanpos]->lastcid_name, cmdcl->connected.id.name, sizeof(pri->pvts[chanpos]->lastcid_name)); + + pri->pvts[chanpos]->subs[SUB_REAL].needcallerid = 1; + //dahdi_enable_ec(pri->pvts[chanpos]); + } + break; + case CMD_REDIRECTING: + owner = pri->pvts[chanpos]->owner; + if (owner) { + struct ast_party_redirecting redirecting = {{0,},}; + struct cmd_redirecting *cmdr; + + cmdr = &subcmd->redirecting; + redirecting.from.number = cmdr->redirecting.from.number; + redirecting.from.name = cmdr->redirecting.from.name; + redirecting.from.number_type = cmdr->redirecting.from.number_type; + redirecting.from.number_presentation = pri_to_ast_presentation(cmdr->redirecting.from.number_presentation); + redirecting.to.number = cmdr->redirecting.to.number; + redirecting.to.name = cmdr->redirecting.to.name; + redirecting.to.number_type = cmdr->redirecting.to.number_type; + redirecting.to.number_presentation = pri_to_ast_presentation(cmdr->redirecting.to.number_presentation); + redirecting.count = 0; + redirecting.reason = pri_to_ast_reason(cmdr->redirecting.reason); + ast_channel_queue_redirecting_update(owner, &redirecting); + } + break; + default: + ast_log(LOG_WARNING, + "Illegal subcommand %d in facility request on channel %d/%d not in use on span %d\n", + subcmd->cmd, PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span); + break; + } + } + ast_mutex_unlock(&pri->pvts[chanpos]->lock); + } + } + break; case PRI_EVENT_ANSWER: chanpos = pri_find_principle(pri, e->answer.channel); if (chanpos < 0) { @@ -13067,6 +13442,9 @@ ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n", PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); } else { + struct ast_party_connected_line connected; + struct ast_channel *owner; + ast_mutex_lock(&pri->pvts[chanpos]->lock); /* Now we can do call progress detection */ @@ -13105,15 +13483,26 @@ dahdi_enable_ec(pri->pvts[chanpos]); } + owner = pri->pvts[chanpos]->owner; #ifdef SUPPORT_USERUSER if (!ast_strlen_zero(e->answer.useruserinfo)) { - struct ast_channel *owner = pri->pvts[chanpos]->owner; ast_mutex_unlock(&pri->pvts[chanpos]->lock); pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo); ast_mutex_lock(&pri->pvts[chanpos]->lock); } #endif + if (owner) { + /* Update the connected line information on the other channel */ + ast_party_connected_line_init(&connected); + connected.id.name = e->answer.connectedname; + connected.id.number = e->answer.connectednum; + connected.id.number_type = e->answer.connectedplan; + connected.id.number_presentation = pri_to_ast_presentation(e->answer.connectedpres); + connected.source = pri_to_ast_connected_line_update_source(e->answer.source); + ast_channel_queue_connected_line_update(owner, &connected); + } + ast_mutex_unlock(&pri->pvts[chanpos]->lock); } } @@ -13152,6 +13541,7 @@ break; default: pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; + break; } } } Index: CHANGES =================================================================== --- a/CHANGES (.../trunk) (revision 186562) +++ b/CHANGES (.../team/group/issue14068) (revision 186562) @@ -55,6 +55,10 @@ received number from the ISDN link if that number has the corresponding Type-Of-Number. +libpri channel driver (chan_dahdi) changes +------------------------------------------- + * The channel variable PRIREDIRECTREASON is now just a status variable. + Use the REDIRECTING(reason) dialplan function to alter the reason. SIP channel driver (chan_sip) changes ------------------------------------------- Index: funcs/func_redirecting.c =================================================================== --- a/funcs/func_redirecting.c (.../trunk) (revision 0) +++ b/funcs/func_redirecting.c (.../team/group/issue14068) (revision 186562) @@ -0,0 +1,474 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2008 Digium, Inc. + * + * Richard Mudgett + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Redirecting data dialplan function + * \ingroup functions + * + * \author Richard Mudgett + * + * See Also: + * \arg \ref AstCREDITS + */ + + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +/* ------------------------------------------------------------------- */ + + +#include +#include +#include +#include + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/options.h" +#include "asterisk/callerid.h" + +/*** DOCUMENTATION + + + Gets or sets Redirecting data on the channel. + + + + The allowable datatypes are: + + + + + + + + + + + + + + + + If set, this will prevent the channel from sending out protocol + messages because of the value being set + + + + Gets or sets Redirecting data on the channel. The allowable values + for the reason field are the following: + + Unknown + Call Forwarding Busy + Call Forwarding No Reply + Callee is Unavailable + Time of Day + Do Not Disturb + Call Deflection + Follow Me + Called DTE Out-Of-Order + Callee is Away + Call Forwarding By The Called DTE + Call Forwarding Unconditional + + + + ***/ + +enum ID_FIELD_STATUS { + ID_FIELD_VALID, + ID_FIELD_INVALID, + ID_FIELD_UNKNOWN +}; + + + + +/* ******************************************************************* */ +/*! + * \internal + * \brief Read values from the party id struct. + * + * \param buf Buffer to fill with read value. + * \param len Length of the buffer + * \param data Remaining function datatype string + * + * \retval ID_FIELD_VALID on success. + * \retval ID_FIELD_UNKNOWN on unknown field name. + */ +static enum ID_FIELD_STATUS redirecting_id_read(char *buf, size_t len, char *data, const struct ast_party_id *id) +{ + enum ID_FIELD_STATUS status; + + status = ID_FIELD_VALID; + + if (!strncasecmp("all", data, 3)) { + snprintf(buf, len, "\"%s\" <%s>", + S_OR(id->name, ""), + S_OR(id->number, "")); + } else if (!strncasecmp("name", data, 4)) { + if (id->name) { + ast_copy_string(buf, id->name, len); + } + } else if (!strncasecmp("num", data, 3)) { + if (id->number) { + ast_copy_string(buf, id->number, len); + } + } else if (!strncasecmp("ton", data, 3)) { + snprintf(buf, len, "%d", id->number_type); + } else if (!strncasecmp("pres", data, 4)) { + ast_copy_string(buf, ast_named_caller_presentation(id->number_presentation), len); + } else { + status = ID_FIELD_UNKNOWN; + } + + return status; +} + + + + +/* ******************************************************************* */ +/*! + * \internal + * \brief Read values from the redirecting information struct. + * + * \param chan Asterisk channel to read + * \param cmd Not used + * \param data Redirecting function datatype string + * \param buf Buffer to fill with read value. + * \param len Length of the buffer + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + /* Ensure that the buffer is empty */ + *buf = 0; + + if (!chan) + return -1; + + ast_channel_lock(chan); + + if (!strncasecmp("from-", data, 5)) { + struct ast_party_id from_id; + + from_id = chan->redirecting.from; + from_id.number = chan->cid.cid_rdnis; + switch (redirecting_id_read(buf, len, data + 5, &from_id)) { + case ID_FIELD_VALID: + case ID_FIELD_INVALID: + break; + + default: + ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); + break; + } + } else if (!strncasecmp("to-", data, 3)) { + switch (redirecting_id_read(buf, len, data + 3, &chan->redirecting.to)) { + case ID_FIELD_VALID: + case ID_FIELD_INVALID: + break; + + default: + ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); + break; + } + } else if (!strncasecmp("pres", data, 4)) { + ast_copy_string(buf, ast_named_caller_presentation(chan->redirecting.from.number_presentation), len); + } else if (!strncasecmp("reason", data, 6)) { + ast_copy_string(buf, ast_redirecting_reason_name(chan->redirecting.reason), len); + } else if (!strncasecmp("count", data, 5)) { + snprintf(buf, len, "%d", chan->redirecting.count); + } else { + ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); + } + + ast_channel_unlock(chan); + + return 0; +} + + + + +/* ******************************************************************* */ +/*! + * \internal + * \brief Write new values to the party id struct + * + * \param id Party ID struct to write values + * \param data Remaining function datatype string + * \param value Value to assign to the party id. + * + * \retval ID_FIELD_VALID on success. + * \retval ID_FIELD_INVALID on error with field value. + * \retval ID_FIELD_UNKNOWN on unknown field name. + */ +static enum ID_FIELD_STATUS redirecting_id_write(struct ast_party_id *id, char *data, const char *value) +{ + char *val; + enum ID_FIELD_STATUS status; + + status = ID_FIELD_VALID; + + if (!strncasecmp("all", data, 3)) { + char name[256]; + char num[256]; + + ast_callerid_split(value, name, sizeof(name), num, sizeof(num)); + if (!(id->name = ast_strdup(name))) { + return ID_FIELD_INVALID; + } + if (!(id->number = ast_strdup(num))) { + return ID_FIELD_INVALID; + } + } else if (!strncasecmp("name", data, 4)) { + id->name = ast_strdup(value); + ast_trim_blanks(id->name); + } else if (!strncasecmp("num", data, 3)) { + id->number = ast_strdup(value); + ast_trim_blanks(id->number); + } else if (!strncasecmp("ton", data, 3)) { + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + id->number_type = atoi(val); + } else { + ast_log(LOG_ERROR, "Unknown redirecting type of number '%s', value unchanged\n", val); + status = ID_FIELD_INVALID; + } + } else if (!strncasecmp("pres", data, 4)) { + int pres; + + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + pres = atoi(val); + } else { + pres = ast_parse_caller_presentation(val); + } + + if (pres < 0) { + ast_log(LOG_ERROR, "Unknown redirecting number presentation '%s', value unchanged\n", val); + status = ID_FIELD_INVALID; + } else { + id->number_presentation = pres; + } + } else { + status = ID_FIELD_UNKNOWN; + } + + return status; +} + + + + +/* ******************************************************************* */ +/*! + * \internal + * \brief Write new values to the redirecting information struct. + * + * \param chan Asterisk channel to update + * \param cmd Not used + * \param data Redirecting function datatype string + * \param value Value to assign to the redirecting information struct. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) +{ + struct ast_party_redirecting redirecting; + char *val; + char *option; + void (*set_it)(struct ast_channel *chan, const struct ast_party_redirecting *redirecting); + + if (!value || !chan) { + return -1; + } + + /* Determine if the update indication inhibit option is present */ + option = strchr(data, ','); + if (option) { + option = ast_skip_blanks(option + 1); + switch (*option) { + case 'i': + set_it = ast_channel_set_redirecting; + break; + + default: + ast_log(LOG_ERROR, "Unknown redirecting option '%s'.\n", option); + return 0; + } + } + else { + set_it = ast_channel_update_redirecting; + } + + ast_channel_lock(chan); + ast_party_redirecting_set_init(&redirecting, &chan->redirecting); + ast_channel_unlock(chan); + + value = ast_skip_blanks(value); + + if (!strncasecmp("from-", data, 5)) { + switch (redirecting_id_write(&redirecting.from, data + 5, value)) { + case ID_FIELD_VALID: + set_it(chan, &redirecting); + ast_party_redirecting_free(&redirecting); + break; + + case ID_FIELD_INVALID: + break; + + default: + ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); + break; + } + } else if (!strncasecmp("to-", data, 3)) { + switch (redirecting_id_write(&redirecting.to, data + 3, value)) { + case ID_FIELD_VALID: + set_it(chan, &redirecting); + ast_party_redirecting_free(&redirecting); + break; + + case ID_FIELD_INVALID: + break; + + default: + ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); + break; + } + } else if (!strncasecmp("pres", data, 4)) { + int pres; + + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + pres = atoi(val); + } else { + pres = ast_parse_caller_presentation(val); + } + + if (pres < 0) { + ast_log(LOG_ERROR, "Unknown redirecting number presentation '%s', value unchanged\n", val); + } else { + redirecting.from.number_presentation = pres; + redirecting.to.number_presentation = pres; + set_it(chan, &redirecting); + } + } else if (!strncasecmp("reason", data, 6)) { + int reason; + + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + reason = atoi(val); + } else { + reason = ast_redirecting_reason_parse(val); + } + + if (reason < 0) { + ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val); + } else { + redirecting.reason = reason; + set_it(chan, &redirecting); + } + } else if (!strncasecmp("count", data, 5)) { + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + redirecting.count = atoi(val); + set_it(chan, &redirecting); + } else { + ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val); + } + } else { + ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); + } + + return 0; +} + + + + +static struct ast_custom_function redirecting_function = { + .name = "REDIRECTING", + .read = redirecting_read, + .write = redirecting_write, +}; + + + + +/* ******************************************************************* */ +/*! + * \internal + * \brief Unload the function module + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int unload_module(void) +{ + return ast_custom_function_unregister(&redirecting_function); +} + + + + +/* ******************************************************************* */ +/*! + * \internal + * \brief Load and initialize the function module. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int load_module(void) +{ + return ast_custom_function_register(&redirecting_function) + ? AST_MODULE_LOAD_DECLINE + : AST_MODULE_LOAD_SUCCESS; +} + + + + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Redirecting data dialplan function"); + + +/* ------------------------------------------------------------------- */ +/* end func_redirecting.c */ Property changes on: funcs/func_redirecting.c ___________________________________________________________________ Added: svn:eol-style + native Added: svn:mime-type + text/plain Added: svn:keywords + Author Date Id Revision Index: funcs/func_connectedline.c =================================================================== --- a/funcs/func_connectedline.c (.../trunk) (revision 0) +++ b/funcs/func_connectedline.c (.../team/group/issue14068) (revision 186562) @@ -0,0 +1,239 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2007, Gareth Palmer + * + * Gareth Palmer + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Connected Line dialplan function + * + * \ingroup functions + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include +#include +#include +#include + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/options.h" +#include "asterisk/callerid.h" + +/*** DOCUMENTATION + + + Gets or sets Connected Line data on the channel. + + + + The allowable datatypes are: + + + + + + + + + + + If set, this will prevent the channel from sending out protocol + messages because of the value being set + + + + Gets or sets Connected Line data on the channel. Possible values + for the source datatype are: + + Normal Call Answering + Call Transfer(Alerting) + Call Transfer(Active) + + + + ***/ + +static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data, + char *buf, size_t len) +{ + /* Ensure that the buffer is empty */ + *buf = 0; + + if (!chan) + return -1; + + ast_channel_lock(chan); + + if (!strncasecmp("all", data, 3)) { + snprintf(buf, len, "\"%s\" <%s>", + S_OR(chan->connected.id.name, ""), + S_OR(chan->connected.id.number, "")); + } else if (!strncasecmp("name", data, 4)) { + if (chan->connected.id.name) { + ast_copy_string(buf, chan->connected.id.name, len); + } + } else if (!strncasecmp("num", data, 3)) { + if (chan->connected.id.number) { + ast_copy_string(buf, chan->connected.id.number, len); + } + } else if (!strncasecmp("ton", data, 3)) { + snprintf(buf, len, "%d", chan->connected.id.number_type); + } else if (!strncasecmp("pres", data, 4)) { + ast_copy_string(buf, ast_named_caller_presentation(chan->connected.id.number_presentation), len); + } else if (!strncasecmp("source", data, 6)) { + ast_copy_string(buf, ast_connected_line_source_name(chan->connected.source), len); + } else { + ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data); + } + + ast_channel_unlock(chan); + + return 0; +} + +static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data, + const char *value) +{ + struct ast_party_connected_line connected; + char *val; + char *option; + void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected); + + if (!value || !chan) { + return -1; + } + + /* Determine if the update indication inhibit option is present */ + option = strchr(data, ','); + if (option) { + option = ast_skip_blanks(option + 1); + switch (*option) { + case 'i': + set_it = ast_channel_set_connected_line; + break; + + default: + ast_log(LOG_ERROR, "Unknown connectedline option '%s'.\n", option); + return 0; + } + } + else { + set_it = ast_channel_update_connected_line; + } + + ast_channel_lock(chan); + ast_party_connected_line_set_init(&connected, &chan->connected); + ast_channel_unlock(chan); + + value = ast_skip_blanks(value); + + if (!strncasecmp("all", data, 3)) { + char name[256]; + char num[256]; + + ast_callerid_split(value, name, sizeof(name), num, sizeof(num)); + connected.id.name = name; + connected.id.number = num; + set_it(chan, &connected); + } else if (!strncasecmp("name", data, 4)) { + connected.id.name = ast_strdupa(value); + ast_trim_blanks(connected.id.name); + set_it(chan, &connected); + } else if (!strncasecmp("num", data, 3)) { + connected.id.number = ast_strdupa(value); + ast_trim_blanks(connected.id.number); + set_it(chan, &connected); + } else if (!strncasecmp("ton", data, 3)) { + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + connected.id.number_type = atoi(val); + set_it(chan, &connected); + } else { + ast_log(LOG_ERROR, "Unknown connectedline type of number '%s', value unchanged\n", val); + } + } else if (!strncasecmp("pres", data, 4)) { + int pres; + + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + pres = atoi(val); + } else { + pres = ast_parse_caller_presentation(val); + } + + if (pres < 0) { + ast_log(LOG_ERROR, "Unknown connectedline number presentation '%s', value unchanged\n", val); + } else { + connected.id.number_presentation = pres; + set_it(chan, &connected); + } + } else if (!strncasecmp("source", data, 6)) { + int source; + + val = ast_strdupa(value); + ast_trim_blanks(val); + + if (('0' <= val[0]) && (val[0] <= '9')) { + source = atoi(val); + } else { + source = ast_connected_line_source_parse(val); + } + + if (source < 0) { + ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val); + } else { + connected.source = source; + set_it(chan, &connected); + } + } else { + ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data); + } + + return 0; +} + +static struct ast_custom_function connectedline_function = { + .name = "CONNECTEDLINE", + .read = connectedline_read, + .write = connectedline_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&connectedline_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&connectedline_function) + ? AST_MODULE_LOAD_DECLINE + : AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Connected Line dialplan function"); Property changes on: funcs/func_connectedline.c ___________________________________________________________________ Added: svn:eol-style + native Added: svn:mime-type + text/plain Added: svn:keywords + Author Date Id Revision Property changes on: . ___________________________________________________________________ Added: automerge + * Added: svnmerge-integrated + /trunk:1-186557 Added: automerge-email + rmudgett@digium.com