Skip to content
Snippets Groups Projects
channel.c 78.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	peerf = peer->nativeformats;
    
    	ast_mutex_unlock(&peer->lock);
    	ast_mutex_lock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	chanf = chan->nativeformats;
    
    	ast_mutex_unlock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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, };
    
    	int res = -1;
    	ast_mutex_lock(&original->lock);
    	while(ast_mutex_trylock(&clone->lock)) {
    		ast_mutex_unlock(&original->lock);
    		usleep(1);
    		ast_mutex_lock(&original->lock);
    	}
    
    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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
    			clone->name, clone->masqr->name);
    
    	} else {
    		original->masq = clone;
    		clone->masqr = original;
    		ast_queue_frame(original, &null);
    		ast_queue_frame(clone, &null);
    		ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
    		res = 0;
    	}
    	ast_mutex_unlock(&clone->lock);
    	ast_mutex_unlock(&original->lock);
    	return res;
    
    Mark Spencer's avatar
    Mark Spencer committed
    void ast_change_name(struct ast_channel *chan, char *newname)
    {
    	char tmp[256];
    
    	strncpy(tmp, chan->name, sizeof(tmp) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    int ast_do_masquerade(struct ast_channel *original)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int x,i;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res=0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_var_t *varptr;
    
    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_callerid tmpcid;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 
    
    Mark Spencer's avatar
    Mark Spencer committed
    	   while the features are nice, the cost is very high in terms of pure nastiness. XXX */
    
    
    	/* We need the clone's lock, too */
    	ast_mutex_lock(&clone->lock);
    
    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\nUniqueid: %s\r\n", newn, masqn, clone->uniqueid);
    	manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", orig, newn, original->uniqueid);
    
    	/* Swap the guts */	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 */
    	if (prev) {
    		prev->next = original->pvt->readq;
    		original->pvt->readq = clone->pvt->readq;
    		clone->pvt->readq = NULL;
    		if (original->pvt->alertpipe[1] > -1) {
    			for (i=0;i<x;i++)
    				write(original->pvt->alertpipe[1], &x, sizeof(x));
    		}
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	clone->_softhangup = AST_SOFTHANGUP_DEV;
    
    	/* And of course, so does our current state.  Note we need not
    	   call ast_setstate since the event manager doesn't really consider
    	   these separate.  We do this early so that the clone has the proper
    	   state of the original channel. */
    	origstate = original->_state;
    	original->_state = clone->_state;
    	clone->_state = origstate;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (clone->pvt->fixup){
    
    		res = clone->pvt->fixup(original, clone);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (res) 
    			ast_log(LOG_WARNING, "Fixup failed on channel %s, strange things may happen.\n", clone->name);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Start by disconnecting the original's physical side */
    	if (clone->pvt->hangup)
    		res = clone->pvt->hangup(clone);
    	if (res) {
    		ast_log(LOG_WARNING, "Hangup failed!  Strange things may happen!\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	snprintf(zombn, sizeof(zombn), "%s<ZOMBIE>", orig);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Mangle the name of the clone channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(clone->name, zombn, sizeof(clone->name) - 1);
    
    	manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", masqn, zombn, clone->uniqueid);
    
    	/* Keep the same language.  */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Update the type. */
    	original->type = clone->type;
    	/* Copy the FD's */
    
    	for (x=0;x<AST_MAX_FDS;x++) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		original->fds[x] = clone->fds[x];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Append variables from clone channel into original channel */
    
    	/* XXX Is this always correct?  We have to in order to keep MACROS working XXX */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	varptr = original->varshead.first;
    	if (varptr) {
    		while(varptr->entries.next) {
    			varptr = varptr->entries.next;
    		}
    		varptr->entries.next = clone->varshead.first;
    	} else {
    		original->varshead.first = clone->varshead.first;
    	}
    	clone->varshead.first = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Presense of ADSI capable CPE follows clone */
    	original->adsicpe = clone->adsicpe;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Bridge remains the same */
    	/* CDR fields remain the same */
    	/* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
    	/* Application and data remain the same */
    
    	/* Clone exception  becomes real one, as with fdno */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	original->exception = clone->exception;
    	original->fdno = clone->fdno;
    	/* Schedule context remains the same */
    	/* Stream stuff stays the same */
    
    	/* Keep the original state.  The fixup code will need to work with it most likely */
    
    	/* Just swap the whole structures, nevermind the allocations, they'll work themselves
    	   out. */
    	tmpcid = original->cid;
    	original->cid = clone->cid;
    	clone->cid = tmpcid;
    
    	/* Restore original timing file descriptor */
    	original->fds[AST_MAX_FDS - 2] = original->timingfd;
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Our native formats are different now */
    	original->nativeformats = clone->nativeformats;
    	
    
    	/* Context, extension, priority, app data, jump table,  remain the same */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* pvt switches.  pbx stays the same, as does next */
    	
    	/* Set the write format */
    
    	ast_set_write_format(original, wformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Set the read format */
    
    	ast_set_read_format(original, rformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	ast_log(LOG_DEBUG, "Putting channel %s in %d/%d formats\n", original->name, wformat, rformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Okay.  Last thing is to let the channel driver know about all this mess, so he
    	   can fix up everything as best as possible */
    	if (original->pvt->fixup) {
    
    		res = original->pvt->fixup(clone, original);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (res) {
    			ast_log(LOG_WARNING, "Driver for '%s' could not fixup channel %s\n",
    				original->type, original->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    		}
    	} else
    		ast_log(LOG_WARNING, "Driver '%s' does not have a fixup routine (for %s)!  Bad things may happen.\n",
    			original->type, original->name);
    
    	
    	/* Now, at this point, the "clone" channel is totally F'd up.  We mark it as
    	   a zombie so nothing tries to touch it.  If it's already been marked as a
    	   zombie, then free it now (since it already is considered invalid). */
    	if (clone->zombie) {
    		ast_log(LOG_DEBUG, "Destroying clone '%s'\n", clone->name);
    
    		ast_channel_free(clone);
    		manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
    	} else {
    		ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
    		clone->zombie=1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Signal any blocker */
    	if (original->blocking)
    		pthread_kill(original->blocker, SIGURG);
    
    	ast_log(LOG_DEBUG, "Done Masquerading %s (%d)\n",
    		original->name, original->_state);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    void ast_set_callerid(struct ast_channel *chan, const char *callerid, const char *calleridname, const char *ani)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (callerid) {
    
    		if (chan->cid.cid_num)
    			free(chan->cid.cid_num);
    		if (ast_strlen_zero(callerid))
    			chan->cid.cid_num = NULL;
    		else
    			chan->cid.cid_num = strdup(callerid);
    	}
    	if (calleridname) {
    		if (chan->cid.cid_name)
    			free(chan->cid.cid_name);
    		if (ast_strlen_zero(calleridname))
    			chan->cid.cid_name = NULL;
    		else
    			chan->cid.cid_name = strdup(calleridname);
    	}
    	if (ani) {
    		if (chan->cid.cid_ani)
    			free(chan->cid.cid_ani);
    		if (ast_strlen_zero(ani))
    			chan->cid.cid_ani = NULL;
    		else
    			chan->cid.cid_ani = strdup(ani);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	if (chan->cdr)
    		ast_cdr_setcid(chan->cdr, chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	manager_event(EVENT_FLAG_CALL, "Newcallerid", 
    				"Channel: %s\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    				"Callerid: %s\r\n"
    
    				"CalleridName: %s\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    				"Uniqueid: %s\r\n",
    
    				chan->name, chan->cid.cid_num ? 
    				chan->cid.cid_num : "<Unknown>",
    				chan->cid.cid_name ? 
    				chan->cid.cid_name : "<Unknown>",
    
    Mark Spencer's avatar
    Mark Spencer committed
    				chan->uniqueid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    int ast_setstate(struct ast_channel *chan, int state)
    {
    	if (chan->_state != state) {
    		int oldstate = chan->_state;
    		chan->_state = state;
    		if (oldstate == AST_STATE_DOWN) {
    
    			ast_device_state_changed(chan->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			manager_event(EVENT_FLAG_CALL, "Newchannel",
    			"Channel: %s\r\n"
    			"State: %s\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    			"Callerid: %s\r\n"
    
    			"CalleridName: %s\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    			"Uniqueid: %s\r\n",
    
    			chan->name, ast_state2str(chan->_state), 
    			chan->cid.cid_num ? chan->cid.cid_num : "<unknown>", 
    			chan->cid.cid_name ? chan->cid.cid_name : "<unknown>", 
    			chan->uniqueid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else {
    			manager_event(EVENT_FLAG_CALL, "Newstate", 
    				"Channel: %s\r\n"
    				"State: %s\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    				"Callerid: %s\r\n"
    
    				"CalleridName: %s\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    				"Uniqueid: %s\r\n",
    
    				chan->name, ast_state2str(chan->_state), 
    				chan->cid.cid_num ? chan->cid.cid_num : "<unknown>", 
    				chan->cid.cid_name ? chan->cid.cid_name : "<unknown>", 
    				chan->uniqueid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    static long tvdiff(struct timeval *now, struct timeval *then) 
    {
    
    	return (((now->tv_sec * 1000) + now->tv_usec / 1000) - ((then->tv_sec * 1000) + then->tv_usec / 1000));
    }
    
    
    struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
    {
    	struct ast_channel *bridged;
    	bridged = chan->_bridge;
    	if (bridged && bridged->pvt->bridged_channel) 
    		bridged = bridged->pvt->bridged_channel(chan, bridged);
    	return bridged;
    }
    
    
    static void bridge_playfile(struct ast_channel *chan, struct ast_channel *peer, char *sound, int remain) 
    
    	int res=0, min=0, sec=0,check=0;
    
    	check = ast_autoservice_start(peer);
    	if(check) 
    		return;
    
    
    	if (remain > 0) {
    		if (remain / 60 > 1) {
    
    			min = remain / 60;
    			sec = remain % 60;
    
    	if (!strcmp(sound,"timeleft")) {
    		res = ast_streamfile(chan, "vm-youhave", chan->language);
    
    		res = ast_waitstream(chan, "");
    
    		if (min) {
    			res = ast_say_number(chan, min, AST_DIGIT_ANY, chan->language, (char *) NULL);
    
    			res = ast_streamfile(chan, "queue-minutes", chan->language);
    
    		if (sec) {
    			res = ast_say_number(chan, sec, AST_DIGIT_ANY, chan->language, (char *) NULL);
    
    			res = ast_streamfile(chan, "queue-seconds", chan->language);
    
    	} else {
    		res = ast_streamfile(chan, sound, chan->language);
    
    int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) 
    {
    
    	/* Copy voice back and forth between the two channels.	Give the peer
    
    Mark Spencer's avatar
    Mark Spencer committed
    	   the ability to transfer calls with '#<extension' syntax. */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_channel *cs[3];
    	int to = -1;
    	struct ast_frame *f;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_channel *who = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int nativefailed=0;
    
    	int firstpass;
    
    	int o0nativeformats;
    	int o1nativeformats;
    
    	struct timeval start_time,precise_now;
    
    	long elapsed_ms=0, time_left_ms=0;
    	int playit=0, playitagain=1, first_time=1;
    
    	flags = (config->allowdisconnect_out||config->allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (config->allowdisconnect_in||config->allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	*fo = NULL;
    
    	firstpass = config->firstpass;
    	config->firstpass = 0;
    
    
    	/* timestamp */
    	gettimeofday(&start_time,NULL);
    	time_left_ms = config->timelimit;
    
    
    	if (config->play_to_caller && config->start_sound && firstpass)
    
    		bridge_playfile(c0,c1,config->start_sound,time_left_ms / 1000);
    
    	if (config->play_to_callee && config->start_sound && firstpass)
    
    		bridge_playfile(c1,c0,config->start_sound,time_left_ms / 1000);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Stop if we're a zombie or need a soft hangup */
    
    	if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	
    	/* Keep track of bridge */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	cs[0] = c0;
    	cs[1] = c1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	manager_event(EVENT_FLAG_CALL, "Link", 
    			"Channel1: %s\r\n"
    
    			"Channel2: %s\r\n"
    			"Uniqueid1: %s\r\n"
    			"Uniqueid2: %s\r\n",
    			c0->name, c1->name, c0->uniqueid, c1->uniqueid);
    
    	o1nativeformats = c1->nativeformats;
    	o0nativeformats = c0->nativeformats;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	for (/* ever */;;) {
    
    		if (config->timelimit) {
    
    			gettimeofday(&precise_now,NULL);
    			elapsed_ms = tvdiff(&precise_now,&start_time);
    			time_left_ms = config->timelimit - elapsed_ms;
    
    
    			if (playitagain && (config->play_to_caller || config->play_to_callee) && (config->play_warning && time_left_ms <= config->play_warning)) { 
    
    				/* narrowing down to the end */
    
    				if (config->warning_freq == 0) {
    
    					playit = 1;
    					first_time=0;
    					playitagain=0;
    
    				} else if (first_time) {
    
    				} else {
    					if ((time_left_ms % config->warning_freq) <= 50) {
    
    			if (time_left_ms <= 0) {
    				if (config->play_to_caller && config->end_sound)
    
    					bridge_playfile(c0,c1,config->end_sound,0);
    
    				if (config->play_to_callee && config->end_sound)
    
    					bridge_playfile(c1,c0,config->end_sound,0);
    
    Anthony Minessale II's avatar
    Anthony Minessale II committed
    				*fo = NULL;
    				if (who) *rc = who;
    				res = 0;
    
    			if (time_left_ms >= 5000 && playit) {
    				if (config->play_to_caller && config->warning_sound && config->play_warning)
    
    					bridge_playfile(c0,c1,config->warning_sound,time_left_ms / 1000);
    
    				if (config->play_to_callee && config->warning_sound && config->play_warning)
    
    					bridge_playfile(c1,c0,config->warning_sound,time_left_ms / 1000);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Stop if we're a zombie or need a soft hangup */
    
    		if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			*fo = NULL;
    			if (who) *rc = who;
    			res = 0;
    
    			ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",c0->name,c1->name,c0->zombie?"Yes":"No",ast_check_hangup(c0)?"Yes":"No",c1->zombie?"Yes":"No",ast_check_hangup(c1)?"Yes":"No");
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    		}
    
    		if (c0->pvt->bridge && config->timelimit==0 &&
    
    			(c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				/* Looks like they share a bridge code */
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (option_verbose > 2) 
    				ast_verbose(VERBOSE_PREFIX_3 "Attempting native bridge of %s and %s\n", c0->name, c1->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (!(res = c0->pvt->bridge(c0, c1, flags, fo, rc))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				manager_event(EVENT_FLAG_CALL, "Unlink", 
    					"Channel1: %s\r\n"
    
    					"Channel2: %s\r\n"
    					"Uniqueid1: %s\r\n"
    					"Uniqueid2: %s\r\n",
    					c0->name, c1->name, c0->uniqueid, c1->uniqueid);
    
    				ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n",c0->name ,c1->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return 0;
    			}
    			/* If they return non-zero then continue on normally.  Let "-2" mean don't worry about
    			   my not wanting to bridge */
    			if ((res != -2) && (res != -3))
    				ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
    			if (res != -3) nativefailed++;
    		}
    	
    
    		if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) || (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) &&
    
    Mark Spencer's avatar
    Mark Spencer committed
    			!(c0->generator || c1->generator))  {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (ast_channel_make_compatible(c0, c1)) {
    				ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				manager_event(EVENT_FLAG_CALL, "Unlink", 
    					"Channel1: %s\r\n"
    
    					"Channel2: %s\r\n"
    					"Uniqueid1: %s\r\n"
    					"Uniqueid2: %s\r\n",
    					c0->name, c1->name, c0->uniqueid, c1->uniqueid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return -1;
    			}
    
    			o0nativeformats = c0->nativeformats;
    			o1nativeformats = c1->nativeformats;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		who = ast_waitfor_n(cs, 2, &to);
    		if (!who) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_DEBUG, "Nobody there, continuing...\n"); 
    
    Mark Spencer's avatar
    Mark Spencer committed
    			continue;
    		}
    		f = ast_read(who);
    		if (!f) {
    			*fo = NULL;
    			*rc = who;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			res = 0;
    
    			ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
    			*fo = f;
    			*rc = who;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			res =  0;
    
    			ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		if ((f->frametype == AST_FRAME_VOICE) ||
    			(f->frametype == AST_FRAME_TEXT) ||
    			(f->frametype == AST_FRAME_VIDEO) || 
    			(f->frametype == AST_FRAME_IMAGE) ||
    			(f->frametype == AST_FRAME_DTMF)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if ((f->frametype == AST_FRAME_DTMF) && 
    				(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
    				if ((who == c0)) {
    					if  ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
    						*rc = c0;
    						*fo = f;
    						/* Take out of conference mode */
    						res = 0;
    
    Martin Pycko's avatar
    Martin Pycko committed
    						ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_0 on c0 (%s)\n",c0->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						break;
    					} else 
    						goto tackygoto;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				} else
    
    Mark Spencer's avatar
    Mark Spencer committed
    				if ((who == c1)) {
    					if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
    						*rc = c1;
    						*fo = f;
    						res =  0;
    
    Martin Pycko's avatar
    Martin Pycko committed
    						ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_1 on c1 (%s)\n",c1->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						break;
    					} else
    						goto tackygoto;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    			} else {
    #if 0
    				ast_log(LOG_DEBUG, "Read from %s\n", who->name);
    				if (who == last) 
    					ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
    				last = who;
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    tackygoto:
    
    Mark Spencer's avatar
    Mark Spencer committed
    				/* Don't copy packets if there is a generator on either one, since they're
    				   not supposed to be listening anyway */
    
    				if (who == c0) 
    					ast_write(c1, f);
    				else 
    					ast_write(c0, f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    			ast_frfree(f);
    		} else
    			ast_frfree(f);
    		/* Swap who gets priority */
    		cs[2] = cs[0];
    		cs[0] = cs[1];
    		cs[1] = cs[2];
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	manager_event(EVENT_FLAG_CALL, "Unlink", 
    					"Channel1: %s\r\n"
    
    					"Channel2: %s\r\n"
    					"Uniqueid1: %s\r\n"
    					"Uniqueid2: %s\r\n",
    					c0->name, c1->name, c0->uniqueid, c1->uniqueid);
    
    	ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n",c0->name,c1->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int datalen, int block)
    {
    	int res;
    	if (chan->pvt->setoption) {
    		res = chan->pvt->setoption(chan, option, data, datalen);
    		if (res < 0)
    			return res;
    	} else {
    		errno = ENOSYS;
    		return -1;
    	}
    	if (block) {
    		/* XXX Implement blocking -- just wait for our option frame reply, discarding
    		   intermediate packets. XXX */
    		ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n");
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct tonepair_def {
    	int freq1;
    	int freq2;
    	int duration;
    	int vol;
    };
    
    struct tonepair_state {
    	float freq1;
    	float freq2;
    	float vol;
    	int duration;
    	int pos;
    	int origwfmt;
    	struct ast_frame f;
    	unsigned char offset[AST_FRIENDLY_OFFSET];
    	short data[4000];
    };
    
    static void tonepair_release(struct ast_channel *chan, void *params)
    {
    	struct tonepair_state *ts = params;
    	if (chan) {
    
    		ast_set_write_format(chan, ts->origwfmt);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	free(ts);
    }
    
    static void * tonepair_alloc(struct ast_channel *chan, void *params)
    {
    	struct tonepair_state *ts;
    	struct tonepair_def *td = params;
    	ts = malloc(sizeof(struct tonepair_state));
    	if (!ts)
    		return NULL;
    	memset(ts, 0, sizeof(struct tonepair_state));
    	ts->origwfmt = chan->writeformat;
    
    	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
    		tonepair_release(NULL, ts);
    		ts = NULL;
    	} else {
    		ts->freq1 = td->freq1;
    		ts->freq2 = td->freq2;
    		ts->duration = td->duration;
    		ts->vol = td->vol;
    	}
    	/* Let interrupts interrupt :) */
    	chan->writeinterrupt = 1;
    	return ts;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int tonepair_generator(struct ast_channel *chan, void *data, int len, int samples)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct tonepair_state *ts = data;
    	int x;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* we need to prepare a frame with 16 * timelen samples as we're 
    	 * generating SLIN audio
    	 */
    	len = samples * 2;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (len > sizeof(ts->data) / 2 - 1) {
    		ast_log(LOG_WARNING, "Can't generate that much data!\n");
    		return -1;
    	}
    	memset(&ts->f, 0, sizeof(ts->f));
    	for (x=0;x<len/2;x++) {
    		ts->data[x] = ts->vol * (
    				sin((ts->freq1 * 2.0 * M_PI / 8000.0) * (ts->pos + x)) +
    				sin((ts->freq2 * 2.0 * M_PI / 8000.0) * (ts->pos + x))
    			);
    	}
    	ts->f.frametype = AST_FRAME_VOICE;
    	ts->f.subclass = AST_FORMAT_SLINEAR;
    	ts->f.datalen = len;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ts->f.samples = samples;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ts->f.offset = AST_FRIENDLY_OFFSET;
    	ts->f.data = ts->data;
    	ast_write(chan, &ts->f);
    	ts->pos += x;
    	if (ts->duration > 0) {
    		if (ts->pos >= ts->duration * 8)
    			return -1;
    	}
    	return 0;
    }
    
    static struct ast_generator tonepair = {
    	alloc: tonepair_alloc,
    	release: tonepair_release,
    	generate: tonepair_generator,
    };
    
    int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
    {
    	struct tonepair_def d = { 0, };
    	d.freq1 = freq1;
    	d.freq2 = freq2;
    	d.duration = duration;
    	if (vol < 1)
    		d.vol = 8192;
    	else
    		d.vol = vol;
    	if (ast_activate_generator(chan, &tonepair, &d))
    		return -1;
    	return 0;
    }
    
    void ast_tonepair_stop(struct ast_channel *chan)
    {
    	ast_deactivate_generator(chan);
    }
    
    int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
    {
    	struct ast_frame *f;
    	int res;
    	if ((res = ast_tonepair_start(chan, freq1, freq2, duration, vol)))
    		return res;
    
    	/* Give us some wiggle room */
    	while(chan->generatordata && (ast_waitfor(chan, 100) >= 0)) {
    		f = ast_read(chan);
    		if (f)
    			ast_frfree(f);
    		else
    			return -1;
    	}
    	return 0;
    }
    
    unsigned int ast_get_group(char *s)
    {
    	char *copy;
    	char *piece;
    	char *c=NULL;
    	int start=0, finish=0,x;
    	unsigned int group = 0;
    	copy = ast_strdupa(s);
    	if (!copy) {
    		ast_log(LOG_ERROR, "Out of memory\n");
    		return 0;
    	}
    	c = copy;
    	
    	while((piece = strsep(&c, ","))) {
    		if (sscanf(piece, "%d-%d", &start, &finish) == 2) {
    			/* Range */
    		} else if (sscanf(piece, "%d", &start)) {
    			/* Just one */
    			finish = start;
    		} else {
    			ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'.  Using '0'\n", s,piece);
    			return 0;
    		}
    		for (x=start;x<=finish;x++) {
    			if ((x > 31) || (x < 0)) {
    
    				ast_log(LOG_WARNING, "Ignoring invalid group %d (maximum group is 31)\n", x);