diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 55a00905042f46ecceac8f0881a73a766c1c705d..5adb797a5aae2fdff433e746cf5e664dbc5b1bc9 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -1642,19 +1642,29 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle
 	}
 
 	if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
+		int pres = ast_party_id_presentation(&caller->id);
 		if (cwcid == 0) {
-			p->cidlen = ast_callerid_generate(p->cidspill,
+			p->cidlen = ast_callerid_full_generate(p->cidspill,
 				caller->id.name.str,
 				caller->id.number.str,
+				NULL,
+				-1,
+				pres,
+				0,
+				CID_TYPE_MDMF,
 				AST_LAW(p));
 		} else {
 			ast_verb(3, "CPE supports Call Waiting Caller*ID.  Sending '%s/%s'\n",
 				caller->id.name.str, caller->id.number.str);
 			p->callwaitcas = 0;
 			p->cidcwexpire = 0;
-			p->cidlen = ast_callerid_callwaiting_generate(p->cidspill,
+			p->cidlen = ast_callerid_callwaiting_full_generate(p->cidspill,
 				caller->id.name.str,
 				caller->id.number.str,
+				NULL,
+				-1,
+				pres,
+				0,
 				AST_LAW(p));
 			p->cidlen += READ_SIZE * 4;
 		}
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index bd16d3561475b78644e7f7c7c6fb3d7cd3d7da60..76ee645c26f03bbf56d6a61a0d6b508cff4a595b 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -1089,6 +1089,10 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest
 		if (p->use_callerid) {
 			p->caller.id.name.str = p->lastcid_name;
 			p->caller.id.number.str = p->lastcid_num;
+			p->caller.id.name.valid = ast_channel_connected(ast)->id.name.valid;
+			p->caller.id.number.valid = ast_channel_connected(ast)->id.number.valid;
+			p->caller.id.name.presentation = ast_channel_connected(ast)->id.name.presentation;
+			p->caller.id.number.presentation = ast_channel_connected(ast)->id.number.presentation;
 		}
 
 		ast_setstate(ast, AST_STATE_RINGING);
@@ -2264,10 +2268,8 @@ static void *__analog_ss_thread(void *data)
 				ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
 				/* Disable Caller*ID if enabled */
 				p->hidecallerid = 1;
-				ast_party_number_free(&ast_channel_caller(chan)->id.number);
-				ast_party_number_init(&ast_channel_caller(chan)->id.number);
-				ast_party_name_free(&ast_channel_caller(chan)->id.name);
-				ast_party_name_init(&ast_channel_caller(chan)->id.name);
+				ast_channel_caller(chan)->id.number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+				ast_channel_caller(chan)->id.name.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
 				res = analog_play_tone(p, idx, ANALOG_TONE_DIALRECALL);
 				if (res) {
 					ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
@@ -2353,7 +2355,8 @@ static void *__analog_ss_thread(void *data)
 				ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
 				/* Enable Caller*ID if enabled */
 				p->hidecallerid = 0;
-				ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
+				ast_channel_caller(chan)->id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+				ast_channel_caller(chan)->id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
 				res = analog_play_tone(p, idx, ANALOG_TONE_DIALRECALL);
 				if (res) {
 					ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h
index 460f105c18fb010cc56c7d99db7aff8980783a6e..16a3df11f49ce00cba3efb44c400435526f65185 100644
--- a/include/asterisk/callerid.h
+++ b/include/asterisk/callerid.h
@@ -55,6 +55,7 @@
 #define CID_UNKNOWN_NUMBER		(1 << 3)
 #define CID_MSGWAITING			(1 << 4)
 #define CID_NOMSGWAITING		(1 << 5)
+#define CID_QUALIFIER			(1 << 6)
 
 #define CID_SIG_BELL	1
 #define CID_SIG_V23	2
@@ -67,6 +68,12 @@
 #define CID_START_POLARITY_IN 	3
 #define CID_START_DTMF_NOALERT	4
 
+/* Caller ID message formats */
+/*! SDMF - number only */
+#define CID_TYPE_SDMF			0x00
+/*! MDMF - name, number, etc. */
+#define CID_TYPE_MDMF			0x01
+
 /* defines dealing with message waiting indication generation */
 /*! MWI SDMF format */
 #define CID_MWI_TYPE_SDMF		0x00
@@ -101,7 +108,26 @@ void callerid_init(void);
  * \return It returns the size
  * (in bytes) of the data (if it returns a size of 0, there is probably an error)
  */
-int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, struct ast_format *codec);
+int callerid_generate(unsigned char *buf, const char *number, const char *name,	int flags, int callwaiting, struct ast_format *codec);
+
+/*! \brief Generates a CallerID FSK stream in ulaw format suitable for transmission.
+ * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own.
+ *   "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
+ * \param number Use NULL for no number or "P" for "private"
+ * \param name name to be used
+ * \param ddn Dialable Directory Number (or NULL)
+ * \param redirecting Redirecting reason
+ * \param flags passed flags
+ * \param format Message format
+ * \param callwaiting callwaiting flag
+ * \param codec -- either AST_FORMAT_ULAW or AST_FORMAT_ALAW
+ * \details
+ * This function creates a stream of callerid (a callerid spill) data in ulaw format.
+ * \return It returns the size
+ * (in bytes) of the data (if it returns a size of 0, there is probably an error)
+ */
+int callerid_full_generate(unsigned char *buf, const char *number, const char *name, const char *ddn, int redirecting,
+	int flags, int format, int callwaiting, struct ast_format *codec);
 
 /*! \brief Create a callerID state machine
  * \param cid_signalling Type of signalling in use
@@ -177,6 +203,23 @@ void callerid_free(struct callerid_state *cid);
  */
 int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec);
 
+/*! \brief Generate Caller-ID spill from the "callerid" field of asterisk (in e-mail address like format)
+ * \param buf buffer for output samples. See callerid_generate() for details regarding buffer.
+ * \param name Caller-ID Name
+ * \param number Caller-ID Number
+ * \param ddn Dialable Directory Number (or NULL)
+ * \param redirecting Redirecting Reason (-1 if N/A)
+ * \param pres Presentation (0 for default)
+ * \param qualifier Call Qualifier (0 for no, 1 for yes)
+ * \param format Message Format
+ * \param codec Asterisk codec (either AST_FORMAT_ALAW or AST_FORMAT_ULAW)
+ *
+ * \details
+ * Like ast_callerid_generate but with additional parameters.
+ */
+int ast_callerid_full_generate(unsigned char *buf, const char *name, const char *number,
+	const char *ddn, int redirecting, int pres, int qualifier, int format, struct ast_format *codec);
+
 /*!
  * \brief Generate message waiting indicator
  * \param buf
@@ -198,6 +241,12 @@ int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct
  */
 int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec);
 
+/*! \brief Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
+ * \see ast_callerid_generate() for other details
+ */
+int ast_callerid_callwaiting_full_generate(unsigned char *buf, const char *name, const char *number,
+	const char *ddn, int redirecting, int pres, int qualifier, struct ast_format *codec);
+
 /*! \brief Destructively parse inbuf into name and location (or number)
  * \details
  * Parses callerid stream from inbuf and changes into useable form, outputted in name and location.
diff --git a/main/callerid.c b/main/callerid.c
index 4d6186b3bccd4c93cea95b2cf6bf5cb8e45f24e3..c6c29a002a649ed7757f8401eaa8bf08b7863a4f 100644
--- a/main/callerid.c
+++ b/main/callerid.c
@@ -736,7 +736,8 @@ void callerid_free(struct callerid_state *cid)
 	ast_free(cid);
 }
 
-static int callerid_genmsg(char *msg, int size, const char *number, const char *name, int flags)
+static int callerid_genmsg(char *msg, int size, const char *number, const char *name, int flags, int format,
+	const char *ddn, int redirecting)
 {
 	struct timeval now = ast_tvnow();
 	struct ast_tm tm;
@@ -754,6 +755,7 @@ static int callerid_genmsg(char *msg, int size, const char *number, const char *
 				tm.tm_mday, tm.tm_hour, tm.tm_min);
 	size -= res;
 	ptr += res;
+
 	if (ast_strlen_zero(number) || (flags & CID_UNKNOWN_NUMBER)) {
 		/* Indicate number not known */
 		res = snprintf(ptr, size, "\004\001O");
@@ -779,6 +781,11 @@ static int callerid_genmsg(char *msg, int size, const char *number, const char *
 		size -= i;
 	}
 
+	if (format == CID_TYPE_SDMF) { /* If Simple Data Message Format, we're done. */
+		/* (some older Caller ID units only support SDMF. If they get an MDMF spill, it's useless.) */
+		return (ptr - msg);
+	}
+
 	if (ast_strlen_zero(name) || (flags & CID_UNKNOWN_NAME)) {
 		/* Indicate name not known */
 		res = snprintf(ptr, size, "\010\001O");
@@ -803,8 +810,44 @@ static int callerid_genmsg(char *msg, int size, const char *number, const char *
 		ptr += i;
 		size -= i;
 	}
-	return (ptr - msg);
 
+	/* Call Qualifier */
+	if (flags & CID_QUALIFIER) {
+		res = snprintf(ptr, size, "\006\001L"); /* LDC (Long Distance Call) is the only valid option */
+		size -= res;
+		ptr += res;
+	}
+
+	/* DDN (Dialable Directory Number) - 11 digits MAX, parameter 003 */
+	/* some CPE seem to display the DDN instead of the CLID, if sent */
+
+	/* Redirecting Reason */
+	if (redirecting >= 0) {
+		res = 0;
+		switch (redirecting) {
+		case AST_REDIRECTING_REASON_USER_BUSY:
+			res = snprintf(ptr, size, "\005\001\001");
+			break;
+		case AST_REDIRECTING_REASON_NO_ANSWER:
+			res = snprintf(ptr, size, "\005\001\002");
+			break;
+		case AST_REDIRECTING_REASON_UNCONDITIONAL:
+			res = snprintf(ptr, size, "\005\001\003");
+			break;
+		case AST_REDIRECTING_REASON_CALL_FWD_DTE:
+			res = snprintf(ptr, size, "\005\001\004");
+			break;
+		case AST_REDIRECTING_REASON_DEFLECTION:
+			res = snprintf(ptr, size, "\005\001\005");
+			break;
+		default:
+			break;
+		}
+		ptr += res;
+		size -= res;
+	}
+
+	return (ptr - msg);
 }
 
 int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct ast_format *codec,
@@ -824,7 +867,7 @@ int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct
 		msg[0] = 0x82;
 
 		/* put date, number info at the right place */
-		len = callerid_genmsg(msg+2, sizeof(msg)-2, number, name, flags);
+		len = callerid_genmsg(msg+2, sizeof(msg)-2, number, name, flags, CID_TYPE_MDMF, "", -1);
 
 		/* length of MDMF CLI plus Message Waiting Structure */
 		msg[1] = len+3;
@@ -896,6 +939,12 @@ int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct
 }
 
 int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, struct ast_format *codec)
+{
+	return callerid_full_generate(buf, number, name, NULL, -1, flags, CID_TYPE_MDMF, callwaiting, codec);
+}
+
+int callerid_full_generate(unsigned char *buf, const char *number, const char *name, const char *ddn, int redirecting,
+	int flags, int format, int callwaiting, struct ast_format *codec)
 {
 	int bytes = 0;
 	int x, sum;
@@ -906,7 +955,7 @@ int callerid_generate(unsigned char *buf, const char *number, const char *name,
 	float ci = 0.0;
 	float scont = 0.0;
 	char msg[256];
-	len = callerid_genmsg(msg, sizeof(msg), number, name, flags);
+	len = callerid_genmsg(msg, sizeof(msg), number, name, flags, format, ddn, redirecting);
 	if (!callwaiting) {
 		/* Wait a half a second */
 		for (x = 0; x < 4000; x++)
@@ -1051,23 +1100,56 @@ int ast_callerid_parse(char *input_str, char **name, char **location)
 	return 0;
 }
 
-static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, struct ast_format *codec)
+static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number,
+	const char *ddn, int redirecting, int pres, int qualifier, int format, int callwaiting, struct ast_format *codec)
 {
+	int flags = 0;
+
+	ast_debug(1, "Caller ID Type %s: Number: %s, Name: %s, Redirecting No: %s, Redirecting Reason: %s, Pres: %s, Qualifier: %s, Format: %s\n",
+		callwaiting ? "II" : "I", number, name, ddn, ast_redirecting_reason_describe(redirecting),
+		ast_named_caller_presentation(pres), qualifier ? "LDC" : "None", format == CID_TYPE_MDMF ? "MDMF" : "SDMF");
+
 	if (ast_strlen_zero(name))
 		name = NULL;
 	if (ast_strlen_zero(number))
 		number = NULL;
-	return callerid_generate(buf, number, name, 0, callwaiting, codec);
+
+	if (pres & AST_PRES_RESTRICTED) {
+		flags |= CID_PRIVATE_NUMBER;
+		flags |= CID_PRIVATE_NAME;
+	} else if (pres & AST_PRES_UNAVAILABLE) {
+		flags |= CID_UNKNOWN_NUMBER;
+		flags |= CID_UNKNOWN_NAME;
+	}
+
+	if (qualifier) {
+		flags |= CID_QUALIFIER;
+	}
+
+	return callerid_full_generate(buf, number, name, ddn, redirecting, flags, format, callwaiting, codec);
 }
 
 int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec)
 {
-	return __ast_callerid_generate(buf, name, number, 0, codec);
+	return __ast_callerid_generate(buf, name, number, "", -1, 0, 0, CID_TYPE_MDMF, 0, codec);
 }
 
 int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec)
 {
-	return __ast_callerid_generate(buf, name, number, 1, codec);
+	return __ast_callerid_generate(buf, name, number, "", -1, 0, 0, CID_TYPE_MDMF, 1, codec);
+}
+
+int ast_callerid_full_generate(unsigned char *buf, const char *name, const char *number,
+	const char *ddn, int redirecting, int pres, int qualifier, int format, struct ast_format *codec)
+{
+	return __ast_callerid_generate(buf, name, number, ddn, redirecting, pres, qualifier, format, 0, codec);
+}
+
+int ast_callerid_callwaiting_full_generate(unsigned char *buf, const char *name, const char *number,
+	const char *ddn, int redirecting, int pres, int qualifier, struct ast_format *codec)
+{
+	/* Type II Caller ID (CWCID) only uses MDMF, so format isn't an argument */
+	return __ast_callerid_generate(buf, name, number, ddn, redirecting, pres, qualifier, CID_TYPE_MDMF, 1, codec);
 }
 
 char *ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)