Skip to content
Snippets Groups Projects
sig_analog.c 124 KiB
Newer Older
  • Learn to ignore specific revisions
  • 				analog_cancel_cidspill(p);
    
    				analog_set_dialing(p, 0);
    
    				if (analog_check_confirmanswer(p)) {
    					/* Ignore answer if "confirm answer" is enabled */
    
    					p->subs[idx].f.frametype = AST_FRAME_NULL;
    					p->subs[idx].f.subclass.integer = 0;
    
    				} else if (!ast_strlen_zero(p->dop.dialstr)) {
    
    					/* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
    					res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
    					if (res < 0) {
    						ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
    						p->dop.dialstr[0] = '\0';
    						return NULL;
    					} else {
    						ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
    
    						p->subs[idx].f.frametype = AST_FRAME_NULL;
    						p->subs[idx].f.subclass.integer = 0;
    
    						analog_set_dialing(p, 1);
    
    					}
    					p->dop.dialstr[0] = '\0';
    					ast_setstate(ast, AST_STATE_DIALING);
    
    					ast_setstate(ast, AST_STATE_UP);
    
    				return &p->subs[idx].f;
    
    			case AST_STATE_DOWN:
    				ast_setstate(ast, AST_STATE_RING);
    
    				ast_channel_rings_set(ast, 1);
    
    				p->subs[idx].f.frametype = AST_FRAME_CONTROL;
    				p->subs[idx].f.subclass.integer = AST_CONTROL_OFFHOOK;
    
    				ast_debug(1, "channel %d picked up\n", p->channel);
    
    				return &p->subs[idx].f;
    
    			case AST_STATE_UP:
    				/* Make sure it stops ringing */
    				analog_off_hook(p);
    				/* Okay -- probably call waiting*/
    
    				if (ast_bridged_channel(p->owner)) {
    
    					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
    
    				break;
    			case AST_STATE_RESERVED:
    				/* Start up dialtone */
    
    				if (analog_has_voicemail(p)) {
    
    					res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_STUTTER);
    
    					res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_DIALTONE);
    
    				ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast_channel_state(ast));
    
    			}
    			break;
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSGS:
    		case ANALOG_SIG_FXSKS:
    
    			if (ast_channel_state(ast) == AST_STATE_RING) {
    
    				analog_set_ringtimeout(p, p->ringt_base);
    
    			}
    
    			/* Fall through */
    		case ANALOG_SIG_EM:
    		case ANALOG_SIG_EM_E1:
    		case ANALOG_SIG_EMWINK:
    		case ANALOG_SIG_FEATD:
    		case ANALOG_SIG_FEATDMF:
    		case ANALOG_SIG_FEATDMF_TA:
    		case ANALOG_SIG_E911:
    		case ANALOG_SIG_FGC_CAMA:
    		case ANALOG_SIG_FGC_CAMAMF:
    		case ANALOG_SIG_FEATB:
    		case ANALOG_SIG_SF:
    		case ANALOG_SIG_SFWINK:
    		case ANALOG_SIG_SF_FEATD:
    		case ANALOG_SIG_SF_FEATDMF:
    		case ANALOG_SIG_SF_FEATB:
    
    			switch (ast_channel_state(ast)) {
    
    			case AST_STATE_PRERING:
    
    				ast_setstate(ast, AST_STATE_RING);
    
    				/* Fall through */
    			case AST_STATE_DOWN:
    			case AST_STATE_RING:
    
    				ast_debug(1, "Ring detected\n");
    
    				p->subs[idx].f.frametype = AST_FRAME_CONTROL;
    				p->subs[idx].f.subclass.integer = AST_CONTROL_RING;
    
    				break;
    			case AST_STATE_RINGING:
    			case AST_STATE_DIALING:
    				if (p->outgoing) {
    					ast_debug(1, "Line answered\n");
    					if (analog_check_confirmanswer(p)) {
    
    						p->subs[idx].f.frametype = AST_FRAME_NULL;
    						p->subs[idx].f.subclass.integer = 0;
    
    						p->subs[idx].f.frametype = AST_FRAME_CONTROL;
    						p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
    
    						ast_setstate(ast, AST_STATE_UP);
    					}
    					break;
    
    				/* Fall through */
    			default:
    
    				ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast_channel_state(ast), p->channel);
    
    			break;
    		default:
    			ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
    
    		}
    		break;
    	case ANALOG_EVENT_RINGBEGIN:
    		switch (p->sig) {
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSGS:
    		case ANALOG_SIG_FXSKS:
    
    			if (ast_channel_state(ast) == AST_STATE_RING) {
    
    				analog_set_ringtimeout(p, p->ringt_base);
    
    		}
    		break;
    	case ANALOG_EVENT_RINGEROFF:
    		if (p->inalarm) break;
    
    		ast_channel_rings_set(ast, ast_channel_rings(ast) + 1);
    		if (ast_channel_rings(ast) == p->cidrings) {
    
    			analog_send_callerid(p, 0, &p->caller);
    
    		if (ast_channel_rings(ast) > p->cidrings) {
    
    			analog_cancel_cidspill(p);
    
    		p->subs[idx].f.frametype = AST_FRAME_CONTROL;
    		p->subs[idx].f.subclass.integer = AST_CONTROL_RINGING;
    
    		break;
    	case ANALOG_EVENT_RINGERON:
    		break;
    	case ANALOG_EVENT_NOALARM:
    
    		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
    
    		/*** DOCUMENTATION
    			<managerEventInstance>
    				<synopsis>Raised when an Alarm is cleared on an Analog channel.</synopsis>
    			</managerEventInstance>
    		***/
    
    		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
    			"Channel: %d\r\n", p->channel);
    
    		break;
    	case ANALOG_EVENT_WINKFLASH:
    
    		/* Remember last time we got a flash-hook */
    		gettimeofday(&p->flashtime, NULL);
    		switch (mysig) {
    		case ANALOG_SIG_FXOLS:
    		case ANALOG_SIG_FXOGS:
    		case ANALOG_SIG_FXOKS:
    			ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
    
    				idx, analog_get_sub_fd(p, ANALOG_SUB_REAL), analog_get_sub_fd(p, ANALOG_SUB_CALLWAIT), analog_get_sub_fd(p, ANALOG_SUB_THREEWAY));
    
    			/* Cancel any running CallerID spill */
    			analog_cancel_cidspill(p);
    
    			if (idx != ANALOG_SUB_REAL) {
    				ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
    
    				goto winkflashdone;
    			}
    
    			if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
    
    				/* Need to hold the lock for real-call, private, and call-waiting call */
    				analog_lock_sub_owner(p, ANALOG_SUB_CALLWAIT);
    				if (!p->subs[ANALOG_SUB_CALLWAIT].owner) {
    					/*
    					 * The call waiting call dissappeared.
    					 * Let's just ignore this flash-hook.
    					 */
    					ast_log(LOG_NOTICE, "Whoa, the call-waiting call disappeared.\n");
    					goto winkflashdone;
    
    
    				/* Swap to call-wait */
    
    				analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_CALLWAIT);
    				analog_play_tone(p, ANALOG_SUB_REAL, -1);
    
    				analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
    
    				ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));
    
    				if (ast_channel_state(p->subs[ANALOG_SUB_REAL].owner) == AST_STATE_RINGING) {
    
    					ast_setstate(p->subs[ANALOG_SUB_REAL].owner, AST_STATE_UP);
    
    					ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
    				}
    				analog_stop_callwait(p);
    
    				/* Start music on hold if appropriate */
    				if (!p->subs[ANALOG_SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[ANALOG_SUB_CALLWAIT].owner)) {
    					ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
    						S_OR(p->mohsuggest, NULL),
    						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
    				}
    				if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
    					ast_queue_control_data(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_HOLD,
    						S_OR(p->mohsuggest, NULL),
    						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
    				}
    				ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
    
    
    				/* Unlock the call-waiting call that we swapped to real-call. */
    				ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner);
    
    			} else if (!p->subs[ANALOG_SUB_THREEWAY].owner) {
    				if (!p->threewaycalling) {
    					/* Just send a flash if no 3-way calling */
    					ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_FLASH);
    					goto winkflashdone;
    				} else if (!analog_check_for_conference(p)) {
    
    					struct ast_callid *callid = NULL;
    					int callid_created;
    
    					char cid_num[256];
    					char cid_name[256];
    
    					cid_num[0] = '\0';
    					cid_name[0] = '\0';
    
    					if (p->dahditrcallerid && p->owner) {
    
    						if (ast_channel_caller(p->owner)->id.number.valid
    							&& ast_channel_caller(p->owner)->id.number.str) {
    							ast_copy_string(cid_num, ast_channel_caller(p->owner)->id.number.str,
    
    								sizeof(cid_num));
    
    						if (ast_channel_caller(p->owner)->id.name.valid
    							&& ast_channel_caller(p->owner)->id.name.str) {
    							ast_copy_string(cid_name, ast_channel_caller(p->owner)->id.name.str,
    
    								sizeof(cid_name));
    
    					}
    					/* XXX This section needs much more error checking!!! XXX */
    					/* Start a 3-way call if feasible */
    
    					if (!((ast_channel_pbx(ast)) ||
    						(ast_channel_state(ast) == AST_STATE_UP) ||
    						(ast_channel_state(ast) == AST_STATE_RING))) {
    
    						ast_debug(1, "Flash when call not up or ringing\n");
    
    						goto winkflashdone;
    
    					}
    					if (analog_alloc_sub(p, ANALOG_SUB_THREEWAY)) {
    						ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
    						goto winkflashdone;
    					}
    
    					callid_created = ast_callid_threadstorage_auto(&callid);
    
    
    					/*
    					 * Make new channel
    					 *
    					 * We cannot hold the p or ast locks while creating a new
    					 * channel.
    					 */
    					analog_unlock_private(p);
    					ast_channel_unlock(ast);
    
    					chan = analog_new_ast_channel(p, AST_STATE_RESERVED, 0, ANALOG_SUB_THREEWAY, NULL);
    
    					ast_channel_lock(ast);
    					analog_lock_private(p);
    
    					if (!chan) {
    						ast_log(LOG_WARNING,
    							"Cannot allocate new call structure on channel %d\n",
    							p->channel);
    						analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
    
    						ast_callid_threadstorage_auto_clean(callid, callid_created);
    
    							p->origcid_num = ast_strdup(p->cid_num);
    
    							p->origcid_name = ast_strdup(p->cid_name);
    
    						ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
    						ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
    					}
    					/* Swap things around between the three-way and real call */
    					analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
    					/* Disable echo canceller for better dialing */
    					analog_set_echocanceller(p, 0);
    					res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_DIALRECALL);
    
    						ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
    
    					analog_set_new_owner(p, chan);
    					p->ss_astchan = chan;
    
    					if (ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, p)) {
    
    						ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
    						res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
    						analog_set_echocanceller(p, 1);
    						ast_hangup(chan);
    					} else {
    
    						ast_verb(3, "Started three way call on channel %d\n", p->channel);
    
    						/* Start music on hold if appropriate */
    						if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
    							ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
    								S_OR(p->mohsuggest, NULL),
    								!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
    						}
    					}
    
    					ast_callid_threadstorage_auto_clean(callid, callid_created);
    
    				}
    			} else {
    				/* Already have a 3 way call */
    
    				enum analog_sub orig_3way_sub;
    
    				/* Need to hold the lock for real-call, private, and 3-way call */
    				analog_lock_sub_owner(p, ANALOG_SUB_THREEWAY);
    				if (!p->subs[ANALOG_SUB_THREEWAY].owner) {
    					/*
    					 * The 3-way call dissappeared.
    					 * Let's just ignore this flash-hook.
    					 */
    					ast_log(LOG_NOTICE, "Whoa, the 3-way call disappeared.\n");
    					goto winkflashdone;
    				}
    				orig_3way_sub = ANALOG_SUB_THREEWAY;
    
    
    				if (p->subs[ANALOG_SUB_THREEWAY].inthreeway) {
    					/* Call is already up, drop the last person */
    					ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
    					/* If the primary call isn't answered yet, use it */
    
    					if ((ast_channel_state(p->subs[ANALOG_SUB_REAL].owner) != AST_STATE_UP) &&
    						(ast_channel_state(p->subs[ANALOG_SUB_THREEWAY].owner) == AST_STATE_UP)) {
    
    						/* Swap back -- we're dropping the real 3-way that isn't finished yet*/
    						analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
    
    						orig_3way_sub = ANALOG_SUB_REAL;
    
    						analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
    
    					}
    					/* Drop the last call and stop the conference */
    
    					ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p->subs[ANALOG_SUB_THREEWAY].owner));
    
    					ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
    
    					analog_set_inthreeway(p, ANALOG_SUB_REAL, 0);
    					analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
    
    				} else {
    					/* Lets see what we're up to */
    
    					if (((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) &&
    						(p->transfertobusy || (ast_channel_state(ast) != AST_STATE_BUSY))) {
    
    						ast_verb(3, "Building conference call with %s and %s\n",
    
    							ast_channel_name(p->subs[ANALOG_SUB_THREEWAY].owner),
    							ast_channel_name(p->subs[ANALOG_SUB_REAL].owner));
    
    						/* Put them in the threeway, and flip */
    
    						analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 1);
    						analog_set_inthreeway(p, ANALOG_SUB_REAL, 1);
    
    						if (ast_channel_state(ast) == AST_STATE_UP) {
    
    							analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
    
    							orig_3way_sub = ANALOG_SUB_REAL;
    
    						if (ast_bridged_channel(p->subs[orig_3way_sub].owner)) {
    							ast_queue_control(p->subs[orig_3way_sub].owner, AST_CONTROL_UNHOLD);
    
    						analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
    
    						ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[ANALOG_SUB_THREEWAY].owner));
    
    						analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
    
    						orig_3way_sub = ANALOG_SUB_REAL;
    
    						ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
    
    						analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
    
    						if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
    
    							ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
    
    				ast_channel_unlock(p->subs[orig_3way_sub].owner);
    
    			analog_update_conf(p);
    			break;
    		case ANALOG_SIG_EM:
    		case ANALOG_SIG_EM_E1:
    		case ANALOG_SIG_FEATD:
    		case ANALOG_SIG_SF:
    		case ANALOG_SIG_SFWINK:
    		case ANALOG_SIG_SF_FEATD:
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSGS:
    
    				ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
    
    				ast_debug(1, "Got wink in weird state %d on channel %d\n", ast_channel_state(ast), p->channel);
    
    			break;
    		case ANALOG_SIG_FEATDMF_TA:
    			switch (p->whichwink) {
    			case 0:
    
    				ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p->owner)->ani2,
    					S_COR(ast_channel_caller(p->owner)->ani.number.valid,
    						ast_channel_caller(p->owner)->ani.number.str, ""));
    
    				snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#",
    
    					ast_channel_caller(p->owner)->ani2,
    					S_COR(ast_channel_caller(p->owner)->ani.number.valid,
    						ast_channel_caller(p->owner)->ani.number.str, ""));
    
    				break;
    			case 1:
    				ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
    				break;
    			case 2:
    				ast_log(LOG_WARNING, "Received unexpected wink on channel of type ANALOG_SIG_FEATDMF_TA\n");
    				return NULL;
    			}
    			p->whichwink++;
    			/* Fall through */
    		case ANALOG_SIG_FEATDMF:
    		case ANALOG_SIG_E911:
    		case ANALOG_SIG_FGC_CAMAMF:
    		case ANALOG_SIG_FGC_CAMA:
    		case ANALOG_SIG_FEATB:
    		case ANALOG_SIG_SF_FEATDMF:
    		case ANALOG_SIG_SF_FEATB:
    
    		case ANALOG_SIG_EMWINK:
    			/* FGD MF and EMWINK *Must* wait for wink */
    
    			if (!ast_strlen_zero(p->dop.dialstr)) {
    				res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
    				if (res < 0) {
    					ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
    					p->dop.dialstr[0] = '\0';
    					return NULL;
    
    					ast_debug(1, "Sent deferred digit string on channel %d: %s\n", p->channel, p->dop.dialstr);
    
    			}
    			p->dop.dialstr[0] = '\0';
    			break;
    		default:
    
    			ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
    
    		}
    		break;
    	case ANALOG_EVENT_HOOKCOMPLETE:
    		if (p->inalarm) break;
    
    		if (analog_check_waitingfordt(p)) {
    			break;
    		}
    
    		switch (mysig) {
    		case ANALOG_SIG_FXSLS:  /* only interesting for FXS */
    		case ANALOG_SIG_FXSGS:
    		case ANALOG_SIG_FXSKS:
    		case ANALOG_SIG_EM:
    		case ANALOG_SIG_EM_E1:
    		case ANALOG_SIG_EMWINK:
    		case ANALOG_SIG_FEATD:
    		case ANALOG_SIG_SF:
    		case ANALOG_SIG_SFWINK:
    		case ANALOG_SIG_SF_FEATD:
    			if (!ast_strlen_zero(p->dop.dialstr)) {
    				res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
    				if (res < 0) {
    					ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
    					p->dop.dialstr[0] = '\0';
    					return NULL;
    
    					ast_debug(1, "Sent deferred digit string on channel %d: %s\n", p->channel, p->dop.dialstr);
    
    			}
    			p->dop.dialstr[0] = '\0';
    			p->dop.op = ANALOG_DIAL_OP_REPLACE;
    			break;
    		case ANALOG_SIG_FEATDMF:
    		case ANALOG_SIG_FEATDMF_TA:
    		case ANALOG_SIG_E911:
    		case ANALOG_SIG_FGC_CAMA:
    		case ANALOG_SIG_FGC_CAMAMF:
    		case ANALOG_SIG_FEATB:
    		case ANALOG_SIG_SF_FEATDMF:
    		case ANALOG_SIG_SF_FEATB:
    			ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
    			break;
    		default:
    			break;
    		}
    		break;
    	case ANALOG_EVENT_POLARITY:
    		/*
    
    		 * If we get a Polarity Switch event, this could be
    		 * due to line seizure, remote end connect or remote end disconnect.
    		 *
    		 * Check to see if we should change the polarity state and
    
    		 * mark the channel as UP or if this is an indication
    		 * of remote end disconnect.
    		 */
    
    		if (p->polarityonanswerdelay > 0) {
    			/* check if event is not too soon after OffHook or Answer */
    
    			if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
    
    				switch (ast_channel_state(ast)) {
    
    				case AST_STATE_DIALING:			/*!< Digits (or equivalent) have been dialed */
    				case AST_STATE_RINGING:			/*!< Remote end is ringing */
    					if (p->answeronpolarityswitch) {
    						ast_debug(1, "Answering on polarity switch! channel %d\n", p->channel);
    						ast_setstate(p->owner, AST_STATE_UP);
    						p->polarity = POLARITY_REV;
    						if (p->hanguponpolarityswitch) {
    							p->polaritydelaytv = ast_tvnow();
    						}
    					} else {
    						ast_debug(1, "Ignore Answer on polarity switch, channel %d\n", p->channel);
    					}
    					break;
    
    				case AST_STATE_UP:				/*!< Line is up */
    				case AST_STATE_RING:			/*!< Line is ringing */
    					if (p->hanguponpolarityswitch) {
    						ast_debug(1, "HangingUp on polarity switch! channel %d\n", p->channel);
    
    						ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
    
    						ast_channel_hangupcause_hash_set(ast, cause_code, data_size);
    
    						ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
    						p->polarity = POLARITY_IDLE;
    					} else {
    						ast_debug(1, "Ignore Hangup on polarity switch, channel %d\n", p->channel);
    					}
    					break;
    
    				case AST_STATE_DOWN:				/*!< Channel is down and available */
    				case AST_STATE_RESERVED:			/*!< Channel is down, but reserved */
    				case AST_STATE_OFFHOOK:				/*!< Channel is off hook */
    				case AST_STATE_BUSY:				/*!< Line is busy */
    				case AST_STATE_DIALING_OFFHOOK:		/*!< Digits (or equivalent) have been dialed while offhook */
    				case AST_STATE_PRERING:				/*!< Channel has detected an incoming call and is waiting for ring */
    				default:
    					if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
    
    						ast_debug(1, "Ignoring Polarity switch on channel %d, state %d\n", p->channel, ast_channel_state(ast));
    
    				/* event is too soon after OffHook or Answer */
    
    				switch (ast_channel_state(ast)) {
    
    				case AST_STATE_DIALING:		/*!< Digits (or equivalent) have been dialed */
    				case AST_STATE_RINGING:		/*!< Remote end is ringing */
    					if (p->answeronpolarityswitch) {
    
    						ast_debug(1, "Polarity switch detected but NOT answering (too close to OffHook event) on channel %d, state %d\n", p->channel, ast_channel_state(ast));
    
    					}
    					break;
    
    				case AST_STATE_UP:			/*!< Line is up */
    				case AST_STATE_RING:		/*!< Line is ringing */
    					if (p->hanguponpolarityswitch) {
    
    						ast_debug(1, "Polarity switch detected but NOT hanging up (too close to Answer event) on channel %d, state %d\n", p->channel, ast_channel_state(ast));
    
    				default:
    
    					if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
    
    						ast_debug(1, "Polarity switch detected (too close to previous event) on channel %d, state %d\n", p->channel, ast_channel_state(ast));
    
    		/* Added more log_debug information below to provide a better indication of what is going on */
    
    		ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64 "\n", p->channel, ast_channel_state(ast), p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
    
    		break;
    	default:
    		ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
    	}
    
    	return &p->subs[idx].f;
    
    }
    
    struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast)
    {
    	int res;
    
    	ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
    
    	idx = analog_get_index(ast, p, 1);
    	if (idx < 0) {
    		idx = ANALOG_SUB_REAL;
    
    	p->subs[idx].f.frametype = AST_FRAME_NULL;
    	p->subs[idx].f.datalen = 0;
    	p->subs[idx].f.samples = 0;
    	p->subs[idx].f.mallocd = 0;
    	p->subs[idx].f.offset = 0;
    	p->subs[idx].f.subclass.integer = 0;
    	p->subs[idx].f.delivery = ast_tv(0,0);
    	p->subs[idx].f.src = "dahdi_exception";
    	p->subs[idx].f.data.ptr = NULL;
    
    
    	if (!p->owner) {
    		/* If nobody owns us, absorb the event appropriately, otherwise
    		   we loop indefinitely.  This occurs when, during call waiting, the
    		   other end hangs up our channel so that it no longer exists, but we
    		   have neither FLASH'd nor ONHOOK'd to signify our desire to
    		   change to the other channel. */
    		res = analog_get_event(p);
    
    		/* Switch to real if there is one and this isn't something really silly... */
    		if ((res != ANALOG_EVENT_RINGEROFF) && (res != ANALOG_EVENT_RINGERON) &&
    			(res != ANALOG_EVENT_HOOKCOMPLETE)) {
    			ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
    
    			analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
    
    			if (p->owner && ast != p->owner) {
    				/*
    				 * Could this even happen?
    				 * Possible deadlock because we do not have the real-call lock.
    				 */
    				ast_log(LOG_WARNING, "Event %s on %s is not restored owner %s\n",
    
    					analog_event2str(res), ast_channel_name(ast), ast_channel_name(p->owner));
    
    			if (p->owner && ast_bridged_channel(p->owner)) {
    
    				ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
    
    		}
    		switch (res) {
    		case ANALOG_EVENT_ONHOOK:
    			analog_set_echocanceller(p, 0);
    			if (p->owner) {
    
    				ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
    
    				analog_ring(p);
    				analog_stop_callwait(p);
    
    				ast_log(LOG_WARNING, "Absorbed %s, but nobody is left!?!?\n",
    					analog_event2str(res));
    
    			analog_update_conf(p);
    			break;
    		case ANALOG_EVENT_RINGOFFHOOK:
    			analog_set_echocanceller(p, 1);
    			analog_off_hook(p);
    
    			if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
    
    				ast_queue_control(p->owner, AST_CONTROL_ANSWER);
    
    				analog_set_dialing(p, 0);
    
    			}
    			break;
    		case ANALOG_EVENT_HOOKCOMPLETE:
    		case ANALOG_EVENT_RINGERON:
    		case ANALOG_EVENT_RINGEROFF:
    			/* Do nothing */
    			break;
    		case ANALOG_EVENT_WINKFLASH:
    			gettimeofday(&p->flashtime, NULL);
    			if (p->owner) {
    
    				ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, ast_channel_name(p->owner));
    
    				if (ast_channel_state(p->owner) != AST_STATE_UP) {
    
    					ast_queue_control(p->owner, AST_CONTROL_ANSWER);
    
    					ast_setstate(p->owner, AST_STATE_UP);
    				}
    				analog_stop_callwait(p);
    
    				if (ast_bridged_channel(p->owner)) {
    
    					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
    
    				ast_log(LOG_WARNING, "Absorbed %s, but nobody is left!?!?\n",
    					analog_event2str(res));
    
    			analog_update_conf(p);
    			break;
    		default:
    			ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", analog_event2str(res));
    
    		f = &p->subs[idx].f;
    
    	ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast, 0), p->channel);
    
    	/* If it's not us, return NULL immediately */
    	if (ast != p->owner) {
    
    		ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
    
    		f = &p->subs[idx].f;
    
    	f = __analog_handle_event(p, ast);
    
    	if (!f) {
    		const char *name = ast_strdupa(ast_channel_name(ast));
    
    		/* Tell the CDR this DAHDI device hung up */
    		analog_unlock_private(p);
    		ast_channel_unlock(ast);
    		ast_set_hangupsource(ast, name, 0);
    		ast_channel_lock(ast);
    		analog_lock_private(p);
    	}
    
    void *analog_handle_init_event(struct analog_pvt *i, int event)
    
    {
    	int res;
    	pthread_t threadid;
    	struct ast_channel *chan;
    
    	struct ast_callid *callid = NULL;
    	int callid_created;
    
    
    	ast_debug(1, "channel (%d) - signaling (%d) - event (%s)\n",
    				i->channel, i->sig, analog_event2str(event));
    
    	/* Handle an event on a given channel for the monitor thread. */
    	switch (event) {
    	case ANALOG_EVENT_WINKFLASH:
    	case ANALOG_EVENT_RINGOFFHOOK:
    
    		/* Got a ring/answer.  What kind of channel are we? */
    		switch (i->sig) {
    		case ANALOG_SIG_FXOLS:
    		case ANALOG_SIG_FXOGS:
    		case ANALOG_SIG_FXOKS:
    			res = analog_off_hook(i);
    
    			i->fxsoffhookstate = 1;
    
    			if (res && (errno == EBUSY)) {
    
    			callid_created = ast_callid_threadstorage_auto(&callid);
    
    
    			/* Cancel VMWI spill */
    
    			analog_cancel_cidspill(i);
    
    			if (i->immediate) {
    				analog_set_echocanceller(i, 1);
    				/* The channel is immediately up.  Start right away */
    				res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
    
    				chan = analog_new_ast_channel(i, AST_STATE_RING, 1, ANALOG_SUB_REAL, NULL);
    
    				if (!chan) {
    					ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
    					res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
    
    						ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
    
    				}
    			} else {
    				/* Check for callerid, digits, etc */
    
    				chan = analog_new_ast_channel(i, AST_STATE_RESERVED, 0, ANALOG_SUB_REAL, NULL);
    
    				i->ss_astchan = chan;
    				if (chan) {
    
    					if (analog_has_voicemail(i)) {
    
    						res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_STUTTER);
    
    						res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_DIALTONE);
    
    					if (res < 0)
    						ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
    
    
    					if (ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
    
    						ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
    						res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
    
    							ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
    
    						ast_hangup(chan);
    					}
    				} else
    					ast_log(LOG_WARNING, "Unable to create channel\n");
    			}
    
    			ast_callid_threadstorage_auto_clean(callid, callid_created);
    
    			break;
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSGS:
    		case ANALOG_SIG_FXSKS:
    
    			analog_set_ringtimeout(i, i->ringt_base);
    			/* Fall through */
    
    		case ANALOG_SIG_EMWINK:
    		case ANALOG_SIG_FEATD:
    		case ANALOG_SIG_FEATDMF:
    		case ANALOG_SIG_FEATDMF_TA:
    		case ANALOG_SIG_E911:
    		case ANALOG_SIG_FGC_CAMA:
    		case ANALOG_SIG_FGC_CAMAMF:
    		case ANALOG_SIG_FEATB:
    		case ANALOG_SIG_EM:
    		case ANALOG_SIG_EM_E1:
    		case ANALOG_SIG_SFWINK:
    		case ANALOG_SIG_SF_FEATD:
    		case ANALOG_SIG_SF_FEATDMF:
    		case ANALOG_SIG_SF_FEATB:
    		case ANALOG_SIG_SF:
    
    			callid_created = ast_callid_threadstorage_auto(&callid);
    
    			/* Check for callerid, digits, etc */
    
    			if (i->cid_start == ANALOG_CID_START_POLARITY_IN || i->cid_start == ANALOG_CID_START_DTMF_NOALERT) {
    
    				chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
    			} else {
    				chan = analog_new_ast_channel(i, AST_STATE_RING, 0, ANALOG_SUB_REAL, NULL);
    			}
    			i->ss_astchan = chan;
    
    			if (!chan) {
    				ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
    			} else if (ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
    
    				ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
    				res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
    				if (res < 0) {
    					ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
    
    			ast_callid_threadstorage_auto_clean(callid, callid_created);
    
    		default:
    			ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", analog_sigtype_to_str(i->sig), i->channel);
    			res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
    
    			if (res < 0) {
    				ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
    			}
    
    		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
    		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
    			"Channel: %d\r\n", i->channel);
    
    		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;
    
    			/* Fall through */
    
    		case ANALOG_SIG_FEATD:
    		case ANALOG_SIG_FEATDMF:
    		case ANALOG_SIG_FEATDMF_TA:
    		case ANALOG_SIG_E911:
    		case ANALOG_SIG_FGC_CAMA:
    		case ANALOG_SIG_FGC_CAMAMF:
    		case ANALOG_SIG_FEATB:
    		case ANALOG_SIG_EM:
    		case ANALOG_SIG_EM_E1:
    		case ANALOG_SIG_EMWINK:
    		case ANALOG_SIG_SF_FEATD:
    		case ANALOG_SIG_SF_FEATDMF:
    		case ANALOG_SIG_SF_FEATB:
    		case ANALOG_SIG_SF:
    		case ANALOG_SIG_SFWINK:
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSGS:
    		case ANALOG_SIG_FXSKS:
    			analog_set_echocanceller(i, 0);
    			res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
    			analog_on_hook(i);
    			break;
    		case ANALOG_SIG_FXOKS:
    
    			i->fxsoffhookstate = 0;
    
    			analog_start_polarityswitch(i);
    
    			analog_set_echocanceller(i, 0);
    			/* Diddle the battery for the zhone */
    #ifdef ZHONE_HACK
    			analog_off_hook(i);
    			usleep(1);
    #endif
    			res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
    			analog_on_hook(i);
    			break;
    		default:
    			ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", analog_sigtype_to_str(i->sig), i->channel);
    			res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
    
    		}
    		break;
    	case ANALOG_EVENT_POLARITY:
    		switch (i->sig) {
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSKS:
    		case ANALOG_SIG_FXSGS:
    
    			callid_created = ast_callid_threadstorage_auto(&callid);
    
    			/* We have already got a PR before the channel was
    			   created, but it wasn't handled. We need polarity
    			   to be REV for remote hangup detection to work.
    			   At least in Spain */
    
    			if (i->hanguponpolarityswitch) {
    
    				i->polarity = POLARITY_REV;
    
    			if (i->cid_start == ANALOG_CID_START_POLARITY || i->cid_start == ANALOG_CID_START_POLARITY_IN) {
    				i->polarity = POLARITY_REV;
    
    				ast_verb(2, "Starting post polarity "
    					"CID detection on channel %d\n",
    					i->channel);
    
    				chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
    
    				if (!chan) {
    					ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
    				} else if (ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
    
    					ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
    
    			ast_callid_threadstorage_auto_clean(callid, callid_created);
    
    			break;
    		default:
    			ast_log(LOG_WARNING, "handle_init_event detected "
    				"polarity reversal on non-FXO (ANALOG_SIG_FXS) "
    				"interface %d\n", i->channel);
    
    	case ANALOG_EVENT_DTMFCID:
    		switch (i->sig) {
    
    		case ANALOG_SIG_FXSLS:
    		case ANALOG_SIG_FXSKS:
    		case ANALOG_SIG_FXSGS:
    
    			callid_created = ast_callid_threadstorage_auto(&callid);
    
    			if (i->cid_start == ANALOG_CID_START_DTMF_NOALERT) {
    				ast_verb(2, "Starting DTMF CID detection on channel %d\n",
    					i->channel);
    				chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
    				i->ss_astchan = chan;
    				if (!chan) {
    					ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
    				} else if (ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
    					ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
    
    			ast_callid_threadstorage_auto_clean(callid, callid_created);
    
    			break;
    		default:
    			ast_log(LOG_WARNING, "handle_init_event detected "
    				"dtmfcid generation event on non-FXO (ANALOG_SIG_FXS) "
    				"interface %d\n", i->channel);
    			break;
    
    	case ANALOG_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
    
    		ast_log(LOG_NOTICE, "Got ANALOG_EVENT_REMOVED. Destroying channel %d\n",
    
    			i->channel);
    		return i->chan_pvt;
    
    	case ANALOG_EVENT_NEONMWI_ACTIVE:
    		analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_ACTIVE);
    		break;
    	case ANALOG_EVENT_NEONMWI_INACTIVE:
    		analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_INACTIVE);
    		break;
    	}
    
    struct analog_pvt *analog_new(enum analog_sigtype signallingtype, void *private_data)
    
    {
    	struct analog_pvt *p;
    
    	p = ast_calloc(1, sizeof(*p));
    
    
    	p->outsigmod = ANALOG_SIG_NONE;
    	p->sig = signallingtype;
    	p->chan_pvt = private_data;
    
    	/* Some defaults for values */
    	p->cid_start = ANALOG_CID_START_RING;
    	p->cid_signalling = CID_SIG_BELL;
    	/* Sub real is assumed to always be alloc'd */
    	p->subs[ANALOG_SUB_REAL].allocd = 1;
    
    	return p;
    }
    
    
    /*!
     * \brief Delete the analog private structure.
    
     *
     * \param doomed Analog private structure to delete.
     *
     * \return Nothing
     */
    void analog_delete(struct analog_pvt *doomed)
    {
    	ast_free(doomed);
    }
    
    
    int analog_config_complete(struct analog_pvt *p)
    {
    	/* No call waiting on non FXS channels */
    
    	if ((p->sig != ANALOG_SIG_FXOKS) && (p->sig != ANALOG_SIG_FXOLS) && (p->sig != ANALOG_SIG_FXOGS)) {
    
    	analog_set_callwaiting(p, p->permcallwaiting);
    
    
    	return 0;
    }
    
    void analog_free(struct analog_pvt *p)
    {
    
    }
    
    /* called while dahdi_pvt is locked in dahdi_fixup */
    int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
    {