aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_dial.c144
-rw-r--r--apps/app_queue.c52
-rw-r--r--channels/chan_local.c1
-rw-r--r--include/asterisk/channel.h1
-rw-r--r--include/asterisk/global_datastores.h36
-rw-r--r--main/Makefile2
-rw-r--r--main/global_datastores.c78
7 files changed, 243 insertions, 71 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index a071f5e0f..20ea83e57 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -54,6 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/manager.h"
#include "asterisk/privacy.h"
#include "asterisk/stringfields.h"
+#include "asterisk/global_datastores.h"
static char *app = "Dial";
@@ -326,7 +327,6 @@ struct chanlist {
struct chanlist *next;
struct ast_channel *chan;
uint64_t flags;
- int forwards;
};
@@ -347,8 +347,6 @@ static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception,
}
}
-#define AST_MAX_FORWARDS 8
-
#define AST_MAX_WATCHERS 256
/*
@@ -480,28 +478,22 @@ static void do_forward(struct chanlist *o,
tech = "Local";
}
/* Before processing channel, go ahead and check for forwarding */
- o->forwards++;
- if (o->forwards < AST_MAX_FORWARDS) {
- ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
- /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
- if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
- ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff);
- c = o->chan = NULL;
- cause = AST_CAUSE_BUSY;
- } else {
- /* Setup parameters */
- c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
- if (c) {
- if (single)
- ast_channel_make_compatible(o->chan, in);
- ast_channel_inherit_variables(in, o->chan);
- } else
- ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
- }
- } else {
- ast_verb(3, "Too many forwards from %s\n", c->name);
- cause = AST_CAUSE_CONGESTION;
+ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
+ /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
+ if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
+ ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff);
c = o->chan = NULL;
+ cause = AST_CAUSE_BUSY;
+ } else {
+ /* Setup parameters */
+ c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
+ if (c) {
+ if (single)
+ ast_channel_make_compatible(o->chan, in);
+ ast_channel_inherit_variables(in, o->chan);
+ ast_channel_datastore_inherit(in, o->chan);
+ } else
+ ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
}
if (!c) {
ast_clear_flag64(o, DIAL_STILLGOING);
@@ -1252,6 +1244,8 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
);
struct ast_flags64 opts = { 0, };
char *opt_args[OPT_ARG_ARRAY_SIZE];
+ struct ast_datastore *datastore;
+ int fulldial = 0, num_dialed = 0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
@@ -1333,7 +1327,13 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
struct ast_channel *tc; /* channel for this destination */
/* Get a technology/[device:]number pair */
char *number = cur;
+ char *interface = ast_strdupa(number);
char *tech = strsep(&number, "/");
+ /* find if we already dialed this interface */
+ int dialed = 0;
+ struct ast_dialed_interface *di;
+ AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
+ num_dialed++;
if (!number) {
ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
goto out;
@@ -1353,6 +1353,50 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
}
ast_copy_string(numsubst, number, sizeof(numsubst));
/* Request the peer */
+ if (!(datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
+ if(!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
+ ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n");
+ free(tmp);
+ goto out;
+ }
+ else {
+ datastore->inheritance = DATASTORE_INHERIT_FOREVER;
+ if((dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
+ datastore->data = dialed_interfaces;
+ AST_LIST_HEAD_INIT(dialed_interfaces);
+ ast_channel_datastore_add(chan, datastore);
+ } else {
+ free(tmp);
+ goto out;
+ }
+ }
+ } else
+ dialed_interfaces = datastore->data;
+ AST_LIST_LOCK(dialed_interfaces);
+ AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
+ /* XXX case sensitive??? */
+ if(!strcasecmp(di->interface, interface)) {
+ dialed = 1;
+ break;
+ }
+ }
+ if(!dialed && strcasecmp(tech, "Local")) {
+ if(!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) {
+ AST_LIST_UNLOCK(dialed_interfaces);
+ free(tmp);
+ goto out;
+ }
+ strcpy(di->interface, interface);
+ AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
+ } else {
+ AST_LIST_UNLOCK(dialed_interfaces);
+ ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n", di->interface);
+ fulldial++;
+ free(tmp);
+ continue;
+ }
+ AST_LIST_UNLOCK(dialed_interfaces);
+
tc = ast_request(tech, chan->nativeformats, numsubst, &cause);
if (!tc) {
/* If we can't, just go on to the next call */
@@ -1365,50 +1409,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
continue;
}
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
- if (!ast_strlen_zero(tc->call_forward)) {
- char tmpchan[256];
- char *stuff;
- char *tech;
- ast_copy_string(tmpchan, tc->call_forward, sizeof(tmpchan));
- if ((stuff = strchr(tmpchan, '/'))) {
- *stuff++ = '\0';
- tech = tmpchan;
- } else {
- snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tc->call_forward, tc->context);
- stuff = tmpchan;
- tech = "Local";
- }
- tmp->forwards++;
- if (tmp->forwards < AST_MAX_FORWARDS) {
- ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n",
- chan->name, tech, stuff, tc->name);
- ast_hangup(tc);
- /* If we have been told to ignore forwards, just set this channel to null
- * and continue processing extensions normally */
- if (ast_test_flag64(&opts, OPT_IGNORE_FORWARDING)) {
- tc = NULL;
- cause = AST_CAUSE_BUSY;
- ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n",
- chan->name, tech, stuff);
- } else {
- tc = ast_request(tech, chan->nativeformats, stuff, &cause);
- }
- if (!tc)
- ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
- else
- ast_channel_inherit_variables(chan, tc);
- } else {
- ast_verb(3, "Too many forwards from %s\n", tc->name);
- ast_hangup(tc);
- tc = NULL;
- cause = AST_CAUSE_CONGESTION;
- }
- if (!tc) {
- handle_cause(cause, &num);
- ast_free(tmp);
- continue;
- }
- }
/* Setup outgoing SDP to match incoming one */
ast_rtp_make_compatible(tc, chan, !outgoing && !rest);
@@ -1498,6 +1498,10 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
if (!outgoing) {
strcpy(pa.status, "CHANUNAVAIL");
+ if(fulldial == num_dialed) {
+ res = -1;
+ goto out;
+ }
} else {
/* Our status will at least be NOANSWER */
strcpy(pa.status, "NOANSWER");
@@ -1520,7 +1524,9 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
time(&start_time);
peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result);
-
+
+ ast_channel_datastore_remove(chan, datastore);
+ ast_channel_datastore_free(datastore);
if (!peer) {
if (result) {
res = result;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index a6cf340be..a1219e45f 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -87,6 +87,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/event.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
+#include "asterisk/global_datastores.h"
enum {
QUEUE_STRATEGY_RINGALL = 0,
@@ -2295,6 +2296,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
numnochan++;
} else {
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);
@@ -2733,6 +2735,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
int forwardsallowed = 1;
int callcompletedinsl;
struct ao2_iterator memi;
+ struct ast_datastore *datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
memset(&bridge_config, 0, sizeof(bridge_config));
tmpid[0] = 0;
@@ -2802,7 +2805,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
memi = ao2_iterator_init(qe->parent->members, 0);
while ((cur = ao2_iterator_next(&memi))) {
struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
-
+ struct ast_dialed_interface *di;
+ int dialed = 0;
+ AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
if (!tmp) {
ao2_ref(cur, -1);
ao2_unlock(qe->parent);
@@ -2810,6 +2815,49 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
ao2_unlock(queues);
goto out;
}
+ if (!datastore) {
+ if(!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
+ ao2_ref(cur, -1);
+ ast_mutex_unlock(&qe->parent->lock);
+ if(use_weight)
+ AST_LIST_UNLOCK(&queues);
+ free(tmp);
+ goto out;
+ }
+ datastore->inheritance = DATASTORE_INHERIT_FOREVER;
+ dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces));
+ datastore->data = dialed_interfaces;
+ AST_LIST_HEAD_INIT(dialed_interfaces);
+ ast_channel_datastore_add(qe->chan, datastore);
+ } else
+ dialed_interfaces = datastore->data;
+ AST_LIST_LOCK(dialed_interfaces);
+ AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
+ /* XXX case sensitive ?? */
+ if(!strcasecmp(cur->interface, di->interface)) {
+ dialed = 1;
+ break;
+ }
+ }
+ if (!dialed && strncasecmp(cur->interface, "Local/", 6)) {
+ if(!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
+ ao2_ref(cur, -1);
+ AST_LIST_UNLOCK(dialed_interfaces);
+ ast_mutex_unlock(&qe->parent->lock);
+ if(use_weight)
+ AST_LIST_UNLOCK(&queues);
+ free(tmp);
+ goto out;
+ }
+ strcpy(di->interface, cur->interface);
+ AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
+ } else {
+ AST_LIST_UNLOCK(dialed_interfaces);
+ ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n", di->interface);
+ free(tmp);
+ continue;
+ }
+ AST_LIST_UNLOCK(dialed_interfaces);
tmp->stillgoing = -1;
tmp->member = cur;
tmp->oldstatus = cur->status;
@@ -2842,6 +2890,8 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
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);
+ ast_channel_datastore_remove(qe->chan, datastore);
+ ast_channel_datastore_free(datastore);
ao2_lock(qe->parent);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
store_next_rr(qe, outgoing);
diff --git a/channels/chan_local.c b/channels/chan_local.c
index 99b23cdee..3f4cfb5fb 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -473,6 +473,7 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
}
}
+ ast_channel_datastore_inherit(p->owner, p->chan);
/* Start switch on sub channel */
if (!(res = ast_pbx_start(p->chan)))
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 8a20d3b91..db760410c 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -649,6 +649,7 @@ int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *
* \retval 0 success
* \retval non-zero failure
*/
+
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore);
/*!
diff --git a/include/asterisk/global_datastores.h b/include/asterisk/global_datastores.h
new file mode 100644
index 000000000..72edabac5
--- /dev/null
+++ b/include/asterisk/global_datastores.h
@@ -0,0 +1,36 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2007, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@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 globally accessible channel datastores
+ * \author Mark Michelson <mmichelson@digium.com>
+ */
+
+#ifndef _ASTERISK_GLOBAL_DATASTORE_H
+#define _ASTERISK_GLOBAL_DATASTORE_H
+
+#include "asterisk/channel.h"
+
+extern const struct ast_datastore_info dialed_interface_info;
+
+struct ast_dialed_interface {
+ AST_LIST_ENTRY(ast_dialed_interface) list;
+ char interface[1];
+};
+
+#endif
diff --git a/main/Makefile b/main/Makefile
index b9894e7ab..ca3d8dabd 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -27,7 +27,7 @@ OBJS= io.o sched.o logger.o frame.o loader.o config.o channel.o \
netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
- astobj2.o hashtab.o
+ astobj2.o hashtab.o global_datstores.o
# we need to link in the objects statically, not as a library, because
# otherwise modules will not have them available if none of the static
diff --git a/main/global_datastores.c b/main/global_datastores.c
new file mode 100644
index 000000000..340e71de1
--- /dev/null
+++ b/main/global_datastores.c
@@ -0,0 +1,78 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2007, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@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 globally-accessible datastore information and callbacks
+ *
+ * \author Mark Michelson <mmichelson@digium.com>
+ */
+
+#include "asterisk/global_datastores.h"
+#include "asterisk/linkedlists.h"
+
+static void dialed_interface_destroy(void *data)
+{
+ struct ast_dialed_interface *di = NULL;
+ AST_LIST_HEAD(, ast_dialed_interface) *dialed_interface_list = data;
+
+ if (!dialed_interface_list)
+ return;
+
+ AST_LIST_LOCK(dialed_interface_list);
+ while ((di = AST_LIST_REMOVE_HEAD(dialed_interface_list, list)))
+ ast_free(di);
+ AST_LIST_UNLOCK(dialed_interface_list);
+
+ AST_LIST_HEAD_DESTROY(dialed_interface_list);
+ ast_free(dialed_interface_list);
+}
+
+static void *dialed_interface_duplicate(void *data)
+{
+ struct ast_dialed_interface *di = NULL;
+ AST_LIST_HEAD(, ast_dialed_interface) *old_list;
+ AST_LIST_HEAD(, ast_dialed_interface) *new_list = NULL;
+
+ if(!(old_list = data))
+ return NULL;
+
+ if(!(new_list = ast_calloc(1, sizeof(*new_list))))
+ return NULL;
+
+ AST_LIST_HEAD_INIT(new_list);
+ AST_LIST_LOCK(old_list);
+ AST_LIST_TRAVERSE(old_list, di, list) {
+ struct ast_dialed_interface *di2 = ast_calloc(1, sizeof(*di2) + strlen(di->interface));
+ if(!di2) {
+ AST_LIST_UNLOCK(old_list);
+ return NULL;
+ }
+ strcpy(di2->interface, di->interface);
+ AST_LIST_INSERT_TAIL(new_list, di2, list);
+ }
+ AST_LIST_UNLOCK(old_list);
+
+ return new_list;
+}
+
+const struct ast_datastore_info dialed_interface_info = {
+ .type ="dialed-interface",
+ .destroy = dialed_interface_destroy,
+ .duplicate = dialed_interface_duplicate,
+};