Skip to content
Snippets Groups Projects
chan_misdn.c 104 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, AST_CID_P(ast));
    
      
    	strncpy(ast->exten,"s", 2);
      
    	if (ast_pbx_start(ast)<0) {
    		ast=NULL;
    
    		tone_indicate(ch,TONE_BUSY);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		if (bc->nt)
    
    			misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
    		else
    			misdn_lib_send_event(bc, EVENT_DISCONNECT );
    	}
      
      
    	while (!ast_strlen_zero(p) ) {
    		fr.frametype = AST_FRAME_DTMF;
    		fr.subclass = *p ;
    		fr.src=NULL;
    		fr.data = NULL ;
    		fr.datalen = 0;
    		fr.samples = 0 ;
    		fr.mallocd =0 ;
    		fr.offset= 0 ;
    
    		if (ch->ast && MISDN_ASTERISK_PVT(ch->ast) && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
    			ast_queue_frame(ch->ast, &fr);
    		}
    		p++;
    	}
    }
    
    
    
    
    static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc) {
    
    	
    	ast->hangupcause=bc->cause;
    	
    	switch ( bc->cause) {
    		
    	case 1: /** Congestion Cases **/
    	case 2:
    	case 3:
     	case 4:
     	case 22:
     	case 27:
    
    		/*
    		 * Not Queueing the Congestion anymore, since we want to hear
    		 * the inband message
    		 *
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		chan_misdn_log(1, bc?bc->port:0, " --> * SEND: Queue Congestion pid:%d\n", bc?bc->pid:-1);
    
    		
    		ast_queue_control(ast, AST_CONTROL_CONGESTION);
    
    		break;
    		
    	case 21:
    	case 17: /* user busy */
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		chan_misdn_log(1,  bc?bc->port:0, " --> * SEND: Queue Busy pid:%d\n", bc?bc->pid:-1);
    
    
    void import_ies(struct ast_channel *chan, struct misdn_bchannel *bc)
    {
    
    
    	tmp=pbx_builtin_getvar_helper(chan,"PRI_MODE");
    	if (tmp) bc->mode=atoi(tmp);
    
    	tmp=pbx_builtin_getvar_helper(chan,"PRI_URATE");
    	if (tmp) bc->urate=atoi(tmp);
    
    	tmp=pbx_builtin_getvar_helper(chan,"PRI_RATE");
    	if (tmp) bc->rate=atoi(tmp);
    
    	tmp=pbx_builtin_getvar_helper(chan,"PRI_USER1");
    	if (tmp) bc->user1=atoi(tmp);
    
    	
    	tmp=pbx_builtin_getvar_helper(chan,"RDNIS");
    	if (tmp) ast_copy_string(bc->rad,tmp,sizeof(bc->rad));
    	
    
    }
    
    void export_ies(struct ast_channel *chan, struct misdn_bchannel *bc)
    {
    	char tmp[32];
    	
    	sprintf(tmp,"%d",bc->mode);
    	pbx_builtin_setvar_helper(chan,"PRI_MODE",tmp);
    
    	sprintf(tmp,"%d",bc->urate);
    	pbx_builtin_setvar_helper(chan,"PRI_URATE",tmp);
    
    	sprintf(tmp,"%d",bc->rate);
    	pbx_builtin_setvar_helper(chan,"PRI_RATE",tmp);
    	
    	sprintf(tmp,"%d",bc->user1);
    	pbx_builtin_setvar_helper(chan,"PRI_USER1",tmp);
    
    	
    	pbx_builtin_setvar_helper(chan,"RDNIS",bc->rad);
    
    /************************************************************/
    /*  Receive Events from isdn_lib  here                     */
    /************************************************************/
    
    cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
    {
    	struct chan_list *ch=find_chan_by_bc(cl_te, bc);
    	
    	if (!ch)
    		ch=find_chan_by_l3id(cl_te, bc->l3_id);
    	
    
    	if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /*  Debug Only Non-Bchan */
    
    		chan_misdn_log(1, bc->port, "I IND :%s oad:%s dad:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad);
    
    		chan_misdn_log(2,bc->port," --> bc_state:%s\n",bc_state2str(bc->bc_state));
    
    	}
    	
    	if (event != EVENT_SETUP) {
    		if (!ch) {
    			if (event != EVENT_CLEANUP )
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				ast_log(LOG_WARNING, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n",bc->l3_id, bc, manager_isdn_get_info( event), bc->port,bc->channel);
    
    			return -1;
    		}
    	}
    	
    	if (ch ) {
    		switch (event) {
    		case EVENT_RELEASE:
    		case EVENT_RELEASE_COMPLETE:
    		case EVENT_CLEANUP:
    			break;
    		default:
    			if ( !ch->ast  || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
    				if (event!=EVENT_BCHAN_DATA)
    					ast_log(LOG_WARNING, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
    				return -1;
    			}
    		}
    	}
    	
    	
    	switch (event) {
    
    	case EVENT_NEW_L3ID:
    		ch->l3id=bc->l3_id;
    		break;
    
    	case EVENT_NEW_BC:
    		if (bc)
    			ch->bc=bc;
    		break;
    		
    	case EVENT_DTMF_TONE:
    	{
    		/*  sending INFOS as DTMF-Frames :) */
    		struct ast_frame fr;
    		memset(&fr, 0 , sizeof(fr));
    		fr.frametype = AST_FRAME_DTMF;
    		fr.subclass = bc->dtmf ;
    		fr.src=NULL;
    		fr.data = NULL ;
    		fr.datalen = 0;
    		fr.samples = 0 ;
    		fr.mallocd =0 ;
    		fr.offset= 0 ;
    		
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
    
    		
    		ast_queue_frame(ch->ast, &fr);
    	}
    	break;
    	case EVENT_STATUS:
    		break;
        
    	case EVENT_INFORMATION:
    	{
    		int stop_tone;
    		misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int));
    
    		if ( stop_tone ) {
    			tone_indicate(ch,TONE_NONE);
    
    		}
    		
    		if (ch->state == MISDN_WAITING4DIGS ) {
    			/*  Ok, incomplete Setup, waiting till extension exists */
    			{
    				int l = sizeof(bc->dad);
    				strncat(bc->dad,bc->info_dad, l);
    				bc->dad[l-1] = 0;
    			}
    			
    			
    			{
    				int l = sizeof(ch->ast->exten);
    				strncpy(ch->ast->exten, bc->dad, l);
    				ch->ast->exten[l-1] = 0;
    			}
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    /*			chan_misdn_log(5, bc->port, "Can Match Extension: dad:%s oad:%s\n",bc->dad,bc->oad);*/
    
    			/* Check for Pickup Request first */
    			if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
    				int ret;/** Sending SETUP_ACK**/
    				ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
    				if (ast_pickup_call(ch->ast)) {
    					ast_hangup(ch->ast);
    				} else {
    					struct ast_channel *chan=ch->ast;
    					ch->state = MISDN_CALLING_ACKNOWLEDGE;
    					ch->ast=NULL;
    					ast_setstate(chan, AST_STATE_DOWN);
    					ast_hangup(chan);
    					break;
    				}
    			}
    
    			
    			if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
    
    				chan_misdn_log(-1, bc->port, "Extension can never match, so disconnecting\n");
    
    				tone_indicate(ch,TONE_BUSY);
    
    				ch->state=MISDN_EXTCANTMATCH;
    				bc->out_cause=1;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				if (bc->nt)
    
    					misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
    				else
    					misdn_lib_send_event(bc, EVENT_DISCONNECT );
    				break;
    			}
    
    			if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
    
    				tone_indicate(ch,TONE_NONE);
    
    /*				chan_misdn_log(1, bc->port, " --> * Starting Ast ctx:%s\n", ch->context);*/
    
    				if (ast_pbx_start(ch->ast)<0) {
    
    
    					chan_misdn_log(-1, bc->port, "ast_pbx_start returned < 0 in INFO\n");
    
    					tone_indicate(ch,TONE_BUSY);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    					if (bc->nt)
    
    						misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
    					else
    						misdn_lib_send_event(bc, EVENT_DISCONNECT );
    				}
    			}
    	
    		} else {
    			/*  sending INFOS as DTMF-Frames :) */
    			struct ast_frame fr;
    			fr.frametype = AST_FRAME_DTMF;
    			fr.subclass = bc->info_dad[0] ;
    			fr.src=NULL;
    			fr.data = NULL ;
    			fr.datalen = 0;
    			fr.samples = 0 ;
    			fr.mallocd =0 ;
    			fr.offset= 0 ;
    
    			
    			int digits;
    			misdn_cfg_get( 0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(int));
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			if (ch->state != MISDN_CONNECTED ) {
    				if (digits) {
    
    					int l = sizeof(bc->dad);
    					strncat(bc->dad,bc->info_dad, l);
    					bc->dad[l-1] = 0;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    					l = sizeof(ch->ast->exten);
    
    					strncpy(ch->ast->exten, bc->dad, l);
    					ch->ast->exten[l-1] = 0;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    
    					ast_cdr_update(ch->ast);
    
    				}
    				
    				ast_queue_frame(ch->ast, &fr);
    			}
    			
    		}
    	}
    	break;
    	case EVENT_SETUP:
    	{
    		struct chan_list *ch=find_chan_by_bc(cl_te, bc);
    		if (ch && ch->state != MISDN_NOTHING ) {
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
    
    			return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE; /*  Ignore MSNs which are not in our List */
    		}
    	}
    	
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad);
    	if (!bc->nt && ! msn_valid) {
    		chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
    
    		return RESPONSE_IGNORE_SETUP; /*  Ignore MSNs which are not in our List */
    	}
    	
    	print_bearer(bc);
        
    	{
    		struct chan_list *ch=init_chan_list();
    		struct ast_channel *chan;
    
    
    		if (!ch) { chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n"); return 0;}
    
    		
    		ch->bc = bc;
    		ch->l3id=bc->l3_id;
    		ch->addr=bc->addr;
    		ch->orginator = ORG_MISDN;
    
    		chan=misdn_new(ch, AST_STATE_RESERVED,bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel);
    
    		ch->ast->rings=1;
    		ast_setstate(ch->ast, AST_STATE_RINGING);
    
    
    		if ( bc->pres ) {
    			chan->cid.cid_pres=AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
    		}  else {
    			chan->cid.cid_pres=AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
    		}
          
    		pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
    		chan->transfercapability=bc->capability;
    
    		switch (bc->capability) {
    		case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
    			pbx_builtin_setvar_helper(chan,"CALLTYPE","DIGITAL");
    			break;
    		default:
    			pbx_builtin_setvar_helper(chan,"CALLTYPE","SPEECH");
    		}
    
    		/** queue new chan **/
    		cl_queue_chan(&cl_te, ch) ;
    
    		
    		/* Check for Pickup Request first */
    		if (!strcmp(chan->exten, ast_pickup_ext())) {
    			int ret;/** Sending SETUP_ACK**/
    			ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
    			if (ast_pickup_call(chan)) {
    				ast_hangup(chan);
    			} else {
    				ch->state = MISDN_CALLING_ACKNOWLEDGE;
    				ch->ast=NULL;
    				ast_setstate(chan, AST_STATE_DOWN);
    				ast_hangup(chan);
    				break;
    			}
    		}
    
    		/*
    		  added support for s extension hope it will help those poor cretains
    		  which haven't overlap dial.
    		*/
    		{
    			int ai;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
    
    			if ( ai ) {
    				do_immediate_setup(bc, ch , chan);
    				break;
    			}
    			
    			
    
    		}
    
    		/* check if we should jump into s when we have no dad */
    		{
    			int im;
    			misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
    			if ( im && ast_strlen_zero(bc->dad) ) {
    				do_immediate_setup(bc, ch , chan);
    				break;
    			}
    
    			chan_misdn_log(5,bc->port,"CONTEXT:%s\n",ch->context);
    
    			if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
    			
    			chan_misdn_log(-1, bc->port, "Extension can never match, so disconnecting\n");
    
    
    			tone_indicate(ch,TONE_BUSY);
    
    			ch->state=MISDN_EXTCANTMATCH;
    			bc->out_cause=1;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			if (bc->nt)
    
    				misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
    			else
    				misdn_lib_send_event(bc, EVENT_DISCONNECT );
    			break;
    		}
    		
    
    		if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
    
    			ch->state=MISDN_DIALING;
    
    			if (bc->nt || (bc->need_more_infos && misdn_lib_is_ptp(bc->port)) ) {
    
    				int ret; 
    				ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
    			} else {
    				int ret;
    				ret= misdn_lib_send_event(bc, EVENT_PROCEEDING );
    			}
    	
    			if (ast_pbx_start(chan)<0) {
    
    
    				chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
    
    				tone_indicate(ch,TONE_BUSY);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				if (bc->nt)
    
    					misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
    				else
    					misdn_lib_send_event(bc, EVENT_DISCONNECT );
    			}
    		} else {
    			int ret= misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
    			if (ret == -ENOCHAN) {
    				ast_log(LOG_WARNING,"Channel was catched, before we could Acknowledge\n");
    				misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
    			}
    			/*  send tone to phone :) */
    
    			
    			int stop_tone;
    			misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int));
    			if ( (!ast_strlen_zero(bc->dad)) && stop_tone ) 
    
    				tone_indicate(ch,TONE_NONE);
    
    				tone_indicate(ch,TONE_DIAL);
    
    			ch->state=MISDN_WAITING4DIGS;
    		}
          
    	}
    	break;
    	case EVENT_SETUP_ACKNOWLEDGE:
    	{
    		ch->state = MISDN_CALLING_ACKNOWLEDGE;
    		if (!ast_strlen_zero(bc->infos_pending)) {
    			/* TX Pending Infos */
    			
    			{
    				int l = sizeof(bc->dad);
    				strncat(bc->dad,bc->infos_pending, l - strlen(bc->dad));
    				bc->dad[l-1] = 0;
    			}	
    			{
    				int l = sizeof(ch->ast->exten);
    				strncpy(ch->ast->exten, bc->dad, l);
    				ch->ast->exten[l-1] = 0;
    			}
    			{
    				int l = sizeof(bc->info_dad);
    				strncpy(bc->info_dad, bc->infos_pending, l);
    				bc->info_dad[l-1] = 0;
    			}
    			strncpy(bc->infos_pending,"", 1);
    
    			misdn_lib_send_event(bc, EVENT_INFORMATION);
    		}
    	}
    	break;
    	case EVENT_PROCEEDING:
    	{
    		
    		if ( misdn_cap_is_speech(bc->capability) &&
    		     misdn_inband_avail(bc) ) {
    			start_bc_tones(ch);
    		}
    
    		ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		if (!bc->nt ) {
    
    			if ( misdn_cap_is_speech(bc->capability) &&
    			     misdn_inband_avail(bc)
    				) {
    				start_bc_tones(ch);
    			}
    			
    			ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
    			
    			ch->state=MISDN_PROGRESS;
    		}
    		break;
    		
    		
    	case EVENT_ALERTING:
    	{
    		ch->state = MISDN_ALERTING;
    		
    
    		ast_queue_control(ch->ast, AST_CONTROL_RINGING);
    		ast_setstate(ch->ast, AST_STATE_RINGING);
    		
    		cb_log(1,bc->port,"Set State Ringing\n");
    		
    		if ( misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
    
    		misdn_lib_send_event(bc,EVENT_CONNECT_ACKNOWLEDGE);
    
    	
    		struct ast_channel *bridged=AST_BRIDGED_P(ch->ast);
    		
    		if (bridged && strcasecmp(bridged->tech->type,"mISDN")) {
    			struct chan_list *bridged_ch=MISDN_ASTERISK_TECH_PVT(bridged);
    
    			chan_misdn_log(1,bc->port," --> copying cpndialplan:%d and cad:%s to the A-Channel\n",bc->cpnnumplan,bc->cad);
    
    			bridged_ch->bc->cpnnumplan=bc->cpnnumplan;
    			ast_copy_string(bridged_ch->bc->cad,bc->cad,sizeof(bc->cad));
    		}
    	}
    
    
    	case EVENT_CONNECT_ACKNOWLEDGE:
    	{
    		ch->l3id=bc->l3_id;
    		ch->addr=bc->addr;
    		
    		start_bc_tones(ch);
    		
    		
    		ch->state = MISDN_CONNECTED;
    		ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
    	}
    	break;
    	case EVENT_DISCONNECT:
    	{
    		
    		struct chan_list *holded_ch=find_holded(cl_te, bc);
    		
    
    		
    		send_cause2ast(ch->ast,bc);
    
    		if (misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
    			/* If there's inband information available (e.g. a
    			   recorded message saying what was wrong with the
    			   dialled number, or perhaps even giving an
    			   alternative number, then play it instead of
    			   immediately releasing the call */
    
    			chan_misdn_log(0,bc->port, " --> Inband Info Avail, not sending RELEASE\n");
    			ch->state = MISDN_DISCONNECTED;
    
    			start_bc_tones(ch);
    			break;
    		}
    		
    		/*Check for holded channel, to implement transfer*/
    
    		if (holded_ch ) {
    			if  (ch->state == MISDN_CONNECTED ) {
    				misdn_transfer_bc(ch, holded_ch) ;
    				misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
    				break;
    			}
    		}
    
    		/*if (ch->state == MISDN_CONNECTED) 
    		misdn_lib_send_event(bc,EVENT_RELEASE);
    		else
    		misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
    		*/
    
    		misdn_lib_send_event(bc,EVENT_RELEASE);
    		
    	}
    	break;
    	
    	case EVENT_RELEASE:
    		{
    			
    			switch ( bc->cause) {
    				
    			case -1:
    				/*
    				  OK, it really sucks, this is a RELEASE from NT-Stack So we take
    				  it and return easylie, It seems that we've send a DISCONNECT
    				  before, so we should RELEASE_COMPLETE after that Disconnect
    				  (looks like ALERTING State at misdn_hangup !!
    				*/
    
    			/*stop_bc_tones(ch);
    			  release_chan(bc);*/
    			
    			misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
    
    		}
    		break;
    	case EVENT_RELEASE_COMPLETE:
    	{
    		stop_bc_tones(ch);
    		release_chan(bc);
    	}
    	break;
    
    		int tone_len=bc->tone_cnt;
    		struct ast_channel *ast=ch->ast;
    		void *tmp;
    		int res;
    		int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
    
    
    		chan_misdn_log(9,bc->port,"TONE_GEN: len:%d\n");
    
    		
    		if (!ast->generator) break;
    		
    		tmp = ast->generatordata;
    		ast->generatordata = NULL;
    		generate = ast->generator->generate;
    		res = generate(ast, tmp, tone_len, tone_len);
    		ast->generatordata = tmp;
    		if (res) {
    			ast_log(LOG_WARNING, "Auto-deactivating generator\n");
    			ast_deactivate_generator(ast);
    		} else {
    			bc->tone_cnt=0;
    		}
    		
    	}
    	break;
    
    		if ( !misdn_cap_is_speech(ch->bc->capability) || bc->nojitter) {
    			misdn_tx2ast_frm(ch, bc->bframe, bc->bframe_len );
    		} else {
    			int len=bc->bframe_len;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			int free=misdn_ibuf_freecount(bc->astbuf);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			if (bc->bframe_len > free) {
    
    				ast_log(LOG_DEBUG, "sbuf overflow!\n");
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				len=misdn_ibuf_freecount(bc->astbuf);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    
    				if (len == 0) {
    					ast_log(LOG_WARNING, "BCHAN_DATA: write buffer overflow port:%d channel:%d!\n",bc->port,bc->channel);
    				}
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			misdn_ibuf_memcpy_w(bc->astbuf, bc->bframe, len);
    
    			
    			{
    				char blah[1]="\0";
    #ifdef FLATTEN_JITTER
    				{
    					struct timeval tv;
    					gettimeofday(&tv,NULL);
    					
    					if (tv.tv_usec % 10000 > 0 ) {
    						write(ch->pipe[1], blah,sizeof(blah));
    						bc->time_usec=tv.tv_usec;
    					}
    				}
    #else
    				write(ch->pipe[1], blah,sizeof(blah));
    #endif
    				
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				
    
    
    		misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
    		break;
    
    		{
    			switch (ch->state) {
    			case MISDN_CALLING:
    
    
    				chan_misdn_log(-1, bc?bc->port:0, "GOT TIMOUT AT CALING pid:%d\n", bc?bc->pid:-1);
    
    					break;
    			case MISDN_DIALING:
    			case MISDN_PROGRESS:
    				break;
    			default:
    				misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
    			}
    		}
    		break;
    	case EVENT_CLEANUP:
    	{
    		stop_bc_tones(ch);
    		release_chan(bc);
    	}
    	break;
        
    	/***************************/
    	/** Suplementary Services **/
    	/***************************/
    	case EVENT_RETRIEVE:
    	{
    		struct ast_channel *hold_ast=AST_BRIDGED_P(ch->ast);
    		ch->state = MISDN_CONNECTED;
    		
    		if (hold_ast) {
    			ast_moh_stop(hold_ast);
    		}
    		
    		if ( misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0)
    			misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
    		
    		
    	}
    	break;
        
    	case EVENT_HOLD:
    	{
    		int hold_allowed;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		misdn_cfg_get( bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(int));
    
    
    			chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
    
    			misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
    			break;
    		}
    
    
    		{
    			struct chan_list *holded_ch=find_holded(cl_te, bc);
    			if (holded_ch) {
    				misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
    
    
    				chan_misdn_log(-1, bc->port, "We can't use RETRIEVE at the moment due to mISDN bug!\n");
    
    		struct ast_channel *bridged=AST_BRIDGED_P(ch->ast);
    
    		if (bridged){
    			struct chan_list *bridged_ch=MISDN_ASTERISK_TECH_PVT(bridged);
    
    			ch->state = MISDN_HOLDED;
    			ch->l3id = bc->l3_id;
    			
    
    			bc->holded_bc=bridged_ch->bc;
    
    			misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
    
    
    			ast_moh_start(bridged, NULL);
    
    		} else {
    			misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
    
    	
    	case EVENT_FACILITY:
    		print_facility(bc);
    		
    		switch (bc->fac_type) {
    		case FACILITY_CALLDEFLECT:
    		{
    			struct ast_channel *bridged=AST_BRIDGED_P(ch->ast);
    			struct chan_list *ch;
    			
    			if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
    				ch=MISDN_ASTERISK_TECH_PVT(bridged);
    				//ch->state=MISDN_FACILITY_DEFLECTED;
    				if (ch->bc) {
    					/* todo */
    				}
    				
    			}
    			
    		} 
    		
    		break;
    		default:
    
    			chan_misdn_log(1, bc->port," --> not yet handled\n");
    
    	default:
    		ast_log(LOG_WARNING, "Got Unknown Event\n");
    		break;
    	}
    	
    	return RESPONSE_OK;
    }
    
    /** TE STUFF END **/
    
    /******************************************
     *
     *   Asterisk Channel Endpoint END
     *
     *
     *******************************************/
    
    
    
    
    int load_module(void)
    {
    	int i;
    	
    	char ports[256]="";
    	
    	max_ports=misdn_lib_maxports_get();
    	
    	if (max_ports<=0) {
    		ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
    		return -1;
    	}
    	
    	
    	misdn_cfg_init(max_ports);
    	g_config_initialized=1;
    	
    	misdn_debug = (int *)malloc(sizeof(int) * (max_ports+1));
    	misdn_cfg_get( 0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(int));
    	for (i = 1; i <= max_ports; i++)
    		misdn_debug[i] = misdn_debug[0];
    	misdn_debug_only = (int *)calloc(max_ports + 1, sizeof(int));
    
    	
    	{
    
    		char tempbuf[BUFFERSIZE+1];
    
    		misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, tempbuf, BUFFERSIZE);
    		if (strlen(tempbuf))
    			tracing = 1;
    	}
    
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	ast_mutex_init(&cl_te_lock);
    	ast_mutex_init(&release_lock_mutex);
    
    	misdn_cfg_get_ports_string(ports);
    
    	if (strlen(ports))
    		chan_misdn_log(0, 0, "Got: %s from get_ports\n",ports);
    	
    	{
    		struct misdn_lib_iface iface = {
    			.cb_event = cb_events,
    			.cb_log = chan_misdn_log,
    
    		};
    		if (misdn_lib_init(ports, &iface, NULL))
    			chan_misdn_log(0, 0, "No te ports initialized\n");
    	}
    
    
    	{
    		if (ast_channel_register(&misdn_tech)) {
    
    			ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
    
    			unload_module();
    			return -1;
    		}
    	}
      
    	ast_cli_register(&cli_send_display);
    	ast_cli_register(&cli_send_cd);
    	ast_cli_register(&cli_send_digit);
    	ast_cli_register(&cli_toggle_echocancel);
    	ast_cli_register(&cli_set_tics);
    
    	ast_cli_register(&cli_show_cls);
    	ast_cli_register(&cli_show_cl);
    	ast_cli_register(&cli_show_config);
    	ast_cli_register(&cli_show_port);
    	ast_cli_register(&cli_show_stacks);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    
    
    	ast_cli_register(&cli_restart_port);
    	ast_cli_register(&cli_port_up);
    
    	ast_cli_register(&cli_set_debug);
    	ast_cli_register(&cli_set_crypt_debug);
    	ast_cli_register(&cli_reload);
    
      
    	ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_flags",
    				 "misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n"
    				 "Sets mISDN opts. and optargs\n"
    				 "\n"
    		);
    
    	
    	ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
    				 "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
    				 "Sends the Facility Message FACILITY_TYPE with \n"
    				 "the given Arguments to the current ISDN Channel\n"
    				 "Supported Facilities are:\n"
    				 "\n"
    				 "type=calldeflect args=Nr where to deflect\n"
    				 "\n"
    		);
    
    
    
    	misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
    	
    
    	chan_misdn_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n");
    
    	return 0;
    }
    
    
    
    int unload_module(void)
    {
    	/* First, take us out of the channel loop */
    
    	ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
    	
    
    	if (!g_config_initialized) return 0;
    	
    	ast_cli_unregister(&cli_send_display);
    	
    	ast_cli_unregister(&cli_send_cd);
    	
    	ast_cli_unregister(&cli_send_digit);
    	ast_cli_unregister(&cli_toggle_echocancel);
    	ast_cli_unregister(&cli_set_tics);
      
    	ast_cli_unregister(&cli_show_cls);
    	ast_cli_unregister(&cli_show_cl);
    	ast_cli_unregister(&cli_show_config);
    	ast_cli_unregister(&cli_show_port);
    	ast_cli_unregister(&cli_show_stacks);
    	ast_cli_unregister(&cli_restart_port);
    	ast_cli_unregister(&cli_port_up);
    
    	ast_cli_unregister(&cli_set_debug);
    	ast_cli_unregister(&cli_set_crypt_debug);
    	ast_cli_unregister(&cli_reload);
    	/* ast_unregister_application("misdn_crypt"); */
    	ast_unregister_application("misdn_set_opt");
    	ast_unregister_application("misdn_facility");
      
    	ast_channel_unregister(&misdn_tech);
    
    
    	free_robin_list();
    	misdn_cfg_destroy();
    	misdn_lib_destroy();
      
    	if (misdn_debug)
    		free(misdn_debug);
    	if (misdn_debug_only)
    		free(misdn_debug_only);
    	
    	return 0;
    }
    
    
    int reload(void)
    {
    	reload_config();
    
    	return 0;
    }
    
    
    int usecount(void)
    {
    	int res;
    	ast_mutex_lock(&usecnt_lock);
    	res = usecnt;
    	ast_mutex_unlock(&usecnt_lock);
    	return res;
    }
    
    char *description(void)