Skip to content
Snippets Groups Projects
channel.c 89.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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->tech->type)) {
    			capabilities = chan->tech->capabilities;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			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->tech->capabilities, format);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    			if (chan->tech->requester)
    				c = chan->tech->requester(type, capabilities, data, cause);
    
    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"
    					"CallerIDName: %s\r\n"
    
    					"Uniqueid: %s\r\n",
    
    					c->name, ast_state2str(c->_state), c->cid.cid_num ? c->cid.cid_num : "<unknown>", c->cid.cid_name ? c->cid.cid_name : "<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;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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_locked(NULL);
    
    	while (chan) {
    		strncpy(name, chan->name, sizeof(name)-1);
    
    		ast_mutex_unlock(&chan->lock);
    
    		cut = strchr(name,'-');
    		if (cut)
    
    		        *cut = 0;
    
    		if (!strcmp(name, device))
    
    		        return AST_DEVICE_INUSE;
    
    		chan = ast_channel_walk_locked(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;
    
    		ast_log(LOG_WARNING, "Unable to lock channel list\n");
    		return -1;
    	}
    	chanls = backends;
    	while(chanls) {
    
    		if (!strcasecmp(tech, chanls->tech->type)) {
    
    				return ast_parse_device_state(device);
    			else {
    
    				res = chanls->tech->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 */
    
    	if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) 
    
    		if (chan->tech->call)
    			res = chan->tech->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 (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) {
    
    		if (chan->tech->transfer) {
    			res = chan->tech->transfer(chan, dest);
    
    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 */
    
    	if (ast_test_flag(c, AST_FLAG_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 (ast_test_flag(c, AST_FLAG_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)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 1;
    	return 0;
    }
    
    
    int ast_channel_sendhtml(struct ast_channel *chan, int subclass, const char *data, int datalen)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (chan->tech->send_html)
    		return chan->tech->send_html(chan, subclass, data, datalen);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return -1;
    }
    
    
    int ast_channel_sendurl(struct ast_channel *chan, const char *url)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (chan->tech->send_html)
    		return chan->tech->send_html(chan, AST_HTML_URL, url, strlen(url) + 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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, };
    
    	if (original == clone) {
    		ast_log(LOG_WARNING, "Can't masquerade channel '%s' into itself!\n", original->name);
    		return -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);
    
    void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
    {
    	struct ast_var_t *current, *newvar;
    	char *varname;
    
    	AST_LIST_TRAVERSE(&parent->varshead, current, entries) {
    		int vartype = 0;
    
    		varname = ast_var_full_name(current);
    		if (!varname)
    			continue;
    
    		if (varname[0] == '_') {
    			vartype = 1;
    			if (varname[1] == '_')
    				vartype = 2;
    		}
    
    		switch (vartype) {
    		case 1:
    			newvar = ast_var_assign(&varname[1], ast_var_value(current));
    			if (newvar) {
    				AST_LIST_INSERT_HEAD(&child->varshead, newvar, entries);
    				if (option_debug)
    					ast_log(LOG_DEBUG, "Copying soft-transferable variable %s.\n", ast_var_name(newvar));
    			}
    			break;
    		case 2:
    			newvar = ast_var_assign(ast_var_full_name(current), ast_var_value(current));
    			if (newvar) {
    				AST_LIST_INSERT_HEAD(&child->varshead, newvar, entries);
    				if (option_debug)
    					ast_log(LOG_DEBUG, "Copying hard-transferable variable %s.\n", ast_var_name(newvar));
    			}
    			break;
    		default:
    			if (option_debug)
    				ast_log(LOG_DEBUG, "Not copying variable %s.\n", ast_var_name(current));
    			break;
    		}
    	}
    }
    
    
    /* Clone channel variables from 'clone' channel into 'original' channel
       All variables except those related to app_groupcount are cloned
       Variables are actually _removed_ from 'clone' channel, presumably
       because it will subsequently be destroyed.
       Assumes locks will be in place on both channels when called.
    */
       
    static void clone_variables(struct ast_channel *original, struct ast_channel *clone)
    {
    	struct ast_var_t *varptr;
    
    	/* we need to remove all app_groupcount related variables from the original
    	   channel before merging in the clone's variables; any groups assigned to the
    	   original channel should be released, only those assigned to the clone
    	   should remain
    	*/
    
    	AST_LIST_TRAVERSE_SAFE_BEGIN(&original->varshead, varptr, entries) {
    		if (!strncmp(ast_var_name(varptr), GROUP_CATEGORY_PREFIX, strlen(GROUP_CATEGORY_PREFIX))) {
    			AST_LIST_REMOVE(&original->varshead, varptr, entries);
    			ast_var_delete(varptr);
    		}
    	}
    	AST_LIST_TRAVERSE_SAFE_END;
    
    	/* Append variables from clone channel into original channel */
    	/* XXX Is this always correct?  We have to in order to keep MACROS working XXX */
    
    	if (AST_LIST_FIRST(&clone->varshead))
    		AST_LIST_INSERT_TAIL(&original->varshead, AST_LIST_FIRST(&clone->varshead), entries);
    
    }
    
    /* Assumes channel will be locked when called */
    
    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_frame *cur, *prev;
    
    	const struct ast_channel_tech *t;
    	void *t_pvt;
    
    	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 technlogies */	
    	t = original->tech;
    	original->tech = clone->tech;
    	clone->tech = t;
    
    	t_pvt = original->tech_pvt;
    	original->tech_pvt = clone->tech_pvt;
    	clone->tech_pvt = t_pvt;
    
    	/* Swap the readq's */
    	cur = original->readq;
    	original->readq = clone->readq;
    	clone->readq = cur;
    
    	/* Swap the alertpipes */
    	for (i = 0; i < 2; i++) {
    		x = original->alertpipe[i];
    		original->alertpipe[i] = clone->alertpipe[i];
    		clone->alertpipe[i] = x;
    	}
    
    	/* Swap the raw formats */
    	x = original->rawreadformat;
    	original->rawreadformat = clone->rawreadformat;
    	clone->rawreadformat = x;
    	x = original->rawwriteformat;
    	original->rawwriteformat = clone->rawwriteformat;
    	clone->rawwriteformat = x;
    
    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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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->readq;
    		original->readq = clone->readq;
    		clone->readq = NULL;
    		if (original->alertpipe[1] > -1) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			for (i=0;i<x;i++)
    
    				write(original->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;
    
    
    	if (clone->tech->fixup){
    		res = clone->tech->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->tech->hangup)
    		res = clone->tech->hangup(clone);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Update the type. */
    	original->type = clone->type;
    
    	
    	/* Keep the same language.  */
    	strncpy(original->language, clone->language, sizeof(original->language));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* 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];
    
    	clone_variables(original, clone);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 */
    
    	ast_copy_flags(original, clone, AST_FLAG_EXCEPTION);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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);
    
    	/* Copy the music class */
    	strncpy(original->musicclass, clone->musicclass, sizeof(original->musicclass) - 1);
    
    
    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->tech->fixup) {
    		res = original->tech->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 (ast_test_flag(clone, AST_FLAG_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 {
    
    		struct ast_frame null_frame = { AST_FRAME_NULL, };
    
    		ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
    
    		ast_set_flag(clone, AST_FLAG_ZOMBIE);
    
    		ast_queue_frame(clone, &null_frame);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Signal any blocker */
    
    	if (ast_test_flag(original, AST_FLAG_BLOCKING))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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"
    
    				"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"
    
    			"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"
    
    				"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));
    
    #else
    	return (now->tv_sec - then->tv_sec) * 1000 + (now->tv_usec - then->tv_usec) / 1000;	
    #endif
    
    struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
    {
    	struct ast_channel *bridged;
    	bridged = chan->_bridge;
    
    	if (bridged && bridged->tech->bridged_channel) 
    		bridged = bridged->tech->bridged_channel(chan, 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);
    
    static int ast_generic_bridge(int *playitagain, int *playit, struct timeval *start_time, 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. */
    	struct ast_channel *cs[3];
    	int to = -1;
    	struct ast_frame *f;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_channel *who = NULL;
    
    	void *pvt0, *pvt1;
    	int res=0;
    	int o0nativeformats;
    	int o1nativeformats;
    	struct timeval precise_now;
    	long elapsed_ms=0, time_left_ms=0;
    	
    	cs[0] = c0;
    	cs[1] = c1;
    	pvt0 = c0->pvt;
    	pvt1 = c1->pvt;
    	o0nativeformats = c0->nativeformats;
    	o1nativeformats = c1->nativeformats;
    
    	for (;;) {
    		if ((c0->pvt != pvt0) || (c1->pvt != pvt1) ||
    		    (o0nativeformats != c0->nativeformats) ||
    			(o1nativeformats != c1->nativeformats)) {
    			/* Check for Masquerade, codec changes, etc */
    			res = -3;
    			break;
    		}
    		/* timestamp */
    		if (config->timelimit) {
    			/* If there is a time limit, return now */
    			gettimeofday(&precise_now,NULL);
    			elapsed_ms = tvdiff(&precise_now,start_time);
    			time_left_ms = config->timelimit - elapsed_ms;
    
    			if (*playitagain && ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && (config->play_warning && time_left_ms <= config->play_warning)) { 
    				res = -3;
    				break;
    			}
    			if (time_left_ms <= 0) {
    				res = -3;
    				break;
    			}
    			if (time_left_ms >= 5000 && *playit) {
    				res = -3;
    				break;
    			}
    			
    		}
    
    		who = ast_waitfor_n(cs, 2, &to);
    		if (!who) {
    			ast_log(LOG_DEBUG, "Nobody there, continuing...\n"); 
    		if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) {
    			if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE)
                    c0->_softhangup = 0;
                if (c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE)
                    c1->_softhangup = 0;
    			c0->_bridge = c1;
    			c1->_bridge = c0;
    			continue;
    		}
    
    			continue;
    		}
    		f = ast_read(who);
    		if (!f) {
    			*fo = NULL;
    			*rc = who;
    			res = 0;
    			ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
    			break;
    		}
    
    		if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) {
    			if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD)) {
    				ast_indicate(who == c0 ? c1 : c0, f->subclass);
    			} else {
    				*fo = f;
    				*rc = who;
    				res =  0;
    				ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
    				break;
    			}
    		}
    		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_HTML) ||
    			(f->frametype == AST_FRAME_DTMF)) {
    
    			if ((f->frametype == AST_FRAME_DTMF) && 
    				(config->flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
    				if ((who == c0)) {
    					if  ((config->flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
    						*rc = c0;
    						*fo = f;
    						/* Take out of conference mode */
    						res = 0;
    						ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_0 on c0 (%s)\n",c0->name);
    						break;
    					} else 
    						goto tackygoto;
    				} else
    				if ((who == c1)) {
    					if (config->flags & AST_BRIDGE_DTMF_CHANNEL_1) {
    						*rc = c1;
    						*fo = f;
    						res =  0;
    						ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_1 on c1 (%s)\n",c1->name);
    						break;
    					} else
    						goto tackygoto;
    				}
    			} 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
    tackygoto:
    				/* 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);
    			}
    		}
    		ast_frfree(f);
    
    		/* Swap who gets priority */
    		cs[2] = cs[0];
    		cs[0] = cs[1];
    		cs[1] = cs[2];
    	}
    	return res;
    }
    
    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
    	   the ability to transfer calls with '#<extension' syntax. */
    	struct ast_channel *cs[3];
    	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;
    
    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 ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->start_sound && firstpass)
    
    		bridge_playfile(c0,c1,config->start_sound,time_left_ms / 1000);
    
    	if ((ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING)) && 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 (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) || ast_test_flag(c1, AST_FLAG_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 && ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && (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 ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->end_sound)
    
    					bridge_playfile(c0,c1,config->end_sound,0);
    
    				if ((ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING)) && 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 ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->warning_sound && config->play_warning)
    
    					bridge_playfile(c0,c1,config->warning_sound,time_left_ms / 1000);
    
    				if ((ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING)) && config->warning_sound && config->play_warning)
    
    					bridge_playfile(c1,c0,config->warning_sound,time_left_ms / 1000);