| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com) | 
					
						
							| 
									
										
										
										
											2008-03-12 19:59:05 +00:00
										 |  |  |  * Copyright (C) 2005 - 2008, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-06-14 14:12:56 +00:00
										 |  |  |  * A license has been granted to Digium (via disclaimer) for the use of | 
					
						
							|  |  |  |  * this code. | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * 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
 | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief ChanSpy: Listen in on any channel. | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Anthony Minessale II <anthmct@yahoo.com> | 
					
						
							| 
									
										
										
										
											2008-03-12 19:59:05 +00:00
										 |  |  |  * \author Joshua Colp <jcolp@digium.com> | 
					
						
							|  |  |  |  * \author Russell Bryant <russell@digium.com> | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \ingroup applications | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | #include "asterisk/audiohook.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/features.h"
 | 
					
						
							|  |  |  | #include "asterisk/app.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/say.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/translate.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | #define AST_NAME_STRLEN 256
 | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | #define NUM_SPYGROUPS 128
 | 
					
						
							| 
									
										
										
										
											2005-04-01 01:03:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | static const char *tdesc = "Listen to a channel, and optionally whisper into it"; | 
					
						
							|  |  |  | static const char *app_chan = "ChanSpy"; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | static const char *desc_chan = | 
					
						
							| 
									
										
										
										
											2007-07-31 01:10:47 +00:00
										 |  |  | "  ChanSpy([chanprefix][,options]): This application is used to listen to the\n" | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | "audio from an Asterisk channel. This includes the audio coming in and\n" | 
					
						
							| 
									
										
										
										
											2005-11-10 20:56:45 +00:00
										 |  |  | "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n" | 
					
						
							|  |  |  | "only channels beginning with this string will be spied upon.\n" | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | "  While spying, the following actions may be performed:\n" | 
					
						
							| 
									
										
										
										
											2005-11-10 20:56:45 +00:00
										 |  |  | "    - Dialing # cycles the volume level.\n" | 
					
						
							|  |  |  | "    - Dialing * will stop spying and look for another channel to spy on.\n" | 
					
						
							|  |  |  | "    - Dialing a series of digits followed by # builds a channel name to append\n" | 
					
						
							|  |  |  | "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n" | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | "      the digits '1234#' while spying will begin spying on the channel\n" | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | "      'Agent/1234'. Note that this feature will be overriden if the 'd' option\n" | 
					
						
							|  |  |  | "       is used\n" | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | "  Note: The X option supersedes the three features above in that if a valid\n" | 
					
						
							|  |  |  | "        single digit extension exists in the correct context ChanSpy will\n" | 
					
						
							|  |  |  | "        exit to it. This also disables choosing a channel based on 'chanprefix'\n" | 
					
						
							|  |  |  | "        and a digit sequence.\n" | 
					
						
							| 
									
										
										
										
											2005-11-10 20:56:45 +00:00
										 |  |  | "  Options:\n" | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | "    b                      - Only spy on channels involved in a bridged call.\n" | 
					
						
							| 
									
										
										
										
											2008-05-05 13:52:44 +00:00
										 |  |  | "    B                      - Instead of whispering on a single channel barge in on both\n" | 
					
						
							|  |  |  | "                             channels involved in the call.\n" | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | "    d                      - Override the typical numeric DTMF functionality and instead\n" | 
					
						
							|  |  |  | "                             use DTMF to switch between spy modes.\n" | 
					
						
							|  |  |  | "                                     4 = spy mode\n" | 
					
						
							|  |  |  | "                                     5 = whisper mode\n" | 
					
						
							|  |  |  | "                                     6 = barge mode\n" | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | "    g(grp)                 - Only spy on channels in which one or more of the groups \n" | 
					
						
							|  |  |  | "                             listed in 'grp' matches one or more groups from the\n" | 
					
						
							|  |  |  | "                             SPYGROUP variable set on the channel to be spied upon.\n" | 
					
						
							|  |  |  | "                             Note that both 'grp' and SPYGROUP can contain either a\n" | 
					
						
							|  |  |  | "                             single group or a colon-delimited list of groups, such\n" | 
					
						
							|  |  |  | "                             as 'sales:support:accounting'.\n" | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | "    n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n" | 
					
						
							|  |  |  | "                             his/her name. If a context is specified, then that voicemail context will\n" | 
					
						
							|  |  |  | "                             be searched when retrieving the name, otherwise the \"default\" context\n" | 
					
						
							|  |  |  | "                             will be searched. If no mailbox is specified, then the channel name will\n" | 
					
						
							|  |  |  | "                             be used when searching for the name (i.e. if SIP/1000 is the channel being\n" | 
					
						
							|  |  |  | "                             spied on and no mailbox is specified, then \"1000\" will be used when searching\n" | 
					
						
							|  |  |  | "                             for the name).\n" | 
					
						
							|  |  |  | "    q                      - Don't play a beep when beginning to spy on a channel, or speak the\n" | 
					
						
							|  |  |  | "                             selected channel name.\n" | 
					
						
							|  |  |  | "    r[(basename)]          - Record the session to the monitor spool directory. An\n" | 
					
						
							|  |  |  | "                             optional base for the filename may be specified. The\n" | 
					
						
							|  |  |  | "                             default is 'chanspy'.\n" | 
					
						
							|  |  |  | "    s                      - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n" | 
					
						
							|  |  |  | "                             speaking the selected channel name.\n" | 
					
						
							|  |  |  | "    v([value])             - Adjust the initial volume in the range from -4 to 4. A\n" | 
					
						
							|  |  |  | "                             negative value refers to a quieter setting.\n" | 
					
						
							|  |  |  | "    w                      - Enable 'whisper' mode, so the spying channel can talk to\n" | 
					
						
							|  |  |  | "                             the spied-on channel.\n" | 
					
						
							|  |  |  | "    W                      - Enable 'private whisper' mode, so the spying channel can\n" | 
					
						
							|  |  |  | "                             talk to the spied-on channel but cannot listen to that\n" | 
					
						
							|  |  |  | "                             channel.\n" | 
					
						
							|  |  |  | "    o                      - Only listen to audio coming from this channel.\n" | 
					
						
							|  |  |  | "    X                      - Allow the user to exit ChanSpy to a valid single digit\n" | 
					
						
							|  |  |  | "                             numeric extension in the current context or the context\n" | 
					
						
							|  |  |  | "                             specified by the SPY_EXIT_CONTEXT channel variable. The\n" | 
					
						
							|  |  |  | "                             name of the last channel that was spied on will be stored\n" | 
					
						
							|  |  |  | "                             in the SPY_CHANNEL variable.\n" | 
					
						
							|  |  |  | "    e(ext)                 - Enable 'enforced' mode, so the spying channel can\n" | 
					
						
							|  |  |  | "                             only monitor extensions whose name is in the 'ext' : \n" | 
					
						
							|  |  |  | "                             delimited list.\n" | 
					
						
							| 
									
										
										
										
											2005-11-10 20:56:45 +00:00
										 |  |  | ; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | static const char *app_ext = "ExtenSpy"; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | static const char *desc_ext = | 
					
						
							| 
									
										
										
										
											2007-07-31 01:10:47 +00:00
										 |  |  | "  ExtenSpy(exten[@context][,options]): This application is used to listen to the\n" | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | "audio from an Asterisk channel. This includes the audio coming in and\n" | 
					
						
							|  |  |  | "out of the channel being spied on. Only channels created by outgoing calls for the\n" | 
					
						
							|  |  |  | "specified extension will be selected for spying. If the optional context is not\n" | 
					
						
							|  |  |  | "supplied, the current channel's context will be used.\n" | 
					
						
							|  |  |  | "  While spying, the following actions may be performed:\n" | 
					
						
							|  |  |  | "    - Dialing # cycles the volume level.\n" | 
					
						
							|  |  |  | "    - Dialing * will stop spying and look for another channel to spy on.\n" | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | "  Note: The X option superseeds the two features above in that if a valid\n" | 
					
						
							|  |  |  | "        single digit extension exists in the correct context it ChanSpy will\n" | 
					
						
							|  |  |  | "        exit to it.\n" | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | "  Options:\n" | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | "    b                      - Only spy on channels involved in a bridged call.\n" | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | "    B                      - Instead of whispering on a single channel barge in on both\n" | 
					
						
							|  |  |  | "                             channels involved in the call.\n" | 
					
						
							|  |  |  | "    d                      - Override the typical numeric DTMF functionality and instead\n" | 
					
						
							|  |  |  | "                             use DTMF to switch between spy modes.\n" | 
					
						
							|  |  |  | "                                     4 = spy mode\n" | 
					
						
							|  |  |  | "                                     5 = whisper mode\n" | 
					
						
							|  |  |  | "                                     6 = barge mode\n" | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | "    g(grp)                 - Only spy on channels in which one or more of the groups \n" | 
					
						
							|  |  |  | "                             listed in 'grp' matches one or more groups from the\n" | 
					
						
							|  |  |  | "                             SPYGROUP variable set on the channel to be spied upon.\n" | 
					
						
							|  |  |  | "                             Note that both 'grp' and SPYGROUP can contain either a\n" | 
					
						
							|  |  |  | "                             single group or a colon-delimited list of groups, such\n" | 
					
						
							|  |  |  | "                             as 'sales:support:accounting'.\n" | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | "    n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n" | 
					
						
							|  |  |  | "                             his/her name. If a context is specified, then that voicemail context will\n" | 
					
						
							|  |  |  | "                             be searched when retrieving the name, otherwise the \"default\" context\n" | 
					
						
							|  |  |  | "                             will be searched. If no mailbox is specified, then the channel name will\n" | 
					
						
							|  |  |  | "                             be used when searching for the name (i.e. if SIP/1000 is the channel being\n" | 
					
						
							|  |  |  | "                             spied on and no mailbox is specified, then \"1000\" will be used when searching\n" | 
					
						
							|  |  |  | "                             for the name).\n" | 
					
						
							|  |  |  | "    q                      - Don't play a beep when beginning to spy on a channel, or speak the\n" | 
					
						
							|  |  |  | "                             selected channel name.\n" | 
					
						
							|  |  |  | "    r[(basename)]          - Record the session to the monitor spool directory. An\n" | 
					
						
							|  |  |  | "                             optional base for the filename may be specified. The\n" | 
					
						
							|  |  |  | "                             default is 'chanspy'.\n" | 
					
						
							|  |  |  | "    s                      - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n" | 
					
						
							|  |  |  | "                             speaking the selected channel name.\n" | 
					
						
							|  |  |  | "    v([value])             - Adjust the initial volume in the range from -4 to 4. A\n" | 
					
						
							|  |  |  | "                             negative value refers to a quieter setting.\n" | 
					
						
							|  |  |  | "    w                      - Enable 'whisper' mode, so the spying channel can talk to\n" | 
					
						
							|  |  |  | "                             the spied-on channel.\n" | 
					
						
							|  |  |  | "    W                      - Enable 'private whisper' mode, so the spying channel can\n" | 
					
						
							|  |  |  | "                             talk to the spied-on channel but cannot listen to that\n" | 
					
						
							|  |  |  | "                             channel.\n" | 
					
						
							|  |  |  | "    o                      - Only listen to audio coming from this channel.\n" | 
					
						
							|  |  |  | "    X                      - Allow the user to exit ChanSpy to a valid single digit\n" | 
					
						
							|  |  |  | "                             numeric extension in the current context or the context\n" | 
					
						
							|  |  |  | "                             specified by the SPY_EXIT_CONTEXT channel variable. The\n" | 
					
						
							|  |  |  | "                             name of the last channel that was spied on will be stored\n" | 
					
						
							|  |  |  | "                             in the SPY_CHANNEL variable.\n" | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | ; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | enum { | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | 	OPTION_QUIET             = (1 << 0),    /* Quiet, no announcement */ | 
					
						
							|  |  |  | 	OPTION_BRIDGED           = (1 << 1),    /* Only look at bridged calls */ | 
					
						
							|  |  |  | 	OPTION_VOLUME            = (1 << 2),    /* Specify initial volume */ | 
					
						
							|  |  |  | 	OPTION_GROUP             = (1 << 3),    /* Only look at channels in group */ | 
					
						
							|  |  |  | 	OPTION_RECORD            = (1 << 4), | 
					
						
							|  |  |  | 	OPTION_WHISPER           = (1 << 5), | 
					
						
							|  |  |  | 	OPTION_PRIVATE           = (1 << 6),    /* Private Whisper mode */ | 
					
						
							|  |  |  | 	OPTION_READONLY          = (1 << 7),    /* Don't mix the two channels */ | 
					
						
							|  |  |  | 	OPTION_EXIT              = (1 << 8),    /* Exit to a valid single digit extension */ | 
					
						
							|  |  |  | 	OPTION_ENFORCED          = (1 << 9),    /* Enforced mode */ | 
					
						
							|  |  |  | 	OPTION_NOTECH            = (1 << 10),   /* Skip technology name playback */ | 
					
						
							|  |  |  | 	OPTION_BARGE             = (1 << 11),   /* Barge mode (whisper to both channels) */ | 
					
						
							|  |  |  | 	OPTION_NAME              = (1 << 12),   /* Say the name of the person on whom we will spy */ | 
					
						
							|  |  |  | 	OPTION_DTMF_SWITCH_MODES = (1 << 13),   /*Allow numeric DTMF to switch between chanspy modes */ | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | } chanspy_opt_flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  | 	OPT_ARG_VOLUME = 0, | 
					
						
							|  |  |  | 	OPT_ARG_GROUP, | 
					
						
							|  |  |  | 	OPT_ARG_RECORD, | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 	OPT_ARG_ENFORCED, | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	OPT_ARG_NAME, | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 	OPT_ARG_ARRAY_SIZE, | 
					
						
							|  |  |  | } chanspy_opt_args; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | AST_APP_OPTIONS(spy_opts, { | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 	AST_APP_OPTION('q', OPTION_QUIET), | 
					
						
							|  |  |  | 	AST_APP_OPTION('b', OPTION_BRIDGED), | 
					
						
							| 
									
										
										
										
											2008-04-25 22:24:32 +00:00
										 |  |  | 	AST_APP_OPTION('B', OPTION_BARGE), | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	AST_APP_OPTION('w', OPTION_WHISPER), | 
					
						
							|  |  |  | 	AST_APP_OPTION('W', OPTION_PRIVATE), | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 	AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), | 
					
						
							|  |  |  | 	AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), | 
					
						
							|  |  |  | 	AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD), | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 	AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED), | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 	AST_APP_OPTION('o', OPTION_READONLY), | 
					
						
							|  |  |  | 	AST_APP_OPTION('X', OPTION_EXIT), | 
					
						
							| 
									
										
										
										
											2008-04-16 12:23:13 +00:00
										 |  |  | 	AST_APP_OPTION('s', OPTION_NOTECH), | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME), | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | 	AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES), | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-27 19:08:24 +00:00
										 |  |  | int next_unique_id_to_use = 0; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct chanspy_translation_helper { | 
					
						
							| 
									
										
										
										
											2005-03-31 18:00:35 +00:00
										 |  |  | 	/* spy data */ | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	struct ast_audiohook spy_audiohook; | 
					
						
							|  |  |  | 	struct ast_audiohook whisper_audiohook; | 
					
						
							| 
									
										
										
										
											2008-04-25 22:24:32 +00:00
										 |  |  | 	struct ast_audiohook bridge_whisper_audiohook; | 
					
						
							| 
									
										
										
										
											2005-04-01 16:09:52 +00:00
										 |  |  | 	int fd; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	int volfactor; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static void *spy_alloc(struct ast_channel *chan, void *data) | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	/* just store the data pointer in the channel structure */ | 
					
						
							|  |  |  | 	return data; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static void spy_release(struct ast_channel *chan, void *data) | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	/* nothing to do */ | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-01 01:03:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-09-07 01:30:01 +00:00
										 |  |  | 	struct chanspy_translation_helper *csth = data; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	struct ast_frame *f = NULL; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	ast_audiohook_lock(&csth->spy_audiohook); | 
					
						
							|  |  |  | 	if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { | 
					
						
							| 
									
										
										
										
											2005-10-13 22:10:16 +00:00
										 |  |  | 		/* Channel is already gone more than likely */ | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 		ast_audiohook_unlock(&csth->spy_audiohook); | 
					
						
							| 
									
										
										
										
											2005-09-07 01:30:01 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	ast_audiohook_unlock(&csth->spy_audiohook); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (!f) | 
					
						
							| 
									
										
										
										
											2005-09-07 01:30:01 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (ast_write(chan, f)) { | 
					
						
							|  |  |  | 		ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2005-09-07 01:30:01 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-03-31 19:00:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (csth->fd) | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 		write(csth->fd, f->data.ptr, f->datalen); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-07 01:30:01 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_generator spygen = { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	.alloc = spy_alloc, | 
					
						
							|  |  |  | 	.release = spy_release, | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 	.generate = spy_generate, | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-25 22:24:32 +00:00
										 |  |  | static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	struct ast_channel *peer = NULL; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name); | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	res = ast_audiohook_attach(chan, audiohook); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-25 19:33:27 +00:00
										 |  |  | 	if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {  | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); | 
					
						
							| 
									
										
										
										
											2008-04-25 19:33:27 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | struct chanspy_ds { | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							| 
									
										
										
										
											2008-05-27 19:08:24 +00:00
										 |  |  | 	char unique_id[20]; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	ast_mutex_t lock; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | static void change_spy_mode(const char digit, struct ast_flags *flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (digit == '4') { | 
					
						
							|  |  |  | 		ast_clear_flag(flags, OPTION_WHISPER); | 
					
						
							|  |  |  | 		ast_clear_flag(flags, OPTION_BARGE); | 
					
						
							|  |  |  | 	} else if (digit == '5') { | 
					
						
							|  |  |  | 		ast_clear_flag(flags, OPTION_BARGE); | 
					
						
							|  |  |  | 		ast_set_flag(flags, OPTION_WHISPER); | 
					
						
							|  |  |  | 	} else if (digit == '6') { | 
					
						
							|  |  |  | 		ast_clear_flag(flags, OPTION_WHISPER); | 
					
						
							|  |  |  | 		ast_set_flag(flags, OPTION_BARGE); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,  | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | 	int *volfactor, int fd, struct ast_flags *flags, char *exitcontext)  | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct chanspy_translation_helper csth; | 
					
						
							| 
									
										
										
										
											2006-08-05 11:25:36 +00:00
										 |  |  | 	int running = 0, res, x = 0; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	char inp[24] = {0}; | 
					
						
							|  |  |  | 	char *name; | 
					
						
							| 
									
										
										
										
											2005-03-31 19:00:40 +00:00
										 |  |  | 	struct ast_frame *f; | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	struct ast_silence_generator *silgen = NULL; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	struct ast_channel *spyee = NULL; | 
					
						
							|  |  |  | 	const char *spyer_name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_channel_lock(chan); | 
					
						
							|  |  |  | 	spyer_name = ast_strdupa(chan->name); | 
					
						
							|  |  |  | 	ast_channel_unlock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&spyee_chanspy_ds->lock); | 
					
						
							|  |  |  | 	if (spyee_chanspy_ds->chan) { | 
					
						
							|  |  |  | 		spyee = spyee_chanspy_ds->chan; | 
					
						
							|  |  |  | 		ast_channel_lock(spyee); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&spyee_chanspy_ds->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!spyee) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We now hold the channel lock on spyee */ | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-17 14:21:14 +00:00
										 |  |  | 	if (ast_check_hangup(chan) || ast_check_hangup(spyee)) { | 
					
						
							|  |  |  | 		ast_channel_unlock(spyee); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-03-17 14:21:14 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	name = ast_strdupa(spyee->name); | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(2, "Spying on channel %s\n", name); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memset(&csth, 0, sizeof(csth)); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-25 19:33:27 +00:00
										 |  |  | 	if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 		ast_audiohook_destroy(&csth.spy_audiohook); | 
					
						
							| 
									
										
										
										
											2008-04-25 19:33:27 +00:00
										 |  |  | 		ast_channel_unlock(spyee); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | 	ast_channel_lock(chan); | 
					
						
							|  |  |  | 	ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); | 
					
						
							|  |  |  | 	ast_channel_unlock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  	ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); | 
					
						
							|  |  |  | 	ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); | 
					
						
							|  |  |  |   	start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */ | 
					
						
							|  |  |  | 	start_spying(ast_bridged_channel(spyee), spyer_name, &csth.bridge_whisper_audiohook); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:47:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-25 19:33:27 +00:00
										 |  |  | 	ast_channel_unlock(spyee); | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	spyee = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-31 17:25:16 +00:00
										 |  |  | 	csth.volfactor = *volfactor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (csth.volfactor) { | 
					
						
							|  |  |  | 		csth.spy_audiohook.options.read_volume = csth.volfactor; | 
					
						
							|  |  |  | 		csth.spy_audiohook.options.write_volume = csth.volfactor; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	csth.fd = fd; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	if (ast_test_flag(flags, OPTION_PRIVATE)) | 
					
						
							|  |  |  | 		silgen = ast_channel_start_silence_generator(chan); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ast_activate_generator(chan, &spygen, &csth); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We can no longer rely on 'spyee' being an actual channel;
 | 
					
						
							|  |  |  | 	   it can be hung up and freed out from under us. However, the | 
					
						
							|  |  |  | 	   channel destructor will put NULL into our csth.spy.chan | 
					
						
							|  |  |  | 	   field when that happens, so that is our signal that the spyee | 
					
						
							|  |  |  | 	   channel has gone away. | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Note: it is very important that the ast_waitfor() be the first
 | 
					
						
							|  |  |  | 	   condition in this expression, so that if we wait for some period | 
					
						
							|  |  |  | 	   of time before receiving a frame from our spying channel, we check | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	   for hangup on the spied-on channel _after_ knowing that a frame | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	   has arrived, since the spied-on channel could have gone away while | 
					
						
							|  |  |  | 	   we were waiting | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { | 
					
						
							| 
									
										
										
										
											2006-09-03 23:30:37 +00:00
										 |  |  | 		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { | 
					
						
							|  |  |  | 			running = -1; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2006-09-03 23:30:37 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-25 22:24:32 +00:00
										 |  |  | 		if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { | 
					
						
							|  |  |  | 			ast_audiohook_lock(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 			ast_audiohook_lock(&csth.bridge_whisper_audiohook); | 
					
						
							|  |  |  | 			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); | 
					
						
							|  |  |  | 			ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); | 
					
						
							|  |  |  | 			ast_audiohook_unlock(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 			ast_audiohook_unlock(&csth.bridge_whisper_audiohook); | 
					
						
							|  |  |  | 			ast_frfree(f); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 			ast_audiohook_lock(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); | 
					
						
							|  |  |  | 			ast_audiohook_unlock(&csth.whisper_audiohook); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 			ast_frfree(f); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; | 
					
						
							|  |  |  | 		ast_frfree(f); | 
					
						
							|  |  |  | 		if (!res) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (x == sizeof(inp)) | 
					
						
							|  |  |  | 			x = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (res < 0) { | 
					
						
							|  |  |  | 			running = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 		if (ast_test_flag(flags, OPTION_EXIT)) { | 
					
						
							|  |  |  | 			char tmp[2]; | 
					
						
							|  |  |  | 			tmp[0] = res; | 
					
						
							|  |  |  | 			tmp[1] = '\0'; | 
					
						
							|  |  |  | 			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); | 
					
						
							|  |  |  | 				running = -2; | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else if (res >= '0' && res <= '9') { | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | 			if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) { | 
					
						
							|  |  |  | 				change_spy_mode(res, flags); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				inp[x++] = res; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (res == '*') { | 
					
						
							|  |  |  | 			running = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} else if (res == '#') { | 
					
						
							|  |  |  | 			if (!ast_strlen_zero(inp)) { | 
					
						
							|  |  |  | 				running = atoi(inp); | 
					
						
							| 
									
										
										
										
											2005-04-01 01:03:22 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2005-03-31 19:00:40 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			(*volfactor)++; | 
					
						
							|  |  |  | 			if (*volfactor > 4) | 
					
						
							|  |  |  | 				*volfactor = -4; | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 			ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor); | 
					
						
							| 
									
										
										
										
											2007-10-31 17:25:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			csth.volfactor = *volfactor; | 
					
						
							|  |  |  | 			csth.spy_audiohook.options.read_volume = csth.volfactor; | 
					
						
							|  |  |  | 			csth.spy_audiohook.options.write_volume = csth.volfactor; | 
					
						
							| 
									
										
										
										
											2005-03-31 18:00:35 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	if (ast_test_flag(flags, OPTION_PRIVATE)) | 
					
						
							|  |  |  | 		ast_channel_stop_silence_generator(chan, silgen); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ast_deactivate_generator(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | 	ast_channel_lock(chan); | 
					
						
							|  |  |  | 	ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); | 
					
						
							|  |  |  | 	ast_channel_unlock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_audiohook_lock(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_detach(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_unlock(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_destroy(&csth.whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_lock(&csth.bridge_whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_detach(&csth.bridge_whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_unlock(&csth.bridge_whisper_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_destroy(&csth.bridge_whisper_audiohook); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_audiohook_lock(&csth.spy_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_detach(&csth.spy_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_unlock(&csth.spy_audiohook); | 
					
						
							|  |  |  | 	ast_audiohook_destroy(&csth.spy_audiohook); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2007-12-14 14:48:38 +00:00
										 |  |  | 	ast_verb(2, "Done Spying on channel %s\n", name); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 	return running; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \note This relies on the embedded lock to be recursive, as it may be called | 
					
						
							|  |  |  |  * due to a call to chanspy_ds_free with the lock held there. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void chanspy_ds_destroy(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct chanspy_ds *chanspy_ds = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Setting chan to be NULL is an atomic operation, but we don't want this
 | 
					
						
							|  |  |  | 	 * value to change while this lock is held.  The lock is held elsewhere | 
					
						
							|  |  |  | 	 * while it performs non-atomic operations with this channel pointer */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&chanspy_ds->lock); | 
					
						
							|  |  |  | 	chanspy_ds->chan = NULL; | 
					
						
							|  |  |  | 	ast_mutex_unlock(&chanspy_ds->lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-13 21:40:43 +00:00
										 |  |  | static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct chanspy_ds *chanspy_ds = data; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ast_mutex_lock(&chanspy_ds->lock); | 
					
						
							|  |  |  | 	chanspy_ds->chan = new_chan; | 
					
						
							|  |  |  | 	ast_mutex_unlock(&chanspy_ds->lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | static const struct ast_datastore_info chanspy_ds_info = { | 
					
						
							|  |  |  | 	.type = "chanspy", | 
					
						
							|  |  |  | 	.destroy = chanspy_ds_destroy, | 
					
						
							| 
									
										
										
										
											2008-03-13 21:40:43 +00:00
										 |  |  | 	.chan_fixup = chanspy_ds_chan_fixup, | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!chanspy_ds) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&chanspy_ds->lock); | 
					
						
							|  |  |  | 	if (chanspy_ds->chan) { | 
					
						
							|  |  |  | 		struct ast_datastore *datastore; | 
					
						
							|  |  |  | 		struct ast_channel *chan; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		chan = chanspy_ds->chan; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ast_channel_lock(chan); | 
					
						
							| 
									
										
										
										
											2008-05-27 19:08:24 +00:00
										 |  |  | 		if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) { | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			ast_channel_datastore_remove(chan, datastore); | 
					
						
							|  |  |  | 			/* chanspy_ds->chan is NULL after this call */ | 
					
						
							| 
									
										
										
										
											2008-02-27 01:16:06 +00:00
										 |  |  | 			chanspy_ds_destroy(datastore->data); | 
					
						
							|  |  |  | 			datastore->data = NULL; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			ast_channel_datastore_free(datastore); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ast_channel_unlock(chan); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&chanspy_ds->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */ | 
					
						
							|  |  |  | static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_datastore *datastore = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&chanspy_ds->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-27 19:08:24 +00:00
										 |  |  | 	if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) { | 
					
						
							| 
									
										
										
										
											2008-03-19 20:34:13 +00:00
										 |  |  | 		ast_mutex_unlock(&chanspy_ds->lock); | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 		chanspy_ds = chanspy_ds_free(chanspy_ds); | 
					
						
							|  |  |  | 		ast_channel_unlock(chan); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-19 20:34:13 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	chanspy_ds->chan = chan; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	datastore->data = chanspy_ds; | 
					
						
							|  |  |  | 	ast_channel_datastore_add(chan, datastore); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return chanspy_ds; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct chanspy_ds *next_channel(struct ast_channel *chan, | 
					
						
							|  |  |  | 	const struct ast_channel *last, const char *spec, | 
					
						
							|  |  |  | 	const char *exten, const char *context, struct chanspy_ds *chanspy_ds) | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 	struct ast_channel *next; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | redo: | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 	if (!ast_strlen_zero(spec)) | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 		next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 	else if (!ast_strlen_zero(exten)) | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 		next = ast_walk_channel_by_exten_locked(last, exten, context); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:16:08 +00:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 		next = ast_channel_walk_locked(last); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:16:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 	if (!next) | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 	if (!strncmp(next->name, "Zap/pseudo", 10)) { | 
					
						
							|  |  |  | 		ast_channel_unlock(next); | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 		goto redo; | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 	} else if (next == chan) { | 
					
						
							|  |  |  | 		last = next; | 
					
						
							|  |  |  | 		ast_channel_unlock(next); | 
					
						
							| 
									
										
										
										
											2008-02-27 21:02:08 +00:00
										 |  |  | 		goto redo; | 
					
						
							| 
									
										
										
										
											2006-09-03 15:21:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-15 17:54:38 +00:00
										 |  |  | 	return setup_chanspy_ds(next, chanspy_ds); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-14 22:15:12 +00:00
										 |  |  | static int common_exec(struct ast_channel *chan, struct ast_flags *flags, | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 	int volfactor, const int fd, const char *mygroup, const char *myenforced, | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	const char *spec, const char *exten, const char *context, const char *mailbox, | 
					
						
							|  |  |  | 	const char *name_context) | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char nameprefix[AST_NAME_STRLEN]; | 
					
						
							|  |  |  | 	char peer_name[AST_NAME_STRLEN + 5]; | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 	char exitcontext[AST_MAX_CONTEXT] = ""; | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 	signed char zero_volume = 0; | 
					
						
							|  |  |  | 	int waitms; | 
					
						
							|  |  |  | 	int res; | 
					
						
							|  |  |  | 	char *ptr; | 
					
						
							|  |  |  | 	int num; | 
					
						
							| 
									
										
										
										
											2008-01-23 17:48:08 +00:00
										 |  |  | 	int num_spyed_upon = 1; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	struct chanspy_ds chanspy_ds; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 	if (ast_test_flag(flags, OPTION_EXIT)) { | 
					
						
							|  |  |  | 		const char *c; | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		ast_channel_lock(chan); | 
					
						
							|  |  |  | 		if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 			ast_copy_string(exitcontext, c, sizeof(exitcontext)); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		} else if (!ast_strlen_zero(chan->macrocontext)) { | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 			ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 			ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	ast_mutex_init(&chanspy_ds.lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-27 19:08:24 +00:00
										 |  |  | 	snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 	if (chan->_state != AST_STATE_UP) | 
					
						
							|  |  |  | 		ast_answer(chan); | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	waitms = 100; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 		struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; | 
					
						
							|  |  |  | 		struct ast_channel *prev = NULL, *peer = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-23 17:48:08 +00:00
										 |  |  | 		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { | 
					
						
							| 
									
										
										
										
											2005-05-26 16:05:07 +00:00
										 |  |  | 			res = ast_streamfile(chan, "beep", chan->language); | 
					
						
							|  |  |  | 			if (!res) | 
					
						
							|  |  |  | 				res = ast_waitstream(chan, ""); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			else if (res < 0) { | 
					
						
							| 
									
										
										
										
											2005-05-26 16:05:07 +00:00
										 |  |  | 				ast_clear_flag(chan, AST_FLAG_SPYING); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 			if (!ast_strlen_zero(exitcontext)) { | 
					
						
							|  |  |  | 				char tmp[2]; | 
					
						
							|  |  |  | 				tmp[0] = res; | 
					
						
							|  |  |  | 				tmp[1] = '\0'; | 
					
						
							|  |  |  | 				if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) | 
					
						
							|  |  |  | 					goto exit; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				else | 
					
						
							|  |  |  | 					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-05-26 16:05:07 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		res = ast_waitfordigit(chan, waitms); | 
					
						
							|  |  |  | 		if (res < 0) { | 
					
						
							|  |  |  | 			ast_clear_flag(chan, AST_FLAG_SPYING); | 
					
						
							| 
									
										
										
										
											2005-04-01 16:09:52 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 		if (!ast_strlen_zero(exitcontext)) { | 
					
						
							|  |  |  | 			char tmp[2]; | 
					
						
							|  |  |  | 			tmp[0] = res; | 
					
						
							|  |  |  | 			tmp[1] = '\0'; | 
					
						
							|  |  |  | 			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) | 
					
						
							|  |  |  | 				goto exit; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			else | 
					
						
							|  |  |  | 				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 		/* reset for the next loop around, unless overridden later */ | 
					
						
							|  |  |  | 		waitms = 100; | 
					
						
							| 
									
										
										
										
											2008-01-23 17:48:08 +00:00
										 |  |  | 		num_spyed_upon = 0; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 		for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); | 
					
						
							|  |  |  | 		     peer_chanspy_ds; | 
					
						
							|  |  |  | 			 chanspy_ds_free(peer_chanspy_ds), prev = peer, | 
					
						
							|  |  |  | 		     peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :  | 
					
						
							|  |  |  | 			 	next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			const char *group; | 
					
						
							| 
									
										
										
										
											2006-07-27 23:16:08 +00:00
										 |  |  | 			int igrp = !mygroup; | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | 			char *groups[NUM_SPYGROUPS]; | 
					
						
							|  |  |  | 			char *mygroups[NUM_SPYGROUPS]; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			int num_groups = 0; | 
					
						
							|  |  |  | 			char *dup_group; | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | 			int num_mygroups = 0; | 
					
						
							|  |  |  | 			char *dup_mygroup; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			int x; | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | 			int y; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			char *s; | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 			char *buffer; | 
					
						
							|  |  |  | 			char *end; | 
					
						
							|  |  |  | 			char *ext; | 
					
						
							|  |  |  | 			char *form_enforced; | 
					
						
							|  |  |  | 			int ienf = !myenforced; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			peer = peer_chanspy_ds->chan; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ast_mutex_unlock(&peer_chanspy_ds->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (peer == prev) { | 
					
						
							|  |  |  | 				ast_channel_unlock(peer); | 
					
						
							|  |  |  | 				chanspy_ds_free(peer_chanspy_ds); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-05-03 22:25:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-27 17:36:50 +00:00
										 |  |  | 			if (ast_check_hangup(chan)) { | 
					
						
							|  |  |  | 				ast_channel_unlock(peer); | 
					
						
							|  |  |  | 				chanspy_ds_free(peer_chanspy_ds); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { | 
					
						
							|  |  |  | 				ast_channel_unlock(peer); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { | 
					
						
							|  |  |  | 				ast_channel_unlock(peer); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			if (mygroup) { | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | 				dup_mygroup = ast_strdupa(mygroup); | 
					
						
							|  |  |  | 				num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, | 
					
						
							|  |  |  | 					sizeof(mygroups) / sizeof(mygroups[0])); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 				if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { | 
					
						
							|  |  |  | 					dup_group = ast_strdupa(group); | 
					
						
							|  |  |  | 					num_groups = ast_app_separate_args(dup_group, ':', groups, | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 						sizeof(groups) / sizeof(groups[0])); | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-29 21:07:36 +00:00
										 |  |  | 				for (y = 0; y < num_mygroups; y++) { | 
					
						
							|  |  |  | 					for (x = 0; x < num_groups; x++) { | 
					
						
							|  |  |  | 						if (!strcmp(mygroups[y], groups[x])) { | 
					
						
							|  |  |  | 							igrp = 1; | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2006-07-27 23:16:08 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			if (!igrp) { | 
					
						
							|  |  |  | 				ast_channel_unlock(peer); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 			if (myenforced) { | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 				/* We don't need to allocate more space than just the
 | 
					
						
							|  |  |  | 				length of (peer->name) for ext as we will cut the | 
					
						
							|  |  |  | 				channel name's ending before copying into ext */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				ext = alloca(strlen(peer->name)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 				form_enforced = alloca(strlen(myenforced) + 3); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 				strcpy(form_enforced, ":"); | 
					
						
							|  |  |  | 				strcat(form_enforced, myenforced); | 
					
						
							|  |  |  | 				strcat(form_enforced, ":"); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 				buffer = ast_strdupa(peer->name); | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				if ((end = strchr(buffer, '-'))) { | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 					*end++ = ':'; | 
					
						
							|  |  |  | 					*end = '\0'; | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 				strcpy(ext, ":"); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 				strcat(ext, buffer); | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (strcasestr(form_enforced, ext)) | 
					
						
							|  |  |  | 					ienf = 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!ienf) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			strcpy(peer_name, "spy-"); | 
					
						
							| 
									
										
										
										
											2008-03-07 06:54:47 +00:00
										 |  |  | 			strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			ptr = strchr(peer_name, '/'); | 
					
						
							|  |  |  | 			*ptr++ = '\0'; | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 			ptr = strsep(&ptr, "-"); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			for (s = peer_name; s < ptr; s++) | 
					
						
							|  |  |  | 				*s = tolower(*s); | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			/* We have to unlock the peer channel here to avoid a deadlock.
 | 
					
						
							| 
									
										
										
										
											2008-04-23 20:53:05 +00:00
										 |  |  | 			 * So, when we need to dereference it again, we have to lock the  | 
					
						
							|  |  |  | 			 * datastore and get the pointer from there to see if the channel  | 
					
						
							|  |  |  | 			 * is still valid. */ | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			ast_channel_unlock(peer); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 			if (!ast_test_flag(flags, OPTION_QUIET)) { | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 				if (ast_test_flag(flags, OPTION_NAME)) { | 
					
						
							|  |  |  | 					const char *local_context = S_OR(name_context, "default"); | 
					
						
							|  |  |  | 					const char *local_mailbox = S_OR(mailbox, ptr); | 
					
						
							|  |  |  | 					res = ast_app_sayname(chan, local_mailbox, local_context); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { | 
					
						
							|  |  |  | 					if (!ast_test_flag(flags, OPTION_NOTECH)) { | 
					
						
							|  |  |  | 						if (ast_fileexists(peer_name, NULL, NULL) != -1) { | 
					
						
							|  |  |  | 							res = ast_streamfile(chan, peer_name, chan->language); | 
					
						
							|  |  |  | 							if (!res) { | 
					
						
							|  |  |  | 								res = ast_waitstream(chan, ""); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (res) { | 
					
						
							|  |  |  | 								chanspy_ds_free(peer_chanspy_ds); | 
					
						
							|  |  |  | 								break; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							res = ast_say_character_str(chan, peer_name, "", chan->language); | 
					
						
							| 
									
										
										
										
											2008-04-16 12:23:13 +00:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2008-03-18 22:36:02 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 					if ((num = atoi(ptr))) | 
					
						
							|  |  |  | 						ast_say_digits(chan, atoi(ptr), "", chan->language); | 
					
						
							| 
									
										
										
										
											2008-04-16 12:23:13 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 			res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); | 
					
						
							|  |  |  | 			num_spyed_upon++;	 | 
					
						
							| 
									
										
										
										
											2008-01-23 17:48:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			if (res == -1) { | 
					
						
							| 
									
										
										
										
											2008-02-27 21:02:08 +00:00
										 |  |  | 				chanspy_ds_free(peer_chanspy_ds); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 				goto exit; | 
					
						
							|  |  |  | 			} else if (res == -2) { | 
					
						
							|  |  |  | 				res = 0; | 
					
						
							| 
									
										
										
										
											2008-03-18 22:36:02 +00:00
										 |  |  | 				chanspy_ds_free(peer_chanspy_ds); | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | 				goto exit; | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 			} else if (res > 1 && spec) { | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 				struct ast_channel *next; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 				if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 					peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); | 
					
						
							|  |  |  | 					next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 					/* stay on this channel, if it is still valid */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					ast_mutex_lock(&peer_chanspy_ds->lock); | 
					
						
							|  |  |  | 					if (peer_chanspy_ds->chan) { | 
					
						
							|  |  |  | 						ast_channel_lock(peer_chanspy_ds->chan); | 
					
						
							|  |  |  | 						next_chanspy_ds = peer_chanspy_ds; | 
					
						
							|  |  |  | 						peer_chanspy_ds = NULL; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						/* the channel is gone */ | 
					
						
							|  |  |  | 						ast_mutex_unlock(&peer_chanspy_ds->lock); | 
					
						
							|  |  |  | 						next_chanspy_ds = NULL; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 				peer = NULL; | 
					
						
							| 
									
										
										
										
											2005-03-30 16:57:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-27 17:36:50 +00:00
										 |  |  | 		if (res == -1 || ast_check_hangup(chan)) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-02-16 01:17:25 +00:00
										 |  |  | exit: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 	ast_clear_flag(chan, AST_FLAG_SPYING); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 23:48:16 +00:00
										 |  |  | 	ast_mutex_destroy(&chanspy_ds.lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int chanspy_exec(struct ast_channel *chan, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 	char *myenforced = NULL; | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 	char *mygroup = NULL; | 
					
						
							|  |  |  | 	char *recbase = NULL; | 
					
						
							|  |  |  | 	int fd = 0; | 
					
						
							|  |  |  | 	struct ast_flags flags; | 
					
						
							|  |  |  | 	int oldwf = 0; | 
					
						
							|  |  |  | 	int volfactor = 0; | 
					
						
							|  |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	char *mailbox = NULL; | 
					
						
							|  |  |  | 	char *name_context = NULL; | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(spec); | 
					
						
							|  |  |  | 		AST_APP_ARG(options); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 	char *opts[OPT_ARG_ARRAY_SIZE]; | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data = ast_strdupa(data); | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	if (args.spec && !strcmp(args.spec, "all")) | 
					
						
							|  |  |  | 		args.spec = NULL; | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	if (args.options) { | 
					
						
							|  |  |  | 		ast_app_parse_options(spy_opts, &flags, opts, args.options); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 		if (ast_test_flag(&flags, OPTION_GROUP)) | 
					
						
							|  |  |  | 			mygroup = opts[OPT_ARG_GROUP]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_RECORD) && | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 			!(recbase = opts[OPT_ARG_RECORD])) | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 			recbase = "chanspy"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { | 
					
						
							|  |  |  | 			int vol; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) | 
					
						
							|  |  |  | 				ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				volfactor = vol; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_PRIVATE)) | 
					
						
							|  |  |  | 			ast_set_flag(&flags, OPTION_WHISPER); | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_ENFORCED)) | 
					
						
							|  |  |  | 			myenforced = opts[OPT_ARG_ENFORCED]; | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_NAME)) { | 
					
						
							|  |  |  | 			if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { | 
					
						
							|  |  |  | 				char *delimiter; | 
					
						
							|  |  |  | 				if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { | 
					
						
							|  |  |  | 					mailbox = opts[OPT_ARG_NAME]; | 
					
						
							|  |  |  | 					*delimiter++ = '\0'; | 
					
						
							|  |  |  | 					name_context = delimiter; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					mailbox = opts[OPT_ARG_NAME]; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-13 20:16:40 +00:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		ast_clear_flag(&flags, AST_FLAGS_ALL); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	oldwf = chan->writeformat; | 
					
						
							|  |  |  | 	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (recbase) { | 
					
						
							| 
									
										
										
										
											2008-04-17 10:55:05 +00:00
										 |  |  | 		char filename[PATH_MAX]; | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); | 
					
						
							| 
									
										
										
										
											2006-12-21 19:44:20 +00:00
										 |  |  | 		if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); | 
					
						
							|  |  |  | 			fd = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (fd) | 
					
						
							|  |  |  | 		close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (oldwf && ast_set_write_format(chan, oldwf) < 0) | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int extenspy_exec(struct ast_channel *chan, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	char *ptr, *exten = NULL; | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	char *mygroup = NULL; | 
					
						
							|  |  |  | 	char *recbase = NULL; | 
					
						
							|  |  |  | 	int fd = 0; | 
					
						
							|  |  |  | 	struct ast_flags flags; | 
					
						
							|  |  |  | 	int oldwf = 0; | 
					
						
							|  |  |  | 	int volfactor = 0; | 
					
						
							|  |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	char *mailbox = NULL; | 
					
						
							|  |  |  | 	char *name_context = NULL; | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(context); | 
					
						
							|  |  |  | 		AST_APP_ARG(options); | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data = ast_strdupa(data); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { | 
					
						
							|  |  |  | 		exten = args.context; | 
					
						
							|  |  |  | 		*ptr++ = '\0'; | 
					
						
							|  |  |  | 		args.context = ptr; | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	if (ast_strlen_zero(args.context)) | 
					
						
							|  |  |  | 		args.context = ast_strdupa(chan->context); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (args.options) { | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 		char *opts[OPT_ARG_ARRAY_SIZE]; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 		ast_app_parse_options(spy_opts, &flags, opts, args.options); | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 		if (ast_test_flag(&flags, OPTION_GROUP)) | 
					
						
							|  |  |  | 			mygroup = opts[OPT_ARG_GROUP]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_RECORD) && | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 			!(recbase = opts[OPT_ARG_RECORD])) | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 			recbase = "chanspy"; | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { | 
					
						
							|  |  |  | 			int vol; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) | 
					
						
							|  |  |  | 				ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				volfactor = vol; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_PRIVATE)) | 
					
						
							|  |  |  | 			ast_set_flag(&flags, OPTION_WHISPER); | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, OPTION_NAME)) { | 
					
						
							|  |  |  | 			if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { | 
					
						
							|  |  |  | 				char *delimiter; | 
					
						
							|  |  |  | 				if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { | 
					
						
							|  |  |  | 					mailbox = opts[OPT_ARG_NAME]; | 
					
						
							|  |  |  | 					*delimiter++ = '\0'; | 
					
						
							|  |  |  | 					name_context = delimiter; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					mailbox = opts[OPT_ARG_NAME]; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-13 20:16:40 +00:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		ast_clear_flag(&flags, AST_FLAGS_ALL); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	oldwf = chan->writeformat; | 
					
						
							|  |  |  | 	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (recbase) { | 
					
						
							| 
									
										
										
										
											2008-04-17 10:55:05 +00:00
										 |  |  | 		char filename[PATH_MAX]; | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); | 
					
						
							| 
									
										
										
										
											2006-12-21 19:44:20 +00:00
										 |  |  | 		if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); | 
					
						
							|  |  |  | 			fd = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 21:37:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-28 22:38:07 +00:00
										 |  |  | 	res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); | 
					
						
							| 
									
										
										
										
											2006-07-27 23:00:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	if (fd) | 
					
						
							| 
									
										
										
										
											2005-04-01 16:09:52 +00:00
										 |  |  | 		close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	if (oldwf && ast_set_write_format(chan, oldwf) < 0) | 
					
						
							| 
									
										
										
										
											2005-04-01 16:09:52 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-27 22:20:52 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	res |= ast_unregister_application(app_chan); | 
					
						
							|  |  |  | 	res |= ast_unregister_application(app_ext); | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-07-28 23:36:06 +00:00
										 |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); | 
					
						
							|  |  |  | 	res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-03-24 01:19:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel"); |