diff --git a/apps/app_dial.c b/apps/app_dial.c
index a071f5e0f47d1d6057f06603e621b9b0792f123c..20ea83e571586a2109b5cb5b13e2c2ab6cfb4d75 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 a6cf340be314ce578fe3297c04c7bb98d4bfb332..a1219e45f03de533b202d969d1cfc64da317e511 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 99b23cdeee8f0ce78a40477c376f1ab07074346f..3f4cfb5fb48df46da02d54a2b8de978a093cbb6e 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 8a20d3b91bd921ee8074f282dc408690a2084eb7..db760410c456c1640dbfea3e32ff4b4d13612dab 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 0000000000000000000000000000000000000000..72edabac5f089e805190a24b2cfcc5483e584733
--- /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 b9894e7ab4d6a925ce0b5bb527ecf8354db53a58..ca3d8dabd5013ba708dfa36e525ef639130fea8a 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 0000000000000000000000000000000000000000..340e71de19f23f52727b5cf185fe49359b0f1e05
--- /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,
+};