mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	add ExtenSpy variant of ChanSpy
implement whisper mode for ExtenSpy/ChanSpy git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@38465 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -53,40 +53,74 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | ||||
|  | ||||
| #define AST_NAME_STRLEN 256 | ||||
|  | ||||
| static const char *tdesc = "Listen to the audio of an active channel"; | ||||
| static const char *app = "ChanSpy"; | ||||
| static const char *desc =  | ||||
| static const char *tdesc = "Listen to a channel, and optionally whisper into it"; | ||||
| static const char *app_chan = "ChanSpy"; | ||||
| static const char *desc_chan =  | ||||
| "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n" | ||||
| "audio from an active Asterisk channel. This includes the audio coming in and\n" | ||||
| "audio from an Asterisk channel. This includes the audio coming in and\n" | ||||
| "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" | ||||
| "  While Spying, the following actions may be performed:\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" | ||||
| "    - 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" | ||||
| "      the digits '1234#' while spying will begin spying on the channel,\n" | ||||
| "      the digits '1234#' while spying will begin spying on the channel\n" | ||||
| "      'Agent/1234'.\n" | ||||
| "  Options:\n" | ||||
| "    b - Only spy on channels involved in a bridged call.\n" | ||||
| "    g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n" | ||||
| "             contain 'grp' in an optional : delimited list.\n" | ||||
| "    q - Don't play a beep when beginning to spy on a channel.\n" | ||||
| "    b             - Only spy on channels involved in a bridged call.\n" | ||||
| "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n" | ||||
| "                    contain 'grp' in an optional : delimited list.\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" | ||||
| "    v([value]) - Adjust the initial volume in the range from -4 to 4. A\n" | ||||
| "                 negative value refers to a quieter setting.\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" | ||||
| ; | ||||
|  | ||||
| static const char *chanspy_spy_type = "ChanSpy"; | ||||
| static const char *app_ext = "ExtenSpy"; | ||||
| static const char *desc_ext =  | ||||
| "  ExtenSpy(exten[@context][|options]): This application is used to listen to the\n" | ||||
| "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" | ||||
| "  Options:\n" | ||||
| "    b             - Only spy on channels involved in a bridged call.\n" | ||||
| "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n" | ||||
| "                    contain 'grp' in an optional : delimited list.\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" | ||||
| "    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" | ||||
| ; | ||||
|  | ||||
| enum { | ||||
| 	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),	/* Record */ | ||||
| 	OPTION_RECORD    = (1 << 4), | ||||
| 	OPTION_WHISPER	 = (1 << 5), | ||||
| 	OPTION_PRIVATE   = (1 << 6),	/* Private Whisper mode */ | ||||
| } chanspy_opt_flags; | ||||
|  | ||||
| enum { | ||||
| @@ -96,9 +130,11 @@ enum { | ||||
| 	OPT_ARG_ARRAY_SIZE, | ||||
| } chanspy_opt_args; | ||||
|  | ||||
| AST_APP_OPTIONS(chanspy_opts, { | ||||
| AST_APP_OPTIONS(spy_opts, { | ||||
| 	AST_APP_OPTION('q', OPTION_QUIET), | ||||
| 	AST_APP_OPTION('b', OPTION_BRIDGED), | ||||
| 	AST_APP_OPTION('w', OPTION_WHISPER), | ||||
| 	AST_APP_OPTION('W', OPTION_PRIVATE), | ||||
| 	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), | ||||
| @@ -176,19 +212,19 @@ static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, s | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy)  | ||||
| static void stop_spying(struct ast_channel_spy *spy)  | ||||
| { | ||||
| 	/* If our status has changed to DONE, then the channel we're spying on is gone.... | ||||
| 	   DON'T TOUCH IT!!!  RUN AWAY!!! */ | ||||
| 	if (spy->status == CHANSPY_DONE) | ||||
| 		return; | ||||
|  | ||||
| 	if (!chan) | ||||
| 	if (!spy->chan) | ||||
| 		return; | ||||
|  | ||||
| 	ast_channel_lock(chan); | ||||
| 	ast_channel_spy_remove(chan, spy); | ||||
| 	ast_channel_unlock(chan); | ||||
| 	ast_channel_lock(spy->chan); | ||||
| 	ast_channel_spy_remove(spy->chan, spy); | ||||
| 	ast_channel_unlock(spy->chan); | ||||
| }; | ||||
|  | ||||
| /* Map 'volume' levels from -4 through +4 into | ||||
| @@ -220,15 +256,17 @@ static void set_volume(struct ast_channel *chan, struct chanspy_translation_help | ||||
| 	csth->spy.write_vol_adjustment = csth->volfactor; | ||||
| } | ||||
|  | ||||
| static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)  | ||||
| static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd, | ||||
| 		       const struct ast_flags *flags)  | ||||
| { | ||||
| 	struct chanspy_translation_helper csth; | ||||
| 	int running, res, x = 0; | ||||
| 	char inp[24] = {0}; | ||||
| 	char *name; | ||||
| 	struct ast_frame *f; | ||||
| 	struct ast_silence_generator *silgen = NULL; | ||||
|  | ||||
| 	if (!(chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee))) | ||||
| 	if (ast_check_hangup(chan) || ast_check_hangup(spyee)) | ||||
| 		return 0; | ||||
|  | ||||
| 	name = ast_strdupa(spyee->name); | ||||
| @@ -239,7 +277,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int | ||||
| 	ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO); | ||||
| 	ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE); | ||||
| 	ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO); | ||||
| 	csth.spy.type = chanspy_spy_type; | ||||
| 	csth.spy.type = "ChanSpy"; | ||||
| 	csth.spy.status = CHANSPY_RUNNING; | ||||
| 	csth.spy.read_queue.format = AST_FORMAT_SLINEAR; | ||||
| 	csth.spy.write_queue.format = AST_FORMAT_SLINEAR; | ||||
| @@ -253,22 +291,42 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	ast_activate_generator(chan, &spygen, &csth); | ||||
| 	if (ast_test_flag(flags, OPTION_PRIVATE)) | ||||
| 		silgen = ast_channel_start_silence_generator(chan); | ||||
| 	else | ||||
| 		ast_activate_generator(chan, &spygen, &csth); | ||||
|  | ||||
| 	if (ast_test_flag(flags, OPTION_WHISPER)) | ||||
| 		ast_channel_whisper_start(csth.spy.chan); | ||||
|  | ||||
| 	/* 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. | ||||
| 	*/ | ||||
|  | ||||
| 	/* 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 | ||||
| 	   for hangup on the spied-on channel _after_ knowing that frame | ||||
| 	   for hangup on the spied-on channel _after_ knowing that a frame | ||||
| 	   has arrived, since the spied-on channel could have gone away while | ||||
| 	   we were waiting | ||||
| 	*/ | ||||
| 	while ((res = ast_waitfor(chan, -1) > -1) && | ||||
| 	       csth.spy.status == CHANSPY_RUNNING && | ||||
| 	       !ast_check_hangup(chan) && | ||||
| 	       !ast_check_hangup(spyee)) { | ||||
| 	       csth.spy.chan) { | ||||
| 		if (!(f = ast_read(chan))) | ||||
| 			break; | ||||
|  | ||||
| 		if (ast_test_flag(flags, OPTION_WHISPER) && | ||||
| 		    (f->frametype == AST_FRAME_VOICE)) { | ||||
| 			ast_channel_whisper_feed(csth.spy.chan, f); | ||||
| 			ast_frfree(f); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; | ||||
| 		ast_frfree(f); | ||||
| 		if (!res) | ||||
| @@ -303,8 +361,15 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ast_deactivate_generator(chan); | ||||
| 	stop_spying(spyee, &csth.spy); | ||||
| 	if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan) | ||||
| 		ast_channel_whisper_stop(csth.spy.chan); | ||||
|  | ||||
| 	if (ast_test_flag(flags, OPTION_PRIVATE)) | ||||
| 		ast_channel_stop_silence_generator(chan, silgen); | ||||
| 	else | ||||
| 		ast_deactivate_generator(chan); | ||||
|  | ||||
| 	stop_spying(&csth.spy); | ||||
| 	 | ||||
| 	if (option_verbose >= 2) | ||||
| 		ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); | ||||
| @@ -314,12 +379,15 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int | ||||
| 	return running; | ||||
| } | ||||
|  | ||||
| static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec) | ||||
| static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec, | ||||
| 					const char *exten, const char *context) | ||||
| { | ||||
| 	struct ast_channel *this; | ||||
|  | ||||
| 	if (spec) | ||||
| 		this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); | ||||
| 	else if (exten) | ||||
| 		this = ast_walk_channel_by_exten_locked(last, exten, context); | ||||
| 	else | ||||
| 		this = ast_channel_walk_locked(last); | ||||
|  | ||||
| @@ -329,8 +397,9 @@ static struct ast_channel *next_channel(const struct ast_channel *last, const ch | ||||
| 	return this; | ||||
| } | ||||
|  | ||||
| static int common_exec(struct ast_channel *chan, const int silent, const int bronly, | ||||
| 		       int volfactor, const int fd, const char *spec, const char *mygroup) | ||||
| static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, | ||||
| 		       int volfactor, const int fd, const char *mygroup, const char *spec, | ||||
| 		       const char *exten, const char *context) | ||||
| { | ||||
| 	struct ast_channel *peer, *prev, *next; | ||||
| 	char nameprefix[AST_NAME_STRLEN]; | ||||
| @@ -349,7 +418,7 @@ static int common_exec(struct ast_channel *chan, const int silent, const int bro | ||||
| 	waitms = 100; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		if (!silent) { | ||||
| 		if (!ast_test_flag(flags, OPTION_QUIET)) { | ||||
| 			res = ast_streamfile(chan, "beep", chan->language); | ||||
| 			if (!res) | ||||
| 				res = ast_waitstream(chan, ""); | ||||
| @@ -369,9 +438,9 @@ static int common_exec(struct ast_channel *chan, const int silent, const int bro | ||||
| 		waitms = 100; | ||||
| 		peer = prev = next = NULL; | ||||
|  | ||||
| 		for (peer = next_channel(peer, spec); | ||||
| 		for (peer = next_channel(peer, spec, exten, context); | ||||
| 		     peer; | ||||
| 		     prev = peer, peer = next ? next : next_channel(peer, spec), next = NULL) { | ||||
| 		     prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) { | ||||
| 			const char *group; | ||||
| 			int igrp = !mygroup; | ||||
| 			char *groups[25]; | ||||
| @@ -386,6 +455,12 @@ static int common_exec(struct ast_channel *chan, const int silent, const int bro | ||||
| 			if (peer == chan) | ||||
| 				continue; | ||||
|  | ||||
| 			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) | ||||
| 				continue; | ||||
|  | ||||
| 			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) | ||||
| 				continue; | ||||
|  | ||||
| 			if (mygroup) { | ||||
| 				if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { | ||||
| 					dup_group = ast_strdupa(group); | ||||
| @@ -404,12 +479,6 @@ static int common_exec(struct ast_channel *chan, const int silent, const int bro | ||||
| 			if (!igrp) | ||||
| 				continue; | ||||
|  | ||||
| 			if (bronly && !ast_bridged_channel(peer)) | ||||
| 				continue; | ||||
|  | ||||
| 			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) | ||||
| 				continue; | ||||
|  | ||||
| 			strcpy(peer_name, "spy-"); | ||||
| 			strncat(peer_name, peer->name, AST_NAME_STRLEN); | ||||
| 			ptr = strchr(peer_name, '/'); | ||||
| @@ -418,7 +487,7 @@ static int common_exec(struct ast_channel *chan, const int silent, const int bro | ||||
| 			for (s = peer_name; s < ptr; s++) | ||||
| 				*s = tolower(*s); | ||||
| 			 | ||||
| 			if (!silent) { | ||||
| 			if (!ast_test_flag(flags, OPTION_QUIET)) { | ||||
| 				if (ast_fileexists(peer_name, NULL, NULL) != -1) { | ||||
| 					res = ast_streamfile(chan, peer_name, chan->language); | ||||
| 					if (!res) | ||||
| @@ -432,7 +501,7 @@ static int common_exec(struct ast_channel *chan, const int silent, const int bro | ||||
| 			} | ||||
| 			 | ||||
| 			waitms = 5000; | ||||
| 			res = channel_spy(chan, peer, &volfactor, fd); | ||||
| 			res = channel_spy(chan, peer, &volfactor, fd, flags); | ||||
| 			 | ||||
| 			if (res == -1) { | ||||
| 				break; | ||||
| @@ -461,15 +530,13 @@ static int chanspy_exec(struct ast_channel *chan, void *data) | ||||
| 	struct localuser *u; | ||||
| 	char *options = NULL; | ||||
| 	char *spec = NULL; | ||||
| 	char *argv[5]; | ||||
| 	char *argv[2]; | ||||
| 	char *mygroup = NULL; | ||||
| 	char *recbase = NULL; | ||||
| 	int fd = 0; | ||||
| 	struct ast_flags flags; | ||||
| 	int oldwf = 0; | ||||
| 	int argc = 0; | ||||
| 	int silent = 0; | ||||
| 	int bronly = 0; | ||||
| 	int volfactor = 0; | ||||
| 	int res; | ||||
|  | ||||
| @@ -479,18 +546,17 @@ static int chanspy_exec(struct ast_channel *chan, void *data) | ||||
|  | ||||
| 	if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { | ||||
| 		spec = argv[0]; | ||||
| 		if (argc > 1) { | ||||
| 		if (argc > 1) | ||||
| 			options = argv[1]; | ||||
| 		} | ||||
| 		if (ast_strlen_zero(spec) || !strcmp(spec, "all")) { | ||||
|  | ||||
| 		if (ast_strlen_zero(spec) || !strcmp(spec, "all")) | ||||
| 			spec = NULL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (options) { | ||||
| 		char *opts[OPT_ARG_ARRAY_SIZE]; | ||||
| 		 | ||||
| 		ast_app_parse_options(chanspy_opts, &flags, opts, options); | ||||
| 		ast_app_parse_options(spy_opts, &flags, opts, options); | ||||
| 		if (ast_test_flag(&flags, OPTION_GROUP)) | ||||
| 			mygroup = opts[OPT_ARG_GROUP]; | ||||
|  | ||||
| @@ -498,9 +564,6 @@ static int chanspy_exec(struct ast_channel *chan, void *data) | ||||
| 		    !(recbase = opts[OPT_ARG_RECORD])) | ||||
| 			recbase = "chanspy"; | ||||
|  | ||||
| 		silent = ast_test_flag(&flags, OPTION_QUIET); | ||||
| 		bronly = ast_test_flag(&flags, OPTION_BRIDGED); | ||||
|  | ||||
| 		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { | ||||
| 			int vol; | ||||
|  | ||||
| @@ -509,6 +572,9 @@ static int chanspy_exec(struct ast_channel *chan, void *data) | ||||
| 			else | ||||
| 				volfactor = vol; | ||||
| 		} | ||||
|  | ||||
| 		if (ast_test_flag(&flags, OPTION_PRIVATE)) | ||||
| 			ast_set_flag(&flags, OPTION_WHISPER); | ||||
| 	} | ||||
|  | ||||
| 	oldwf = chan->writeformat; | ||||
| @@ -528,7 +594,90 @@ static int chanspy_exec(struct ast_channel *chan, void *data) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	res = common_exec(chan, silent, bronly, volfactor, fd, mygroup, spec); | ||||
| 	res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL); | ||||
|  | ||||
| 	if (fd) | ||||
| 		close(fd); | ||||
|  | ||||
| 	if (oldwf && ast_set_write_format(chan, oldwf) < 0) | ||||
| 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); | ||||
|  | ||||
| 	LOCAL_USER_REMOVE(u); | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static int extenspy_exec(struct ast_channel *chan, void *data) | ||||
| { | ||||
| 	struct localuser *u; | ||||
| 	char *options = NULL; | ||||
| 	char *exten = NULL; | ||||
| 	char *context = NULL; | ||||
| 	char *argv[2]; | ||||
| 	char *mygroup = NULL; | ||||
| 	char *recbase = NULL; | ||||
| 	int fd = 0; | ||||
| 	struct ast_flags flags; | ||||
| 	int oldwf = 0; | ||||
| 	int argc = 0; | ||||
| 	int volfactor = 0; | ||||
| 	int res; | ||||
|  | ||||
| 	data = ast_strdupa(data); | ||||
|  | ||||
| 	LOCAL_USER_ADD(u); | ||||
|  | ||||
| 	if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { | ||||
| 		context = argv[0]; | ||||
| 		exten = strsep(&context, "@"); | ||||
| 		if (ast_strlen_zero(context)) | ||||
| 			context = ast_strdupa(chan->context); | ||||
| 		if (argc > 1) | ||||
| 			options = argv[1]; | ||||
| 	} | ||||
|  | ||||
| 	if (options) { | ||||
| 		char *opts[OPT_ARG_ARRAY_SIZE]; | ||||
| 		 | ||||
| 		ast_app_parse_options(spy_opts, &flags, opts, options); | ||||
| 		if (ast_test_flag(&flags, OPTION_GROUP)) | ||||
| 			mygroup = opts[OPT_ARG_GROUP]; | ||||
|  | ||||
| 		if (ast_test_flag(&flags, OPTION_RECORD) && | ||||
| 		    !(recbase = opts[OPT_ARG_RECORD])) | ||||
| 			recbase = "chanspy"; | ||||
|  | ||||
| 		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); | ||||
| 	} | ||||
|  | ||||
| 	oldwf = chan->writeformat; | ||||
| 	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { | ||||
| 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); | ||||
| 		LOCAL_USER_REMOVE(u); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (recbase) { | ||||
| 		char filename[512]; | ||||
|  | ||||
| 		snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); | ||||
| 		if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { | ||||
| 			ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); | ||||
| 			fd = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context); | ||||
|  | ||||
| 	if (fd) | ||||
| 		close(fd); | ||||
| @@ -543,9 +692,10 @@ static int chanspy_exec(struct ast_channel *chan, void *data) | ||||
|  | ||||
| static int unload_module(void *mod) | ||||
| { | ||||
| 	int res; | ||||
| 	int res = 0; | ||||
|  | ||||
| 	res = ast_unregister_application(app); | ||||
| 	res |= ast_unregister_application(app_chan); | ||||
| 	res |= ast_unregister_application(app_ext); | ||||
|  | ||||
| 	STANDARD_HANGUP_LOCALUSERS; | ||||
|  | ||||
| @@ -554,9 +704,14 @@ static int unload_module(void *mod) | ||||
|  | ||||
| static int load_module(void *mod) | ||||
| { | ||||
| 	int res = 0; | ||||
|  | ||||
| 	__mod_desc = mod; | ||||
|  | ||||
| 	return ast_register_application(app, chanspy_exec, tdesc, desc); | ||||
| 	res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); | ||||
| 	res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static const char *description(void) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user