| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1999 - 2005, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief feature Proxy Channel | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \note *** Experimental code **** | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  |  *  | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \ingroup channel_drivers | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-06-07 19:49:15 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  |         <defaultenabled>no</defaultenabled> | 
					
						
							|  |  |  |  ***/ | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2005-06-07 17:06:33 +00:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2005-06-06 21:09:59 +00:00
										 |  |  | #include <sys/socket.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <netdb.h>
 | 
					
						
							| 
									
										
										
										
											2005-06-07 17:06:33 +00:00
										 |  |  | #include <netinet/in.h>
 | 
					
						
							| 
									
										
										
										
											2005-06-06 21:09:59 +00:00
										 |  |  | #include <arpa/inet.h>
 | 
					
						
							|  |  |  | #include <sys/signal.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/logger.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/options.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/sched.h"
 | 
					
						
							|  |  |  | #include "asterisk/io.h"
 | 
					
						
							|  |  |  | #include "asterisk/rtp.h"
 | 
					
						
							|  |  |  | #include "asterisk/acl.h"
 | 
					
						
							|  |  |  | #include "asterisk/callerid.h"
 | 
					
						
							|  |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/cli.h"
 | 
					
						
							|  |  |  | #include "asterisk/app.h"
 | 
					
						
							|  |  |  | #include "asterisk/musiconhold.h"
 | 
					
						
							|  |  |  | #include "asterisk/manager.h"
 | 
					
						
							| 
									
										
										
										
											2006-02-01 23:05:28 +00:00
										 |  |  | #include "asterisk/stringfields.h"
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | static const char tdesc[] = "Feature Proxy Channel Driver"; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct feature_sub { | 
					
						
							|  |  |  | 	struct ast_channel *owner; | 
					
						
							|  |  |  | 	int inthreeway; | 
					
						
							|  |  |  | 	int pfd; | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	int timingfdbackup; | 
					
						
							|  |  |  | 	int alertpipebackup[2]; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | struct feature_pvt { | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | 	ast_mutex_t lock;			/* Channel private lock */ | 
					
						
							|  |  |  | 	char tech[AST_MAX_EXTENSION];		/* Technology to abstract */ | 
					
						
							|  |  |  | 	char dest[AST_MAX_EXTENSION];		/* Destination to abstract */ | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	struct ast_channel *subchan; | 
					
						
							|  |  |  | 	struct feature_sub subs[3];		/* Subs */ | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | 	struct ast_channel *owner;		/* Current Master Channel */ | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	AST_LIST_ENTRY(feature_pvt) list;	/* Next entity */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static AST_LIST_HEAD_STATIC(features, feature_pvt); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | #define SUB_REAL	0			/* Active call */
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | #define SUB_CALLWAIT	1			/* Call-Waiting call on hold */
 | 
					
						
							|  |  |  | #define SUB_THREEWAY	2			/* Three-way call */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | static struct ast_channel *features_request(const char *type, int format, void *data, int *cause); | 
					
						
							| 
									
										
										
										
											2006-08-31 01:59:02 +00:00
										 |  |  | static int features_digit_begin(struct ast_channel *ast, char digit); | 
					
						
							| 
									
										
											  
											
												Merged revisions 51311 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged.  So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio.  However,
since there was no audio coming in, the DTMF_END was never generated.  This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf).  If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback.  This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-01-19 18:06:03 +00:00
										 |  |  | static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration); | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | static int features_call(struct ast_channel *ast, char *dest, int timeout); | 
					
						
							|  |  |  | static int features_hangup(struct ast_channel *ast); | 
					
						
							|  |  |  | static int features_answer(struct ast_channel *ast); | 
					
						
							|  |  |  | static struct ast_frame *features_read(struct ast_channel *ast); | 
					
						
							|  |  |  | static int features_write(struct ast_channel *ast, struct ast_frame *f); | 
					
						
							| 
									
										
										
										
											2006-05-10 12:24:11 +00:00
										 |  |  | static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct ast_channel_tech features_tech = { | 
					
						
							| 
									
										
										
										
											2006-02-01 23:05:28 +00:00
										 |  |  | 	.type = "Feature", | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	.description = tdesc, | 
					
						
							|  |  |  | 	.capabilities = -1, | 
					
						
							|  |  |  | 	.requester = features_request, | 
					
						
							| 
									
										
										
										
											2006-08-31 01:59:02 +00:00
										 |  |  | 	.send_digit_begin = features_digit_begin, | 
					
						
							|  |  |  | 	.send_digit_end = features_digit_end, | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	.call = features_call, | 
					
						
							|  |  |  | 	.hangup = features_hangup, | 
					
						
							|  |  |  | 	.answer = features_answer, | 
					
						
							|  |  |  | 	.read = features_read, | 
					
						
							|  |  |  | 	.write = features_write, | 
					
						
							|  |  |  | 	.exception = features_read, | 
					
						
							|  |  |  | 	.indicate = features_indicate, | 
					
						
							|  |  |  | 	.fixup = features_fixup, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | static inline void init_sub(struct feature_sub *sub) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	sub->inthreeway = 0; | 
					
						
							|  |  |  | 	sub->pfd = -1; | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	sub->timingfdbackup = -1; | 
					
						
							|  |  |  | 	sub->alertpipebackup[0] = sub->alertpipebackup[1] = -1; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int indexof(struct feature_pvt *p, struct ast_channel *owner, int nullok) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int x; | 
					
						
							|  |  |  | 	if (!owner) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "indexof called on NULL owner??\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 	for (x=0; x<3; x++) { | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		if (owner == p->subs[x].owner) | 
					
						
							|  |  |  | 			return x; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:30:23 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | static void wakeup_sub(struct feature_pvt *p, int a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame null = { AST_FRAME_NULL, }; | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		if (p->subs[a].owner) { | 
					
						
							|  |  |  | 			if (ast_mutex_trylock(&p->subs[a].owner->lock)) { | 
					
						
							|  |  |  | 				ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 				usleep(1); | 
					
						
							|  |  |  | 				ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				ast_queue_frame(p->subs[a].owner, &null); | 
					
						
							|  |  |  | 				ast_mutex_unlock(&p->subs[a].owner->lock); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-21 06:30:23 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | static void restore_channel(struct feature_pvt *p, int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Restore timing/alertpipe */ | 
					
						
							|  |  |  | 	p->subs[index].owner->timingfd = p->subs[index].timingfdbackup; | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	p->subs[index].owner->alertpipe[0] = p->subs[index].alertpipebackup[0]; | 
					
						
							|  |  |  | 	p->subs[index].owner->alertpipe[1] = p->subs[index].alertpipebackup[1]; | 
					
						
							| 
									
										
										
										
											2007-08-08 21:44:58 +00:00
										 |  |  | 	ast_channel_set_fd(p->subs[index].owner, AST_ALERT_FD, p->subs[index].alertpipebackup[0]); | 
					
						
							|  |  |  | 	ast_channel_set_fd(p->subs[index].owner, AST_TIMING_FD, p->subs[index].timingfdbackup); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void update_features(struct feature_pvt *p, int index) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	if (p->subs[index].owner) { | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 		for (x=0; x<AST_MAX_FDS; x++) { | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 			if (index)  | 
					
						
							| 
									
										
										
										
											2007-08-08 21:44:58 +00:00
										 |  |  | 				ast_channel_set_fd(p->subs[index].owner, x, -1); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 			else | 
					
						
							| 
									
										
										
										
											2007-08-08 21:44:58 +00:00
										 |  |  | 				ast_channel_set_fd(p->subs[index].owner, x, p->subchan->fds[x]); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!index) { | 
					
						
							|  |  |  | 			/* Copy timings from master channel */ | 
					
						
							|  |  |  | 			p->subs[index].owner->timingfd = p->subchan->timingfd; | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 			p->subs[index].owner->alertpipe[0] = p->subchan->alertpipe[0]; | 
					
						
							|  |  |  | 			p->subs[index].owner->alertpipe[1] = p->subchan->alertpipe[1]; | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 			if (p->subs[index].owner->nativeformats != p->subchan->readformat) { | 
					
						
							|  |  |  | 				p->subs[index].owner->nativeformats = p->subchan->readformat; | 
					
						
							|  |  |  | 				if (p->subs[index].owner->readformat) | 
					
						
							|  |  |  | 					ast_set_read_format(p->subs[index].owner, p->subs[index].owner->readformat); | 
					
						
							|  |  |  | 				if (p->subs[index].owner->writeformat) | 
					
						
							|  |  |  | 					ast_set_write_format(p->subs[index].owner, p->subs[index].owner->writeformat); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else{ | 
					
						
							|  |  |  | 			restore_channel(p, index); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:30:23 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | static void swap_subs(struct feature_pvt *p, int a, int b) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int tinthreeway; | 
					
						
							|  |  |  | 	struct ast_channel *towner; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 	ast_debug(1, "Swapping %d and %d\n", a, b); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	towner = p->subs[a].owner; | 
					
						
							|  |  |  | 	tinthreeway = p->subs[a].inthreeway; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p->subs[a].owner = p->subs[b].owner; | 
					
						
							|  |  |  | 	p->subs[a].inthreeway = p->subs[b].inthreeway; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p->subs[b].owner = towner; | 
					
						
							|  |  |  | 	p->subs[b].inthreeway = tinthreeway; | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	update_features(p,a); | 
					
						
							|  |  |  | 	update_features(p,b); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	wakeup_sub(p, a); | 
					
						
							|  |  |  | 	wakeup_sub(p, b); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-21 06:30:23 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int features_answer(struct ast_channel *ast) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 	if (!x && p->subchan) | 
					
						
							|  |  |  | 		res = ast_answer(p->subchan); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_frame  *features_read(struct ast_channel *ast) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	struct ast_frame *f; | 
					
						
							|  |  |  | 	int x; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-01-31 17:18:58 +00:00
										 |  |  | 	f = &ast_null_frame; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	if (!x && p->subchan) { | 
					
						
							|  |  |  | 		update_features(p, x); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		f = ast_read(p->subchan); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int features_write(struct ast_channel *ast, struct ast_frame *f) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 	if (!x && p->subchan) | 
					
						
							|  |  |  | 		res = ast_write(p->subchan, f); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = newchan->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	if (p->owner == oldchan) | 
					
						
							|  |  |  | 		p->owner = newchan; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 	for (x = 0; x < 3; x++) { | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		if (p->subs[x].owner == oldchan) | 
					
						
							|  |  |  | 			p->subs[x].owner = newchan; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-10 12:24:11 +00:00
										 |  |  | static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	/* Queue up a frame representing the indication as a control frame */ | 
					
						
							|  |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 	if (!x && p->subchan) | 
					
						
							|  |  |  | 		res = ast_indicate(p->subchan, condition); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-31 01:59:02 +00:00
										 |  |  | static int features_digit_begin(struct ast_channel *ast, char digit) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	/* Queue up a frame representing the indication as a control frame */ | 
					
						
							|  |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 	if (!x && p->subchan) | 
					
						
							| 
									
										
										
										
											2006-08-31 01:59:02 +00:00
										 |  |  | 		res = ast_senddigit_begin(p->subchan, digit); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Merged revisions 51311 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged.  So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio.  However,
since there was no audio coming in, the DTMF_END was never generated.  This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf).  If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback.  This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-01-19 18:06:03 +00:00
										 |  |  | static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration) | 
					
						
							| 
									
										
										
										
											2006-08-31 01:59:02 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							|  |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Queue up a frame representing the indication as a control frame */ | 
					
						
							|  |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 	if (!x && p->subchan) | 
					
						
							| 
									
										
											  
											
												Merged revisions 51311 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged.  So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio.  However,
since there was no audio coming in, the DTMF_END was never generated.  This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf).  If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback.  This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-01-19 18:06:03 +00:00
										 |  |  | 		res = ast_senddigit_end(p->subchan, digit, duration); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int features_call(struct ast_channel *ast, char *dest, int timeout) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	char *dest2; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	dest2 = strchr(dest, '/'); | 
					
						
							|  |  |  | 	if (dest2) { | 
					
						
							|  |  |  | 		ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 		x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 		if (!x && p->subchan) { | 
					
						
							| 
									
										
										
										
											2006-04-21 10:37:59 +00:00
										 |  |  | 			p->subchan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); | 
					
						
							|  |  |  | 			p->subchan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); | 
					
						
							|  |  |  | 			p->subchan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); | 
					
						
							|  |  |  | 			p->subchan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 			p->subchan->cid.cid_pres = p->owner->cid.cid_pres; | 
					
						
							| 
									
										
										
										
											2006-02-01 23:05:28 +00:00
										 |  |  | 			ast_string_field_set(p->subchan, language, p->owner->language); | 
					
						
							|  |  |  | 			ast_string_field_set(p->subchan, accountcode, p->owner->accountcode); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 			p->subchan->cdrflags = p->owner->cdrflags; | 
					
						
							|  |  |  | 			res = ast_call(p->subchan, dest2, timeout); | 
					
						
							|  |  |  | 			update_features(p, x); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			ast_log(LOG_NOTICE, "Uhm yah, not quite there with the call waiting...\n"); | 
					
						
							|  |  |  | 		ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int features_hangup(struct ast_channel *ast) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	struct feature_pvt *p = ast->tech_pvt; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	int x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 	x = indexof(p, ast, 0); | 
					
						
							|  |  |  | 	if (x > -1) { | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 		restore_channel(p, x); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		p->subs[x].owner = NULL; | 
					
						
							|  |  |  | 		/* XXX Re-arrange, unconference, etc XXX */ | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	ast->tech_pvt = NULL; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) { | 
					
						
							|  |  |  | 		ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 		/* Remove from list */ | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 		AST_LIST_LOCK(&features); | 
					
						
							|  |  |  | 		AST_LIST_REMOVE(&features, p, list); | 
					
						
							|  |  |  | 		AST_LIST_UNLOCK(&features); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		ast_mutex_lock(&p->lock); | 
					
						
							|  |  |  | 		/* And destroy */ | 
					
						
							|  |  |  | 		if (p->subchan) | 
					
						
							|  |  |  | 			ast_hangup(p->subchan); | 
					
						
							|  |  |  | 		ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 		ast_mutex_destroy(&p->lock); | 
					
						
							| 
									
										
										
										
											2007-06-03 06:10:27 +00:00
										 |  |  | 		ast_free(p); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct feature_pvt *features_alloc(char *data, int format) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct feature_pvt *tmp; | 
					
						
							|  |  |  | 	char *dest=NULL; | 
					
						
							|  |  |  | 	char *tech; | 
					
						
							|  |  |  | 	int x; | 
					
						
							|  |  |  | 	int status; | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	tech = ast_strdupa(data); | 
					
						
							|  |  |  | 	if (tech) { | 
					
						
							|  |  |  | 		dest = strchr(tech, '/'); | 
					
						
							|  |  |  | 		if (dest) { | 
					
						
							|  |  |  | 			*dest = '\0'; | 
					
						
							|  |  |  | 			dest++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!tech || !dest) { | 
					
						
							|  |  |  | 		ast_log(LOG_NOTICE, "Format for feature channel is Feature/Tech/Dest ('%s' not valid)!\n",  | 
					
						
							|  |  |  | 			data); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	AST_LIST_LOCK(&features); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&features, tmp, list) { | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		if (!strcasecmp(tmp->tech, tech) && !strcmp(tmp->dest, dest)) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&features); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	if (!tmp) { | 
					
						
							|  |  |  | 		chan = ast_request(tech, format, dest, &status); | 
					
						
							|  |  |  | 		if (!chan) { | 
					
						
							|  |  |  | 			ast_log(LOG_NOTICE, "Unable to allocate subchannel '%s/%s'\n", tech, dest); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-06-03 06:10:27 +00:00
										 |  |  | 		tmp = ast_calloc(1, sizeof(*tmp)); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		if (tmp) { | 
					
						
							|  |  |  | 			for (x=0;x<3;x++) | 
					
						
							|  |  |  | 				init_sub(tmp->subs + x); | 
					
						
							|  |  |  | 			ast_mutex_init(&tmp->lock); | 
					
						
							| 
									
										
										
										
											2006-10-25 14:44:50 +00:00
										 |  |  | 			ast_copy_string(tmp->tech, tech, sizeof(tmp->tech)); | 
					
						
							|  |  |  | 			ast_copy_string(tmp->dest, dest, sizeof(tmp->dest)); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 			tmp->subchan = chan; | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 			AST_LIST_LOCK(&features); | 
					
						
							|  |  |  | 			AST_LIST_INSERT_HEAD(&features, tmp, list); | 
					
						
							|  |  |  | 			AST_LIST_UNLOCK(&features); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return tmp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_channel *features_new(struct feature_pvt *p, int state, int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_channel *tmp; | 
					
						
							|  |  |  | 	int x,y; | 
					
						
							| 
									
										
										
										
											2006-11-07 21:47:49 +00:00
										 |  |  | 	char *b2 = 0; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	if (!p->subchan) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Called upon channel with no subchan:(\n"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-12-23 22:29:23 +00:00
										 |  |  | 	if (p->subs[index].owner) { | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Called to put index %d already there!\n", index); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-11-07 21:47:49 +00:00
										 |  |  | 	/* figure out what you want the name to be */ | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | 	for (x=1;x<4;x++) { | 
					
						
							| 
									
										
										
										
											2006-11-07 21:47:49 +00:00
										 |  |  | 		if (b2) | 
					
						
							| 
									
										
										
										
											2007-06-03 06:10:27 +00:00
										 |  |  | 			ast_free(b2); | 
					
						
							| 
									
										
										
										
											2007-05-30 16:11:57 +00:00
										 |  |  | 		asprintf(&b2, "%s/%s-%d", p->tech, p->dest, x); | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | 		for (y=0;y<3;y++) { | 
					
						
							|  |  |  | 			if (y == index) | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2006-11-07 21:47:49 +00:00
										 |  |  | 			if (p->subs[y].owner && !strcasecmp(p->subs[y].owner->name, b2)) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | 		if (y >= 3) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-05-30 16:11:57 +00:00
										 |  |  | 	tmp = ast_channel_alloc(0, state, 0,0, "", "", "", 0, "Feature/%s", b2); | 
					
						
							| 
									
										
										
										
											2006-11-07 21:47:49 +00:00
										 |  |  | 	/* free up the name, it was copied into the channel name */ | 
					
						
							|  |  |  | 	if (b2) | 
					
						
							| 
									
										
										
										
											2007-06-03 06:10:27 +00:00
										 |  |  | 		ast_free(b2); | 
					
						
							| 
									
										
										
										
											2006-11-07 21:47:49 +00:00
										 |  |  | 	if (!tmp) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tmp->tech = &features_tech; | 
					
						
							| 
									
										
										
										
											2005-05-07 19:51:39 +00:00
										 |  |  | 	tmp->writeformat = p->subchan->writeformat; | 
					
						
							|  |  |  | 	tmp->rawwriteformat = p->subchan->rawwriteformat; | 
					
						
							|  |  |  | 	tmp->readformat = p->subchan->readformat; | 
					
						
							|  |  |  | 	tmp->rawreadformat = p->subchan->rawreadformat; | 
					
						
							|  |  |  | 	tmp->nativeformats = p->subchan->readformat; | 
					
						
							|  |  |  | 	tmp->tech_pvt = p; | 
					
						
							|  |  |  | 	p->subs[index].owner = tmp; | 
					
						
							|  |  |  | 	if (!p->owner) | 
					
						
							|  |  |  | 		p->owner = tmp; | 
					
						
							| 
									
										
										
										
											2007-01-23 22:59:55 +00:00
										 |  |  | 	ast_module_ref(ast_module_info->self); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	return tmp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_channel *features_request(const char *type, int format, void *data, int *cause) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct feature_pvt *p; | 
					
						
							|  |  |  | 	struct ast_channel *chan = NULL; | 
					
						
							| 
									
										
										
										
											2005-07-25 20:04:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	p = features_alloc(data, format); | 
					
						
							| 
									
										
										
										
											2004-11-25 03:19:18 +00:00
										 |  |  | 	if (p && !p->subs[SUB_REAL].owner) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		chan = features_new(p, AST_STATE_DOWN, SUB_REAL); | 
					
						
							| 
									
										
										
										
											2004-12-26 11:08:34 +00:00
										 |  |  | 	if (chan) | 
					
						
							|  |  |  | 		update_features(p,SUB_REAL); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	return chan; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-18 22:43:45 +00:00
										 |  |  | static char *features_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct feature_pvt *p; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-18 22:43:45 +00:00
										 |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							|  |  |  | 		e->command = "feature show channels"; | 
					
						
							|  |  |  | 		e->usage = | 
					
						
							|  |  |  | 			"Usage: feature show channels\n" | 
					
						
							|  |  |  | 			"       Provides summary information on feature channels.\n"; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc != 3) | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (AST_LIST_EMPTY(&features)) { | 
					
						
							| 
									
										
										
										
											2007-09-18 22:43:45 +00:00
										 |  |  | 		ast_cli(a->fd, "No feature channels in use\n"); | 
					
						
							|  |  |  | 		return CLI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&features); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&features, p, list) { | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		ast_mutex_lock(&p->lock); | 
					
						
							| 
									
										
										
										
											2007-09-18 22:43:45 +00:00
										 |  |  | 		ast_cli(a->fd, "%s -- %s/%s\n", p->owner ? p->owner->name : "<unowned>", p->tech, p->dest); | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		ast_mutex_unlock(&p->lock); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&features); | 
					
						
							| 
									
										
										
										
											2007-09-18 22:43:45 +00:00
										 |  |  | 	return CLI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-18 19:54:18 +00:00
										 |  |  | static struct ast_cli_entry cli_features[] = { | 
					
						
							| 
									
										
										
										
											2007-10-22 20:05:18 +00:00
										 |  |  | 	AST_CLI_DEFINE(features_show, "List status of feature channels"), | 
					
						
							| 
									
										
										
										
											2006-09-18 19:54:18 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Make sure we can register our sip channel type */ | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	if (ast_channel_register(&features_tech)) { | 
					
						
							| 
									
										
										
										
											2006-02-01 23:05:28 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Unable to register channel class 'Feature'\n"); | 
					
						
							| 
									
										
										
										
											2007-10-26 21:37:02 +00:00
										 |  |  | 		return AST_MODULE_LOAD_FAILURE; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-09-18 19:54:18 +00:00
										 |  |  | 	ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); | 
					
						
							| 
									
										
										
										
											2007-10-26 21:37:02 +00:00
										 |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct feature_pvt *p; | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	/* First, take us out of the channel loop */ | 
					
						
							| 
									
										
										
										
											2006-09-18 19:54:18 +00:00
										 |  |  | 	ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); | 
					
						
							| 
									
										
										
										
											2005-03-04 06:47:24 +00:00
										 |  |  | 	ast_channel_unregister(&features_tech); | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if (!AST_LIST_LOCK(&features)) | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	/* Hangup all interfaces if they have an owner */ | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(&features, p, list) { | 
					
						
							|  |  |  | 		if (p->owner) | 
					
						
							|  |  |  | 			ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); | 
					
						
							|  |  |  | 		AST_LIST_REMOVE_CURRENT(&features, list); | 
					
						
							| 
									
										
										
										
											2007-06-03 06:10:27 +00:00
										 |  |  | 		ast_free(p); | 
					
						
							| 
									
										
										
										
											2006-01-25 18:24:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&features); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2004-11-06 21:33:01 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Feature Proxy Channel"); | 
					
						
							| 
									
										
										
										
											2006-04-14 14:08:19 +00:00
										 |  |  | 
 |