[asterisk-commits] jpeeler: trunk r198088 - /trunk/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri May 29 14:19:57 CDT 2009


Author: jpeeler
Date: Fri May 29 14:19:51 2009
New Revision: 198088

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=198088
Log:
New signaling module to handle analog operations in chan_dahdi

This branch splits all the analog signaling logic out of chan_dahdi.c into
sig_analog.c. Functionality in theory should not change at all. As noted
in the code, there is still some unused code remaining that will be cleaned
up in a later commit.

Review: https://reviewboard.asterisk.org/r/253/

Added:
    trunk/channels/sig_analog.c   (with props)
    trunk/channels/sig_analog.h   (with props)
Modified:
    trunk/channels/Makefile
    trunk/channels/chan_dahdi.c

Modified: trunk/channels/Makefile
URL: http://svn.asterisk.org/svn-view/asterisk/trunk/channels/Makefile?view=diff&rev=198088&r1=198087&r2=198088
==============================================================================
--- trunk/channels/Makefile (original)
+++ trunk/channels/Makefile Fri May 29 14:19:51 2009
@@ -69,6 +69,7 @@
 	rm -f h323/Makefile
 
 $(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): iax2-parser.o iax2-provision.o
+$(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): sig_analog.o
 
 ifneq ($(filter chan_h323,$(EMBEDDED_MODS)),)
 modules.link: h323/libchanh323.a

Modified: trunk/channels/chan_dahdi.c
URL: http://svn.asterisk.org/svn-view/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=198088&r1=198087&r2=198088
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Fri May 29 14:19:51 2009
@@ -62,6 +62,7 @@
 
 #include <dahdi/user.h>
 #include <dahdi/tonezone.h>
+#include "sig_analog.h"
 
 #ifdef HAVE_PRI
 #include <libpri.h>
@@ -468,6 +469,8 @@
 
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
 
+static int analog_lib_handles(int signalling, int radio, int oprmode);
+
 static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	/* This module does not handle MWI in an event-based manner.  However, it
@@ -753,6 +756,7 @@
 
 static struct dahdi_pvt {
 	ast_mutex_t lock;
+	struct callerid_state *cs;
 	struct ast_channel *owner;			/*!< Our current active owner (if applicable) */
 							/*!< Up to three channels can be associated with this call */
 
@@ -1333,6 +1337,7 @@
 	char begindigit;
 	/*! \brief TRUE if confrence is muted. */
 	int muting;
+	void *sig_pvt;
 } *iflist = NULL, *ifend = NULL;
 
 /*! \brief Channel configuration from chan_dahdi.conf .
@@ -1527,6 +1532,911 @@
 #else
 #define GET_CHANNEL(p) ((p)->channel)
 #endif
+
+static enum analog_sigtype dahdisig_to_analogsig(int sig)
+{
+	switch (sig) {
+	case SIG_FXOLS:
+		return ANALOG_SIG_FXOLS;
+	case SIG_FXOGS:
+		return ANALOG_SIG_FXOGS;
+	case SIG_FXOKS:
+		return ANALOG_SIG_FXOKS;
+	case SIG_FXSLS:
+		return ANALOG_SIG_FXSLS;
+	case SIG_FXSGS:
+		return ANALOG_SIG_FXSGS;
+	case SIG_FXSKS:
+		return ANALOG_SIG_FXSKS;
+	case SIG_EMWINK:
+		return ANALOG_SIG_EMWINK;
+	case SIG_EM:
+		return ANALOG_SIG_EM;
+	case SIG_EM_E1:
+		return ANALOG_SIG_EM_E1;
+	case SIG_FEATD:
+		return ANALOG_SIG_FEATD;
+	case SIG_FEATDMF:
+		return ANALOG_SIG_FEATDMF;
+	case SIG_E911:
+		return SIG_E911;
+	case SIG_FGC_CAMA:
+		return ANALOG_SIG_FGC_CAMA;
+	case SIG_FGC_CAMAMF:
+		return ANALOG_SIG_FGC_CAMAMF;
+	case SIG_FEATB:
+		return ANALOG_SIG_FEATB;
+	case SIG_SFWINK:
+		return ANALOG_SIG_SFWINK;
+	case SIG_SF:
+		return ANALOG_SIG_SF;
+	case SIG_SF_FEATD:
+		return ANALOG_SIG_SF_FEATD;
+	case SIG_SF_FEATDMF:
+		return ANALOG_SIG_SF_FEATDMF;
+	case SIG_FEATDMF_TA:
+		return ANALOG_SIG_FEATDMF_TA;
+	case SIG_SF_FEATB:
+		return ANALOG_SIG_FEATB;
+	default:
+		return -1;
+	}
+}
+
+
+static int analog_tone_to_dahditone(enum analog_tone tone)
+{
+	switch (tone) {
+	case ANALOG_TONE_RINGTONE:
+		return DAHDI_TONE_RINGTONE;
+	case ANALOG_TONE_STUTTER:
+		return DAHDI_TONE_STUTTER;
+	case ANALOG_TONE_CONGESTION:
+		return DAHDI_TONE_CONGESTION;
+	case ANALOG_TONE_DIALTONE:
+		return DAHDI_TONE_DIALTONE;
+	case ANALOG_TONE_DIALRECALL:
+		return DAHDI_TONE_DIALRECALL;
+	case ANALOG_TONE_INFO:
+		return DAHDI_TONE_INFO;
+	default:
+		return -1;
+	}
+}
+
+static int analogsub_to_dahdisub(enum analog_sub analogsub)
+{
+	int index;
+
+	switch (analogsub) {
+	case ANALOG_SUB_REAL:
+		index = SUB_REAL;
+		break;
+	case ANALOG_SUB_CALLWAIT:
+		index = SUB_CALLWAIT;
+		break;
+	case ANALOG_SUB_THREEWAY:
+		index = SUB_THREEWAY;
+		break;
+	default:
+		ast_log(LOG_ERROR, "Unidentified sub!\n");
+		index = SUB_REAL;
+	}
+
+	return index;
+}
+
+static enum analog_event dahdievent_to_analogevent(int event);
+static int bump_gains(struct dahdi_pvt *p);
+static int dahdi_setlinear(int dfd, int linear);
+
+static int my_start_cid_detect(void *pvt, int cid_signalling)
+{
+	struct dahdi_pvt *p = pvt;
+	int index = SUB_REAL;
+	p->cs = callerid_new(cid_signalling);
+	if (!p->cs) {
+		ast_log(LOG_ERROR, "Unable to alloc callerid\n");
+		return -1;
+	}
+	bump_gains(p);
+	dahdi_setlinear(p->subs[index].dfd, 0);
+
+	return 0;
+}
+
+static int my_stop_cid_detect(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	int index = SUB_REAL;
+	if (p->cs)
+		callerid_free(p->cs);
+	dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
+	return 0;
+}
+
+static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
+{
+	struct dahdi_pvt *p = pvt;
+	struct pollfd poller;
+	char *name, *num;
+	int index = SUB_REAL;
+	int res;
+	unsigned char buf[256];
+	int flags;
+
+	poller.fd = p->subs[SUB_REAL].dfd;
+	poller.events = POLLPRI | POLLIN;
+	poller.revents = 0;
+
+	res = poll(&poller, 1, timeout);
+
+	if (poller.revents & POLLPRI) {
+		*ev = dahdievent_to_analogevent(dahdi_get_event(p->subs[SUB_REAL].dfd));
+		return 1;
+	}
+
+	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 */
+		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(p->cs);
+				return -1;
+			}
+		}
+		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;
+		}
+
+		if (res == 1) {
+			callerid_get(p->cs, &name, &num, &flags);
+			if (name)
+				ast_copy_string(namebuf, name, ANALOG_MAX_CID);
+			if (num)
+				ast_copy_string(numbuf, num, ANALOG_MAX_CID);
+
+			ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
+			return 0;
+		}
+	}
+
+	*ev = ANALOG_EVENT_NONE;
+	return 1;
+}
+
+static int send_callerid(struct dahdi_pvt *p);
+
+static int my_stop_callwait(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	p->callwaitingrepeat = 0;
+	p->cidcwexpire = 0;
+
+	return 0;
+}
+
+static int save_conference(struct dahdi_pvt *p);
+
+static int my_callwait(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
+	if (p->cidspill) {
+		ast_log(LOG_WARNING, "Spill already exists?!?\n");
+		free(p->cidspill);
+	}
+	if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
+		return -1;
+	save_conference(p);
+	/* Silence */
+	memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
+	if (!p->callwaitrings && p->callwaitingcallerid) {
+		ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
+		p->callwaitcas = 1;
+		p->cidlen = 2400 + 680 + READ_SIZE * 4;
+	} else {
+		ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
+		p->callwaitcas = 0;
+		p->cidlen = 2400 + READ_SIZE * 4;
+	}
+	p->cidpos = 0;
+	send_callerid(p);
+
+	return 0;
+}
+
+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");
+
+	if (p->cidspill) {
+		ast_log(LOG_WARNING, "cidspill already exists??\n");
+		free(p->cidspill);
+	}
+
+	if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
+		if (cwcid == 0) {
+			p->cidlen = ast_callerid_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
+		} else {
+			p->callwaitcas = 0;
+			p->cidcwexpire = 0;
+			p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
+			p->cidlen += READ_SIZE * 4;
+		}
+		p->cidpos = 0;
+		send_callerid(p);
+	}
+	return 0;
+}
+
+static int my_dsp_reset_and_flush_digits(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	if (p->dsp)
+		ast_dsp_digitreset(p->dsp);
+
+	return 0;
+}
+
+static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
+{
+	struct dahdi_pvt *p = pvt;
+
+	if (p->channel == CHAN_PSEUDO)
+		ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
+
+	if (mode == ANALOG_DIGITMODE_DTMF) {
+		/* If we do hardware dtmf, no need for a DSP */
+		if (p->hardwaredtmf) {
+			if (p->dsp) {
+				ast_dsp_free(p->dsp);
+				p->dsp = NULL;
+			}
+			return 0;
+		}
+
+		if (!p->dsp) {
+			p->dsp = ast_dsp_new();
+			if (!p->dsp) {
+				ast_log(LOG_ERROR, "Unable to allocate DSP\n");
+				return -1;
+			}
+		}
+
+		ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
+	} else if (mode == ANALOG_DIGITMODE_MF) {
+		if (!p->dsp) {
+			p->dsp = ast_dsp_new();
+			if (!p->dsp) {
+				ast_log(LOG_ERROR, "Unable to allocate DSP\n");
+				return -1;
+			}
+		}
+		ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
+	}
+	return 0;
+}
+
+static int dahdi_wink(struct dahdi_pvt *p, int index);
+
+static int my_wink(void *pvt, enum analog_sub sub)
+{
+	struct dahdi_pvt *p = pvt;
+	int index = analogsub_to_dahdisub(sub);
+	if (index != SUB_REAL) {
+		ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
+	}
+	return dahdi_wink(p, index);
+}
+
+static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri);
+
+static int reset_conf(struct dahdi_pvt *p);
+
+static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
+
+static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+{
+	struct ast_frame *f = *dest;
+	struct dahdi_pvt *p = pvt;
+	int idx = analogsub_to_dahdisub(analog_index);
+
+	ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
+
+	if (f->subclass == 'f') {
+		/* Fax tone -- Handle and return NULL */
+		if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+			/* If faxbuffers are configured, use them for the fax transmission */
+			if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+				struct dahdi_bufferinfo bi = {
+					.txbufpolicy = p->faxbuf_policy,
+					.bufsize = p->bufsize,
+					.numbufs = p->faxbuf_no
+				};
+				int res;
+
+				if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+					ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+				} else {
+					p->bufferoverrideinuse = 1;
+				}
+			}
+			p->faxhandled = 1;
+			if (strcmp(ast->exten, "fax")) {
+				const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+				/* We need to unlock 'ast' here because ast_exists_extension has the
+				 * potential to start autoservice on the channel. Such action is prone
+				 * to deadlock.
+				 */
+				ast_mutex_unlock(&p->lock);
+				ast_channel_unlock(ast);
+				if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
+					ast_channel_lock(ast);
+					ast_mutex_lock(&p->lock);
+					ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+					/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+					pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+					if (ast_async_goto(ast, target_context, "fax", 1))
+						ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+				} else {
+					ast_channel_lock(ast);
+					ast_mutex_lock(&p->lock);
+					ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+				}
+			} else {
+				ast_debug(1, "Already in a fax extension, not redirecting\n");
+			}
+		} else {
+			ast_debug(1, "Fax already handled\n");
+		}
+		dahdi_confmute(p, 0);
+		p->subs[idx].f.frametype = AST_FRAME_NULL;
+		p->subs[idx].f.subclass = 0;
+		*dest = &p->subs[idx].f;
+	}
+}
+
+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 void my_increase_ss_count(void)
+{
+	ast_mutex_lock(&ss_thread_lock);
+	ss_thread_count++;
+	ast_mutex_unlock(&ss_thread_lock);
+}
+
+static void my_decrease_ss_count(void)
+{
+	ast_mutex_lock(&ss_thread_lock);
+	ss_thread_count--;
+	ast_cond_signal(&ss_thread_complete);
+	ast_mutex_unlock(&ss_thread_lock);
+}
+
+static void my_all_subchannels_hungup(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	int res, law;
+
+	p->faxhandled = 0;
+	p->didtdd = 0;
+
+	if (p->dsp) {
+		ast_dsp_free(p->dsp);
+		p->dsp = NULL;
+	}
+
+	law = DAHDI_LAW_DEFAULT;
+	res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
+	if (res < 0) 
+		ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
+
+	dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
+
+#if 1
+	{
+	int i;
+	p->owner = NULL;
+	/* Cleanup owners here */
+	for (i = 0; i < 3; i++) {
+		p->subs[i].owner = NULL;
+	}
+	}
+#endif
+
+	reset_conf(p);
+	if (num_restart_pending == 0) {
+		restart_monitor();
+	}
+}
+
+static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
+
+static int my_conf_del(void *pvt, enum analog_sub sub)
+{
+	struct dahdi_pvt *p = pvt;
+	int x = analogsub_to_dahdisub(sub);
+
+	return conf_del(p, &p->subs[x], x);
+}
+
+static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
+
+static int my_conf_add(void *pvt, enum analog_sub sub)
+{
+	struct dahdi_pvt *p = pvt;
+	int x = analogsub_to_dahdisub(sub);
+
+	return conf_add(p, &p->subs[x], x, 0);
+}
+
+static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
+
+static int my_complete_conference_update(void *pvt, int needconference)
+{
+	struct dahdi_pvt *p = pvt;
+	int needconf = needconference;
+	int x;
+	int useslavenative;
+	struct dahdi_pvt *slave = NULL;
+
+	useslavenative = isslavenative(p, &slave);
+
+	/* If we have a slave, add him to our conference now. or DAX
+	   if this is slave native */
+	for (x = 0; x < MAX_SLAVES; x++) {
+		if (p->slaves[x]) {
+			if (useslavenative)
+				conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
+			else {
+				conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
+				needconf++;
+			}
+		}
+	}
+	/* If we're supposed to be in there, do so now */
+	if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
+		if (useslavenative)
+			conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
+		else {
+			conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
+			needconf++;
+		}
+	}
+	/* If we have a master, add ourselves to his conference */
+	if (p->master) {
+		if (isslavenative(p->master, NULL)) {
+			conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
+		} else {
+			conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
+		}
+	}
+	if (!needconf) {
+		/* Nobody is left (or should be left) in our conference.
+		   Kill it. */
+		p->confno = -1;
+	}
+
+	return 0;
+}
+
+static int check_for_conference(struct dahdi_pvt *p);
+
+static int my_check_for_conference(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	return check_for_conference(p);
+}
+
+static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a,  enum analog_sub b, struct ast_channel *ast_b)
+{
+	struct dahdi_pvt *p = pvt;
+	int da, db;
+	int tchan;
+
+	da = analogsub_to_dahdisub(a);
+	db = analogsub_to_dahdisub(b);
+
+	tchan = p->subs[da].chan;
+
+	p->subs[da].chan = p->subs[db].chan;
+
+	p->subs[db].chan = tchan;
+
+	if (ast_a)
+		ast_a->fds[0] = p->subs[da].dfd;
+	if (ast_b)
+		ast_b->fds[0] = p->subs[db].dfd;
+
+	p->subs[da].owner = ast_a;
+	p->subs[db].owner = ast_b;
+
+	wakeup_sub(p, a, NULL);
+	wakeup_sub(p, b, NULL);
+
+	return;
+}
+
+static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
+
+static struct ast_channel * my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub)
+{
+	struct dahdi_pvt *p = pvt;
+	int dsub = analogsub_to_dahdisub(sub);
+
+	return dahdi_new(p, state, startpbx, dsub, 0, 0);
+}
+
+static int unalloc_sub(struct dahdi_pvt *p, int x);
+
+static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
+{
+	struct dahdi_pvt *p = pvt;
+
+	return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
+}
+
+static int alloc_sub(struct dahdi_pvt *p, int x);
+
+static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
+{
+	struct dahdi_pvt *p = pvt;
+
+	return alloc_sub(p, analogsub_to_dahdisub(analogsub));
+}
+
+static int has_voicemail(struct dahdi_pvt *p);
+
+static int my_has_voicemail(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+
+	return has_voicemail(p);
+}
+
+static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
+{
+	struct dahdi_pvt *p = pvt;
+	int index;
+
+	index = analogsub_to_dahdisub(sub);
+
+	return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
+}
+
+static enum analog_event dahdievent_to_analogevent(int event)
+{
+	enum analog_event res = ANALOG_EVENT_ERROR;
+
+	switch (event) {
+	case DAHDI_EVENT_DIALCOMPLETE:
+		res = ANALOG_EVENT_DIALCOMPLETE;
+		break;
+	case DAHDI_EVENT_WINKFLASH:
+		res = ANALOG_EVENT_WINKFLASH;
+		break;
+	case DAHDI_EVENT_ONHOOK:
+		res = ANALOG_EVENT_ONHOOK;
+		break;
+	case DAHDI_EVENT_RINGOFFHOOK:
+		res = ANALOG_EVENT_RINGOFFHOOK;
+		break;
+	case DAHDI_EVENT_ALARM:
+		res = ANALOG_EVENT_ALARM;
+		break;
+	case DAHDI_EVENT_NOALARM:
+		res = ANALOG_EVENT_NOALARM;
+		break;
+	case DAHDI_EVENT_HOOKCOMPLETE:
+		res = ANALOG_EVENT_HOOKCOMPLETE;
+		break;
+	case DAHDI_EVENT_POLARITY:
+		res = ANALOG_EVENT_POLARITY;
+		break;
+	case DAHDI_EVENT_RINGERON:
+		res = ANALOG_EVENT_RINGERON;
+		break;
+	case DAHDI_EVENT_RINGEROFF:
+		res = ANALOG_EVENT_RINGEROFF;
+		break;
+	case DAHDI_EVENT_RINGBEGIN:
+		res = ANALOG_EVENT_RINGBEGIN;
+		break;
+	case DAHDI_EVENT_PULSE_START:
+		res = ANALOG_EVENT_PULSE_START;
+	break;
+	case DAHDI_EVENT_NEONMWI_ACTIVE:
+		res = ANALOG_EVENT_NEONMWI_ACTIVE;
+		break;
+	case DAHDI_EVENT_NEONMWI_INACTIVE:
+		res = ANALOG_EVENT_NEONMWI_INACTIVE;
+		break;
+	}
+
+	return res;
+}
+
+static inline int dahdi_wait_event(int fd);
+
+static int my_wait_event(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+
+	return dahdi_wait_event(p->subs[SUB_REAL].dfd);
+}
+
+static int my_get_event(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	int res;
+
+	if (p->fake_event) {
+		res = p->fake_event;
+		p->fake_event = 0;
+	} else
+		res = dahdi_get_event(p->subs[SUB_REAL].dfd);
+
+	return dahdievent_to_analogevent(res);
+}
+
+static int my_is_off_hook(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	int res;
+	struct dahdi_params par;
+
+	if (p->subs[SUB_REAL].dfd > -1)
+		res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
+	else {
+		/* Assume not off hook on CVRS */
+		res = 0;
+		par.rxisoffhook = 0;
+	}
+	if (res) {
+		ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
+	}
+
+	return (par.rxbits > -1) || par.rxisoffhook;
+}
+
+static void dahdi_enable_ec(struct dahdi_pvt *p);
+static void dahdi_disable_ec(struct dahdi_pvt *p);
+
+static int my_set_echocanceller(void *pvt, int enable)
+{
+	struct dahdi_pvt *p = pvt;
+
+	if (enable)
+		dahdi_enable_ec(p);
+	else
+		dahdi_disable_ec(p);
+
+	return 0;
+}
+
+static int dahdi_ring_phone(struct dahdi_pvt *p);
+
+static int my_ring(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+
+	return dahdi_ring_phone(p);
+}
+
+static inline int dahdi_set_hook(int fd, int hs);
+
+static int my_off_hook(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
+}
+
+static int my_start(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	int x = DAHDI_START;
+
+	return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
+}
+
+static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
+{
+	int index = analogsub_to_dahdisub(sub);
+	int res;
+	struct dahdi_pvt *p = pvt;
+	struct dahdi_dialoperation ddop;
+
+	if (dop->op != ANALOG_DIAL_OP_REPLACE) {
+		ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
+		return -1;
+	}
+
+	if (sub != ANALOG_SUB_REAL)
+		printf("Trying to dial digits on sub %d\n", sub);
+
+	ddop.op = DAHDI_DIAL_OP_REPLACE;
+	strncpy(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
+
+	printf("Dialing %s on %d\n", ddop.dialstr, p->channel);
+
+	res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
+
+	if (res == -1)
+		ast_log(LOG_DEBUG, "DAHDI_DIAL ioctl failed on %s: %s\n", p->owner->name, strerror(errno));
+
+	return res;
+}
+
+static void dahdi_train_ec(struct dahdi_pvt *p);
+
+static int my_train_echocanceller(void *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+
+	dahdi_train_ec(p);
+
+	return 0;
+}
+
+static int my_is_dialing(void *pvt, enum analog_sub sub)
+{
+	struct dahdi_pvt *p = pvt;
+	int index;
+	int x;
+
+	index = analogsub_to_dahdisub(sub);
+
+	if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
+		ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed!\n");
+		return -1;
+	}
+
+	return x;
+}
+
+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);
+}
+
+/*!
+ * \brief Send MWI state change
+ *
+ * \arg mailbox_full This is the mailbox associated with the FXO line that the
+ *      MWI state has changed on.
+ * \arg thereornot This argument should simply be set to 1 or 0, to indicate
+ *      whether there are messages waiting or not.
+ *
+ *  \return nothing
+ *
+ * This function does two things:
+ *
+ * 1) It generates an internal Asterisk event notifying any other module that
+ *    cares about MWI that the state of a mailbox has changed.
+ *
+ * 2) It runs the script specified by the mwimonitornotify option to allow
+ *    some custom handling of the state change.
+ */
+static void notify_message(char *mailbox_full, int thereornot)
+{
+	char s[sizeof(mwimonitornotify) + 80];
+	struct ast_event *event;
+	char *mailbox, *context;
+
+	/* Strip off @default */
+	context = mailbox = ast_strdupa(mailbox_full);
+	strsep(&context, "@");
+	if (ast_strlen_zero(context))
+		context = "default";
+
+	if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+			AST_EVENT_IE_END))) {
+		return;
+	}
+
+	ast_event_queue_and_cache(event);
+
+	if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
+		snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
+		ast_safe_system(s);
+	}
+}
+
+static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
+{
+	struct dahdi_pvt *p = pvt;
+
+	if (neon_mwievent > -1 && !p->mwimonitor_neon)
+		return;
+
+	if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
+		ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
+		notify_message(p->mailbox, 1);
+	} else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
+		ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
+		notify_message(p->mailbox, 0);
+	}
+	/* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
+	/* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
+	if (neon_mwievent == -1 && p->mwimonitor_rpas) {
+		ast_hangup(chan);
+		return;
+	}
+}
+
+
+static const char *event2str(int event);
+
+static struct analog_callback dahdi_analog_callbacks =
+{
+	.play_tone = my_play_tone,
+	.get_event = my_get_event,
+	.wait_event = my_wait_event,
+	.is_off_hook = my_is_off_hook,
+	.set_echocanceller = my_set_echocanceller,
+	.ring = my_ring,
+	.off_hook = my_off_hook,
+	.dial_digits = my_dial_digits,
+	.train_echocanceller = my_train_echocanceller,
+	.on_hook = my_on_hook,
+	.is_dialing = my_is_dialing,
+	.allocate_sub = my_allocate_sub,
+	.unallocate_sub = my_unallocate_sub,
+	.swap_subs = my_swap_subchannels,
+	.has_voicemail = my_has_voicemail,
+	.check_for_conference = my_check_for_conference,
+	.conf_add = my_conf_add,
+	.conf_del = my_conf_del,
+	.complete_conference_update = my_complete_conference_update,
+	.start = my_start,
+	.all_subchannels_hungup = my_all_subchannels_hungup,
+	.lock_private = my_lock_private,
+	.unlock_private = my_unlock_private,
+	.handle_dtmfup = my_handle_dtmfup,
+	.wink = my_wink,
+	.new_ast_channel = my_new_analog_ast_channel,
+	.dsp_set_digitmode = my_dsp_set_digitmode,
+	.dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
+	.send_callerid = my_send_callerid,
+	.callwait = my_callwait,
+	.stop_callwait = my_stop_callwait,
+	.get_callerid = my_get_callerid,
+	.start_cid_detect = my_start_cid_detect,
+	.stop_cid_detect = my_stop_cid_detect,
+	.handle_notify_message = my_handle_notify_message,
+	.increase_ss_count = my_increase_ss_count,
+	.decrease_ss_count = my_decrease_ss_count,
+};
 
 struct dahdi_pvt *round_robin[32];
 
@@ -2579,6 +3489,45 @@
 	}
 }
 
+int analog_lib_handles(int signalling, int radio, int oprmode)
+{
+	switch (signalling) {
+	case SIG_FXOLS:
+	case SIG_FXOGS:
+	case SIG_FXOKS:
+	case SIG_FXSLS:
+	case SIG_FXSGS:
+	case SIG_FXSKS:
+	case SIG_EMWINK:
+	case SIG_EM:
+	case SIG_EM_E1:
+	case SIG_FEATD:
+	case SIG_FEATDMF:
+	case SIG_E911:
+	case SIG_FGC_CAMA:
+	case SIG_FGC_CAMAMF:
+	case SIG_FEATB:
+	case SIG_SFWINK:
+	case SIG_SF:
+	case SIG_SF_FEATD:
+	case SIG_SF_FEATDMF:
+	case SIG_FEATDMF_TA:
+	case SIG_SF_FEATB:
+		break;
+	default:
+		/* The rest of the function should cover the remainder of signalling types */
+		return 0;
+	}
+
+	if (radio)
+		return 0;
+
+	if (oprmode)
+		return 0;
+
+	return 1;
+}
+
 #define sig2str dahdi_sig2str
 
 static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
@@ -3025,53 +3974,6 @@
 	return 0;
 }
 
-/*!
- * \brief Send MWI state change
- *
- * \arg mailbox_full This is the mailbox associated with the FXO line that the
- *      MWI state has changed on.
- * \arg thereornot This argument should simply be set to 1 or 0, to indicate
- *      whether there are messages waiting or not.
- *
- *  \return nothing
- *
- * This function does two things:
- *
- * 1) It generates an internal Asterisk event notifying any other module that
- *    cares about MWI that the state of a mailbox has changed.
- *
- * 2) It runs the script specified by the mwimonitornotify option to allow
- *    some custom handling of the state change.
- */
-static void notify_message(char *mailbox_full, int thereornot)
-{
-	char s[sizeof(mwimonitornotify) + 80];
-	struct ast_event *event;
-	char *mailbox, *context;
-
-	/* Strip off @default */
-	context = mailbox = ast_strdupa(mailbox_full);
-	strsep(&context, "@");
-	if (ast_strlen_zero(context))
-		context = "default";
-
-	if (!(event = ast_event_new(AST_EVENT_MWI,
-			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
-			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
-			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
-			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
-			AST_EVENT_IE_END))) {
-		return;
-	}
-
-	ast_event_queue_and_cache(event);
-
-	if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
-		snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
-		ast_safe_system(s);
-	}
-}
-
 static int restore_conference(struct dahdi_pvt *p)
 {
 	int res;
@@ -3128,6 +4030,8 @@
 
 	return new_msgs;
 }
+
+
 
 static int send_callerid(struct dahdi_pvt *p)
 {
@@ -3242,6 +4146,14 @@
 	p->outgoing = 1;
 
 	set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
+
+	/* If this is analog signalling we can exit here */
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		p->callwaitrings = 0;
+		res = analog_call(p->sig_pvt, ast, rdest, timeout);
+		ast_mutex_unlock(&p->lock);
+		return res;
+	}
 
 	mysig = p->sig;
 	if (p->outsigmod > -1)
@@ -4437,6 +5349,34 @@
 		return 0;
 	}
 
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		ast_mutex_lock(&p->lock);
+
+		dahdi_confmute(p, 0);
+		restore_gains(p);
+		p->ignoredtmf = 0;
+
+		if (p->bufferoverrideinuse) {
+			/* faxbuffers are in use, revert them */
+			struct dahdi_bufferinfo bi = {
+				.txbufpolicy = p->buf_policy,
+				.rxbufpolicy = p->buf_policy,
+				.bufsize = p->bufsize,
+				.numbufs = p->buf_no
+			};
+			int bpres;
+
+			if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+				ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast->name, strerror(errno));
+			}
+			p->bufferoverrideinuse = 0;
+		}
+
+		res = analog_hangup(p->sig_pvt, ast);
+
+		goto hangup_out;
+	}
+
 	ast_mutex_lock(&p->lock);
 
 	idx = dahdi_get_index(ast, p, 1);
@@ -4603,9 +5543,9 @@
 			int bpres;
 
 			if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
-				ast_log(LOG_WARNING, "Channel '%s' unable to revert faxbuffer policy: %s\n", ast->name, strerror(errno));
-			}
-			p->bufferoverrideinuse = 0;	
+				ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast->name, strerror(errno));
+			}
+			p->bufferoverrideinuse = 0;
 		}
 
 		law = DAHDI_LAW_DEFAULT;
@@ -4745,15 +5685,12 @@
 		default:
 			tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
 		}
-		if (p->cidspill)
-			ast_free(p->cidspill);
 		if (p->sig)
 			dahdi_disable_ec(p);
 		x = 0;
 		ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
 		ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
 		p->didtdd = 0;
-		p->cidspill = NULL;
 		p->callwaitcas = 0;
 		p->callwaiting = p->permcallwaiting;
 		p->hidecallerid = p->permhidecallerid;
@@ -4789,6 +5726,11 @@
 	p->cidcwexpire = 0;
 	p->oprmode = 0;
 	ast->tech_pvt = NULL;
+hangup_out:
+	if (p->cidspill)
+		ast_free(p->cidspill);
+	p->cidspill = NULL;
+	
 	ast_mutex_unlock(&p->lock);
 	ast_module_unref(ast_module_info->self);
 	ast_verb(3, "Hungup '%s'\n", ast->name);
@@ -4832,6 +5774,13 @@
 		ast_mutex_unlock(&p->lock);
 		return 0;
 	}
+
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		res = analog_answer(p->sig_pvt, ast);
+		ast_mutex_unlock(&p->lock);
+		return res;
+	}
+
 	switch (p->sig) {
 	case SIG_FXSLS:
 	case SIG_FXSGS:
@@ -5666,6 +6615,11 @@
 		}
 	if (newchan->_state == AST_STATE_RINGING)
 		dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
+
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		analog_fixup(oldchan, newchan, p->sig_pvt);
+	}
+
 	update_conf(p);
 	ast_mutex_unlock(&p->lock);
 	return 0;
@@ -5701,7 +6655,7 @@
 	return res;
 }
 
-static void *ss_thread(void *data);
+static void *analog_ss_thread(void *data);
 
 static int attempt_transfer(struct dahdi_pvt *p)
 {
@@ -5848,7 +6802,7 @@
 				int res;
 
 				if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
-					ast_log(LOG_WARNING, "Channel '%s' unable to set faxbuffer policy, reason: %s\n", ast->name, strerror(errno));
+					ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
 				} else {
 					p->bufferoverrideinuse = 1;
 				}
@@ -5961,820 +6915,818 @@
 	}
 
 	switch (res) {
-		case DAHDI_EVENT_EC_DISABLED:
-			ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
-			p->echocanon = 0;
+	case DAHDI_EVENT_EC_DISABLED:
+		ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
+		p->echocanon = 0;
+		break;
+#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
+	case DAHDI_EVENT_TX_CED_DETECTED:
+		ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
+		break;
+	case DAHDI_EVENT_RX_CED_DETECTED:
+		ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
+		break;
+	case DAHDI_EVENT_EC_NLP_DISABLED:
+		ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
+		break;
+	case DAHDI_EVENT_EC_NLP_ENABLED:
+		ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
+		break;
+#endif
+	case DAHDI_EVENT_BITSCHANGED:
+#ifdef HAVE_OPENR2
+		if (p->sig != SIG_MFCR2) {
+			ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
+		} else {
+			ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
+			openr2_chan_handle_cas(p->r2chan);
+		}
+#else
+		ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
+#endif
+	case DAHDI_EVENT_PULSE_START:
+		/* Stop tone if there's a pulse start and the PBX isn't started */
+		if (!ast->pbx)
+			tone_zone_play_tone(p->subs[idx].dfd, -1);
+		break;
+	case DAHDI_EVENT_DIALCOMPLETE:
+#ifdef HAVE_OPENR2
+		if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
+			/* we don't need to do anything for this event for R2 signaling
+			   if the call is being setup */
 			break;
-#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
-		case DAHDI_EVENT_TX_CED_DETECTED:
-			ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
+		}
+#endif
+		if (p->inalarm) break;
+		if ((p->radio || (p->oprmode < 0))) break;
+		if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
+			ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
+			return NULL;
+		}
+		if (!x) { /* if not still dialing in driver */
+			dahdi_enable_ec(p);
+			if (p->echobreak) {
+				dahdi_train_ec(p);
+				ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
+				p->dop.op = DAHDI_DIAL_OP_REPLACE;
+				res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+				p->echobreak = 0;
+			} else {
+				p->dialing = 0;
+				if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
+					/* if thru with dialing after offhook */
+					if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
+						ast_setstate(ast, AST_STATE_UP);
+						p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+						p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
+						break;
+					} else { /* if to state wait for offhook to dial rest */
+						/* we now wait for off hook */
+						ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
+					}
+				}
+				if (ast->_state == AST_STATE_DIALING) {
+					if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
+						ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
+					} else if (p->confirmanswer || (!p->dialednone
+						&& ((mysig == SIG_EM) || (mysig == SIG_EM_E1)
+							|| (mysig == SIG_EMWINK) || (mysig == SIG_FEATD)
+							|| (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF)
+							|| (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA)
+							|| (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB)
+							|| (mysig == SIG_SF) || (mysig == SIG_SFWINK)
+							|| (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF)
+							|| (mysig == SIG_SF_FEATB)))) {
+						ast_setstate(ast, AST_STATE_RINGING);
+					} else if (!p->answeronpolarityswitch) {
+						ast_setstate(ast, AST_STATE_UP);
+						p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+						p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
+						/* If aops=0 and hops=1, this is necessary */
+						p->polarity = POLARITY_REV;
+					} else {
+						/* Start clean, so we can catch the change to REV polarity when party answers */
+						p->polarity = POLARITY_IDLE;
+					}
+				}
+			}
+		}
+		break;
+	case DAHDI_EVENT_ALARM:
+#ifdef HAVE_PRI
+		if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
+			if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
+				/* T309 is not enabled : hangup calls when alarm occurs */
+				if (p->call) {
+					if (p->pri && p->pri->pri) {
+						if (!pri_grab(p, p->pri)) {
+							pri_hangup(p->pri->pri, p->call, -1);
+							pri_destroycall(p->pri->pri, p->call);
+							p->call = NULL;
+							pri_rel(p->pri);
+						} else
+							ast_log(LOG_WARNING, "Failed to grab PRI!\n");
+					} else
+						ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
+				}
+				if (p->owner)
+					p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+			}
+		}
+		if (p->bearer)
+			p->bearer->inalarm = 1;
+		else
+#endif
+		p->inalarm = 1;
+		res = get_alarms(p);
+		handle_alarms(p, res);
+#ifdef HAVE_PRI
+		if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
+			/* fall through intentionally */
+		} else {
 			break;
-		case DAHDI_EVENT_RX_CED_DETECTED:
-			ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
+		}
+#endif
+#ifdef HAVE_SS7
+		if (p->sig == SIG_SS7)
 			break;
-		case DAHDI_EVENT_EC_NLP_DISABLED:
-			ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
+#endif
+#ifdef HAVE_OPENR2
+		if (p->sig == SIG_MFCR2)
 			break;
-		case DAHDI_EVENT_EC_NLP_ENABLED:
-			ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
+#endif
+	case DAHDI_EVENT_ONHOOK:
+		if (p->radio) {
+			p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+			p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
 			break;
-#endif
-		case DAHDI_EVENT_BITSCHANGED:
-#ifdef HAVE_OPENR2
-			if (p->sig != SIG_MFCR2) {
-				ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
-			} else {
-				ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
-				openr2_chan_handle_cas(p->r2chan);
-			}
-#else
-			ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
-#endif
-		case DAHDI_EVENT_PULSE_START:
-			/* Stop tone if there's a pulse start and the PBX isn't started */
-			if (!ast->pbx)
-				tone_zone_play_tone(p->subs[idx].dfd, -1);
+		}
+		if (p->oprmode < 0)
+		{
+			if (p->oprmode != -1) break;
+			if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
+			{
+				/* Make sure it starts ringing */
+				dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
+				dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
+				save_conference(p->oprpeer);
+				tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+			}
 			break;
-		case DAHDI_EVENT_DIALCOMPLETE:
-#ifdef HAVE_OPENR2
-			if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
-				/* we don't need to do anything for this event for R2 signaling
-				   if the call is being setup */
-				break;
-			}
-#endif
-			if (p->inalarm) break;
-			if ((p->radio || (p->oprmode < 0))) break;
-			if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
-				ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
-				return NULL;
-			}
-			if (!x) { /* if not still dialing in driver */
-				dahdi_enable_ec(p);
-				if (p->echobreak) {
-					dahdi_train_ec(p);
-					ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
-					p->dop.op = DAHDI_DIAL_OP_REPLACE;
-					res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
-					p->echobreak = 0;
-				} else {
-					p->dialing = 0;

[... 5432 lines stripped ...]



More information about the asterisk-commits mailing list