<para>Hang up the call <replaceable>x</replaceable> seconds <emphasis>after</emphasis> the called party has
answered the call.</para>
</option>
+ <option name="s">
+ <argument name="x" required="true" />
+ <para>Force the outgoing callerid tag parameter to be set to the string <replaceable>x</replaceable></para>
+ </option>
<option name="t">
<para>Allow the called party to transfer the calling party by sending the
DTMF sequence defined in <filename>features.conf</filename>. This setting does not perform policy enforcement on
so you will not be able to set timeouts via the TIMEOUT() function in this routine.</para>
</note>
</option>
+ <option name="u">
+ <argument name = "x" required="true">
+ <para>Force the outgoing callerid presentation indicator parameter to be set
+ to one of the values passed in <replaceable>x</replaceable>:
+ <literal>allowed_not_screened</literal>
+ <literal>allowed_passed_screen</literal>
+ <literal>allowed_failed_screen</literal>
+ <literal>allowed</literal>
+ <literal>prohib_not_screened</literal>
+ <literal>prohib_passed_screen</literal>
+ <literal>prohib_failed_screen</literal>
+ <literal>prohib</literal>
+ <literal>unavailable</literal></para>
+ </argument>
+ </option>
<option name="w">
<para>Allow the called party to enable recording of the call by sending
the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para>
#define OPT_PEER_H ((uint64_t)1 << 35)
#define OPT_CALLEE_GO_ON ((uint64_t)1 << 36)
#define OPT_CANCEL_TIMEOUT ((uint64_t)1 << 37)
+#define OPT_FORCE_CID_TAG ((uint64_t)1 << 38)
+#define OPT_FORCE_CID_PRES ((uint64_t)1 << 39)
enum {
OPT_ARG_ANNOUNCE = 0,
OPT_ARG_OPERMODE,
OPT_ARG_SCREEN_NOINTRO,
OPT_ARG_FORCECLID,
+ OPT_ARG_FORCE_CID_TAG,
+ OPT_ARG_FORCE_CID_PRES,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE,
};
AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+ AST_APP_OPTION_ARG('s', OPT_FORCE_CID_TAG, OPT_ARG_FORCE_CID_TAG),
+ AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
ast_string_field_set(c, accountcode, in->accountcode);
}
ast_party_connected_line_copy(&c->connected, &original->connected);
-
- ast_channel_update_redirecting(in, &c->redirecting);
+ /*
+ * We must unlock c before calling ast_channel_redirecting_macro, because
+ * we put c into autoservice there. That is pretty much a guaranteed
+ * deadlock. This is why the handling of c's lock may seem a bit unusual
+ * here.
+ */
+ ast_channel_unlock(c);
+ if (ast_channel_redirecting_macro(c, in, &c->redirecting, 1, 0)) {
+ while (ast_channel_trylock(c)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(in);
+ }
+ ast_channel_update_redirecting(in, &c->redirecting);
+ ast_channel_unlock(c);
+ }
ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
}
ast_channel_unlock(in);
- ast_channel_unlock(c);
if (ast_call(c, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
ast_verb(3, "Redirecting update to %s prevented.\n", in->name);
} else {
ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name);
- ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ if (ast_channel_redirecting_macro(c, in, f, 1, 1)) {
+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ }
pa->sentringing = 0;
}
break;
if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) {
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
}
+ } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
+ if (ast_channel_redirecting_macro(in, outgoing->chan, f, 0, 1)) {
+ ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
+ }
}
}
ast_frfree(f);
struct cause_args num = { chan, 0, 0, 0 };
int cause;
char numsubst[256];
- char *cid_num = NULL, *cid_name = NULL;
+ char *cid_num = NULL, *cid_name = NULL, *cid_tag = NULL, *cid_pres = NULL;
struct ast_bridge_config config = { { 0, } };
struct timeval calldurationlimit = { 0, };
if (ast_test_flag64(&opts, OPT_FORCECLID) && !ast_strlen_zero(opt_args[OPT_ARG_FORCECLID]))
ast_callerid_parse(opt_args[OPT_ARG_FORCECLID], &cid_name, &cid_num);
+ if (ast_test_flag64(&opts, OPT_FORCE_CID_TAG) && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CID_TAG]))
+ cid_tag = ast_strdupa(opt_args[OPT_ARG_FORCE_CID_TAG]);
+ if (ast_test_flag64(&opts, OPT_FORCE_CID_PRES) && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CID_PRES]))
+ cid_pres = ast_strdupa(opt_args[OPT_ARG_FORCE_CID_PRES]);
if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr)
ast_cdr_reset(chan->cdr, NULL);
if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
if (ast_test_flag64(peerflags, OPT_FORCECLID) && !ast_strlen_zero(opt_args[OPT_ARG_FORCECLID])) {
struct ast_party_connected_line connected;
+ int pres;
ast_party_connected_line_set_init(&connected, &tmp->chan->connected);
connected.id.number = cid_num;
connected.id.name = cid_name;
- connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+ connected.id.tag = cid_tag;
+ if (cid_pres) {
+ pres = ast_parse_caller_presentation(cid_pres);
+ if (pres >= 0) {
+ connected.id.number_presentation = pres;
+ }
+ } else {
+ connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+ }
ast_channel_set_connected_line(tmp->chan, &connected);
} else {
ast_connected_line_copy_from_caller(&tc->connected, &chan->cid);
{
const char *queue = qe->parent->name;
struct callattempt *o, *start = NULL, *prev = NULL;
+ int res;
int status;
int numbusies = prebusies;
int numnochan = 0;
ast_party_caller_copy(&o->chan->cid, &in->cid);
ast_party_connected_line_copy(&o->chan->connected, &original->connected);
- ast_channel_update_redirecting(in, &o->chan->redirecting);
+ /*
+ * We must unlock o->chan before calling
+ * ast_channel_redirecting_macro, because we put o->chan into
+ * autoservice there. That is pretty much a guaranteed
+ * deadlock. This is why the handling of o->chan's lock may
+ * seem a bit unusual here.
+ */
+ ast_channel_unlock(o->chan);
+ res = ast_channel_redirecting_macro(o->chan, in, &o->chan->redirecting, 1, 0);
+ while (ast_channel_trylock(o->chan)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(in);
+ }
+ if (res) {
+ ast_channel_update_redirecting(in, &o->chan->redirecting);
+ }
update_connectedline = 1;
ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
} else {
ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
- ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ }
}
break;
default:
int cid_ani2;
/*! \brief Caller ID number from an incoming call. */
char cid_num[AST_MAX_EXTENSION];
+ /*!
+ * \brief Caller ID tag from incoming call
+ * \note the "cid_tag" string read in from chan_dahdi.conf
+ */
+ char cid_tag[AST_MAX_EXTENSION];
/*! \brief Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise. */
int cid_ton;
/*! \brief Caller ID name from an incoming call. */
.context = "default",
.cid_num = "",
.cid_name = "",
+ .cid_tag = "",
.mohinterpret = "default",
.mohsuggest = "",
.parkinglot = "",
tmp->cid.cid_pres = i->callingpres;
tmp->cid.cid_ton = i->cid_ton;
tmp->cid.cid_ani2 = i->cid_ani2;
+ tmp->cid.cid_tag = ast_strdup(i->cid_tag);
#if defined(HAVE_SS7)
tmp->transfercapability = transfercapability;
pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
tmp->cid_num[0] = '\0';
tmp->cid_name[0] = '\0';
}
+ ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
tmp->cid_subaddr[0] = '\0';
ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
} else if (!strcasecmp(v->name, "cid_number")) {
ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
+ } else if (!strcasecmp(v->name, "cid_tag")) {
+ ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
} else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
confp->chan.dahditrcallerid = ast_true(v->value);
} else if (!strcasecmp(v->name, "restrictcid")) {
if (the_other_channel) {
unsigned char frame_data[1024];
if (condition == AST_CONTROL_CONNECTED_LINE) {
+ if (isoutbound) {
+ ast_connected_line_copy_to_caller(&the_other_channel->cid, &this_channel->connected);
+ }
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);
ast_mutex_init(&ch->overlap_tv_lock);
} /* ORIG MISDN END */
+ misdn_cfg_get(port, MISDN_CFG_INCOMING_CALLERID_TAG, bc->incoming_cid_tag, sizeof(bc->incoming_cid_tag));
+ if (!ast_strlen_zero(bc->incoming_cid_tag)) {
+ chan_misdn_log(1, port, " --> * Setting incoming caller id tag to \"%s\"\n", bc->incoming_cid_tag);
+ }
ch->overlap_dial_task = -1;
if (ch->faxdetect || ch->ast_dsp) {
* \param ast Current Asterisk channel
* \param id Party id information to send to the other side
* \param source Why are we sending this update
+ * \param cid_tag Caller ID tag to set in the connected line
*
* \return Nothing
*/
-static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source)
+static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
{
struct ast_party_connected_line connected;
| misdn_to_ast_plan(id->number_plan);
connected.id.number_presentation = misdn_to_ast_pres(id->presentation)
| misdn_to_ast_screen(id->screening);
+ connected.id.tag = cid_tag;
connected.source = source;
ast_channel_queue_connected_line_update(ast, &connected);
}
*
* \param ast Current Asterisk channel
* \param redirect Associated B channel redirecting info
+ * \param tag Caller ID tag to set in the redirecting party fields
*
* \return Nothing
*/
-static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect)
+static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect, char *tag)
{
struct ast_party_redirecting redirecting;
redirecting.from.number_presentation =
misdn_to_ast_pres(redirect->from.presentation)
| misdn_to_ast_screen(redirect->from.screening);
+ redirecting.from.tag = tag;
redirecting.to.number = (char *) redirect->to.number;
redirecting.to.number_type =
redirecting.to.number_presentation =
misdn_to_ast_pres(redirect->to.presentation)
| misdn_to_ast_screen(redirect->to.screening);
+ redirecting.to.tag = tag;
redirecting.reason = misdn_to_ast_reason(redirect->reason);
redirecting.count = redirect->count;
struct chan_list *ch;
struct misdn_bchannel *newbc;
char *dest_cp;
+ int append_msn = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(intf); /* The interface token is discarded. */
chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
}
+ misdn_cfg_get(port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
+ if (append_msn) {
+ strncat(newbc->incoming_cid_tag, "_", sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
+ strncat(newbc->incoming_cid_tag, newbc->caller.number, sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
+ }
+
+ ast->cid.cid_tag = ast_strdup(newbc->incoming_cid_tag);
+
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);
++bc->redirecting.count;
bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
- misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
/* Send back positive ACK */
bc->redirecting.to.presentation = 1;/* restricted */
bc->redirecting.to.screening = 0;/* unscreened */
}
- misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
bc->div_leg_3_rx_wanted = 1;
}
break;
/* We have no place to put the OriginalCalled number */
}
#endif
- misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
}
break;
default:
++bc->redirecting.count;
bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
- misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
misdn_lib_send_event(bc, EVENT_DISCONNECT);
misdn_queue_connected_line_update(ch->ast, &party_id,
(bc->fac_in.u.EctInform.Status == 0 /* alerting */)
? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
- : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER);
+ : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
+ bc->incoming_cid_tag);
}
break;
#if 0 /* We don't handle this yet */
int exceed;
int ai;
int im;
+ int append_msn = 0;
if (ch) {
switch (ch->state) {
ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
+ misdn_cfg_get(bc->port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
+ if (append_msn) {
+ strncat(bc->incoming_cid_tag, "_", sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
+ strncat(bc->incoming_cid_tag, bc->dialed.number, sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
+ }
+
+ ast_channel_lock(chan);
+ chan->cid.cid_tag = ast_strdup(bc->incoming_cid_tag);
+ ast_channel_unlock(chan);
+
if (!ast_strlen_zero(bc->redirecting.from.number)) {
/* 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 */
- misdn_copy_redirecting_to_ast(chan, &bc->redirecting);
+ misdn_copy_redirecting_to_ast(chan, &bc->redirecting, bc->incoming_cid_tag);
}
pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
}
#endif /* defined(AST_MISDN_ENHANCEMENTS) */
- /* Add configured prefix to connected.number */
- misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
+ if (!ast_strlen_zero(bc->connected.number)) {
+ /* 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 */
- misdn_queue_connected_line_update(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER);
+ /* Update the connected line information on the other channel */
+ misdn_queue_connected_line_update(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
+ }
ch->l3id = bc->l3_id;
ch->addr = bc->addr;
bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
break;
}
- misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting);
}
}
bc->redirecting.to_changed = 0;
if (ch && ch->ast) {
misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
- AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING);
+ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, bc->incoming_cid_tag);
}
}
break;
bc->redirecting.to_changed = 0;
if (ch && ch->ast) {
misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
- AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER);
+ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
}
}
break;
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, cid_tag, peer->cid_tag);
ast_string_field_set(dialog, mwi_from, peer->mwi_from);
ast_string_field_set(dialog, parkinglot, peer->parkinglot);
ast_string_field_set(dialog, engine, peer->engine);
ast_channel_lock(tmp);
sip_pvt_lock(i);
ast_channel_cc_params_init(tmp, i->cc_params);
+ tmp->cid.cid_tag = ast_strdup(i->cid_tag);
ast_channel_unlock(tmp);
tmp->tech = ( ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO || ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_SHORTINFO) ? &sip_tech_info : &sip_tech;
params++;
/* Check if we have a reason parameter */
if ((reason_param = strcasestr(params, "reason="))) {
+ char *end;
reason_param+=7;
+ if ((end = strchr(reason_param, ';'))) {
+ *end = '\0';
+ }
/* Remove enclosing double-quotes */
if (*reason_param == '"')
ast_strip_quoted(reason_param, "\"", "\"");
}
if (!ast_strlen_zero(peer->cid_name))
ast_string_field_set(p, cid_name, peer->cid_name);
+ if (!ast_strlen_zero(peer->cid_tag))
+ ast_string_field_set(p, cid_tag, peer->cid_tag);
if (peer->callingpres)
p->callingpres = peer->callingpres;
}
ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name);
redirecting->from.name = redirecting_from_name;
}
+ redirecting->from.tag = (char *) p->cid_tag;
if (!ast_strlen_zero(redirecting_to_number)) {
if (redirecting->to.number) {
ast_free(redirecting->to.number);
ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number);
redirecting->to.name = redirecting_to_name;
}
+ redirecting->to.tag = (char *) p->cid_tag;
redirecting->reason = reason;
}
ast_party_connected_line_init(&connected);
connected.id.number = (char *) p->cid_num;
connected.id.name = (char *) p->cid_name;
+ connected.id.tag = (char *) p->cid_tag;
connected.id.number_presentation = p->callingpres;
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
ast_channel_queue_connected_line_update(p->owner, &connected);
ast_party_connected_line_init(&connected);
connected.id.number = (char *) p->cid_num;
connected.id.name = (char *) p->cid_name;
+ connected.id.tag = (char *) p->cid_tag;
connected.id.number_presentation = p->callingpres;
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
ast_channel_queue_connected_line_update(p->owner, &connected);
ast_party_connected_line_init(&connected);
connected.id.number = (char *) p->cid_num;
connected.id.name = (char *) p->cid_name;
+ connected.id.tag = (char *) p->cid_tag;
connected.id.number_presentation = p->callingpres;
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
ast_channel_queue_connected_line_update(p->owner, &connected);
ast_party_connected_line_init(&connected);
connected.id.number = (char *) p->cid_num;
connected.id.name = (char *) p->cid_name;
+ connected.id.tag = (char *) p->cid_tag;
connected.id.number_presentation = p->callingpres;
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
ast_channel_queue_connected_line_update(p->owner, &connected);
ast_party_connected_line_init(&connected);
connected.id.number = (char *) p->cid_num;
connected.id.name = (char *) p->cid_name;
+ connected.id.tag = (char *) p->cid_tag;
connected.id.number_presentation = p->callingpres;
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
ast_channel_queue_connected_line_update(p->owner, &connected);
ast_channel_queue_connected_line_update(target.chan2, &connected_to_target);
} else {
/* Since target.chan1 isn't actually connected to another channel, there is no way for us
- * to queue a frame so that its connected line status will be updated. Instead, we have to
- * change it directly. Since we are not the channel thread, we cannot run a connected line
- * interception macro on target.chan1
+ * to queue a frame so that its connected line status will be updated.
+ *
+ * Instead, we use the somewhat hackish approach of using a special control frame type that
+ * instructs ast_read to perform a specific action. In this case, the frame we queue tells
+ * ast_read to call the connected line interception macro configured for target.chan1.
+ */
+ struct ast_control_read_action_payload *frame_payload;
+ int payload_size;
+ int frame_size;
+ unsigned char connected_line_data[1024];
+ payload_size = ast_connected_line_build_data(connected_line_data, sizeof(connected_line_data), &connected_to_target);
+ frame_size = payload_size + sizeof(*frame_payload);
+ if (payload_size != -1 && (frame_payload = alloca(frame_size))) {
+ frame_payload->payload_size = payload_size;
+ memcpy(frame_payload->payload, connected_line_data, payload_size);
+ frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
+ ast_queue_control_data(target.chan1, AST_CONTROL_READ_ACTION, frame_payload, frame_size);
+ }
+ /* In addition to queueing the read action frame so that target.chan1's connected line info
+ * will be updated, we also are going to queue a plain old connected line update on target.chan1. This
+ * way, either Dial or Queue can apply this connected line update to the outgoing ringing channel.
*/
- ast_channel_update_connected_line(target.chan1, &connected_to_target);
+ ast_channel_queue_connected_line_update(target.chan1, &connected_to_transferee);
+
}
ast_channel_unref(current->chan1);
}
ast_string_field_set(peer, md5secret, "");
ast_string_field_set(peer, cid_num, "");
ast_string_field_set(peer, cid_name, "");
+ ast_string_field_set(peer, cid_tag, "");
ast_string_field_set(peer, fromdomain, "");
ast_string_field_set(peer, fromuser, "");
ast_string_field_set(peer, regexten, "");
ast_string_field_set(peer, cid_name, "");
} else if (!strcasecmp(v->name, "cid_number")) {
ast_string_field_set(peer, cid_num, v->value);
+ } else if (!strcasecmp(v->name, "cid_tag")) {
+ ast_string_field_set(peer, cid_tag, v->value);
} else if (!strcasecmp(v->name, "context")) {
ast_string_field_set(peer, context, v->value);
ast_set_flag(&peer->flags[1], SIP_PAGE2_HAVEPEERCONTEXT);
MISDN_CFG_LANGUAGE, /* char[] */
MISDN_CFG_MUSICCLASS, /* char[] */
MISDN_CFG_CALLERID, /* char[] */
+ MISDN_CFG_INCOMING_CALLERID_TAG, /* char[] */
+ MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, /* int (bool) */
MISDN_CFG_METHOD, /* char[] */
MISDN_CFG_DIALPLAN, /* int */
MISDN_CFG_LOCALDIALPLAN, /* int */
*/
struct misdn_party_id caller;
+ /*! \brief Incoming Caller ID string tag for special purpose
+ * \note The element can be set to "incoming_cid_tag" in /etc/asterisk/misdn.conf for incoming calls
+ */
+ char incoming_cid_tag[MISDN_MAX_NAME_LEN];
+
/*! \brief Connected-Party/Connected-Line ID information struct
* \note The number_type element can be set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls
*/
"Sets the musiconhold class." },
{ "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE,
"Set the outgoing caller id to the value." },
+ { "incoming_cid_tag", MISDN_CFG_INCOMING_CALLERID_TAG, MISDN_CTYPE_STR, "", NONE,
+ "Set the incoming caller id string tag to the value." },
+ { "append_msn_to_cid_tag", MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, MISDN_CTYPE_BOOL, "no", NONE,
+ "Automatically appends incoming or outgoing MSN to the incoming caller\n"
+ "\tid string tag. An underscore '_' is used as delimiter. Incoming calls\n"
+ "\twill have the dialed number appended, and outgoing calls will have the\n"
+ "\tcaller number appended to the tag." },
{ "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"
AST_STRING_FIELD(peermd5secret);
AST_STRING_FIELD(cid_num); /*!< Caller*ID number */
AST_STRING_FIELD(cid_name); /*!< Caller*ID name */
+ AST_STRING_FIELD(cid_tag); /*!< Caller*ID tag */
AST_STRING_FIELD(mwi_from); /*!< Name to place in the From header in outgoing NOTIFY requests */
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(fullcontact); /*!< Contact registered with us (not in sip.conf) */
AST_STRING_FIELD(cid_num); /*!< Caller ID num */
AST_STRING_FIELD(cid_name); /*!< Caller ID name */
+ AST_STRING_FIELD(cid_tag); /*!< Caller ID tag */
AST_STRING_FIELD(vmexten); /*!< Dialplan extension for MWI notify message*/
AST_STRING_FIELD(language); /*!< Default language for prompts */
AST_STRING_FIELD(mohinterpret); /*!< Music on Hold class */
presentation=-1
screen=-1
+; Incoming calls will have a caller ID tag set to this value
+;
+;incoming_cid_tag = "asterisk"
+
+; With this set, you can automatically append the MSN of a party
+; to the cid_tag. Incoming calls have the dialed number appended
+; to the tag, and outgoing calls have the caller number appended
+; to the tag. An '_' is used to separate the tag from the
+; MSN.
+; Default is no.
+;
+;append_msn_to_cid_tag = no
+
; Select what to do with outgoing COLP information on this port.
;
; 0 - Send out COLP information unaltered. (default)
<enum name="all" />
<enum name="num" />
<enum name="name" />
+ <enum name="tag" />
<enum name="ANI" />
<enum name="DNID" />
<enum name="RDNIS" />
if (chan->cid.cid_name) {
ast_copy_string(buf, chan->cid.cid_name, len);
}
+ } else if (!strncasecmp("tag", data, 3)) {
+ if (chan->cid.cid_tag) {
+ ast_copy_string(buf, chan->cid.cid_tag, len);
+ }
} else if (!strncasecmp("num", data, 3)) {
/* also matches "number" */
if (chan->cid.cid_num) {
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
+ } else if (!strncasecmp("tag", data, 3)) {
+ ast_channel_lock(chan);
+ if (chan->cid.cid_tag) {
+ ast_free(chan->cid.cid_tag);
+ }
+ chan->cid.cid_tag = ast_strdup(value);
+ ast_channel_unlock(chan);
} else if (!strncasecmp("ani", data, 3)) {
if (!strncasecmp(data + 3, "2", 1)) {
chan->cid.cid_ani2 = atoi(value);
<enum name = "all" />
<enum name = "num" />
<enum name = "name" />
+ <enum name = "tag" />
<enum name = "ton" />
<enum name = "pres" />
<enum name = "subaddr[-valid]|[-type]|[-odd]">
if (chan->connected.id.number) {
ast_copy_string(buf, chan->connected.id.number, len);
}
+ } else if (!strncasecmp("tag", data, 3)) {
+ if (chan->connected.id.tag) {
+ ast_copy_string(buf, chan->connected.id.tag, len);
+ }
} else if (!strncasecmp("ton", data, 3)) {
snprintf(buf, len, "%d", chan->connected.id.number_type);
} else if (!strncasecmp("pres", data, 4)) {
connected.id.number = ast_strdupa(value);
ast_trim_blanks(connected.id.number);
set_it(chan, &connected);
+ } else if (!strncasecmp("tag", data, 3)) {
+ connected.id.tag = ast_strdupa(value);
+ ast_trim_blanks(connected.id.tag);
+ set_it(chan, &connected);
} else if (!strncasecmp("ton", data, 3)) {
val = ast_strdupa(value);
ast_trim_blanks(val);
<enum name = "from-all" />
<enum name = "from-num" />
<enum name = "from-name" />
+ <enum name = "from-tag" />
<enum name = "from-ton" />
<enum name = "from-pres" />
<enum name = "to-all" />
<enum name = "to-num" />
<enum name = "to-name" />
+ <enum name = "to-tag" />
<enum name = "to-ton" />
<enum name = "to-pres" />
<enum name = "reason" />
if (id->number) {
ast_copy_string(buf, id->number, len);
}
+ } else if (!strncasecmp("tag", data, 3)) {
+ if (id->tag) {
+ ast_copy_string(buf, id->tag, len);
+ }
} else if (!strncasecmp("ton", data, 3)) {
snprintf(buf, len, "%d", id->number_type);
} else if (!strncasecmp("pres", data, 4)) {
} else if (!strncasecmp("num", data, 3)) {
id->number = ast_strdup(value);
ast_trim_blanks(id->number);
+ } else if (!strncasecmp("tag", data, 3)) {
+ id->tag = ast_strdup(value);
+ ast_trim_blanks(id->tag);
} else if (!strncasecmp("ton", data, 3)) {
val = ast_strdupa(value);
ast_trim_blanks(val);
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:
ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
break;
}
+ ast_party_redirecting_free(&redirecting);
} 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:
ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
break;
}
+ ast_party_redirecting_free(&redirecting);
} else if (!strncasecmp("pres", data, 4)) {
int pres;
* (Field will eventually move to struct ast_channel.dialed.transit_network_select)
*/
int cid_tns;
+
+ /*!
+ * \brief Callerid "Tag"
+ * A user-settable field used to help associate some extrinsic information
+ * about the channel or user of the channel to the caller ID. This information
+ * is not transmitted over the wire and so is only useful within an Asterisk
+ * environment.
+ * (Field will eventually move to struct ast_channel.caller.id.tag)
+ */
+ char *cid_tag;
+
/*!
* \brief Caller id subaddress.
* (Field will eventually move to struct ast_channel.caller.id.subaddress)
/*! \brief Subscriber name (Malloced) */
char *name;
+ /*! \brief User-set "tag" */
+ char *tag;
+
/*! \brief Subscriber subaddress. */
struct ast_party_subaddress subaddress;
int ast_channel_data_cmp_structure(const struct ast_data_search *tree, struct ast_channel *chan,
const char *structure_name);
+/*!
+ * \since 1.8
+ * \brief Run a redirecting interception macro and update a channel's redirecting information
+ *
+ * \details
+ * Whenever we want to update a channel's redirecting information, we may need to run
+ * a macro so that an administrator can manipulate the information before sending it
+ * out. This function both runs the macro and sends the update to the channel.
+ *
+ * \param autoservice_chan Channel to place into autoservice while the macro is running.
+ * It is perfectly safe for this to be NULL
+ * \param macro_chan The channel to run the macro on. Also the channel from which we
+ * determine which macro we need to run.
+ * \param redirecting_info Either an ast_party_redirecting or ast_frame pointer of type
+ * AST_CONTROL_REDIRECTING
+ * \param is_caller If true, then run REDIRECTING_CALLER_SEND_MACRO, otherwise run
+ * REDIRECTING_CALLEE_SEND_MACRO
+ * \param is_frame If true, then redirecting_info is an ast_frame pointer, otherwise it is an
+ * ast_party_redirecting pointer.
+ *
+ * \retval 0 Success
+ * \retval -1 Either the macro does not exist, or there was an error while attempting to
+ * run the macro
+ *
+ * \todo Have multiple return codes based on the MACRO_RESULT
+ * \todo Make constants so that caller and frame can be more expressive than just '1' and
+ * '0'
+ */
+int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame);
+
#include "asterisk/ccss.h"
/*!
AST_CONTROL_T38_PARAMETERS = 24, /*! T38 state change request/notification with parameters */
AST_CONTROL_CC = 25, /*!< Indication that Call completion service is possible */
AST_CONTROL_SRCCHANGE = 26, /*!< Media source has changed and requires a new RTP SSRC */
+ AST_CONTROL_READ_ACTION = 27, /*!< Tell ast_read to take a specific action */
+};
+
+enum ast_frame_read_action {
+ AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO,
+};
+
+struct ast_control_read_action_payload {
+ /* An indicator to ast_read of what action to
+ * take with the frame;
+ */
+ enum ast_frame_read_action action;
+ /* The size of the frame's payload
+ */
+ size_t payload_size;
+ /* A payload for the frame.
+ */
+ unsigned char payload[0];
};
enum ast_control_t38 {
ast_free(cid->cid_name);
if (cid->cid_ani)
ast_free(cid->cid_ani);
+ if (cid->cid_tag)
+ ast_free(cid->cid_tag);
cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = NULL;
ast_party_subaddress_free(&cid->subaddress);
ast_party_subaddress_free(&cid->dialed_subaddress);
{
init->number = NULL;
init->name = NULL;
+ init->tag = NULL;
init->number_type = 0; /* Unknown */
init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
ast_party_subaddress_init(&init->subaddress);
}
dest->name = ast_strdup(src->name);
+ if (dest->tag) {
+ ast_free(dest->tag);
+ }
+ dest->tag = ast_strdup(src->tag);
+
dest->number_type = src->number_type;
dest->number_presentation = src->number_presentation;
ast_party_subaddress_copy(&dest->subaddress, &src->subaddress);
{
init->number = NULL;
init->name = NULL;
+ init->tag = NULL;
init->number_type = guide->number_type;
init->number_presentation = guide->number_presentation;
ast_party_subaddress_set_init(&init->subaddress, &guide->subaddress);
dest->number = ast_strdup(src->number);
}
+ if (src->tag && src->tag != dest->tag) {
+ if (dest->tag) {
+ ast_free(dest->tag);
+ }
+ dest->tag = ast_strdup(src->tag);
+ }
+
dest->number_type = src->number_type;
dest->number_presentation = src->number_presentation;
ast_party_subaddress_set(&dest->subaddress, &src->subaddress);
ast_free(doomed->name);
doomed->name = NULL;
}
+
+ if (doomed->tag) {
+ ast_free(doomed->tag);
+ doomed->tag = NULL;
+ }
ast_party_subaddress_free(&doomed->subaddress);
}
}
dest->cid_name = ast_strdup(src->cid_name);
+ if (dest->cid_tag) {
+ ast_free(dest->cid_tag);
+ }
+ dest->cid_tag = ast_strdup(src->cid_tag);
+
dest->cid_ton = src->cid_ton;
dest->cid_pres = src->cid_pres;
connected->id.name = cid->cid_name;
connected->id.number_type = cid->cid_ton;
connected->id.number_presentation = cid->cid_pres;
+ connected->id.tag = cid->cid_tag;
connected->id.subaddress = cid->subaddress;
connected->ani = cid->cid_ani;
if (f) {
struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
+ struct ast_control_read_action_payload *read_action_payload;
+ struct ast_party_connected_line connected;
/* if the channel driver returned more than one frame, stuff the excess
into the readq for the next ast_read call
/* removed a call to ast_cdr_answer(chan->cdr) from here. */
ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
}
+ } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) {
+ ast_party_connected_line_init(&connected);
+ read_action_payload = f->data.ptr;
+ switch (read_action_payload->action) {
+ case AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO:
+ if (ast_connected_line_parse_data(read_action_payload->payload,
+ read_action_payload->payload_size, &connected)) {
+ break;
+ }
+ if (ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) {
+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE,
+ read_action_payload->payload, read_action_payload->payload_size);
+ }
+ break;
+ }
+ ast_frfree(f);
+ f = &ast_null_frame;
}
break;
case AST_FRAME_DTMF_END:
* and synchronous generation of outgoing frames is necessary */
ast_read_generator_actions(chan, f);
}
+ break;
+ case AST_CONTROL_READ_ACTION:
+ ast_log(LOG_NOTICE, "Read a read action frame\n");
+ read_action_payload = f->data.ptr;
+ switch (read_action_payload->action) {
+ case AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO:
+ if (ast_connected_line_parse_data(read_action_payload->payload,
+ read_action_payload->payload_size, &connected)) {
+ break;
+ }
+ if (ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) {
+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE,
+ read_action_payload->payload, read_action_payload->payload_size);
+ }
+ break;
+ }
+ ast_frfree(f);
+ f = &ast_null_frame;
+ break;
default:
/* Just pass it on! */
break;
case AST_CONTROL_T38_PARAMETERS:
case _XXX_AST_CONTROL_T38:
case AST_CONTROL_CC:
+ case AST_CONTROL_READ_ACTION:
break;
case AST_CONTROL_CONGESTION:
case AST_CONTROL_CONNECTED_LINE:
case AST_CONTROL_REDIRECTING:
case AST_CONTROL_CC:
+ case AST_CONTROL_READ_ACTION:
/* Nothing left to do for these. */
res = 0;
break;
switch (f->subclass.integer) {
case AST_CONTROL_REDIRECTING:
- ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+ if (ast_channel_redirecting_macro(who, other, f, other == c0, 1)) {
+ ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+ }
break;
case AST_CONTROL_CONNECTED_LINE:
if (ast_channel_connected_line_macro(who, other, f, other == c0, 1)) {
}
dest->id.name = ast_strdup(src->cid_name);
+ if (dest->id.tag) {
+ ast_free(dest->id.tag);
+ }
+ dest->id.tag = ast_strdup(src->cid_tag);
+
dest->id.number_type = src->cid_ton;
dest->id.number_presentation = src->cid_pres;
}
dest->cid_name = ast_strdup(src->id.name);
+ if (dest->cid_tag) {
+ ast_free(dest->cid_tag);
+ }
+ dest->cid_tag = ast_strdup(src->id.tag);
+
dest->cid_ton = src->id.number_type;
dest->cid_pres = src->id.number_presentation;
AST_CONNECTED_LINE_SUBADDRESS,
AST_CONNECTED_LINE_SUBADDRESS_TYPE,
AST_CONNECTED_LINE_SUBADDRESS_ODD_EVEN,
- AST_CONNECTED_LINE_SUBADDRESS_VALID
+ AST_CONNECTED_LINE_SUBADDRESS_VALID,
+ AST_CONNECTED_LINE_TAG,
};
int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected)
pos += length;
}
+ if (connected->id.tag) {
+ length = strlen(connected->id.tag);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for connected line tag\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_TAG;
+ data[pos++] = length;
+ memcpy(data + pos, connected->id.tag, length);
+ pos += length;
+ }
+
if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
ast_log(LOG_WARNING, "No space left for connected line type of number\n");
return -1;
connected->id.name[ie_len] = 0;
}
break;
+ case AST_CONNECTED_LINE_TAG:
+ if (connected->id.tag) {
+ ast_free(connected->id.tag);
+ }
+ connected->id.tag = ast_malloc(ie_len + 1);
+ if (connected->id.tag) {
+ memcpy(connected->id.tag, data + pos, ie_len);
+ connected->id.tag[ie_len] = 0;
+ }
+ break;
case AST_CONNECTED_LINE_NUMBER_TYPE:
if (ie_len != 1) {
ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len);
AST_REDIRECTING_TO_SUBADDRESS,
AST_REDIRECTING_TO_SUBADDRESS_TYPE,
AST_REDIRECTING_TO_SUBADDRESS_ODD_EVEN,
- AST_REDIRECTING_TO_SUBADDRESS_VALID
+ AST_REDIRECTING_TO_SUBADDRESS_VALID,
+ AST_REDIRECTING_FROM_TAG,
+ AST_REDIRECTING_TO_TAG,
};
int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting)
pos += length;
}
+ if (redirecting->from.tag) {
+ length = strlen(redirecting->from.tag);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting from name\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_TAG;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->from.tag, length);
+ pos += length;
+ }
+
if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
ast_log(LOG_WARNING, "No space left for redirecting from type of number\n");
return -1;
pos += length;
}
+ if (redirecting->to.tag) {
+ length = strlen(redirecting->to.tag);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting to name\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_TAG;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->to.tag, length);
+ pos += length;
+ }
+
if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
ast_log(LOG_WARNING, "No space left for redirecting to type of number\n");
return -1;
redirecting->from.name[ie_len] = 0;
}
break;
+ case AST_REDIRECTING_FROM_TAG:
+ if (redirecting->from.tag) {
+ ast_free(redirecting->from.tag);
+ }
+ redirecting->from.tag = ast_malloc(ie_len + 1);
+ if (redirecting->from.tag) {
+ memcpy(redirecting->from.tag, data + pos, ie_len);
+ redirecting->from.tag[ie_len] = 0;
+ }
+ break;
case AST_REDIRECTING_FROM_NUMBER_TYPE:
if (ie_len != 1) {
ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len);
redirecting->to.name[ie_len] = 0;
}
break;
+ case AST_REDIRECTING_TO_TAG:
+ if (redirecting->to.tag) {
+ ast_free(redirecting->to.tag);
+ }
+ redirecting->to.tag = ast_malloc(ie_len + 1);
+ if (redirecting->to.tag) {
+ memcpy(redirecting->to.tag, data + pos, ie_len);
+ redirecting->to.tag[ie_len] = 0;
+ }
+ break;
case AST_REDIRECTING_TO_NUMBER_TYPE:
if (ie_len != 1) {
ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len);
ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
}
-int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame)
+int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int is_frame)
{
const char *macro;
const char *macro_args;
- union {
- const struct ast_frame *frame;
- const struct ast_party_connected_line *connected;
- } pointer;
int retval;
- if (frame) {
- pointer.frame = connected_info;
+ ast_channel_lock(macro_chan);
+ macro = pbx_builtin_getvar_helper(macro_chan, is_caller
+ ? "CONNECTED_LINE_CALLER_SEND_MACRO" : "CONNECTED_LINE_CALLEE_SEND_MACRO");
+ macro = ast_strdupa(S_OR(macro, ""));
+ macro_args = pbx_builtin_getvar_helper(macro_chan, is_caller
+ ? "CONNECTED_LINE_CALLER_SEND_MACRO_ARSG" : "CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS");
+ macro_args = ast_strdupa(S_OR(macro_args, ""));
+ ast_channel_unlock(macro_chan);
+
+ if (ast_strlen_zero(macro)) {
+ return -1;
+ }
+
+ if (is_frame) {
+ const struct ast_frame *frame = connected_info;
+ ast_connected_line_parse_data(frame->data.ptr, frame->datalen, ¯o_chan->connected);
} else {
- pointer.connected = connected_info;
+ const struct ast_party_connected_line *connected = connected_info;
+ ast_party_connected_line_copy(¯o_chan->connected, connected);
}
+ if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) {
+ ast_channel_update_connected_line(macro_chan, ¯o_chan->connected);
+ }
+
+ return retval;
+}
+
+int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame)
+{
+ const char *macro;
+ const char *macro_args;
+ int retval;
+
ast_channel_lock(macro_chan);
- macro = ast_strdupa(S_OR(pbx_builtin_getvar_helper(macro_chan, caller ? "CONNECTED_LINE_CALLER_SEND_MACRO" : "CONNECTED_LINE_CALLEE_SEND_MACRO"), ""));
- macro_args = ast_strdupa(S_OR(pbx_builtin_getvar_helper(macro_chan, caller ? "CONNECTED_LINE_CALLER_SEND_MACRO_ARGS" : "CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS"), ""));
+ macro = pbx_builtin_getvar_helper(macro_chan, is_caller
+ ? "REDIRECTING_CALLER_SEND_MACRO" : "REDIRECTING_CALLEE_SEND_MACRO");
+ macro = ast_strdupa(S_OR(macro, ""));
+ macro_args = pbx_builtin_getvar_helper(macro_chan, is_caller
+ ? "REDIRECTING_CALLER_SEND_MACRO_ARGS" : "REDIRECTING_CALLEE_SEND_MACRO_ARGS");
+ macro_args = ast_strdupa(S_OR(macro_args, ""));
ast_channel_unlock(macro_chan);
if (ast_strlen_zero(macro)) {
return -1;
}
- if (frame) {
- ast_connected_line_parse_data(pointer.frame->data.ptr, pointer.frame->datalen, ¯o_chan->connected);
+ if (is_frame) {
+ const struct ast_frame *frame = redirecting_info;
+
+ ast_redirecting_parse_data(frame->data.ptr, frame->datalen, ¯o_chan->redirecting);
} else {
- ast_party_connected_line_copy(¯o_chan->connected, pointer.connected);
+ const struct ast_party_redirecting *redirecting = redirecting_info;
+
+ ast_party_redirecting_copy(¯o_chan->redirecting, redirecting);
}
- if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) {
- ast_channel_update_connected_line(macro_chan, ¯o_chan->connected);
+ retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
+ if (!retval) {
+ ast_channel_update_redirecting(macro_chan, ¯o_chan->redirecting);
}
return retval;
break;
case AST_CONTROL_REDIRECTING:
ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name);
- ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
+ if (ast_channel_redirecting_macro(channel->owner, chan, fr, 1, 1)) {
+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
+ }
break;
case AST_CONTROL_PROCEEDING:
ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
}
+ } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
+ if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
+ ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ }
} else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
}
if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
break;
}
- /* The implied "else" falls through purposely */
+ ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+ break;
+ case AST_CONTROL_REDIRECTING:
+ if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
+ break;
+ }
+ ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+ break;
case AST_CONTROL_HOLD:
case AST_CONTROL_UNHOLD:
ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
}
ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
ast_frfree(fr);
+ } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+ if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
+ ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+ }
+ ast_frfree(fr);
+ } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
+ if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
+ ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+ }
+ ast_frfree(fr);
} else {
*fo = fr;
*rc = who;
}
ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
ast_frfree(fr);
+ } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+ if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
+ ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+ }
+ ast_frfree(fr);
+ } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
+ if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
+ ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+ }
+ ast_frfree(fr);
} else {
*fo = fr;
*rc = who;