diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 7e545d098043e7db6439528a2e7385e2e6197b26..c1e8628d508158e59d36d26a96d34c053a59bc69 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -63,6 +63,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <dahdi/user.h>
 #include <dahdi/tonezone.h>
 #include "sig_analog.h"
+/* Analog signaling is currently still present in chan_dahdi for use with
+ * radio. Sig_analog does not currently handle any radio operations. If
+ * radio only uses analog signaling, then the radio handling logic could
+ * be placed in sig_analog and the duplicated code could be removed.
+ */
 
 #ifdef HAVE_PRI
 #include "sig_pri.h"
@@ -364,6 +369,37 @@ static const char config[] = "chan_dahdi.conf";
 #define CALLPROGRESS_FAX_INCOMING	4
 #define CALLPROGRESS_FAX		(CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
 
+#define NUM_CADENCE_MAX 25
+static int num_cadence = 4;
+static int user_has_defined_cadences = 0;
+
+static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
+	{ { 125, 125, 2000, 4000 } },			/*!< Quick chirp followed by normal ring */
+	{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
+	{ { 125, 125, 125, 125, 125, 4000 } },	/*!< Three short bursts */
+	{ { 1000, 500, 2500, 5000 } },	/*!< Long ring */
+};
+
+/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
+ * is 1, the second pause is 2 and so on.
+ */
+
+static int cidrings[NUM_CADENCE_MAX] = {
+	2,										/*!< Right after first long ring */
+	4,										/*!< Right after long part */
+	3,										/*!< After third chirp */
+	2,										/*!< Second spell */
+};
+
+/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
+static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
+
+#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
+			(p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
+
+#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
+#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
+
 static char defaultcic[64] = "";
 static char defaultozz[64] = "";
 
@@ -1153,19 +1189,12 @@ static struct dahdi_pvt {
 	struct ast_event_sub *mwi_event_sub;
 	/*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
 	char dialdest[256];
-	/*! \brief Time the interface went on-hook. */
-	int onhooktime;
-	/*! \brief TRUE if the FXS port is off-hook */
-	int fxsoffhookstate;
-	/*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
-	int msgstate;
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
 	struct dahdi_vmwi_info mwisend_setting;				/*!< Which VMWI methods to use */
 	unsigned int mwisend_fsk: 1;		/*! Variable for enabling FSK MWI handling in chan_dahdi */
 	unsigned int mwisend_rpas:1;		/*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
 #endif
 	int distinctivering;				/*!< Which distinctivering to use */
-	int cidrings;					/*!< Which ring to deliver CID on */
 	int dtmfrelax;					/*!< whether to run in relaxed DTMF mode */
 	/*! \brief Holding place for event injected from outside normal operation. */
 	int fake_event;
@@ -1177,7 +1206,7 @@ static struct dahdi_pvt {
 	/*! \brief Start delay time if polarityonanswerdelay is nonzero. */
 	struct timeval polaritydelaytv;
 	/*!
-	 * \brief Send caller ID after this many rings.
+	 * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
 	 * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
 	 */
 	int sendcalleridafter;
@@ -1557,6 +1586,7 @@ static int my_stop_cid_detect(void *pvt)
 static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
 {
 	struct dahdi_pvt *p = pvt;
+	struct analog_pvt *analog_p = p->sig_pvt;
 	struct pollfd poller;
 	char *name, *num;
 	int index = SUB_REAL;
@@ -1578,9 +1608,9 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 	if (poller.revents & POLLIN) {
 		/*** NOTES ***/
 		/* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
-		 * to enable slin mode and allocate cid detector.  get_callerid should be able to be called any number of times until
-		 * either a timeout occurss or CID is detected (returns 0).  returning 1 should be event received, and -1 should be fail
-		 * and die */
+		 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
+		 * either a timeout occurss or CID is detected (returns 0). returning 1 should be event received, and -1 should be
+		 * a failure and die, and returning 2 means no event was received. */
 		res = read(p->subs[index].dfd, buf, sizeof(buf));
 		if (res < 0) {
 			if (errno != ELAST) {
@@ -1589,7 +1619,20 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 				return -1;
 			}
 		}
-		res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+
+		if (analog_p->ringt) {
+			analog_p->ringt--;
+		}
+		if (analog_p->ringt == 1) {
+			return -1;
+		}
+
+		if (p->cid_signalling == CID_SIG_V23_JP) {
+			res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
+		} else {
+			res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+		}
+
 		if (res < 0) {
 			ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
 			return -1;
@@ -1608,7 +1651,128 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 	}
 
 	*ev = ANALOG_EVENT_NONE;
-	return 1;
+	return 2;
+}
+
+static const char *event2str(int event);
+static int restore_gains(struct dahdi_pvt *p);
+
+static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
+{
+	unsigned char buf[256];
+	int distMatches;
+	int curRingData[3];
+	int receivedRingT;
+	int counter1;
+	int counter;
+	int i;
+	int res;
+	int checkaftercid = 0;
+
+	struct dahdi_pvt *p = pvt;
+	struct analog_pvt *analog_p = p->sig_pvt;
+
+	if (ringdata == NULL) {
+		ringdata = curRingData;
+	} else {
+		checkaftercid = 1;
+	}
+
+	/* We must have a ring by now, so, if configured, lets try to listen for
+	 * distinctive ringing */
+	if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
+		/* Clear the current ring data array so we dont have old data in it. */
+		for (receivedRingT = 0; receivedRingT < ARRAY_LEN(ringdata); receivedRingT++)
+			ringdata[receivedRingT] = 0;
+		receivedRingT = 0;
+		if (checkaftercid && distinctiveringaftercid)
+			ast_verb(3, "Detecting post-CID distinctive ring\n");
+		/* Check to see if context is what it should be, if not set to be. */
+		else if (strcmp(p->context,p->defcontext) != 0) {
+			ast_copy_string(p->context, p->defcontext, sizeof(p->context));
+			ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
+		}
+
+		for (;;) {
+			i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
+			if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
+				ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
+				ast_hangup(chan);
+				return 1;
+			}
+			if (i & DAHDI_IOMUX_SIGEVENT) {
+				res = dahdi_get_event(p->subs[idx].dfd);
+				ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
+				res = 0;
+				/* Let us detect distinctive ring */
+
+				ringdata[receivedRingT] = analog_p->ringt;
+
+				if (analog_p->ringt < analog_p->ringt_base/2)
+					break;
+				/* Increment the ringT counter so we can match it against
+				   values in chan_dahdi.conf for distinctive ring */
+				if (++receivedRingT == ARRAY_LEN(ringdata))
+					break;
+			} else if (i & DAHDI_IOMUX_READ) {
+				res = read(p->subs[idx].dfd, buf, sizeof(buf));
+				if (res < 0) {
+					if (errno != ELAST) {
+						ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
+						ast_hangup(chan);
+						return 1;
+					}
+					break;
+				}
+				if (analog_p->ringt)
+					analog_p->ringt--;
+				if (analog_p->ringt == 1) {
+					res = -1;
+					break;
+				}
+			}
+		}
+	}
+	if ((checkaftercid && usedistinctiveringdetection) || !checkaftercid) {
+		/* this only shows up if you have n of the dring patterns filled in */
+		ast_verb(3, "Detected ring pattern: %d,%d,%d\n",ringdata[0],ringdata[1],ringdata[2]);
+		for (counter = 0; counter < 3; counter++) {
+		/* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
+			distMatches = 0;
+			/* this only shows up if you have n of the dring patterns filled in */
+			ast_verb(3, "Checking %d,%d,%d\n",
+					p->drings.ringnum[counter].ring[0],
+					p->drings.ringnum[counter].ring[1],
+					p->drings.ringnum[counter].ring[2]);
+			for (counter1 = 0; counter1 < 3; counter1++) {
+				ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
+				if (p->drings.ringnum[counter].ring[counter1] == -1) {
+					ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
+					ringdata[counter1]);
+					distMatches++;
+				} else if (ringdata[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
+										ringdata[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
+					ast_verb(3, "Ring pattern matched in range: %d to %d\n",
+					(p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
+					(p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
+					distMatches++;
+				}
+			}
+
+			if (distMatches == 3) {
+				/* The ring matches, set the context to whatever is for distinctive ring.. */
+				ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
+				ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
+				ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
+				break;
+			}
+		}
+	}
+	/* Restore linear mode (if appropriate) for Caller*ID processing */
+	dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
+	restore_gains(p);
+
+	return 0;
 }
 
 static int send_callerid(struct dahdi_pvt *p);
@@ -1656,7 +1820,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_callerid *cid)
 {
 	struct dahdi_pvt *p = pvt;
 
-	ast_log(LOG_ERROR, "Starting cid spill\n");
+	ast_debug(2, "Starting cid spill\n");
 
 	if (p->cidspill) {
 		ast_log(LOG_WARNING, "cidspill already exists??\n");
@@ -1809,17 +1973,66 @@ static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub
 static void my_lock_private(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
-
 	ast_mutex_lock(&p->lock);
 }
 
 static void my_unlock_private(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
-
 	ast_mutex_unlock(&p->lock);
 }
 
+static int my_set_linear_mode(void *pvt, int idx, int linear_mode)
+{
+	struct dahdi_pvt *p = pvt;
+	if (!linear_mode)
+		linear_mode = p->subs[idx].linear;
+	return dahdi_setlinear(p->subs[idx].dfd, linear_mode);
+}
+
+static int get_alarms(struct dahdi_pvt *p);
+static void handle_alarms(struct dahdi_pvt *p, int alms);
+static void my_get_and_handle_alarms(void *pvt)
+{
+	int res;
+	struct dahdi_pvt *p = pvt;
+	
+	res = get_alarms(p);
+	handle_alarms(p, res);
+}
+
+static void *my_get_sigpvt_bridged_channel(struct ast_channel *chan)
+{
+	struct dahdi_pvt *p = ast_bridged_channel(chan)->tech_pvt;
+	if (p)
+		return p->sig_pvt;
+	else
+		return NULL;
+}
+
+static int my_get_sub_fd(void *pvt, enum analog_sub sub)
+{
+	struct dahdi_pvt *p = pvt;
+	int dahdi_sub = analogsub_to_dahdisub(sub);
+	return p->subs[dahdi_sub].dfd;
+}
+
+static void my_set_cadence(void *pvt, int *cidrings, struct ast_channel *ast)
+{
+	struct dahdi_pvt *p = pvt;
+
+	/* Choose proper cadence */
+	if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
+		if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
+			ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
+		*cidrings = cidrings[p->distinctivering - 1];
+	} else {
+		if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
+			ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
+		*cidrings = p->sendcalleridafter;
+	}
+}
+
 static void my_increase_ss_count(void)
 {
 	ast_mutex_lock(&ss_thread_lock);
@@ -2189,6 +2402,13 @@ static int my_ring(void *pvt)
 	return dahdi_ring_phone(p);
 }
 
+static int my_flash(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	int func = DAHDI_FLASH;
+	return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &func);
+}
+
 static inline int dahdi_set_hook(int fd, int hs);
 
 static int my_off_hook(void *pvt)
@@ -2263,9 +2483,7 @@ static int my_is_dialing(void *pvt, enum analog_sub sub)
 static int my_on_hook(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
-	int x = DAHDI_ONHOOK;
-
-	return ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_HOOK, &x);
+	return dahdi_set_hook(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_ONHOOK);
 }
 
 #ifdef HAVE_PRI
@@ -2317,8 +2535,6 @@ static int sig_pri_tone_to_dahditone(enum analog_tone tone)
 	}
 }
 
-static const char *event2str(int event);
-
 static void my_handle_dchan_exception(struct sig_pri_pri *pri, int index)
 {
 	int x, res;
@@ -2433,6 +2649,7 @@ static struct analog_callback dahdi_analog_callbacks =
 	.is_off_hook = my_is_off_hook,
 	.set_echocanceller = my_set_echocanceller,
 	.ring = my_ring,
+	.flash = my_flash,
 	.off_hook = my_off_hook,
 	.dial_digits = my_dial_digits,
 	.train_echocanceller = my_train_echocanceller,
@@ -2464,6 +2681,12 @@ static struct analog_callback dahdi_analog_callbacks =
 	.handle_notify_message = my_handle_notify_message,
 	.increase_ss_count = my_increase_ss_count,
 	.decrease_ss_count = my_decrease_ss_count,
+	.distinctive_ring = my_distinctive_ring,
+	.set_linear_mode = my_set_linear_mode,
+	.get_and_handle_alarms = my_get_and_handle_alarms,
+	.get_sigpvt_bridged_channel = my_get_sigpvt_bridged_channel,
+	.get_sub_fd = my_get_sub_fd,
+	.set_cadence = my_set_cadence,
 };
 
 static struct dahdi_pvt *round_robin[32];
@@ -2492,36 +2715,6 @@ static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
 	return 0;
 }
 #endif	/* defined(HAVE_SS7) */
-#define NUM_CADENCE_MAX 25
-static int num_cadence = 4;
-static int user_has_defined_cadences = 0;
-
-static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
-	{ { 125, 125, 2000, 4000 } },			/*!< Quick chirp followed by normal ring */
-	{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
-	{ { 125, 125, 125, 125, 125, 4000 } },	/*!< Three short bursts */
-	{ { 1000, 500, 2500, 5000 } },	/*!< Long ring */
-};
-
-/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
- * is 1, the second pause is 2 and so on.
- */
-
-static int cidrings[NUM_CADENCE_MAX] = {
-	2,										/*!< Right after first long ring */
-	4,										/*!< Right after long part */
-	3,										/*!< After third chirp */
-	2,										/*!< Second spell */
-};
-
-/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
-static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
-
-#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
-			(p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
-
-#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
-#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
 
 static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
 {
@@ -2673,8 +2866,6 @@ static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
 	ast_log(LOG_NOTICE, "New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
 }
 
-static int get_alarms(struct dahdi_pvt *p);
-static void handle_alarms(struct dahdi_pvt *p, int alms);
 static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
 {
 	int res;
@@ -3051,8 +3242,6 @@ static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
 
 #endif /* HAVE_OPENR2 */
 
-static int restore_gains(struct dahdi_pvt *p);
-
 static void swap_subs(struct dahdi_pvt *p, int a, int b)
 {
 	int tchan;
@@ -4111,29 +4300,6 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
 	}
 #endif
 
-	/* Set the ring cadence */
-	mysig = p->sig;
-	if (p->outsigmod > -1)
-		mysig = p->outsigmod;
-	switch (mysig) {
-	case SIG_FXOLS:
-	case SIG_FXOGS:
-	case SIG_FXOKS:
-		if (p->owner == ast) {
-			/* Choose proper cadence */
-			if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
-				if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
-					ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
-				p->cidrings = cidrings[p->distinctivering - 1];
-			} else {
-				if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
-					ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
-				p->cidrings = p->sendcalleridafter;
-			}
-		}
-		break;
-	}
-
 	/* If this is analog signalling we can exit here */
 	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		p->callwaitrings = 0;
@@ -4142,6 +4308,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
 		return res;
 	}
 
+	mysig = p->outsigmod > -1 ? p->outsigmod : p->sig;
 	switch (mysig) {
 	case 0:
 		/* Special pseudo -- automatically up*/
@@ -4877,12 +5044,10 @@ static int dahdi_hangup(struct ast_channel *ast)
 		p->ringt = 0;
 		p->distinctivering = 0;
 		p->confirmanswer = 0;
-		p->cidrings = 1;
 		p->outgoing = 0;
 		p->digital = 0;
 		p->faxhandled = 0;
 		p->pulsedial = 0;
-		p->onhooktime = time(NULL);
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
 		p->proceeding = 0;
 		p->dialing = 0;
@@ -4970,6 +5135,7 @@ static int dahdi_hangup(struct ast_channel *ast)
 			memset(&par, 0, sizeof(par));
 			res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
 			if (!res) {
+				struct analog_pvt *analog_p = p->sig_pvt;
 #if 0
 				ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
 #endif
@@ -4978,14 +5144,14 @@ static int dahdi_hangup(struct ast_channel *ast)
 					tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
 				else
 					tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-				p->fxsoffhookstate = par.rxisoffhook;
+				analog_p->fxsoffhookstate = par.rxisoffhook;
 			}
 			break;
 		case SIG_FXSGS:
 		case SIG_FXSLS:
 		case SIG_FXSKS:
 			/* Make sure we're not made available for at least two seconds assuming
-			   we were actually used for an inbound or outbound call. */
+			we were actually used for an inbound or outbound call. */
 			if (ast->_state != AST_STATE_RESERVED) {
 				time(&p->guardtime);
 				p->guardtime += 2;
@@ -6371,9 +6537,6 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 		case SIG_FXOLS:
 		case SIG_FXOGS:
 		case SIG_FXOKS:
-			p->onhooktime = time(NULL);
-			p->fxsoffhookstate = 0;
-			p->msgstate = -1;
 			/* Check for some special conditions regarding call waiting */
 			if (idx == SUB_REAL) {
 				/* The normal line was hung up */
@@ -6524,7 +6687,6 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 		case SIG_FXOLS:
 		case SIG_FXOGS:
 		case SIG_FXOKS:
-			p->fxsoffhookstate = 1;
 			switch (ast->_state) {
 			case AST_STATE_RINGING:
 				dahdi_enable_ec(p);
@@ -7324,7 +7486,12 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 				ast_mutex_unlock(&p->lock);
 				return &p->subs[idx].f;
 			} else if (errno == ELAST) {
-				f = __dahdi_exception(ast);
+				if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+					struct analog_pvt *analog_p = p->sig_pvt;
+					f = analog_exception(analog_p, ast);
+				} else {
+					f = __dahdi_exception(ast);
+				}
 			} else
 				ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
 		}
@@ -7333,7 +7500,12 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 	}
 	if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
 		ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-		f = __dahdi_exception(ast);
+		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+			struct analog_pvt *analog_p = p->sig_pvt;
+			f = analog_exception(analog_p, ast);
+		} else {
+			f = __dahdi_exception(ast);
+		}
 		ast_mutex_unlock(&p->lock);
 		return f;
 	}
@@ -7555,8 +7727,10 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
 	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		struct analog_pvt *ap = p->sig_pvt;
 
-		if (ap->dialing)
+		if (ap->dialing) {
+			ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
 			return 0;
+		}
 	}
 	if (p->dialing) {
 		ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
@@ -8934,8 +9108,9 @@ static void *analog_ss_thread(void *data)
 								}
 								break;
 							}
-							if (p->ringt)
+							if (p->ringt) {
 								p->ringt--;
+							}
 							if (p->ringt == 1) {
 								res = -1;
 								break;
@@ -9488,7 +9663,6 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
 		case SIG_FXOGS:
 		case SIG_FXOKS:
 			res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
-			i->fxsoffhookstate = 1;
 			if (res && (errno == EBUSY))
 				break;
 			if (i->cidspill) {
@@ -9636,9 +9810,6 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
 			res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
 			return -1;
 		}
-		if (i->sig & __DAHDI_SIG_FXO) {
-			i->fxsoffhookstate = 0;
-		}
 		break;
 	case DAHDI_EVENT_POLARITY:
 		switch (i->sig) {
@@ -9801,12 +9972,13 @@ static void *do_monitor(void *data)
 				if (!found && ((i == last) || ((i == iflist) && !last))) {
 					last = i;
 					if (last) {
+						struct analog_pvt *analog_p = last->sig_pvt;
 						/* Only allow MWI to be initiated on a quiescent fxs port */
 						if (!last->mwisendactive &&	last->sig & __DAHDI_SIG_FXO &&
-								!last->fxsoffhookstate && !last->owner &&
-								!ast_strlen_zero(last->mailbox) && (thispass - last->onhooktime > 3)) {
+								!analog_p->fxsoffhookstate && !last->owner &&
+								!ast_strlen_zero(last->mailbox) && (thispass - analog_p->onhooktime > 3)) {
 							res = has_voicemail(last);
-							if (last->msgstate != res) {
+							if (analog_p->msgstate != res) {
 								/* Set driver resources for signalling VMWI */
 								res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
 								if (res2) {
@@ -9817,7 +9989,7 @@ static void *do_monitor(void *data)
 								if (mwi_send_init(last)) {
 									ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
 								}
-								last->msgstate = res;
+								analog_p->msgstate = res;
 								found ++;
 							}
 						}
@@ -10746,23 +10918,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
 				AST_EVENT_IE_END);
 		}
-		tmp->msgstate = -1;
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
 		tmp->mwisend_setting = conf->chan.mwisend_setting;
 		tmp->mwisend_fsk  = conf->chan.mwisend_fsk;
 		tmp->mwisend_rpas = conf->chan.mwisend_rpas;
 #endif
-		if (chan_sig & __DAHDI_SIG_FXO) {
-			memset(&p, 0, sizeof(p));
-			res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
-			if (!res) {
-				tmp->fxsoffhookstate = p.rxisoffhook;
-			}
-#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
-			res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
-#endif
-		}
-		tmp->onhooktime = time(NULL);
+		
 		tmp->group = conf->chan.group;
 		tmp->callgroup = conf->chan.callgroup;
 		tmp->pickupgroup= conf->chan.pickupgroup;
@@ -10841,7 +11002,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
 				analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
 				analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
-				analog_p->sendcalleridafter = conf->chan.sendcalleridafter;
 				analog_p->permcallwaiting = 1;
 				analog_p->callreturn = conf->chan.callreturn;
 				analog_p->cancallforward = conf->chan.cancallforward;
@@ -10860,7 +11020,23 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				analog_p->stripmsd = conf->chan.stripmsd;
 				analog_p->cid_start = ANALOG_CID_START_RING;
 				tmp->callwaitingcallerid = analog_p->callwaitingcallerid = 1;
-	
+				analog_p->usedistinctiveringdetection = conf->chan.usedistinctiveringdetection;
+				analog_p->ringt = conf->chan.ringt;
+				analog_p->ringt_base = ringt_base;
+				analog_p->chan_tech = &dahdi_tech;
+				analog_p->onhooktime = time(NULL);
+				if (chan_sig & __DAHDI_SIG_FXO) {
+					memset(&p, 0, sizeof(p));
+					res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
+					if (!res) {
+						analog_p->fxsoffhookstate = p.rxisoffhook;
+					}
+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
+					res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
+#endif
+				}
+				analog_p->msgstate = -1;
+
 				ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
 				ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
 				ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index e397e5f4f9bb24c47e483a6d9fea945f3c249f08..e62eb0443f9f1005bf9a4a97c61254b642c0181b 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -38,6 +38,7 @@
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
 #include "asterisk/cel.h"
+#include "asterisk/causes.h"
 
 #include "sig_analog.h"
 
@@ -89,6 +90,9 @@ static const struct {
 	 * way to do this in the dialplan now. */
 };
 
+#define ISTRUNK(p) ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || \
+					(p->sig == ANALOG_SIG_FXSGS))
+
 enum analog_sigtype analog_str_to_sigtype(const char *name)
 {
 	int i;
@@ -397,6 +401,14 @@ static int analog_ring(struct analog_pvt *p)
 		return -1;
 }
 
+static int analog_flash(struct analog_pvt *p)
+{
+	if (p->calls->flash)
+		return p->calls->flash(p->chan_pvt);
+	else
+		return -1;
+}
+
 static int analog_start(struct analog_pvt *p)
 {
 	if (p->calls->start)
@@ -676,6 +688,13 @@ static int analog_callwait(struct analog_pvt *p)
 		return 0;
 }
 
+static void analog_set_cadence(struct analog_pvt *p, struct ast_channel *chan)
+{
+	if (p->calls->set_cadence) {
+		return p->calls->set_cadence(p->chan_pvt, &p->cidrings, chan);
+	}
+}
+
 int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int timeout)
 {
 	int res, index,mysig;
@@ -712,20 +731,7 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int
 
 			/* Don't send audio while on hook, until the call is answered */
 			p->dialing = 1;
-			/* XXX */
-#if 0
-			/* Choose proper cadence */
-			if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
-				if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
-					ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
-				p->cidrings = cidrings[p->distinctivering - 1];
-			} else {
-				if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
-					ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
-				p->cidrings = p->sendcalleridafter;
-			}
-#endif
-			p->cidrings = p->sendcalleridafter;
+			analog_set_cadence(p, ast); /* and set p->cidrings */
 
 			/* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
 			c = strchr(dest, '/');
@@ -1042,13 +1048,10 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
 
 	if (!p->subs[ANALOG_SUB_REAL].owner && !p->subs[ANALOG_SUB_CALLWAIT].owner && !p->subs[ANALOG_SUB_THREEWAY].owner) {
 		p->owner = NULL;
-#if 0
 		p->ringt = 0;
-#endif
-#if 0 /* Since we set it in _call */
-		p->cidrings = 1;
-#endif
 		p->outgoing = 0;
+		p->onhooktime = time(NULL);
+		p->cidrings = 1;
 
 		/* Perform low level hangup if no owner left */
 		res = analog_on_hook(p);
@@ -1115,9 +1118,7 @@ int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
 	case ANALOG_SIG_FXSLS:
 	case ANALOG_SIG_FXSGS:
 	case ANALOG_SIG_FXSKS:
-#if 0
 		p->ringt = 0;
-#endif
 		/* Fall through */
 	case ANALOG_SIG_EM:
 	case ANALOG_SIG_EM_E1:
@@ -1259,13 +1260,47 @@ static int analog_decrease_ss_count(struct analog_pvt *p)
 		return -1;
 }
 
+static int analog_distinctive_ring(struct ast_channel *chan, struct analog_pvt *p, int idx, int *ringdata)
+{
+	if (p->calls->distinctive_ring) {
+		return p->calls->distinctive_ring(chan, p->chan_pvt, idx, ringdata);
+	} else
+		return -1;
+
+}
+
+static int analog_set_linear_mode(struct analog_pvt *p, int index, int linear_mode)
+{
+	if (p->calls->set_linear_mode) {
+		return p->calls->set_linear_mode(p->chan_pvt, index, linear_mode);
+	} else
+		return -1;
+}
+
+static void analog_get_and_handle_alarms(struct analog_pvt *p)
+{
+	if (p->calls->get_and_handle_alarms)
+		return p->calls->get_and_handle_alarms(p->chan_pvt);
+}
+
+static void *analog_get_bridged_channel(struct analog_pvt *p, struct ast_channel *chan)
+{
+	if (p->calls->get_sigpvt_bridged_channel)
+		return p->calls->get_sigpvt_bridged_channel;
+	else
+		return NULL;
+}
+
+static int analog_get_sub_fd(struct analog_pvt *p, enum analog_sub sub)
+{
+	if (p->calls->get_sub_fd) {
+		return p->calls->get_sub_fd(p->chan_pvt, sub);
+	} else
+		return -1;
+}
+
 #define ANALOG_NEED_MFDETECT(p) (((p)->sig == ANALOG_SIG_FEATDMF) || ((p)->sig == ANALOG_SIG_FEATDMF_TA) || ((p)->sig == ANALOG_SIG_E911) || ((p)->sig == ANALOG_SIG_FGC_CAMA) || ((p)->sig == ANALOG_SIG_FGC_CAMAMF) || ((p)->sig == ANALOG_SIG_FEATB))
 
-/* Note by jpeeler: This function has a rather large section of code ifdefed
- * away. I'd like to leave the code there until more testing is done and I
- * know for sure that nothing got left out. The plan is at the latest for this
- * comment and code below to be removed shortly after the merging of sig_pri.
- */
 static void *__analog_ss_thread(void *data)
 {
 	struct analog_pvt *p = data;
@@ -1279,16 +1314,6 @@ static void *__analog_ss_thread(void *data)
 	struct callerid_state *cs = NULL;
 	char *name = NULL, *number = NULL;
 	int flags;
-#if 0
-	unsigned char buf[256];
-	int distMatches;
-	int curRingData[3];
-	int receivedRingT;
-	int samples = 0;
-	int counter1;
-	int counter;
-	int i;
-#endif
 	int timeout;
 	int getforward = 0;
 	char *s1, *s2;
@@ -1794,21 +1819,19 @@ static void *__analog_ss_thread(void *data)
 				memset(exten, 0, sizeof(exten));
 				timeout = analog_firstdigittimeout;
 			} else if (!strcmp(exten, "*0")) {
-#ifdef XXX
 				struct ast_channel *nbridge = p->subs[ANALOG_SUB_THREEWAY].owner;
-				struct dahdi_pvt *pbridge = NULL;
+				struct analog_pvt *pbridge = NULL;
 				  /* set up the private struct of the bridged one, if any */
 				if (nbridge && ast_bridged_channel(nbridge))
-					pbridge = ast_bridged_channel(nbridge)->tech_pvt;
+					pbridge = analog_get_bridged_channel(p, nbridge);
 				if (nbridge && pbridge &&
-				    (nbridge->tech == chan_tech) &&
-				    (ast_bridged_channel(nbridge)->tech == chan_tech) &&
+				    (nbridge->tech == p->chan_tech) &&
+				    (ast_bridged_channel(nbridge)->tech == p->chan_tech) &&
 				    ISTRUNK(pbridge)) {
-					int func = DAHDI_FLASH;
 					/* Clear out the dial buffer */
 					p->dop.dialstr[0] = '\0';
 					/* flash hookswitch */
-					if ((ioctl(pbridge->subs[ANALOG_SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
+					if ((analog_flash(p) == -1) && (errno != EINPROGRESS)) {
 						ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
 							nbridge->name, strerror(errno));
 					}
@@ -1829,7 +1852,6 @@ static void *__analog_ss_thread(void *data)
 					ast_hangup(chan);
 					goto quit;
 				}
-#endif
 			} else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
 							((exten[0] != '*') || (strlen(exten) > 2))) {
 				ast_debug(1, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
@@ -1855,9 +1877,9 @@ static void *__analog_ss_thread(void *data)
 				cs = NULL;
 				ast_debug(1, "Receiving DTMF cid on "
 					"channel %s\n", chan->name);
-#if 0
-				dahdi_setlinear(p->subs[index].dfd, 0);
-#endif
+
+				analog_set_linear_mode(p, index, 0);
+
 				res = 2000;
 				for (;;) {
 					struct ast_frame *f;
@@ -1868,8 +1890,7 @@ static void *__analog_ss_thread(void *data)
 						ast_hangup(chan);
 						goto quit;
 					}
-					f = ast_read(chan);
-					if (!f)
+					if (!(f = ast_read(chan)))
 						break;
 					if (f->frametype == AST_FRAME_DTMF) {
 						dtmfbuf[i++] = f->subclass;
@@ -1882,9 +1903,9 @@ static void *__analog_ss_thread(void *data)
 						break; /* Got ring */
 				}
 				dtmfbuf[i] = '\0';
-#if 0
-				dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#endif
+
+				analog_set_linear_mode(p, index, 1);
+
 				/* Got cid and ring. */
 				ast_debug(1, "CID got string '%s'\n", dtmfbuf);
 				callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
@@ -1895,82 +1916,51 @@ static void *__analog_ss_thread(void *data)
 					number = dtmfcid;
 				else
 					number = NULL;
-#if 0
+
 			/* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
 			} else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
-				cs = callerid_new(p->cid_signalling);
-				if (cs) {
-					samples = 0;
-#if 1
-					bump_gains(p);
-#endif				
-					/* Take out of linear mode for Caller*ID processing */
-					dahdi_setlinear(p->subs[index].dfd, 0);
-					
-					/* First we wait and listen for the Caller*ID */
-					for (;;) {	
-						i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
-						if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i)))	{
-							ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
-							callerid_free(cs);
-							ast_hangup(chan);
-							goto quit;
+				int timeout = 10000;  /* Ten seconds */
+				struct timeval start = ast_tvnow();
+				enum analog_event ev;
+
+				namebuf[0] = 0;
+				numbuf[0] = 0;
+
+				if (!analog_start_cid_detect(p, p->cid_signalling)) {
+					while (1) {
+						res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
+	
+						if (res == 0) {
+							break;
 						}
-						if (i & DAHDI_IOMUX_SIGEVENT) {
-							res = dahdi_get_event(p->subs[index].dfd);
-							ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
 
+						if (res == 1) {
 							if (p->cid_signalling == CID_SIG_V23_JP) {
-#ifdef DAHDI_EVENT_RINGBEGIN
-								if (res == ANALOG_EVENT_RINGBEGIN) {
-									res = analog_off_hook(p);
+								if (ev == ANALOG_EVENT_RINGBEGIN) {
+									analog_off_hook(p);
 									usleep(1);
-								}
-#endif
+								} 
 							} else {
-								res = 0;
+								ev = ANALOG_EVENT_NONE;
 								break;
 							}
-						} else if (i & DAHDI_IOMUX_READ) {
-							res = read(p->subs[index].dfd, buf, sizeof(buf));
-							if (res < 0) {
-								if (errno != ELAST) {
-									ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
-									callerid_free(cs);
-									ast_hangup(chan);
-									goto quit;
-								}
-								break;
-							}
-							samples += res;
-
-							if  (p->cid_signalling == CID_SIG_V23_JP) {
-								res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
-							} else {
-								res = callerid_feed(cs, buf, res, AST_LAW(p));
-							}
-
-							if (res < 0) {
-								ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
-								break;
-							} else if (res)
-								break;
-							else if (samples > (8000 * 10))
-								break;
 						}
+	
+						if (ast_tvdiff_ms(ast_tvnow(), start) > timeout)
+							break;
+	
 					}
-					if (res == 1) {
-						callerid_get(cs, &name, &number, &flags);
-						ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
-					}
+					name = namebuf;
+					number = numbuf;
+	
+					analog_stop_cid_detect(p);
 
 					if (p->cid_signalling == CID_SIG_V23_JP) {
 						res = analog_on_hook(p);
 						usleep(1);
 						res = 4000;
 					} else {
-
-						/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
+						/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
 						res = 2000;
 					}
 
@@ -1982,7 +1972,7 @@ static void *__analog_ss_thread(void *data)
 								"Exiting simple switch\n");
 							ast_hangup(chan);
 							goto quit;
-						} 
+						}
 						if (!(f = ast_read(chan))) {
 							ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
 							ast_hangup(chan);
@@ -1990,18 +1980,19 @@ static void *__analog_ss_thread(void *data)
 						}
 						ast_frfree(f);
 						if (chan->_state == AST_STATE_RING ||
-						    chan->_state == AST_STATE_RINGING) 
+							chan->_state == AST_STATE_RINGING)
 							break; /* Got ring */
 					}
+
+					if (analog_distinctive_ring(chan, p, index, NULL))
+						goto quit;
 	
-					/* Restore linear mode (if appropriate) for Caller*ID processing */
-					dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#if 1
-					restore_gains(p);
-#endif				
+					if (res < 0) {
+						ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
+					}
 				} else
-					ast_log(LOG_WARNING, "Unable to get caller ID space\n");			
-#endif
+					ast_log(LOG_WARNING, "Unable to get caller ID space\n");
+
 			} else {
 				ast_log(LOG_WARNING, "Channel %s in prering "
 					"state, but I have nothing to do. "
@@ -2015,6 +2006,8 @@ static void *__analog_ss_thread(void *data)
 			int timeout = 10000;  /* Ten seconds */
 			struct timeval start = ast_tvnow();
 			enum analog_event ev;
+			int curRingData[3] = { 0 };
+			int receivedRingT = 0;
 
 			namebuf[0] = 0;
 			numbuf[0] = 0;
@@ -2027,19 +2020,33 @@ static void *__analog_ss_thread(void *data)
 						break;
 					}
 
-					if (res == 1) {
+					if (res == 1 || res == 2) {
 						if (ev == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
 							ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
 							p->polarity = POLARITY_IDLE;
 							ast_hangup(chan);
 							goto quit;
-						} else if (ev != ANALOG_EVENT_NONE) {
+						} else if (ev != ANALOG_EVENT_NONE && ev != ANALOG_EVENT_RINGBEGIN && ev != ANALOG_EVENT_RINGOFFHOOK) { 
 							break;
 						}
+						if (res != 2) {
+							/* Let us detect callerid when the telco uses distinctive ring */
+							curRingData[receivedRingT] = p->ringt;
+
+							if (p->ringt < p->ringt_base/2) {
+								break;
+							}
+							/* Increment the ringT counter so we can match it against
+							   values in chan_dahdi.conf for distinctive ring */
+							if (++receivedRingT == ARRAY_LEN(curRingData)) {
+								break;
+							}
+						}
 					}
 
-					if (ast_tvdiff_ms(ast_tvnow(), start) > timeout)
+					if (ast_tvdiff_ms(ast_tvnow(), start) > timeout) {
 						break;
+					}
 
 				}
 				name = namebuf;
@@ -2047,108 +2054,14 @@ static void *__analog_ss_thread(void *data)
 
 				analog_stop_cid_detect(p);
 
-#if 0
-			/* XXX */
-			if (strcmp(p->context,p->defcontext) != 0) {
-				ast_copy_string(p->context, p->defcontext, sizeof(p->context));
-				ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
-			}
-
-			analog_get_callerid(p, name, number);
-			/* FSK Bell202 callerID */
-			cs = callerid_new(p->cid_signalling);
-			if (cs) {
-#if 1
-				bump_gains(p);
-#endif				
-				samples = 0;
-				len = 0;
-				distMatches = 0;
-				/* Clear the current ring data array so we dont have old data in it. */
-				for (receivedRingT = 0; receivedRingT < (sizeof(curRingData) / sizeof(curRingData[0])); receivedRingT++)
-					curRingData[receivedRingT] = 0;
-				receivedRingT = 0;
-				counter = 0;
-				counter1 = 0;
-				/* Check to see if context is what it should be, if not set to be. */
-
-				/* Take out of linear mode for Caller*ID processing */
-				dahdi_setlinear(p->subs[index].dfd, 0);
-				for (;;) {	
-					i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
-					if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i)))	{
-						ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
-						callerid_free(cs);
-						ast_hangup(chan);
-						goto quit;
-					}
-					if (i & DAHDI_IOMUX_SIGEVENT) {
-						res = dahdi_get_event(p->subs[index].dfd);
-						ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
-						/* If we get a PR event, they hung up while processing calerid */
-						if ( res == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
-							ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
-							p->polarity = POLARITY_IDLE;
-							callerid_free(cs);
-							ast_hangup(chan);
-							goto quit;
-						}
-						res = 0;
-						/* Let us detect callerid when the telco uses distinctive ring */
-
-						curRingData[receivedRingT] = p->ringt;
+				if (analog_distinctive_ring(chan, p, index, curRingData))
+					goto quit;
 
-						if (p->ringt < p->ringt_base/2)
-							break;
-						/* Increment the ringT counter so we can match it against
-						   values in chan_dahdi.conf for distinctive ring */
-						if (++receivedRingT == (sizeof(curRingData) / sizeof(curRingData[0])))
-							break;
-					} else if (i & DAHDI_IOMUX_READ) {
-						res = read(p->subs[index].dfd, buf, sizeof(buf));
-						if (res < 0) {
-							if (errno != ELAST) {
-								ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
-								callerid_free(cs);
-								ast_hangup(chan);
-								goto quit;
-							}
-							break;
-						}
-						if (p->ringt) 
-							p->ringt--;
-						if (p->ringt == 1) {
-							res = -1;
-							break;
-						}
-						samples += res;
-						res = callerid_feed(cs, buf, res, AST_LAW(p));
-						if (res < 0) {
-							ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
-							break;
-						} else if (res)
-							break;
-						else if (samples > (8000 * 10))
-							break;
-					}
-				}
-				if (res == 1) {
-					callerid_get(cs, &name, &number, &flags);
-					ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
-				}
-				/* Restore linear mode (if appropriate) for Caller*ID processing */
-				dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#if 1
-				restore_gains(p);
-#endif				
 				if (res < 0) {
 					ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
 				}
 			} else
 				ast_log(LOG_WARNING, "Unable to get caller ID space\n");
-#endif
-			} else
-				ast_log(LOG_WARNING, "Unable to get caller ID space\n");
 		}
 		else
 			cs = NULL;
@@ -2164,9 +2077,7 @@ static void *__analog_ss_thread(void *data)
 
 		ast_setstate(chan, AST_STATE_RING);
 		chan->rings = 1;
-#if 0
 		p->ringt = p->ringt_base;
-#endif
 		res = ast_pbx_run(chan);
 		if (res) {
 			ast_hangup(chan);
@@ -2287,15 +2198,16 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		break;
 	case ANALOG_EVENT_ALARM:
 		p->inalarm = 1;
-#if 0
-		res = get_alarms(p);
-		handle_alarms(p, res);	
-#endif
+		analog_get_and_handle_alarms(p);
+
 	case ANALOG_EVENT_ONHOOK:
 		switch (p->sig) {
 		case ANALOG_SIG_FXOLS:
 		case ANALOG_SIG_FXOGS:
 		case ANALOG_SIG_FXOKS:
+			p->fxsoffhookstate = 0;
+			p->onhooktime = time(NULL);
+			p->msgstate = -1;
 			/* Check for some special conditions regarding call waiting */
 			if (index == ANALOG_SUB_REAL) {
 				/* The normal line was hung up */
@@ -2337,7 +2249,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 						/* It hasn't been long enough since the last flashook.  This is probably a bounce on
 						   hanging up.  Hangup both channels now */
 						if (p->subs[ANALOG_SUB_THREEWAY].owner)
-							ast_queue_hangup(p->subs[ANALOG_SUB_THREEWAY].owner);
+							ast_queue_hangup_with_cause(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
 						ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
 						ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
 						ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
@@ -2427,6 +2339,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		case ANALOG_SIG_FXOLS:
 		case ANALOG_SIG_FXOGS:
 		case ANALOG_SIG_FXOKS:
+			p->fxsoffhookstate = 1;
 			switch (ast->_state) {
 			case AST_STATE_RINGING:
 				analog_set_echocanceller(p, 1);
@@ -2484,11 +2397,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		case ANALOG_SIG_FXSLS:
 		case ANALOG_SIG_FXSGS:
 		case ANALOG_SIG_FXSKS:
-#if 0
 			if (ast->_state == AST_STATE_RING) {
 				p->ringt = p->ringt_base;
 			}
-#endif
 
 			/* Fall through */
 		case ANALOG_SIG_EM:
@@ -2530,11 +2441,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		case ANALOG_SIG_FXSLS:
 		case ANALOG_SIG_FXSGS:
 		case ANALOG_SIG_FXSKS:
-#if 0
 			if (ast->_state == AST_STATE_RING) {
 				p->ringt = p->ringt_base;
 			}
-#endif
 			break;
 		}
 		break;
@@ -2572,10 +2481,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		case ANALOG_SIG_FXOLS:
 		case ANALOG_SIG_FXOGS:
 		case ANALOG_SIG_FXOKS:
-#if 0
 			ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
-				index, p->subs[ANALOG_SUB_REAL].dfd, p->subs[ANALOG_SUB_CALLWAIT].dfd, p->subs[ANALOG_SUB_THREEWAY].dfd);
-#endif
+				index, analog_get_sub_fd(p, ANALOG_SUB_REAL), analog_get_sub_fd(p, ANALOG_SUB_CALLWAIT), analog_get_sub_fd(p, ANALOG_SUB_THREEWAY));
+
 			p->callwaitcas = 0;
 
 			if (index != ANALOG_SUB_REAL) {
@@ -3045,6 +2953,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
 		case ANALOG_SIG_FXOGS:
 		case ANALOG_SIG_FXOKS:
 			res = analog_off_hook(i);
+			i->fxsoffhookstate = 1;
 			if (res && (errno == EBUSY))
 				break;
 			if (i->immediate) {
@@ -3083,9 +2992,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
 		case ANALOG_SIG_FXSLS:
 		case ANALOG_SIG_FXSGS:
 		case ANALOG_SIG_FXSKS:
-#if 0
 				i->ringt = i->ringt_base;
-#endif
 				/* Fall through */
 		case ANALOG_SIG_EMWINK:
 		case ANALOG_SIG_FEATD:
@@ -3139,16 +3046,15 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
 		break;
 	case ANALOG_EVENT_ALARM:
 		i->inalarm = 1;
-#if 0
-		res = get_alarms(i);
-		handle_alarms(i, res);	
-#endif
+		analog_get_and_handle_alarms(i);
+
 		/* fall thru intentionally */
 	case ANALOG_EVENT_ONHOOK:
 		/* Back on hook.  Hang up. */
 		switch (i->sig) {
 		case ANALOG_SIG_FXOLS:
 		case ANALOG_SIG_FXOGS:
+			i->fxsoffhookstate = 0;
 		case ANALOG_SIG_FEATD:
 		case ANALOG_SIG_FEATDMF:
 		case ANALOG_SIG_FEATDMF_TA:
@@ -3172,6 +3078,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
 			analog_on_hook(i);
 			break;
 		case ANALOG_SIG_FXOKS:
+			i->fxsoffhookstate = 0;
 			analog_set_echocanceller(i, 0);
 			/* Diddle the battery for the zhone */
 #ifdef ZHONE_HACK
@@ -3244,7 +3151,6 @@ struct analog_pvt * analog_new(enum analog_sigtype signallingtype, struct analog
 	p->chan_pvt = private_data;
 
 	/* Some defaults for values */
-	p->sendcalleridafter = 1;
 	p->cid_start = ANALOG_CID_START_RING;
 	p->cid_signalling = CID_SIG_BELL;
 	/* Sub real is assumed to always be alloc'd */
diff --git a/channels/sig_analog.h b/channels/sig_analog.h
index 661179881fac0970bfaa1fa9d01581e42b81a0fc..89ac6b83d3c1733d80b0f4e32d7a42f487926dd8 100644
--- a/channels/sig_analog.h
+++ b/channels/sig_analog.h
@@ -185,6 +185,13 @@ struct analog_callback {
 	/* callbacks for increasing and decreasing ss_thread_count, will handle locking and condition signal */
 	void (* const increase_ss_count)(void);
 	void (* const decrease_ss_count)(void);
+
+	int (* const distinctive_ring)(struct ast_channel *chan, void *pvt, int idx, int *ringdata);
+	int (* const set_linear_mode)(void *pvt, int idx, int linear_mode);
+	void (* const get_and_handle_alarms)(void *pvt);
+	void * (* const get_sigpvt_bridged_channel)(struct ast_channel *chan);
+	int (* const get_sub_fd)(void *pvt, enum analog_sub sub);
+	void (* const set_cadence)(void *pvt, int *cidrings, struct ast_channel *chan);
 };
 
 
@@ -210,8 +217,12 @@ struct analog_pvt {
 	/* All members after this are giong to be transient, and most will probably change */
 	struct ast_channel *owner;			/*!< Our current active owner (if applicable) */
 
-	struct analog_subchannel subs[3];			/*!< Sub-channels */
+	struct analog_subchannel subs[3];		/*!< Sub-channels */
 	struct analog_dialoperation dop;
+	int onhooktime;							/*< Time the interface went on-hook. */
+	int fxsoffhookstate;					/*< TRUE if the FXS port is off-hook */
+	/*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
+	int msgstate;
 
 	/* XXX: Option Variables - Set by allocator of private structure */
 	unsigned int answeronpolarityswitch:1;
@@ -228,17 +239,22 @@ struct analog_pvt {
 	unsigned int transfer:1;
 	unsigned int transfertobusy:1;			/*!< allow flash-transfers to busy channels */
 	unsigned int use_callerid:1;			/*!< Whether or not to use caller id on this channel */
+	const struct ast_channel_tech *chan_tech;
+	/*!
+     * \brief TRUE if distinctive rings are to be detected.
+     * \note For FXO lines
+     * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
+     */
+	unsigned int usedistinctiveringdetection:1;
 
 	/* Not used for anything but log messages.  Could be just the TCID */
-	int channel;					/*!< Channel Number or CRV */
+	int channel;					/*!< Channel Number */
 	enum analog_sigtype outsigmod;
 	int echotraining;
 	int cid_signalling;				/*!< Asterisk callerid type we're using */
 	int polarityonanswerdelay;
 	int stripmsd;
 	enum analog_cid_start cid_start;
-	/* Number of rings to wait to send callerid on FXS.  Set to 1 for US */
-	int sendcalleridafter;
 	int callwaitingcallerid;
 	char mohsuggest[MAX_MUSICCLASS];
 	char cid_num[AST_MAX_EXTENSION];
@@ -282,10 +298,8 @@ struct analog_pvt {
 
 	int callwaitcas;
 
-#if 0
 	int ringt;
 	int ringt_base;
-#endif
 };
 
 struct analog_pvt * analog_new(enum analog_sigtype signallingtype, struct analog_callback *c, void *private_data);