summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/app_dial.c190
-rw-r--r--apps/app_directed_pickup.c13
-rw-r--r--apps/app_queue.c186
3 files changed, 311 insertions, 78 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 96bb57081..ee3953fcc 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -157,6 +157,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<option name="i">
<para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
</option>
+ <option name="I">
+ <para>Asterisk will ignore any connected line update requests or redirecting party update
+ requests it may receiveon this dial attempt.</para>
+ </option>
<option name="k">
<para>Allow the called party to enable parking of the call by sending
the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
@@ -382,7 +386,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
This application will report normal termination if the originating channel
hangs up, or if the call is bridged and either of the parties in the bridge
ends the call.</para>
-
<para>If the <variable>OUTBOUND_GROUP</variable> variable is set, all peer channels created by this
application will be put into that group (as in Set(GROUP()=...).
If the <variable>OUTBOUND_GROUP_ONCE</variable> variable is set, all peer channels created by this
@@ -464,12 +467,13 @@ enum {
OPT_GO_ON = (1 << 5),
OPT_CALLEE_HANGUP = (1 << 6),
OPT_CALLER_HANGUP = (1 << 7),
+ OPT_ORIGINAL_CLID = (1 << 8),
OPT_DURATION_LIMIT = (1 << 9),
OPT_MUSICBACK = (1 << 10),
OPT_CALLEE_MACRO = (1 << 11),
OPT_SCREEN_NOINTRO = (1 << 12),
- OPT_SCREEN_NOCLID = (1 << 13),
- OPT_ORIGINAL_CLID = (1 << 14),
+ OPT_SCREEN_NOCALLERID = (1 << 13),
+ OPT_IGNORE_CONNECTEDLINE = (1 << 14),
OPT_SCREENING = (1 << 15),
OPT_PRIVACY = (1 << 16),
OPT_RINGBACK = (1 << 17),
@@ -490,9 +494,10 @@ enum {
#define DIAL_STILLGOING (1 << 31)
#define DIAL_NOFORWARDHTML ((uint64_t)1 << 32) /* flags are now 64 bits, so keep it up! */
-#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33)
-#define OPT_PEER_H ((uint64_t)1 << 34)
-#define OPT_CALLEE_GO_ON ((uint64_t)1 << 35)
+#define DIAL_NOCONNECTEDLINE ((uint64_t)1 << 33)
+#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 34)
+#define OPT_PEER_H ((uint64_t)1 << 35)
+#define OPT_CALLEE_GO_ON ((uint64_t)1 << 36)
enum {
OPT_ARG_ANNOUNCE = 0,
@@ -524,13 +529,14 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
AST_APP_OPTION('H', OPT_CALLER_HANGUP),
AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
+ AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
AST_APP_OPTION('k', OPT_CALLEE_PARK),
AST_APP_OPTION('K', OPT_CALLER_PARK),
AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
AST_APP_OPTION('n', OPT_SCREEN_NOINTRO),
- AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
+ AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID),
AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
AST_APP_OPTION('p', OPT_SCREENING),
@@ -558,6 +564,7 @@ struct chanlist {
struct chanlist *next;
struct ast_channel *chan;
uint64_t flags;
+ struct ast_party_connected_line connected;
};
static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode);
@@ -654,7 +661,6 @@ static int onedigit_goto(struct ast_channel *chan, const char *context, char ext
return 0;
}
-
static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
{
const char *context = S_OR(chan->macrocontext, chan->context);
@@ -702,6 +708,8 @@ static void do_forward(struct chanlist *o,
struct ast_channel *original = o->chan;
struct ast_channel *c = o->chan; /* the winner */
struct ast_channel *in = num->chan; /* the input channel */
+ struct ast_party_redirecting *apr = &o->chan->redirecting;
+ struct ast_party_connected_line *apc = &o->chan->connected;
char *stuff;
char *tech;
int cause;
@@ -742,30 +750,38 @@ static void do_forward(struct chanlist *o,
handle_cause(cause, num);
ast_hangup(original);
} else {
- char *new_cid_num, *new_cid_name;
- struct ast_channel *src;
-
if (single) {
ast_rtp_instance_early_bridge_make_compatible(c, in);
}
+
+ c->cdrflags = in->cdrflags;
+
+ ast_channel_set_redirecting(c, apr);
+ ast_channel_lock(c);
+ while (ast_channel_trylock(in)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(c);
+ }
+ S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(original->cid.cid_rdnis, S_OR(in->macroexten, in->exten))));
+
+ c->cid.cid_tns = in->cid.cid_tns;
+
if (ast_test_flag64(o, OPT_FORCECLID)) {
- new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten));
- new_cid_name = NULL; /* XXX no name ? */
- src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */
+ S_REPLACE(c->cid.cid_num, ast_strdupa(S_OR(in->macroexten, in->exten)));
+ S_REPLACE(c->cid.cid_name, NULL);
+ ast_string_field_set(c, accountcode, c->accountcode);
} else {
- new_cid_num = ast_strdup(in->cid.cid_num);
- new_cid_name = ast_strdup(in->cid.cid_name);
- src = in;
+ ast_party_caller_copy(&c->cid, &in->cid);
+ ast_string_field_set(c, accountcode, in->accountcode);
}
- ast_string_field_set(c, accountcode, src->accountcode);
- c->cdrflags = src->cdrflags;
- S_REPLACE(c->cid.cid_num, new_cid_num);
- S_REPLACE(c->cid.cid_name, new_cid_name);
+ ast_party_connected_line_copy(&c->connected, apc);
+
+ S_REPLACE(in->cid.cid_rdnis, ast_strdup(c->cid.cid_rdnis));
+ ast_channel_unlock(in);
+ ast_channel_unlock(c);
+ ast_channel_update_redirecting(in, apr);
+
+ ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
- if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */
- S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani));
- }
- S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
if (ast_call(c, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
ast_clear_flag64(o, DIAL_STILLGOING);
@@ -775,7 +791,6 @@ static void do_forward(struct chanlist *o,
num->nochan++;
} else {
senddialevent(in, c, stuff);
- /* After calling, set callerid to extension */
if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
char cidname[AST_MAX_EXTENSION] = "";
ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL);
@@ -808,16 +823,28 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
int orig = *to;
struct ast_channel *peer = NULL;
/* single is set if only one destination is enabled */
- int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
+ int single = outgoing && !outgoing->next;
#ifdef HAVE_EPOLL
struct chanlist *epollo;
#endif
+ struct ast_party_connected_line connected_caller;
struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
if (single) {
/* Turn off hold music, etc */
- ast_deactivate_generator(in);
+ if (!ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK))
+ ast_deactivate_generator(in);
+
/* If we are calling a single channel, make them compatible for in-band tone purpose */
ast_channel_make_compatible(outgoing->chan, in);
+
+ if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_NOCONNECTEDLINE)) {
+ ast_channel_lock(outgoing->chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &outgoing->chan->cid);
+ ast_channel_unlock(outgoing->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
}
#ifdef HAVE_EPOLL
@@ -864,6 +891,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
if (!peer) {
ast_verb(3, "%s answered %s\n", c->name, in->name);
+ if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) {
+ ast_channel_lock(c);
+ ast_connected_line_copy_from_caller(&connected_caller, &c->cid);
+ ast_channel_unlock(c);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = c;
ast_copy_flags64(peerflags, o,
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
@@ -902,6 +941,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
/* This is our guy if someone answered. */
if (!peer) {
ast_verb(3, "%s answered %s\n", c->name, in->name);
+ if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) {
+ ast_channel_lock(c);
+ ast_connected_line_copy_from_caller(&connected_caller, &c->cid);
+ ast_channel_unlock(c);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = c;
if (peer->cdr) {
peer->cdr->answer = ast_tvnow();
@@ -970,6 +1021,29 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name);
ast_indicate(in, AST_CONTROL_SRCUPDATE);
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ ast_verb(3, "Connected line update to %s prevented.\n", in->name);
+ } else if (!single) {
+ struct ast_party_connected_line connected;
+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", c->name, in->name);
+ ast_party_connected_line_set_init(&connected, &o->connected);
+ ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
+ ast_party_connected_line_set(&o->connected, &connected);
+ ast_party_connected_line_free(&connected);
+ } else {
+ ast_verb(3, "%s connected line has changed, passing it to %s\n", c->name, in->name);
+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ }
+ break;
+ case AST_CONTROL_REDIRECTING:
+ if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ 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);
+ }
+ break;
case AST_CONTROL_PROCEEDING:
ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name);
if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
@@ -1084,7 +1158,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
((f->subclass == AST_CONTROL_HOLD) ||
(f->subclass == AST_CONTROL_UNHOLD) ||
(f->subclass == AST_CONTROL_VIDUPDATE) ||
- (f->subclass == AST_CONTROL_SRCUPDATE))) {
+ (f->subclass == AST_CONTROL_SRCUPDATE) ||
+ (f->subclass == AST_CONTROL_CONNECTED_LINE) ||
+ (f->subclass == AST_CONTROL_REDIRECTING))) {
ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen);
}
@@ -1423,11 +1499,11 @@ static int setup_privacy_args(struct privacy_args *pa,
ast_copy_string(pa->privcid, l, sizeof(pa->privcid));
- if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) {
- /* if callerid is set and OPT_SCREEN_NOCLID is set also */
+ if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCALLERID)) {
+ /* if callerid is set and OPT_SCREEN_NOCALLERID is set also */
ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid);
pa->privdb_val = AST_PRIVACY_ALLOW;
- } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
+ } else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
}
@@ -1637,7 +1713,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
outbound_group = ast_strdupa(outbound_group);
}
ast_channel_unlock(chan);
- ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING);
+ ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE);
/* loop through the list of dial destinations */
rest = args.peers;
@@ -1674,6 +1750,14 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
ast_channel_lock(chan);
datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
+ /* If the incoming channel has previously had connected line information
+ * set on it (perhaps through the CONNECTED_LINE dialplan function) then
+ * seed the calllist's connected line information with this previously
+ * acquired info
+ */
+ if (chan->connected.id.number) {
+ ast_party_connected_line_copy(&tmp->connected, &chan->connected);
+ }
ast_channel_unlock(chan);
if (datastore)
@@ -1746,6 +1830,10 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
}
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
+ ast_channel_lock(tc);
+ while (ast_channel_trylock(chan)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(tc);
+ }
/* Setup outgoing SDP to match incoming one */
if (!outgoing && !rest) {
ast_rtp_instance_early_bridge_make_compatible(tc, chan);
@@ -1759,20 +1847,31 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
tc->data = "(Outgoing Line)";
memset(&tc->whentohangup, 0, sizeof(tc->whentohangup));
- S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num));
- S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name));
- S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
- S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+ /* If the new channel has no callerid, try to guess what it should be */
+ if (ast_strlen_zero(tc->cid.cid_num)) {
+ if (!ast_strlen_zero(chan->connected.id.number)) {
+ ast_set_callerid(tc, chan->connected.id.number, chan->connected.id.name, chan->connected.ani);
+ } else if (!ast_strlen_zero(chan->cid.cid_dnid)) {
+ ast_set_callerid(tc, chan->cid.cid_dnid, NULL, NULL);
+ } else if (!ast_strlen_zero(S_OR(chan->macroexten, chan->exten))) {
+ ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), NULL, NULL);
+ }
+ ast_set_flag64(tmp, DIAL_NOCONNECTEDLINE);
+ }
+ ast_connected_line_copy_from_caller(&tc->connected, &chan->cid);
+
+ S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+ ast_party_redirecting_copy(&tc->redirecting, &chan->redirecting);
+
+ tc->cid.cid_tns = chan->cid.cid_tns;
+
ast_string_field_set(tc, accountcode, chan->accountcode);
tc->cdrflags = chan->cdrflags;
if (ast_strlen_zero(tc->musicclass))
ast_string_field_set(tc, musicclass, chan->musicclass);
- /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */
- tc->cid.cid_pres = chan->cid.cid_pres;
- tc->cid.cid_ton = chan->cid.cid_ton;
- tc->cid.cid_tns = chan->cid.cid_tns;
- tc->cid.cid_ani2 = chan->cid.cid_ani2;
+
+ /* Pass ADSI CPE and transfer capability */
tc->adsicpe = chan->adsicpe;
tc->transfercapability = chan->transfercapability;
@@ -1809,6 +1908,8 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
if (tc->hangupcause) {
chan->hangupcause = tc->hangupcause;
}
+ ast_channel_unlock(chan);
+ ast_channel_unlock(tc);
ast_hangup(tc);
tc = NULL;
ast_free(tmp);
@@ -1816,8 +1917,11 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
} else {
senddialevent(chan, tc, numsubst);
ast_verb(3, "Called %s\n", numsubst);
- if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID))
+ if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL);
+ }
+ ast_channel_unlock(chan);
+ ast_channel_unlock(tc);
}
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we're forcibly removed, these outgoing calls won't get
diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c
index 605d11faf..cfba99fce 100644
--- a/apps/app_directed_pickup.c
+++ b/apps/app_directed_pickup.c
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/features.h"
+#include "asterisk/callerid.h"
#define PICKUPMARK "PICKUPMARK"
@@ -91,9 +92,21 @@ static const char *app2 = "PickupChan";
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
{
int res = 0;
+ struct ast_party_connected_line connected_caller;
ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
+ connected_caller = target->connected;
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(chan, &connected_caller);
+
+ ast_channel_lock(chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &chan->cid);
+ ast_channel_unlock(chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(chan, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+
if ((res = ast_answer(chan))) {
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
return -1;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 5726d4c5c..58b1c09ba 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -94,6 +94,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/strings.h"
#include "asterisk/global_datastores.h"
#include "asterisk/taskprocessor.h"
+#include "asterisk/callerid.h"
/*!
* \par Please read before modifying this file.
@@ -141,6 +142,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Ignore call forward requests from queue members and do nothing
when they are requested.</para>
</option>
+ <option name="I">
+ <para>Asterisk will ignore any connected line update requests or any redirecting party
+ update requests it may receive on this dial attempt.</para>
+ </option>
<option name="r">
<para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
</option>
@@ -625,6 +630,8 @@ struct callattempt {
time_t lastcall;
struct call_queue *lastqueue;
struct member *member;
+ unsigned int update_connectedline:1;
+ struct ast_party_connected_line connected;
};
@@ -2479,22 +2486,40 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
(*busies)++;
return 0;
}
-
+
+ ast_channel_lock(tmp->chan);
+ while (ast_channel_trylock(qe->chan)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
+ }
+
if (qe->cancel_answered_elsewhere) {
ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
}
tmp->chan->appl = "AppQueue";
tmp->chan->data = "(Outgoing Line)";
memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
- if (tmp->chan->cid.cid_num)
- ast_free(tmp->chan->cid.cid_num);
- tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
- if (tmp->chan->cid.cid_name)
- ast_free(tmp->chan->cid.cid_name);
- tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
- if (tmp->chan->cid.cid_ani)
- ast_free(tmp->chan->cid.cid_ani);
- tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
+
+ /* If the new channel has no callerid, try to guess what it should be */
+ if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
+ if (!ast_strlen_zero(qe->chan->connected.id.number)) {
+ ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
+ tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
+ } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
+ ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
+ } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
+ ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
+ }
+ tmp->update_connectedline = 0;
+ }
+
+ if (tmp->chan->cid.cid_rdnis)
+ ast_free(tmp->chan->cid.cid_rdnis);
+ tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
+ ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
+
+ tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
+
+ ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
/* Inherit specially named variables from parent channel */
ast_channel_inherit_variables(qe->chan, tmp->chan);
@@ -2503,7 +2528,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
tmp->chan->adsicpe = qe->chan->adsicpe;
/* Inherit context and extension */
- ast_channel_lock(qe->chan);
macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
@@ -2511,13 +2535,14 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
else
ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
- ast_channel_unlock(qe->chan);
/* Place the call, but don't wait on the answer */
if ((res = ast_call(tmp->chan, location, 0))) {
/* Again, keep going even if there's an error */
ast_debug(1, "ast call on peer returned %d\n", res);
ast_verb(3, "Couldn't call %s\n", tmp->interface);
+ ast_channel_unlock(tmp->chan);
+ ast_channel_unlock(qe->chan);
do_hang(tmp);
(*busies)++;
update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
@@ -2545,6 +2570,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
ast_verb(3, "Called %s\n", tmp->interface);
}
+ ast_channel_unlock(tmp->chan);
+ ast_channel_unlock(qe->chan);
update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
return 1;
@@ -2775,7 +2802,7 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
* \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
* \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
*/
-static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
+static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
{
const char *queue = qe->parent->name;
struct callattempt *o, *start = NULL, *prev = NULL;
@@ -2795,6 +2822,12 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
#ifdef HAVE_EPOLL
struct callattempt *epollo;
#endif
+ struct ast_party_connected_line connected_caller;
+ char *inchan_name;
+
+ ast_channel_lock(qe->chan);
+ inchan_name = ast_strdupa(qe->chan->name);
+ ast_channel_unlock(qe->chan);
starttime = (long) time(NULL);
#ifdef HAVE_EPOLL
@@ -2845,9 +2878,28 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
}
winner = ast_waitfor_n(watchers, pos, to);
for (o = start; o; o = o->call_next) {
+ /* We go with a static buffer here instead of using ast_strdupa. Using
+ * ast_strdupa in a loop like this one can cause a stack overflow
+ */
+ char ochan_name[AST_CHANNEL_NAME];
+ ast_channel_lock(o->chan);
+ ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
+ ast_channel_unlock(o->chan);
if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
if (!peer) {
- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
+ ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
+ if (update_connectedline) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (o->update_connectedline) {
+ ast_channel_lock(o->chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
+ ast_channel_unlock(o->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = o;
}
} else if (o->chan && (o->chan == winner)) {
@@ -2856,12 +2908,15 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
ast_copy_string(membername, o->member->membername, sizeof(membername));
if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
- ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
+ ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
numnochan++;
do_hang(o);
winner = NULL;
continue;
} else if (!ast_strlen_zero(o->chan->call_forward)) {
+ struct ast_party_redirecting *apr = &o->chan->redirecting;
+ struct ast_party_connected_line *apc = &o->chan->connected;
+ struct ast_channel *original = o->chan;
char tmpchan[256];
char *stuff;
char *tech;
@@ -2876,7 +2931,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
tech = "Local";
}
/* Before processing channel, go ahead and check for forwarding */
- ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
+ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
/* Setup parameters */
o->chan = ast_request(tech, in->nativeformats, stuff, &status);
if (!o->chan) {
@@ -2884,32 +2939,42 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
o->stillgoing = 0;
numnochan++;
} else {
+ ast_channel_lock(o->chan);
+ while (ast_channel_trylock(in)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(o->chan);
+ }
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
- if (o->chan->cid.cid_num)
- ast_free(o->chan->cid.cid_num);
- o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
-
- if (o->chan->cid.cid_name)
- ast_free(o->chan->cid.cid_name);
- o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
ast_string_field_set(o->chan, accountcode, in->accountcode);
o->chan->cdrflags = in->cdrflags;
- if (in->cid.cid_ani) {
- if (o->chan->cid.cid_ani)
- ast_free(o->chan->cid.cid_ani);
- o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
- }
+ ast_channel_set_redirecting(o->chan, apr);
+
if (o->chan->cid.cid_rdnis)
ast_free(o->chan->cid.cid_rdnis);
- o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
+ o->chan->cid.cid_rdnis = ast_strdup(S_OR(original->cid.cid_rdnis,S_OR(in->macroexten, in->exten)));
+
+ o->chan->cid.cid_tns = in->cid.cid_tns;
+
+ ast_party_caller_copy(&o->chan->cid, &in->cid);
+ ast_party_connected_line_copy(&o->chan->connected, apc);
+
+ ast_channel_update_redirecting(in, apr);
+ if (in->cid.cid_rdnis) {
+ ast_free(in->cid.cid_rdnis);
+ }
+ in->cid.cid_rdnis = ast_strdup(o->chan->cid.cid_rdnis);
+
+ update_connectedline = 1;
+
if (ast_call(o->chan, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
do_hang(o);
numnochan++;
}
+ ast_channel_unlock(in);
+ ast_channel_unlock(o->chan);
}
/* Hangup the original channel now, in case we needed it */
ast_hangup(winner);
@@ -2922,12 +2987,24 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
case AST_CONTROL_ANSWER:
/* This is our guy if someone answered. */
if (!peer) {
- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
+ ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
+ if (update_connectedline) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (o->update_connectedline) {
+ ast_channel_lock(o->chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
+ ast_channel_unlock(o->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = o;
}
break;
case AST_CONTROL_BUSY:
- ast_verb(3, "%s is busy\n", o->chan->name);
+ ast_verb(3, "%s is busy\n", ochan_name);
if (in->cdr)
ast_cdr_busy(in->cdr);
do_hang(o);
@@ -2942,7 +3019,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
numbusies++;
break;
case AST_CONTROL_CONGESTION:
- ast_verb(3, "%s is circuit-busy\n", o->chan->name);
+ ast_verb(3, "%s is circuit-busy\n", ochan_name);
if (in->cdr)
ast_cdr_busy(in->cdr);
endtime = (long) time(NULL);
@@ -2957,13 +3034,37 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
numbusies++;
break;
case AST_CONTROL_RINGING:
- ast_verb(3, "%s is ringing\n", o->chan->name);
+ ast_verb(3, "%s is ringing\n", ochan_name);
break;
case AST_CONTROL_OFFHOOK:
/* Ignore going off hook */
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ if (!update_connectedline) {
+ ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
+ } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
+ struct ast_party_connected_line connected;
+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
+ ast_party_connected_line_set_init(&connected, &o->connected);
+ ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
+ ast_party_connected_line_set(&o->connected, &connected);
+ ast_party_connected_line_free(&connected);
+ } else {
+ ast_verb(3, "%s connected line has changed, passing it to %s\n", ochan_name, inchan_name);
+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ }
+ break;
+ case AST_CONTROL_REDIRECTING:
+ if (!update_connectedline) {
+ 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);
+ }
+ break;
default:
ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
+ break;
}
}
ast_frfree(f);
@@ -3517,6 +3618,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
char *p;
char vars[2048];
int forwardsallowed = 1;
+ int update_connectedline = 1;
int callcompletedinsl;
struct ao2_iterator memi;
struct ast_datastore *datastore, *transfer_ds;
@@ -3582,6 +3684,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
case 'i':
forwardsallowed = 0;
break;
+ case 'I':
+ update_connectedline = 0;
+ break;
case 'x':
ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
break;
@@ -3591,7 +3696,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
case 'C':
qe->cancel_answered_elsewhere = 1;
break;
-
}
/* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited.
@@ -3661,6 +3765,17 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
}
}
AST_LIST_UNLOCK(dialed_interfaces);
+
+ ast_channel_lock(qe->chan);
+ /* If any pre-existing connected line information exists on this
+ * channel, like from the CONNECTED_LINE dialplan function, use this
+ * to seed the connected line information. It may, of course, be updated
+ * during the call
+ */
+ if (qe->chan->connected.id.number) {
+ ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
+ }
+ ast_channel_unlock(qe->chan);
if (di) {
free(tmp);
@@ -3692,6 +3807,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
tmp->oldstatus = cur->status;
tmp->lastcall = cur->lastcall;
tmp->lastqueue = cur->lastqueue;
+ tmp->update_connectedline = 1;
ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
/* Special case: If we ring everyone, go ahead and ring them, otherwise
just calculate their metric for the appropriate strategy */
@@ -3732,7 +3848,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
ring_one(qe, outgoing, &numbusies);
if (use_weight)
ao2_unlock(queues);
- lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
+ lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
/* The ast_channel_datastore_remove() function could fail here if the
* datastore was moved to another channel during a masquerade. If this is
* the case, don't free the datastore here because later, when the channel