diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 1e075224fbcac59be8dd723591fe8fb5671af5f0..81d8b6d19a66075b53755707c3b272336952bbd1 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -1436,6 +1436,7 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 	int res;
 	unsigned char buf[256];
 	int flags;
+	int redirecting;
 
 	poller.fd = p->subs[SUB_REAL].dfd;
 	poller.events = POLLPRI | POLLIN;
@@ -1482,7 +1483,8 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 		}
 
 		if (res == 1) {
-			callerid_get(p->cs, &name, &num, &flags);
+			struct ast_channel *chan = analog_p->ss_astchan;
+			callerid_get_with_redirecting(p->cs, &name, &num, &flags, &redirecting);
 			if (name)
 				ast_copy_string(namebuf, name, ANALOG_MAX_CID);
 			if (num)
@@ -1490,7 +1492,6 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 
 			if (flags & (CID_PRIVATE_NUMBER | CID_UNKNOWN_NUMBER)) {
 				/* If we got a presentation, we must set it on the channel */
-				struct ast_channel *chan = analog_p->ss_astchan;
 				struct ast_party_caller caller;
 
 				ast_party_caller_set_init(&caller, ast_channel_caller(chan));
@@ -1499,8 +1500,19 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 				ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
 				ast_party_caller_free(&caller);
 			}
+			if (redirecting) {
+				/* There is a redirecting reason available in the Caller*ID received.
+				 * No idea what the redirecting number is, since the Caller*ID protocol
+				 * has no parameter for that, but at least we know WHY it was redirected. */
+				ast_channel_redirecting(chan)->reason.code = redirecting;
+			}
+
+			if (flags & CID_QUALIFIER) {
+				/* This is the inverse of how the qualifier is set in sig_analog */
+				pbx_builtin_setvar_helper(chan, "CALL_QUALIFIER", "1");
+			}
 
-			ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
+			ast_debug(1, "CallerID number: %s, name: %s, flags=%d, redirecting=%s\n", num, name, flags, ast_redirecting_reason_name(&ast_channel_redirecting(chan)->reason));
 			return 0;
 		}
 	}
diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c
index 850db5c90699c67a08f71413539fbaf0fc5baab6..1f962aacc9b0aeb1c5038751156e5c1d9487f001 100644
--- a/funcs/func_callerid.c
+++ b/funcs/func_callerid.c
@@ -192,6 +192,8 @@
 					You are responsible for setting it if/when needed.</para>
 					<para>Supporting Caller ID units will display the LDC
 					(Long Distance Call) indicator when they receive this parameter.</para>
+					<para>For incoming calls on FXO ports, if the Call Qualifier parameter is received,
+					this variable will also be set to 1.</para>
 					<para>This option must be used with a channel driver
 					that allows Asterisk to generate the Caller ID spill,
 					which currently only includes <literal>chan_dahdi</literal>.</para>
diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h
index 77b5822ba15aaaadeda40291276f8697f1e8df23..3c6d9c3b7c0a6d6950da089b9d09e49724455889 100644
--- a/include/asterisk/callerid.h
+++ b/include/asterisk/callerid.h
@@ -190,15 +190,29 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int sample
  * \param cid Callerid state machine to act upon
  * \param number Pass the address of a pointer-to-char (will contain the phone number)
  * \param name Pass the address of a pointer-to-char (will contain the name)
- * \param flags Pass the address of an int variable(will contain the various callerid flags)
+ * \param flags Pass the address of an int variable (will contain the various callerid flags - presentation flags and call qualifier)
  *
  * \details
  * This function extracts a callerid string out of a callerid_state state machine.
  * If no number is found, *number will be set to NULL.  Likewise for the name.
- * Flags can contain any of the following:
+ * Flags can contain any of the following: CID_PRIVATE_NAME, CID_PRIVATE_NUMBER, CID_UNKNOWN_NAME, CID_UNKNOWN_NUMBER, CID_MSGWAITING, CID_NOMSGWAITING, CID_QUALIFIER
  */
 void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags);
 
+/*! \brief Extract info out of callerID state machine.  Flags are listed above
+ * \param cid Callerid state machine to act upon
+ * \param[out] number Pass the address of a pointer-to-char (will contain the phone number)
+ * \param[out] name Pass the address of a pointer-to-char (will contain the name)
+ * \param[out] flags Pass the address of an int variable (will contain the various callerid flags)
+ * \param[out] redirecting Pass the address of an int variable (will contain the redirecting reason, if received - presentation flags and call qualifier)
+ *
+ * \details
+ * This function extracts a callerid string out of a callerid_state state machine.
+ * If no number is found, *number will be set to NULL.  Likewise for the name.
+ * Flags can contain any of the following: CID_PRIVATE_NAME, CID_PRIVATE_NUMBER, CID_UNKNOWN_NAME, CID_UNKNOWN_NUMBER, CID_MSGWAITING, CID_NOMSGWAITING, CID_QUALIFIER
+ */
+void callerid_get_with_redirecting(struct callerid_state *cid, char **name, char **number, int *flags, int *redirecting);
+
 /*!
  * \brief Get and parse DTMF-based callerid
  * \param cidstring The actual transmitted string.
diff --git a/main/callerid.c b/main/callerid.c
index 9755c456a76bedb87b860ea5014761f69763881c..da0e7fc68c14da16d0d00b4a8cb7ee67559f2126 100644
--- a/main/callerid.c
+++ b/main/callerid.c
@@ -53,6 +53,7 @@ struct callerid_state {
 	char name[64];
 	char number[64];
 	int flags;
+	int redirecting;
 	int sawflag;
 	int len;
 
@@ -185,17 +186,26 @@ struct callerid_state *callerid_new(int cid_signalling)
 	return cid;
 }
 
-void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
+void callerid_get_with_redirecting(struct callerid_state *cid, char **name, char **number, int *flags, int *redirecting)
 {
 	*flags = cid->flags;
-	if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NAME))
+	if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NAME)) {
 		*name = NULL;
-	else
+	} else {
 		*name = cid->name;
-	if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER))
+	}
+	if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER)) {
 		*number = NULL;
-	else
+	} else {
 		*number = cid->number;
+	}
+	*redirecting = cid->redirecting;
+}
+
+void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
+{
+	int redirecting;
+	return callerid_get_with_redirecting(cid, name, number, flags, &redirecting);
 }
 
 void callerid_get_dtmf(char *cidstring, char *number, int *flags)
@@ -541,6 +551,21 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, s
 	return 0;
 }
 
+static const char *mdmf_param_name(int param)
+{
+	switch (param) {
+	case 0x1: return "Date/Time";
+	case 0x2: return "Caller Number";
+	case 0x3: return "DNIS";
+	case 0x4: return "Reason For Absence of Number";
+	case 0x5: return "Reason For Redirection";
+	case 0x6: return "Call Qualifier";
+	case 0x7: return "Name";
+	case 0x8: return "Reason For Absence of Name";
+	case 0xB: return "Message Waiting";
+	default: return "Unknown";
+	}
+}
 
 int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, struct ast_format *codec)
 {
@@ -631,18 +656,41 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
 				cid->name[0] = '\0';
 				/* Update flags */
 				cid->flags = 0;
+				cid->redirecting = 0;
 				/* If we get this far we're fine.  */
 				if ((cid->type == 0x80) || (cid->type == 0x82)) {
 					/* MDMF */
+					ast_debug(6, "%s Caller*ID spill received\n", cid->type == 0x80 ? "MDMF" : "MDMF Message Waiting");
 					/* Go through each element and process */
 					for (x = 0; x < cid->pos;) {
-						switch (cid->rawdata[x++]) {
+						int param = cid->rawdata[x++];
+						ast_debug(7, "Caller*ID parameter %d (%s), length %d\n", param, mdmf_param_name(param), cid->rawdata[x]);
+						switch (param) {
 						case 1:
-							/* Date */
+							/* Date/Time... in theory we could synchronize our time according to the Caller*ID,
+							 * but it would be silly for a telephone switch to do that. */
 							break;
+						/* For MDMF spills, we would expect to get an "O" or a "P"
+						 * for paramter 4 (or 8) as opposed to 2 (or 7) to indicate
+						 * a blocked or out of area presentation.
+						 * However, for SDMF, which doesn't have parameters,
+						 * there is no differentiation, which is why the logic below
+						 * just checks the number and name field and here, we use the same
+						 * parsing logic for both parameters. Technically, it would be wrong
+						 * to receive an 'O' or 'P' for parameters 2 or 7 and treat it as
+						 * the reason for absence fields, but that is not likely to happen,
+						 * and if it did, could possibly be buggy Caller ID generation we would
+						 * want to treat the same way, anyways.
+						 *
+						 * The "Dialable Directory Number" is how the number would be called back.
+						 * Asterisk doesn't really have a corresponding thing for this,
+						 * so log it if we get it for debugging, but treat the same otherwise.
+						 */
+						case 3: /* Dialable Directory Number / Number (for Zebble) */
+							ast_debug(3, "Caller*ID Dialable Directory Number: '%.*s'\n", cid->rawdata[x], cid->rawdata + x + 1);
+							/* Fall through */
 						case 2: /* Number */
-						case 3: /* Number (for Zebble) */
-						case 4: /* Number */
+						case 4: /* Reason for Absence of Number. */
 							res = cid->rawdata[x];
 							if (res > 32) {
 								ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]);
@@ -654,10 +702,43 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
 								cid->number[res] = '\0';
 							}
 							break;
+						case 5: /* Reason for Redirection */
+							res = cid->rawdata[x];
+							if (res != 1) {
+								ast_log(LOG_WARNING, "Redirecting parameter length is %d?\n", res);
+								break;
+							}
+							switch (*(cid->rawdata + x + 1)) {
+							case 0x1:
+								cid->redirecting = AST_REDIRECTING_REASON_USER_BUSY;
+								break;
+							case 0x2:
+								cid->redirecting = AST_REDIRECTING_REASON_NO_ANSWER;
+								break;
+							case 0x3:
+								cid->redirecting = AST_REDIRECTING_REASON_UNCONDITIONAL;
+								break;
+							case 0x4:
+								cid->redirecting = AST_REDIRECTING_REASON_CALL_FWD_DTE;
+								break;
+							case 0x5:
+								cid->redirecting = AST_REDIRECTING_REASON_DEFLECTION;
+								break;
+							default:
+								ast_log(LOG_WARNING, "Redirecting reason is %02x?\n", *(cid->rawdata + x + 1));
+								break;
+							}
+							break;
 						case 6: /* Stentor Call Qualifier (ie. Long Distance call) */
+							res = cid->rawdata[x];
+							if (res == 1 && *(cid->rawdata + x + 1) == 'L') {
+								cid->flags |= CID_QUALIFIER;
+							} else if (res >= 1) {
+								ast_debug(2, "Invalid value (len %d) received for Call Qualifier: '%c'\n", res, *(cid->rawdata + x + 1));
+							}
 							break;
 						case 7: /* Name */
-						case 8: /* Name */
+						case 8: /* Reason for Absence of Name */
 							res = cid->rawdata[x];
 							if (res > 32) {
 								ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]);
@@ -692,6 +773,7 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
 					}
 				} else if (cid->type == 0x6) {
 					/* VMWI SDMF */
+					ast_debug(6, "VMWI SDMF Caller*ID spill received\n");
 					if (cid->rawdata[2] == 0x42) {
 						cid->flags |= CID_MSGWAITING;
 					} else if (cid->rawdata[2] == 0x6f) {
@@ -699,21 +781,38 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
 					}
 				} else {
 					/* SDMF */
+					ast_debug(6, "SDMF Caller*ID spill received\n");
 					ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number));
 				}
 				if (!strcmp(cid->number, "P")) {
+					ast_debug(6, "Caller*ID number is private\n");
 					strcpy(cid->number, "");
 					cid->flags |= CID_PRIVATE_NUMBER;
-				} else if (!strcmp(cid->number, "O") || ast_strlen_zero(cid->number)) {
+				} else if (!strcmp(cid->number, "O")) {
+					ast_debug(6, "Caller*ID number is out of area\n");
 					strcpy(cid->number, "");
 					cid->flags |= CID_UNKNOWN_NUMBER;
+				} else if (ast_strlen_zero(cid->number)) {
+					ast_debug(6, "No Caller*ID number provided, and no reason provided for its absence\n");
+					strcpy(cid->number, "");
+					cid->flags |= CID_UNKNOWN_NUMBER;
+				} else {
+					ast_debug(6, "Caller*ID number is '%s'\n", cid->number);
 				}
 				if (!strcmp(cid->name, "P")) {
+					ast_debug(6, "Caller*ID name is private\n");
 					strcpy(cid->name, "");
 					cid->flags |= CID_PRIVATE_NAME;
-				} else if (!strcmp(cid->name, "O") || ast_strlen_zero(cid->name)) {
+				} else if (!strcmp(cid->name, "O")) {
+					ast_debug(6, "Caller*ID name is out of area\n");
 					strcpy(cid->name, "");
 					cid->flags |= CID_UNKNOWN_NAME;
+				} else if (ast_strlen_zero(cid->name)) {
+					ast_debug(6, "No Caller*ID name provided, and no reason provided for its absence\n");
+					strcpy(cid->name, "");
+					cid->flags |= CID_UNKNOWN_NAME;
+				} else {
+					ast_debug(6, "Caller*ID name is '%s'\n", cid->name);
 				}
 				return 1;
 				break;