Skip to content
Snippets Groups Projects
app_chanspy.c 43.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 					if (ptr && (num = atoi(ptr))) {
    
    						ast_say_digits(chan, num, "", ast_channel_language(chan));
    					}
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			}
    
    			res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
    			num_spyed_upon++;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			if (res == -1) {
    
    				iter = ast_channel_iterator_destroy(iter);
    
    				iter = ast_channel_iterator_destroy(iter);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			} else if (res > 1 && spec) {
    
    				struct ast_channel *next;
    
    
    				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
    
    				if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
    					next_autochan = ast_autochan_setup(next);
    					next = ast_channel_unref(next);
    
    					/* stay on this channel, if it is still valid */
    
    					if (!ast_check_hangup(autochan->chan)) {
    						next_autochan = ast_autochan_setup(autochan->chan);
    
    					} else {
    						/* the channel is gone */
    
    			} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
    
    				iter = ast_channel_iterator_destroy(iter);
    
    		if (res == -1 || ast_check_hangup(chan))
    			break;
    
    		if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
    			break;
    		}
    
    	ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING);
    
    
    	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
    
    	return res;
    }
    
    
    static int chanspy_exec(struct ast_channel *chan, const char *data)
    
    	char *mygroup = NULL;
    	char *recbase = NULL;
    	int fd = 0;
    	struct ast_flags flags;
    
    	struct spy_dtmf_options user_options = {
    		.cycle = '*',
    		.volume = '#',
    		.exit = '\0',
    	};
    
    	int volfactor = 0;
    	int res;
    
    	AST_DECLARE_APP_ARGS(args,
    		AST_APP_ARG(spec);
    		AST_APP_ARG(options);
    	);
    	char *opts[OPT_ARG_ARRAY_SIZE];
    
    	char *parse = ast_strdupa(data);
    
    	AST_STANDARD_APP_ARGS(args, parse);
    
    	if (args.spec && !strcmp(args.spec, "all"))
    		args.spec = NULL;
    
    		ast_app_parse_options(spy_opts, &flags, opts, args.options);
    
    		if (ast_test_flag(&flags, OPTION_GROUP))
    			mygroup = opts[OPT_ARG_GROUP];
    
    		if (ast_test_flag(&flags, OPTION_RECORD) &&
    
    Michiel van Baak's avatar
    Michiel van Baak committed
    			!(recbase = opts[OPT_ARG_RECORD]))
    
    			recbase = "chanspy";
    
    
    		if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
    			tmp = opts[OPT_ARG_EXIT][0];
    			if (strchr("0123456789*#", tmp) && tmp != '\0') {
    				user_options.exit = tmp;
    			} else {
    
    				ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
    
    			}
    		}
    
    		if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
    			tmp = opts[OPT_ARG_CYCLE][0];
    			if (strchr("0123456789*#", tmp) && tmp != '\0') {
    				user_options.cycle = tmp;
    			} else {
    
    				ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
    
    		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
    			int vol;
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &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);
    
    
    		if (ast_test_flag(&flags, OPTION_ENFORCED))
    			myenforced = opts[OPT_ARG_ENFORCED];
    
    		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];
    				}
    			}
    		}
    
    		ast_clear_flag(&flags, AST_FLAGS_ALL);
    
    	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
    
    	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
    
    		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
    		return -1;
    	}
    
    	if (recbase) {
    
    		char filename[PATH_MAX];
    
    
    		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, AST_FILE_MODE)) <= 0) {
    
    			ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
    			fd = 0;
    		}
    	}
    
    
    	res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
    
    	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
    
    		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
    
    
    	if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
    		ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
    	}
    
    
    static int extenspy_exec(struct ast_channel *chan, const char *data)
    
    	char *mygroup = NULL;
    	char *recbase = NULL;
    	int fd = 0;
    	struct ast_flags flags;
    
    	struct spy_dtmf_options user_options = {
    		.cycle = '*',
    		.volume = '#',
    		.exit = '\0',
    	};
    
    	int volfactor = 0;
    	int res;
    
    	AST_DECLARE_APP_ARGS(args,
    		AST_APP_ARG(context);
    		AST_APP_ARG(options);
    	);
    
    	char *parse = ast_strdupa(data);
    
    	AST_STANDARD_APP_ARGS(args, parse);
    
    	if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
    		exten = args.context;
    		*ptr++ = '\0';
    		args.context = ptr;
    
    		args.context = ast_strdupa(ast_channel_context(chan));
    
    		char *opts[OPT_ARG_ARRAY_SIZE];
    
    		ast_app_parse_options(spy_opts, &flags, opts, args.options);
    
    		if (ast_test_flag(&flags, OPTION_GROUP))
    			mygroup = opts[OPT_ARG_GROUP];
    
    		if (ast_test_flag(&flags, OPTION_RECORD) &&
    
    Michiel van Baak's avatar
    Michiel van Baak committed
    			!(recbase = opts[OPT_ARG_RECORD]))
    
    			recbase = "chanspy";
    
    		if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
    			tmp = opts[OPT_ARG_EXIT][0];
    			if (strchr("0123456789*#", tmp) && tmp != '\0') {
    				user_options.exit = tmp;
    			} else {
    
    				ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
    
    			}
    		}
    
    		if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
    			tmp = opts[OPT_ARG_CYCLE][0];
    			if (strchr("0123456789*#", tmp) && tmp != '\0') {
    				user_options.cycle = tmp;
    			} else {
    
    				ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
    
    		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
    			int vol;
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &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);
    
    
    		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];
    				}
    			}
    		}
    
    
    		/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
    
    		ast_clear_flag(&flags, AST_FLAGS_ALL);
    
    	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
    
    	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
    
    		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
    		return -1;
    	}
    
    	if (recbase) {
    
    		char filename[PATH_MAX];
    
    
    		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, AST_FILE_MODE)) <= 0) {
    
    			ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
    			fd = 0;
    		}
    	}
    
    
    	res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	if (fd)
    
    	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
    
    		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
    
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	return res;
    
    static int dahdiscan_exec(struct ast_channel *chan, const char *data)
    
    {
    	const char *spec = "DAHDI";
    	struct ast_flags flags;
    	struct spy_dtmf_options user_options = {
    		.cycle = '#',
    		.volume = '\0',
    		.exit = '*',
    	};
    
    	/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
    
    	ast_clear_flag(&flags, AST_FLAGS_ALL);
    
    	if (!ast_strlen_zero(data)) {
    		mygroup = ast_strdupa(data);
    	}
    	ast_set_flag(&flags, OPTION_DTMF_EXIT);
    	ast_set_flag(&flags, OPTION_DTMF_CYCLE);
    	ast_set_flag(&flags, OPTION_DAHDI_SCAN);
    
    
    	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
    
    	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
    
    		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
    		return -1;
    	}
    
    	res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
    
    
    	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
    
    		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
    
    	return res;
    }
    
    
    static int unload_module(void)
    
    	int res = 0;
    
    	res |= ast_unregister_application(app_chan);
    	res |= ast_unregister_application(app_ext);
    
    	res |= ast_unregister_application(app_dahdiscan);
    
    static int load_module(void)
    
    	res |= ast_register_application_xml(app_chan, chanspy_exec);
    	res |= ast_register_application_xml(app_ext, extenspy_exec);
    
    	res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
    
    AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");