aboutsummaryrefslogtreecommitdiffstats
path: root/extra/asterisk/asterisk-07-issue14068.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extra/asterisk/asterisk-07-issue14068.patch')
-rw-r--r--extra/asterisk/asterisk-07-issue14068.patch1423
1 files changed, 1423 insertions, 0 deletions
diff --git a/extra/asterisk/asterisk-07-issue14068.patch b/extra/asterisk/asterisk-07-issue14068.patch
new file mode 100644
index 0000000000..49cad1681b
--- /dev/null
+++ b/extra/asterisk/asterisk-07-issue14068.patch
@@ -0,0 +1,1423 @@
+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 <rmudgett@digium.com>
++ *
++ * 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 <rmudgett@digium.com>
++ *
++ * See Also:
++ * \arg \ref AstCREDITS
++ */
++
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++/* ------------------------------------------------------------------- */
++
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++
++#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
++ <function name="REDIRECTING" language="en_US">
++ <synopsis>
++ Gets or sets Redirecting data on the channel.
++ </synopsis>
++ <syntax>
++ <parameter name="datatype" required="true">
++ <para>The allowable datatypes are:</para>
++ <enumlist>
++ <enum name = "from-all" />
++ <enum name = "from-num" />
++ <enum name = "from-name" />
++ <enum name = "from-ton" />
++ <enum name = "to-all" />
++ <enum name = "to-num" />
++ <enum name = "to-name" />
++ <enum name = "to-ton" />
++ <enum name = "pres" />
++ <enum name = "reason" />
++ <enum name = "count" />
++ </enumlist>
++ </parameter>
++ <parameter name="i">
++ <para>If set, this will prevent the channel from sending out protocol
++ messages because of the value being set</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Gets or sets Redirecting data on the channel. The allowable values
++ for the <replaceable>reason</replaceable> field are the following:</para>
++ <enumlist>
++ <enum name = "unknown"><para>Unknown</para></enum>
++ <enum name = "cfb"><para>Call Forwarding Busy</para></enum>
++ <enum name = "cfnr"><para>Call Forwarding No Reply</para></enum>
++ <enum name = "unavailable"><para>Callee is Unavailable</para></enum>
++ <enum name = "time_of_day"><para>Time of Day</para></enum>
++ <enum name = "dnd"><para>Do Not Disturb</para></enum>
++ <enum name = "deflection"><para>Call Deflection</para></enum>
++ <enum name = "follow_me"><para>Follow Me</para></enum>
++ <enum name = "out_of_order"><para>Called DTE Out-Of-Order</para></enum>
++ <enum name = "away"><para>Callee is Away</para></enum>
++ <enum name = "cf_dte"><para>Call Forwarding By The Called DTE</para></enum>
++ <enum name = "cfu"><para>Call Forwarding Unconditional</para></enum>
++ </enumlist>
++ </description>
++ </function>
++ ***/
++
++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 <gareth@acsdata.co.nz>
++ *
++ * 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 <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++
++#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
++ <function name="CONNECTEDLINE" language="en_US">
++ <synopsis>
++ Gets or sets Connected Line data on the channel.
++ </synopsis>
++ <syntax>
++ <parameter name="datatype" required="true">
++ <para>The allowable datatypes are:</para>
++ <enumlist>
++ <enum name = "all" />
++ <enum name = "num" />
++ <enum name = "name" />
++ <enum name = "ton" />
++ <enum name = "pres" />
++ <enum name = "source" />
++ </enumlist>
++ </parameter>
++ <parameter name="i">
++ <para>If set, this will prevent the channel from sending out protocol
++ messages because of the value being set</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Gets or sets Connected Line data on the channel. Possible values
++ for the <replaceable>source</replaceable> datatype are:</para>
++ <enumlist>
++ <enum name="answer"><para>Normal Call Answering</para></enum>
++ <enum name="transfer_alerting"><para>Call Transfer(Alerting)</para></enum>
++ <enum name="transfer_active"><para>Call Transfer(Active)</para></enum>
++ </enumlist>
++ </description>
++ </function>
++ ***/
++
++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
+