Skip to content
Snippets Groups Projects
channel.c 65.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    	static struct ast_frame null_frame = 
    	{
    		AST_FRAME_NULL,
    	};
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan->masq) {
    		if (ast_do_masquerade(chan)) {
    			ast_log(LOG_WARNING, "Failed to perform masquerade\n");
    			f = NULL;
    		} else
    			f =  &null_frame;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return f;
    	}
    
    	/* Stop if we're a zombie or need a soft hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan->zombie || ast_check_hangup(chan)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (chan->generator)
    			ast_deactivate_generator(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return NULL;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!chan->deferdtmf && strlen(chan->dtmfq)) {
    		/* We have DTMF that has been deferred.  Return it now */
    		chan->dtmff.frametype = AST_FRAME_DTMF;
    		chan->dtmff.subclass = chan->dtmfq[0];
    		/* Drop first digit */
    		memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return &chan->dtmff;
    	}
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Read and ignore anything on the alertpipe, but read only
    	   one sizeof(blah) per frame that we send from it */
    	if (chan->pvt->alertpipe[0] > -1) {
    		read(chan->pvt->alertpipe[0], &blah, sizeof(blah));
    	}
    
    #ifdef ZAPTEL_OPTIMIZATIONS
    	if ((chan->timingfd > -1) && (chan->fdno == AST_MAX_FDS - 2) && chan->exception) {
    		chan->exception = 0;
    		blah = -1;
    		ioctl(chan->timingfd, ZT_TIMERACK, &blah);
    
    		func = chan->timingfunc;
    		data = chan->timingdata;
    
    #if 0
    			ast_log(LOG_DEBUG, "Calling private function\n");
    #endif			
    
    			ioctl(chan->timingfd, ZT_TIMERCONFIG, &blah);
    
    			chan->timingdata = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Check for pending read queue */
    	if (chan->pvt->readq) {
    		f = chan->pvt->readq;
    		chan->pvt->readq = f->next;
    		/* Interpret hangup and return NULL */
    
    		if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
    			ast_frfree(f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			f = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		chan->blocker = pthread_self();
    		if (chan->exception) {
    			if (chan->pvt->exception) 
    				f = chan->pvt->exception(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			else {
    				ast_log(LOG_WARNING, "Exception flag set on '%s', but no exception handler\n", chan->name);
    				f = &null_frame;
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Clear the exception flag */
    			chan->exception = 0;
    		} else
    		if (chan->pvt->read)
    			f = chan->pvt->read(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		else
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
    	}
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (f && (f->frametype == AST_FRAME_VOICE)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!(f->subclass & chan->nativeformats)) {
    			/* This frame can't be from the current native formats -- drop it on the
    			   floor */
    
    			ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n", chan->name, ast_getformatname(f->subclass), ast_getformatname(chan->nativeformats));
    
    			ast_frfree(f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			f = &null_frame;
    
    		} else {
    			if (chan->monitor && chan->monitor->read_stream ) {
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    #ifndef MONITOR_CONSTANT_DELAY
    				int jump = chan->outsmpl - chan->insmpl - 2 * f->samples;
    				if (jump >= 0) {
    					if (ast_seekstream(chan->monitor->read_stream, jump + f->samples, SEEK_FORCECUR) == -1)
    						ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
    					chan->insmpl += jump + 2 * f->samples;
    				} else
    					chan->insmpl+= f->samples;
    #else
    				int jump = chan->outsmpl - chan->insmpl;
    				if (jump - MONITOR_DELAY >= 0) {
    					if (ast_seekstream(chan->monitor->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
    						ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
    					chan->insmpl += jump;
    				} else
    					chan->insmpl += f->samples;
    #endif
    				if (ast_writestream(chan->monitor->read_stream, f) < 0)
    
    					ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
    			}
    			if (chan->pvt->readtrans) {
    				f = ast_translate(chan->pvt->readtrans, f, 1);
    				if (!f)
    					f = &null_frame;
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Make sure we always return NULL in the future */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!f) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		chan->_softhangup |= AST_SOFTHANGUP_DEV;
    		if (chan->generator)
    			ast_deactivate_generator(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* End the CDR if appropriate */
    		if (chan->cdr)
    			ast_cdr_end(chan->cdr);
    	} else if (chan->deferdtmf && f->frametype == AST_FRAME_DTMF) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
    			chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
    		else
    			ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
    		f = &null_frame;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
    		/* Answer the CDR */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_setstate(chan, AST_STATE_UP);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_cdr_answer(chan->cdr);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Run any generator sitting on the line */
    	if (f && (f->frametype == AST_FRAME_VOICE) && chan->generatordata) {
    		/* Mask generator data temporarily */
    		void *tmp;
    		int res;
    		tmp = chan->generatordata;
    		chan->generatordata = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = chan->generator->generate(chan, tmp, f->datalen, f->samples);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		chan->generatordata = tmp;
    		if (res) {
    			ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
    			ast_deactivate_generator(chan);
    		}
    	}
    
    	if (chan->fin & 0x80000000)
    		ast_frame_dump(chan->name, f, "<<");
    	if ((chan->fin & 0x7fffffff) == 0x7fffffff)
    		chan->fin &= 0x80000000;
    	else
    		chan->fin++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return f;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_indicate(struct ast_channel *chan, int condition)
    {
    	int res = -1;
    	/* Stop if we're a zombie or need a soft hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan->zombie || ast_check_hangup(chan)) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    	ast_mutex_lock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan->pvt->indicate)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = chan->pvt->indicate(chan, condition);
    
    	ast_mutex_unlock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!chan->pvt->indicate || res) {
    		/*
    		 * Device does not support (that) indication, lets fake
    		 * it by doing our own tone generation. (PM2002)
    		 */
    		if (condition >= 0) {
    			const struct tone_zone_sound *ts = NULL;
    			switch (condition) {
    			 case AST_CONTROL_RINGING:
    				ts = ast_get_indication_tone(chan->zone, "ring");
    				break;
    			 case AST_CONTROL_BUSY:
    				ts = ast_get_indication_tone(chan->zone, "busy");
    				break;
    			 case AST_CONTROL_CONGESTION:
    				ts = ast_get_indication_tone(chan->zone, "congestion");
    				break;
    			}
    			if (ts && ts->data[0]) {
    				ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
    
    				ast_playtones_start(chan,0,ts->data, 1);
    
    			} else if (condition == AST_CONTROL_PROGRESS) {
    				/* ast_playtones_stop(chan); */
    			} else {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				/* not handled */
    				ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    		}
    		else ast_playtones_stop(chan);
    	}
    
    	return res;
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_recvchar(struct ast_channel *chan, int timeout)
    {
    	int res,ourto,c;
    	struct ast_frame *f;
    	
    	ourto = timeout;
    	for(;;)
    	   {
    		if (ast_check_hangup(chan)) return -1;
    		res = ast_waitfor(chan,ourto);
    		if (res <= 0) /* if timeout */
    		   {
    			return 0;
    		   }
    		ourto = res;
    		f = ast_read(chan);
    		if (f == NULL) return -1; /* if hangup */
    		if ((f->frametype == AST_FRAME_CONTROL) &&
    		    (f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */
    		if (f->frametype == AST_FRAME_TEXT)  /* if a text frame */
    		   {
    			c = *((char *)f->data);  /* get the data */
    			ast_frfree(f);
    			return(c);
    		   }
    		ast_frfree(f);
    	}
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_sendtext(struct ast_channel *chan, char *text)
    {
    	int res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Stop if we're a zombie or need a soft hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan->zombie || ast_check_hangup(chan)) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	CHECK_BLOCKING(chan);
    	if (chan->pvt->send_text)
    		res = chan->pvt->send_text(chan, text);
    	chan->blocking = 0;
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int do_senddigit(struct ast_channel *chan, char digit)
    {
    	int res = -1;
    
    	if (chan->pvt->send_digit)
    		res = chan->pvt->send_digit(chan, digit);
    	if (!chan->pvt->send_digit || res) {
    		/*
    		 * Device does not support DTMF tones, lets fake
    		 * it by doing our own generation. (PM2002)
    		 */
    		static const char* dtmf_tones[] = {
    			"!941+1336/50,!0/50",	/* 0 */
    			"!697+1209/50,!0/50",	/* 1 */
    			"!697+1336/50,!0/50",	/* 2 */
    			"!697+1477/50,!0/50",	/* 3 */
    			"!770+1209/50,!0/50",	/* 4 */
    			"!770+1336/50,!0/50",	/* 5 */
    			"!770+1477/50,!0/50",	/* 6 */
    			"!852+1209/50,!0/50",	/* 7 */
    			"!852+1336/50,!0/50",	/* 8 */
    			"!852+1477/50,!0/50",	/* 9 */
    			"!697+1633/50,!0/50",	/* A */
    			"!770+1633/50,!0/50",	/* B */
    			"!852+1633/50,!0/50",	/* C */
    			"!941+1633/50,!0/50",	/* D */
    			"!941+1209/50,!0/50",	/* * */
    			"!941+1477/50,!0/50" };	/* # */
    		if (digit >= '0' && digit <='9')
    
    			ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		else if (digit >= 'A' && digit <= 'D')
    
    			ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		else if (digit == '*')
    
    			ast_playtones_start(chan,0,dtmf_tones[14], 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		else if (digit == '#')
    
    			ast_playtones_start(chan,0,dtmf_tones[15], 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		else {
    			/* not handled */
    			ast_log(LOG_WARNING, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
    			return -1;
    		}
    	}
    	return 0;
    }
    
    
    int ast_prod(struct ast_channel *chan)
    {
    	struct ast_frame a = { AST_FRAME_VOICE };
    	char nothing[128];
    	/* Send an empty audio frame to get things moving */
    	if (chan->_state != AST_STATE_UP) {
    
    		ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
    
    		a.subclass = chan->pvt->rawwriteformat;
    		a.data = nothing + AST_FRIENDLY_OFFSET;
    
    		if (ast_write(chan, &a))
    			ast_log(LOG_WARNING, "Prodding channel '%s' failed\n", chan->name);
    
    int ast_write_video(struct ast_channel *chan, struct ast_frame *fr)
    {
    	int res;
    	if (!chan->pvt->write_video)
    		return 0;
    	res = ast_write(chan, fr);
    	if (!res)
    		res = 1;
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_write(struct ast_channel *chan, struct ast_frame *fr)
    {
    	int res = -1;
    
    	struct ast_frame *f = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Stop if we're a zombie or need a soft hangup */
    
    	if (chan->zombie || ast_check_hangup(chan))  {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Handle any pending masquerades */
    	if (chan->masq) {
    		if (ast_do_masquerade(chan)) {
    			ast_log(LOG_WARNING, "Failed to perform masquerade\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    		}
    	}
    
    	if (chan->masqr) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan->generatordata) {
    		if (chan->writeinterrupt)
    			ast_deactivate_generator(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return 0;
    
    	if (chan->fout & 0x80000000)
    		ast_frame_dump(chan->name, fr, ">>");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	CHECK_BLOCKING(chan);
    	switch(fr->frametype) {
    	case AST_FRAME_CONTROL:
    		/* XXX Interpret control frames XXX */
    		ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
    		break;
    	case AST_FRAME_DTMF:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		chan->blocking = 0;
    		ast_mutex_unlock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = do_senddigit(chan,fr->subclass);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_mutex_lock(&chan->lock);
    		CHECK_BLOCKING(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_FRAME_TEXT:
    		if (chan->pvt->send_text)
    			res = chan->pvt->send_text(chan, (char *) fr->data);
    		break;
    
    	case AST_FRAME_VIDEO:
    		/* XXX Handle translation of video codecs one day XXX */
    		if (chan->pvt->write_video)
    			res = chan->pvt->write_video(chan, fr);
    		else
    			res = 0;
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	default:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (chan->pvt->write) {
    			if (chan->pvt->writetrans) {
    
    				f = ast_translate(chan->pvt->writetrans, fr, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			} else
    				f = fr;
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    			if (f) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				res = chan->pvt->write(chan, f);
    
    				if( chan->monitor &&
    						chan->monitor->write_stream &&
    						f && ( f->frametype == AST_FRAME_VOICE ) ) {
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    #ifndef MONITOR_CONSTANT_DELAY
    					int jump = chan->insmpl - chan->outsmpl - 2 * f->samples;
    					if (jump >= 0) {
    						if (ast_seekstream(chan->monitor->write_stream, jump + f->samples, SEEK_FORCECUR) == -1)
    							ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
    						chan->outsmpl += jump + 2 * f->samples;
    					} else
    						chan->outsmpl += f->samples;
    #else
    					int jump = chan->insmpl - chan->outsmpl;
    					if (jump - MONITOR_DELAY >= 0) {
    						if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
    							ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
    						chan->outsmpl += jump;
    					} else
    						chan->outsmpl += f->samples;
    #endif
    				if (ast_writestream(chan->monitor->write_stream, f) < 0)
    
    						ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
    				}
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    			} else
    
    Mark Spencer's avatar
    Mark Spencer committed
    				res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if (f && (f != fr))
    		ast_frfree(f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	chan->blocking = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Consider a write failure to force a soft hangup */
    	if (res < 0)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		chan->_softhangup |= AST_SOFTHANGUP_DEV;
    
    	else {
    		if ((chan->fout & 0x7fffffff) == 0x7fffffff)
    			chan->fout &= 0x80000000;
    		else
    			chan->fout++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		chan->fout++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_set_write_format(struct ast_channel *chan, int fmts)
    {
    	int fmt;
    	int native;
    	int res;
    	
    	native = chan->nativeformats;
    	fmt = fmts;
    	
    	res = ast_translator_best_choice(&native, &fmt);
    	if (res < 0) {
    
    		ast_log(LOG_NOTICE, "Unable to find a path from %s to %s\n",
    			ast_getformatname(fmts), ast_getformatname(chan->nativeformats));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	
    	/* Now we have a good choice for both.  We'll write using our native format. */
    	chan->pvt->rawwriteformat = native;
    	/* User perspective is fmt */
    	chan->writeformat = fmt;
    	/* Free any write translation we have right now */
    	if (chan->pvt->writetrans)
    		ast_translator_free_path(chan->pvt->writetrans);
    	/* Build a translation path from the user write format to the raw writing format */
    	chan->pvt->writetrans = ast_translator_build_path(chan->pvt->rawwriteformat, chan->writeformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (option_debug)
    
    		ast_log(LOG_DEBUG, "Set channel %s to write format %s\n", chan->name, ast_getformatname(chan->writeformat));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    int ast_set_read_format(struct ast_channel *chan, int fmts)
    {
    	int fmt;
    	int native;
    	int res;
    	
    	native = chan->nativeformats;
    	fmt = fmts;
    	/* Find a translation path from the native read format to one of the user's read formats */
    	res = ast_translator_best_choice(&fmt, &native);
    	if (res < 0) {
    
    		ast_log(LOG_NOTICE, "Unable to find a path from %s to %s\n",
    			ast_getformatname(chan->nativeformats), ast_getformatname(fmts));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	
    	/* Now we have a good choice for both.  We'll write using our native format. */
    	chan->pvt->rawreadformat = native;
    	/* User perspective is fmt */
    	chan->readformat = fmt;
    	/* Free any read translation we have right now */
    	if (chan->pvt->readtrans)
    		ast_translator_free_path(chan->pvt->readtrans);
    	/* Build a translation path from the raw read format to the user reading format */
    	chan->pvt->readtrans = ast_translator_build_path(chan->readformat, chan->pvt->rawreadformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (option_debug)
    
    		ast_log(LOG_DEBUG, "Set channel %s to read format %s\n", 
    			chan->name, ast_getformatname(chan->readformat));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    struct ast_channel *__ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate, char *callerid, struct outgoing_helper *oh)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int state = 0;
    	struct ast_channel *chan;
    	struct ast_frame *f;
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    	int res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	chan = ast_request(type, format, data);
    	if (chan) {
    
    		if (oh) {
    			char *tmp, *var;
    			/* JDG chanvar */
    			tmp = oh->variable;
    			/* FIXME replace this call with strsep  NOT*/
    			while( (var = strtok_r(NULL, "|", &tmp)) ) {
    				pbx_builtin_setvar( chan, var );
    			} /* /JDG */
    
    			if (oh->account && *oh->account)
    				ast_cdr_setaccount(chan, oh->account);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (callerid && strlen(callerid))
    			ast_set_callerid(chan, callerid, 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!ast_call(chan, data, 0)) {
    			while(timeout && (chan->_state != AST_STATE_UP)) {
    				res = ast_waitfor(chan, timeout);
    				if (res < 0) {
    					/* Something not cool, or timed out */
    					break;
    				}
    				/* If done, break out */
    				if (!res)
    					break;
    				if (timeout > -1)
    					timeout = res;
    				f = ast_read(chan);
    				if (!f) {
    					state = AST_CONTROL_HANGUP;
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    					res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    					break;
    				}
    				if (f->frametype == AST_FRAME_CONTROL) {
    					if (f->subclass == AST_CONTROL_RINGING)
    						state = AST_CONTROL_RINGING;
    					else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
    						state = f->subclass;
    
    						ast_frfree(f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						break;
    					} else if (f->subclass == AST_CONTROL_ANSWER) {
    						state = f->subclass;
    
    						ast_frfree(f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						break;
    					} else {
    						ast_log(LOG_NOTICE, "Don't know what to do with control frame %d\n", f->subclass);
    					}
    				}
    				ast_frfree(f);
    			}
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    		} else
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
    	} else
    		ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan) {
    		/* Final fixups */
    		if (oh) {
    			if (oh->context && *oh->context)
    				strncpy(chan->context, oh->context, sizeof(chan->context) - 1);
    			if (oh->exten && *oh->exten)
    				strncpy(chan->exten, oh->exten, sizeof(chan->exten) - 1);
    			chan->priority = oh->priority;
    		}
    		if (chan->_state == AST_STATE_UP) 
    			state = AST_CONTROL_ANSWER;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (outstate)
    		*outstate = state;
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    	if (chan && res <= 0) {
    		if (!chan->cdr) {
    			chan->cdr = ast_cdr_alloc();
    			if (chan->cdr)
    				ast_cdr_init(chan->cdr, chan);
    		}
    		if (chan->cdr) {
    			char tmp[256];
    			sprintf(tmp, "%s/%s",type,(char *)data);
    			ast_cdr_setapp(chan->cdr,"Dial",tmp);
    			ast_cdr_update(chan);
    			ast_cdr_start(chan->cdr);
    			ast_cdr_end(chan->cdr);
    			/* If the cause wasn't handled properly */
    			if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
    				ast_cdr_failed(chan->cdr);
    		} else 
    			ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
    		ast_hangup(chan);
    		chan = NULL;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return chan;
    }
    
    
    struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate, char *callerid)
    {
    	return __ast_request_and_dial(type, format, data, timeout, outstate, callerid, NULL);
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct ast_channel *ast_request(char *type, int format, void *data)
    {
    	struct chanlist *chan;
    	struct ast_channel *c = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int capabilities;
    	int fmt;
    	int res;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to lock channel list\n");
    		return NULL;
    	}
    	chan = backends;
    	while(chan) {
    		if (!strcasecmp(type, chan->type)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			capabilities = chan->capabilities;
    			fmt = format;
    			res = ast_translator_best_choice(&fmt, &capabilities);
    			if (res < 0) {
    				ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %d) to %d\n", type, chan->capabilities, format);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (chan->requester)
    
    Mark Spencer's avatar
    Mark Spencer committed
    				c = chan->requester(type, capabilities, data);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (c) {
    
    				if (c->_state == AST_STATE_DOWN) {
    					manager_event(EVENT_FLAG_CALL, "Newchannel",
    					"Channel: %s\r\n"
    					"State: %s\r\n"
    					"Callerid: %s\r\n"
    					"Uniqueid: %s\r\n",
    					c->name, ast_state2str(c->_state), c->callerid ? c->callerid : "<unknown>", c->uniqueid);
    				}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return c;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		chan = chan->next;
    	}
    	if (!chan)
    		ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return c;
    }
    
    
    int ast_parse_device_state(char *device)
    {
    	char name[AST_CHANNEL_NAME] = "";
    	char *cut;
    	struct ast_channel *chan;
    
    	chan = ast_channel_walk(NULL);
    	while (chan) {
    		strncpy(name, chan->name, sizeof(name)-1);
    		cut = strchr(name,'-');
    		if (cut)
    		        *cut = 0;
    		if (!strcmp(name, device))
    		        return AST_DEVICE_INUSE;
    		chan = ast_channel_walk(chan);
    	}
    	return AST_DEVICE_UNKNOWN;
    }
    
    int ast_device_state(char *device)
    {
    	char tech[AST_MAX_EXTENSION] = "";
    	char *number;
    	struct chanlist *chanls;
    	int res = 0;
    	
    	strncpy(tech, device, sizeof(tech)-1);
    	number = strchr(tech, '/');
    	if (!number) {
    	    return AST_DEVICE_INVALID;
    	}
    	*number = 0;
    	number++;
    		
    
    		ast_log(LOG_WARNING, "Unable to lock channel list\n");
    		return -1;
    	}
    	chanls = backends;
    	while(chanls) {
    		if (!strcasecmp(tech, chanls->type)) {
    
    			if (!chanls->devicestate) 
    				return ast_parse_device_state(device);
    			else {
    				res = chanls->devicestate(number);
    				if (res == AST_DEVICE_UNKNOWN)
    					return ast_parse_device_state(device);
    				else
    					return res;
    			}
    		}
    		chanls = chanls->next;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_call(struct ast_channel *chan, char *addr, int timeout) 
    {
    	/* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
    	   If the remote end does not answer within the timeout, then do NOT hang up, but 
    	   return anyway.  */
    	int res = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Stop if we're a zombie or need a soft hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!chan->zombie && !ast_check_hangup(chan)) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (chan->pvt->call)
    			res = chan->pvt->call(chan, addr, timeout);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    int ast_transfer(struct ast_channel *chan, char *dest) 
    {
    	/* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
    	   If the remote end does not answer within the timeout, then do NOT hang up, but 
    	   return anyway.  */
    	int res = -1;
    	/* Stop if we're a zombie or need a soft hangup */
    
    	if (!chan->zombie && !ast_check_hangup(chan)) {
    		if (chan->pvt->transfer) {
    			res = chan->pvt->transfer(chan, dest);
    			if (!res)
    				res = 1;
    		} else
    			res = 0;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
    {
    	int pos=0;
    	int to = ftimeout;
    	char d;
    
    	/* XXX Merge with full version? XXX */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Stop if we're a zombie or need a soft hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (c->zombie || ast_check_hangup(c)) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!len)
    		return -1;
    	do {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (c->stream) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			d = ast_waitstream(c, AST_DIGIT_ANY);
    			ast_stopstream(c);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			usleep(1000);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (!d)
    				d = ast_waitfordigit(c, to);
    		} else {
    			d = ast_waitfordigit(c, to);
    		}
    		if (d < 0)
    			return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (d == 0) {
    			s[pos]='\0';
    			return 1;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!strchr(enders, d))
    			s[pos++] = d;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (strchr(enders, d) || (pos >= len)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			s[pos]='\0';
    
    			return 0;
    		}
    		to = timeout;
    	} while(1);
    	/* Never reached */
    	return 0;
    }
    
    int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders, int audiofd, int ctrlfd)
    {
    	int pos=0;
    	int to = ftimeout;
    	char d;
    	/* Stop if we're a zombie or need a soft hangup */
    	if (c->zombie || ast_check_hangup(c)) 
    		return -1;
    	if (!len)
    		return -1;
    	do {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (c->stream) {
    
    			d = ast_waitstream_full(c, AST_DIGIT_ANY, audiofd, ctrlfd);
    			ast_stopstream(c);
    			usleep(1000);
    			if (!d)
    				d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
    		} else {
    			d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
    		}
    		if (d < 0)
    			return -1;
    		if (d == 0) {
    			s[pos]='\0';
    			return 1;
    		}
    		if (d == 1) {
    			s[pos]='\0';
    			return 2;
    		}
    		if (!strchr(enders, d))
    			s[pos++] = d;
    		if (strchr(enders, d) || (pos >= len)) {
    			s[pos]='\0';
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return 0;
    		}
    		to = timeout;
    	} while(1);
    	/* Never reached */
    	return 0;
    }
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_channel_supports_html(struct ast_channel *chan)
    {
    	if (chan->pvt->send_html)
    		return 1;
    	return 0;
    }
    
    int ast_channel_sendhtml(struct ast_channel *chan, int subclass, char *data, int datalen)
    {
    	if (chan->pvt->send_html)
    		return chan->pvt->send_html(chan, subclass, data, datalen);
    	return -1;
    }
    
    int ast_channel_sendurl(struct ast_channel *chan, char *url)
    {
    	if (chan->pvt->send_html)
    		return chan->pvt->send_html(chan, AST_HTML_URL, url, strlen(url) + 1);
    	return -1;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
    {
    	int peerf;
    	int chanf;
    	int res;
    	peerf = peer->nativeformats;
    	chanf = chan->nativeformats;
    	res = ast_translator_best_choice(&peerf, &chanf);
    	if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, chan->nativeformats, peer->name, peer->nativeformats);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	/* Set read format on channel */
    	res = ast_set_read_format(chan, peerf);
    	if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan->name, chanf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	/* Set write format on peer channel */
    	res = ast_set_write_format(peer, peerf);
    	if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer->name, peerf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	/* Now we go the other way */
    	peerf = peer->nativeformats;
    	chanf = chan->nativeformats;
    	res = ast_translator_best_choice(&chanf, &peerf);
    	if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, peer->nativeformats, chan->name, chan->nativeformats);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	/* Set writeformat on channel */
    	res = ast_set_write_format(chan, chanf);
    	if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan->name, chanf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	/* Set read format on peer channel */
    	res = ast_set_read_format(peer, chanf);
    	if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer->name, peerf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
    {
    
    	struct ast_frame null = { AST_FRAME_NULL, };
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
    		clone->name, original->name);
    	if (original->masq) {
    		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
    			original->masq->name, original->name);
    		return -1;
    	}
    	if (clone->masqr) {
    		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
    			clone->name, clone->masqr->name);
    		return -1;
    	}
    	original->masq = clone;
    	clone->masqr = original;
    
    	/* XXX can't really hold the lock here, but at the same time, it' s
    	   not really safe not to XXX */
    	ast_queue_frame(original, &null, 0);
    
    	ast_queue_frame(clone, &null, 0);
    
    	ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    void ast_change_name(struct ast_channel *chan, char *newname)
    {
    	char tmp[256];
    	strncpy(tmp, chan->name, 256);
    	strncpy(chan->name, newname, sizeof(chan->name) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", tmp, chan->name, chan->uniqueid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int ast_do_masquerade(struct ast_channel *original)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int x,i;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res=0;
    	char *tmp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	void *tmpv;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_frame *cur, *prev;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_channel_pvt *p;
    	struct ast_channel *clone = original->masq;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int rformat = original->readformat;
    	int wformat = original->writeformat;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char newn[100];
    	char orig[100];
    	char masqn[100];
    	char zombn[100];
    
    Mark Spencer's avatar
    Mark Spencer committed
    #if 1
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
    
    Mark Spencer's avatar
    Mark Spencer committed
    		clone->name, clone->_state, original->name, original->_state);
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
    	   the clone channel into the original channel.  Start by killing off the original
    	   channel's backend.   I'm not sure we're going to keep this function, because 
    	   while the features are nice, the cost is very high in terms of pure nastiness. XXX */
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* We need the clone's lock, too */
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    	ast_log(LOG_DEBUG, "Got clone lock on '%s' at %p\n", clone->name, &clone->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Having remembered the original read/write formats, we turn off any translation on either
    	   one */
    	free_translation(clone);
    	free_translation(original);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Unlink the masquerade */
    	original->masq = NULL;
    	clone->masqr = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	/* Save the original name */
    	strncpy(orig, original->name, sizeof(orig) - 1);
    	/* Save the new name */
    	strncpy(newn, clone->name, sizeof(newn) - 1);
    	/* Create the masq name */
    	snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		
    	/* Copy the name from the clone channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(original->name, newn, sizeof(original->name)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Mangle the name of the clone channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(clone->name, masqn, sizeof(clone->name) - 1);
    	
    	/* Notify any managers of the change, first the masq then the other */
    	manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", newn, masqn);
    	manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", orig, newn);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Swap the guts */	
    	p = original->pvt;
    	original->pvt = clone->pvt;
    	clone->pvt = p;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Save any pending frames on both sides.  Start by counting
    	 * how many we're going to need... */
    	prev = NULL;
    	cur = clone->pvt->readq;
    	x = 0;
    	while(cur) {
    		x++;
    		prev = cur;
    		cur = cur->next;
    	}
    	/* If we had any, prepend them to the ones already in the queue, and 
    	 * load up the alertpipe */