diff --git a/cdr.c b/cdr.c
index 20b3e2cfaaad5b89bb23d4e45dba2cd1aa67f801..3cbaac47ee8fcfe0b1069b3bb576232ffffdf24f 100755
--- a/cdr.c
+++ b/cdr.c
@@ -19,6 +19,7 @@
 #include <asterisk/cdr.h>
 #include <asterisk/logger.h>
 #include <asterisk/callerid.h>
+#include <asterisk/causes.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -163,6 +164,41 @@ void ast_cdr_busy(struct ast_cdr *cdr)
 	}
 }
 
+void ast_cdr_failed(struct ast_cdr *cdr)
+{
+	char *chan; 
+	if (cdr) {
+		chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+		if (cdr->posted)
+			ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
+			cdr->disposition = AST_CDR_FAILED;
+	}
+}
+
+int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
+{
+	int res = 0;
+	if (cdr) {
+		switch(cause) {
+			case AST_CAUSE_BUSY:
+				ast_cdr_busy(cdr);
+				break;
+			case AST_CAUSE_FAILURE:
+				ast_cdr_failed(cdr);
+				break;
+			case AST_CAUSE_NORMAL:
+				break;
+			case AST_CAUSE_NOTDEFINED:
+				res = -1;
+				break;
+			default:
+				res = -1;
+				ast_log(LOG_WARNING, "We don't handle that cause yet\n");
+		}
+	}
+	return res;
+}
+
 void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann)
 {
 	char *chan; 
@@ -275,6 +311,8 @@ char *ast_cdr_disp2str(int disposition)
 	switch (disposition) {
 	case AST_CDR_NOANSWER:
 		return "NO ANSWER";
+	case AST_CDR_FAILED:
+		return "FAILED";		
 	case AST_CDR_BUSY:
 		return "BUSY";		
 	case AST_CDR_ANSWERED:
@@ -313,11 +351,15 @@ int ast_cdr_update(struct ast_channel *c)
 	char *name, *num;
 	char tmp[AST_MAX_EXTENSION] = "";
 	/* Grab source from ANI or normal Caller*ID */
+	if (!cdr) {
+		ast_log(LOG_NOTICE, "The cdr pointer is not set\n");
+		return -1;
+	}
 	if (c->ani)
 		strncpy(tmp, c->ani, sizeof(tmp) - 1);
-	else if (c->callerid)
+	else if (c->callerid && strlen(c->callerid))
 		strncpy(tmp, c->callerid, sizeof(tmp) - 1);
-	if (c->callerid)
+	if (c->callerid && strlen(c->callerid))
 		strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1);
 	else
 		strcpy(cdr->clid, "");
diff --git a/channel.c b/channel.c
index 2ecde4feefa9afe9c6e498fff229ed3bd3df4343..6d704d742408db5aae48aa50d57e0c0f91d2f3a1 100755
--- a/channel.c
+++ b/channel.c
@@ -34,6 +34,7 @@
 #include <asterisk/linkedlists.h>
 #include <asterisk/indications.h>
 #include <asterisk/monitor.h>
+#include <asterisk/causes.h>
 #ifdef ZAPTEL_OPTIMIZATIONS
 #include <sys/ioctl.h>
 #include <linux/zaptel.h>
@@ -1493,8 +1494,7 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
 	int state = 0;
 	struct ast_channel *chan;
 	struct ast_frame *f;
-	int res;
-	
+	int res = 0;
 	chan = ast_request(type, format, data);
 	if (chan) {
 		if (callerid)
@@ -1504,8 +1504,6 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
 				res = ast_waitfor(chan, timeout);
 				if (res < 0) {
 					/* Something not cool, or timed out */
-					ast_hangup(chan);
-					chan = NULL;
 					break;
 				}
 				/* If done, break out */
@@ -1516,8 +1514,7 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
 				f = ast_read(chan);
 				if (!f) {
 					state = AST_CONTROL_HANGUP;
-					ast_hangup(chan);
-					chan = NULL;
+					res = 0;
 					break;
 				}
 				if (f->frametype == AST_FRAME_CONTROL) {
@@ -1537,17 +1534,36 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
 				}
 				ast_frfree(f);
 			}
-		} else {
-			ast_hangup(chan);
-			chan = NULL;
+		} else
 			ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
-		}
 	} else
 		ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
 	if (chan && (chan->_state == AST_STATE_UP))
 		state = AST_CONTROL_ANSWER;
 	if (outstate)
 		*outstate = state;
+	if (chan && res <= 0) {
+		if (!chan->cdr) {
+			chan->cdr = ast_cdr_alloc();
+			if (chan->cdr)
+				ast_cdr_init(chan->cdr, chan);
+		}
+		if (chan->cdr) {
+			char tmp[256];
+			sprintf(tmp, "%s/%s",type,(char *)data);
+			ast_cdr_setapp(chan->cdr,"Dial",tmp);
+			ast_cdr_update(chan);
+			ast_cdr_start(chan->cdr);
+			ast_cdr_end(chan->cdr);
+			/* If the cause wasn't handled properly */
+			if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
+				ast_cdr_failed(chan->cdr);
+			ast_cdr_reset(chan->cdr,1);
+		} else 
+			ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
+		ast_hangup(chan);
+		chan = NULL;
+	}
 	return chan;
 }
 
@@ -2431,4 +2447,3 @@ int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, i
 	return 0;
 }
 
-
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index a0dded75b5b8110e1179c54c4cc862fa3e3385d0..284f70f435d7c33ed23df96d8d192ba31a7fd475 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -36,6 +36,7 @@
 #include <asterisk/dsp.h>
 #include <asterisk/astdb.h>
 #include <asterisk/manager.h>
+#include <asterisk/causes.h>
 #include <sys/signal.h>
 #include <sys/select.h>
 #include <errno.h>
@@ -498,6 +499,23 @@ static int cidrings[] = {
 #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
 #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
 
+/* translate between PRI causes and asterisk's */
+int hangup_pri2cause(int cause)
+{
+	switch(cause) {
+#ifdef ZAPATA_PRI
+		case PRI_CAUSE_USER_BUSY:
+			return AST_CAUSE_BUSY;
+		case PRI_CAUSE_NORMAL_CLEARING:
+			return AST_CAUSE_NORMAL;
+#endif
+		default:
+			return AST_CAUSE_FAILURE;
+	}
+	/* never reached */
+	return 0;
+}
+
 static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
 {
 	int res;
@@ -6049,6 +6067,7 @@ static void *pri_dchannel(void *vpri)
 					if (chan) {
 						ast_mutex_lock(&pri->pvt[chan]->lock);
 						if (pri->pvt[chan]->owner) {
+							pri->pvt[chan]->owner->hangupcause = hangup_pri2cause(e->hangup.cause);
 							pri->pvt[chan]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 							if (option_verbose > 2) 
 								ast_verbose(VERBOSE_PREFIX_3 "Channel %d, span %d got hangup\n", chan, pri->span);
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 0b9681035bfae9cc049191a074c3f1ad309efd2c..3988832df494bef45a059559c876656e0d0e21f5 100755
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -23,6 +23,7 @@
 #define AST_CDR_NOANSWER			(1 << 0)
 #define AST_CDR_BUSY				(1 << 1)
 #define AST_CDR_ANSWERED			(1 << 2)
+#define AST_CDR_FAILED				(1 << 3)
 
 //! AMA Flags
 #define AST_CDR_OMIT				(1)
@@ -142,6 +143,21 @@ extern void ast_cdr_answer(struct ast_cdr *cdr);
  */
 extern void ast_cdr_busy(struct ast_cdr *cdr);
 
+//! Fail a call
+/*!
+ * \param cdr the cdr you wish to associate with the call
+ * Returns nothing important
+ */
+extern void ast_cdr_failed(struct ast_cdr *cdr);
+
+//! Save the result of the call based on the AST_CAUSE_*
+/*!
+ * \param cdr the cdr you wish to associate with the call
+ * Returns nothing important
+ * \param cause the AST_CAUSE_*
+ */
+extern int ast_cdr_disposition(struct ast_cdr *cdr, int cause);
+	
 //! End a call
 /*!
  * \param cdr the cdr you have associated the call with
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 815f882f471bb96dfac6b538e47b58c30190f122..f33bb62d321725191e62e7b6c552162cd61e3701 100755
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -213,6 +213,9 @@ struct ast_channel {
 	/* Unique Channel Identifier */
 	char uniqueid[32];
 
+	/* Why is the channel hanged up */
+	int hangupcause;
+	
 	/* A linked list for variables */
 	struct ast_var_t *vars;	
 	AST_LIST_HEAD(varshead,ast_var_t) varshead;
diff --git a/pbx.c b/pbx.c
index 5ad920948f63e2d33d60e554f4c83d09442cce72..8a7dd2fd7caaeab9d0e94390543e78dcf33fee2c 100755
--- a/pbx.c
+++ b/pbx.c
@@ -3779,7 +3779,7 @@ static void *async_wait(void *data)
 	return NULL;
 }
 
-int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable )
+int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable)
 {
 	struct ast_channel *chan;
 	struct async_stat *as;
@@ -3828,6 +3828,27 @@ int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char
 					ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
 				ast_hangup(chan);
 			}
+		} else {
+			/* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
+			/* check if "failed" exists */
+			if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
+				chan = ast_channel_alloc(0);
+				if (chan) {
+					strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1);
+					if (context && strlen(context))
+						strncpy(chan->context, context, sizeof(chan->context) - 1);
+					strncpy(chan->exten, "failed", sizeof(chan->exten) - 1);
+					chan->priority = 1;
+					/* JDG chanvar */
+					tmp = variable;
+					/* FIXME replace this call with strsep  NOT*/
+					while( (var = strtok_r(NULL, "|", &tmp)) ) {
+						pbx_builtin_setvar( chan, var );
+					} /* /JDG */
+					ast_pbx_run(chan);	
+				} else
+					ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
+			}
 		}
 	} else {
 		as = malloc(sizeof(struct async_stat));