static int app_exec(struct ast_channel *chan, void *data)
{
	struct ast_module_user *lu;
	struct playlist_entry *entry;
	const char *args = data;
	int child_stdin[2] = { 0,0 };
	int child_stdout[2] = { 0,0 };
	int child_stderr[2] = { 0,0 };
	int res = -1;
	int test_available_fd = -1;
	int gen_active = 0;
	int pid;
	char *argv[32];
	int argc = 1;
	char *buf, *command;
	FILE *child_commands = NULL;
	FILE *child_errors = NULL;
	FILE *child_events = NULL;
	struct ivr_localuser foo = {
		.playlist = AST_LIST_HEAD_INIT_VALUE,
		.finishlist = AST_LIST_HEAD_INIT_VALUE,
	};
	struct ivr_localuser *u = &foo;
	sigset_t fullset, oldset;

	lu = ast_module_user_add(chan);

	sigfillset(&fullset);
	pthread_sigmask(SIG_BLOCK, &fullset, &oldset);

	u->abort_current_sound = 0;
	u->chan = chan;
	
	if (ast_strlen_zero(args)) {
		ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
		ast_module_user_remove(lu);
		return -1;	
	}

	buf = ast_strdupa(data);

	argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));

	if (pipe(child_stdin)) {
		ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
		goto exit;
	}

	if (pipe(child_stdout)) {
		ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
		goto exit;
	}

	if (pipe(child_stderr)) {
		ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
		goto exit;
	}

	if (chan->_state != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (ast_activate_generator(chan, &gen, u) < 0) {
		ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
		goto exit;
	} else
		gen_active = 1;

	pid = fork();
	if (pid < 0) {
		ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
		goto exit;
	}

	if (!pid) {
		/* child process */
		int i;
#ifdef HAVE_CAP
		cap_t cap = cap_from_text("cap_net_admin-eip");

		if (cap_set_proc(cap)) {
			/* Careful with order! Logging cannot happen after we close FDs */
			ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
		}
		cap_free(cap);
#endif

		signal(SIGPIPE, SIG_DFL);
		pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);

		if (ast_opt_high_priority)
			ast_set_priority(0);

		dup2(child_stdin[0], STDIN_FILENO);
		dup2(child_stdout[1], STDOUT_FILENO);
		dup2(child_stderr[1], STDERR_FILENO);
		for (i = STDERR_FILENO + 1; i < 1024; i++)
			close(i);
		execv(argv[0], argv);
		fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
		_exit(1);
	} else {
		/* parent process */
		int child_events_fd = child_stdin[1];
		int child_commands_fd = child_stdout[0];
		int child_errors_fd = child_stderr[0];
		struct ast_frame *f;
		int ms;
		int exception;
		int ready_fd;
		int waitfds[2] = { child_errors_fd, child_commands_fd };
		struct ast_channel *rchan;

		pthread_sigmask(SIG_SETMASK, &oldset, NULL);

		close(child_stdin[0]);
		child_stdin[0] = 0;
		close(child_stdout[1]);
		child_stdout[1] = 0;
		close(child_stderr[1]);
		child_stderr[1] = 0;

		if (!(child_events = fdopen(child_events_fd, "w"))) {
			ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n");
			goto exit;
		}

		if (!(child_commands = fdopen(child_commands_fd, "r"))) {
			ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n");
			goto exit;
		}

		if (!(child_errors = fdopen(child_errors_fd, "r"))) {
			ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n");
			goto exit;
		}

		test_available_fd = open("/dev/null", O_RDONLY);

		setvbuf(child_events, NULL, _IONBF, 0);
		setvbuf(child_commands, NULL, _IONBF, 0);
		setvbuf(child_errors, NULL, _IONBF, 0);

		res = 0;

		while (1) {
			if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
				ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
				res = -1;
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
				send_child_event(child_events, 'H', NULL, chan);
				res = -1;
				break;
			}

			ready_fd = 0;
			ms = 100;
			errno = 0;
			exception = 0;

			rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms);

			if (!AST_LIST_EMPTY(&u->finishlist)) {
				AST_LIST_LOCK(&u->finishlist);
				while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
					send_child_event(child_events, 'F', entry->filename, chan);
					free(entry);
				}
				AST_LIST_UNLOCK(&u->finishlist);
			}

			if (rchan) {
				/* the channel has something */
				f = ast_read(chan);
				if (!f) {
					ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
					send_child_event(child_events, 'H', NULL, chan);
					res = -1;
					break;
				}

				if (f->frametype == AST_FRAME_DTMF) {
					send_child_event(child_events, f->subclass, NULL, chan);
					if (u->option_autoclear) {
						if (!u->abort_current_sound && !u->playing_silence)
							send_child_event(child_events, 'T', NULL, chan);
						AST_LIST_LOCK(&u->playlist);
						while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
							send_child_event(child_events, 'D', entry->filename, chan);
							free(entry);
						}
						if (!u->playing_silence)
							u->abort_current_sound = 1;
						AST_LIST_UNLOCK(&u->playlist);
					}
				} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
					ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
					send_child_event(child_events, 'H', NULL, chan);
					ast_frfree(f);
					res = -1;
					break;
				}
				ast_frfree(f);
			} else if (ready_fd == child_commands_fd) {
				char input[1024];

				if (exception || feof(child_commands)) {
					ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
					res = -1;
					break;
				}

				if (!fgets(input, sizeof(input), child_commands))
					continue;

				command = ast_strip(input);

				ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);

				if (strlen(input) < 4)
					continue;

				if (input[0] == 'S') {
					if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
						ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
						send_child_event(child_events, 'Z', NULL, chan);
						strcpy(&input[2], "exception");
					}
					if (!u->abort_current_sound && !u->playing_silence)
						send_child_event(child_events, 'T', NULL, chan);
					AST_LIST_LOCK(&u->playlist);
					while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
						send_child_event(child_events, 'D', entry->filename, chan);
						free(entry);
					}
					if (!u->playing_silence)
						u->abort_current_sound = 1;
					entry = make_entry(&input[2]);
					if (entry)
						AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
					AST_LIST_UNLOCK(&u->playlist);
				} else if (input[0] == 'A') {
					if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
						ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
						send_child_event(child_events, 'Z', NULL, chan);
						strcpy(&input[2], "exception");
					}
					entry = make_entry(&input[2]);
					if (entry) {
						AST_LIST_LOCK(&u->playlist);
						AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
						AST_LIST_UNLOCK(&u->playlist);
					}
				} else if (input[0] == 'H') {
					ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
					send_child_event(child_events, 'H', NULL, chan);
					break;
				} else if (input[0] == 'O') {
					if (!strcasecmp(&input[2], "autoclear"))
						u->option_autoclear = 1;
					else if (!strcasecmp(&input[2], "noautoclear"))
						u->option_autoclear = 0;
					else
						ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
				}
			} else if (ready_fd == child_errors_fd) {
				char input[1024];

				if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) {
					ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
					res = -1;
					break;
				}

				if (fgets(input, sizeof(input), child_errors)) {
					command = ast_strip(input);
					ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
				}
			} else if ((ready_fd < 0) && ms) { 
				if (errno == 0 || errno == EINTR)
					continue;

				ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
				break;
			}
		}
	}

 exit:
	if (gen_active)
		ast_deactivate_generator(chan);

	if (child_events)
		fclose(child_events);

	if (child_commands)
		fclose(child_commands);

	if (child_errors)
		fclose(child_errors);

	if (test_available_fd > -1) {
		close(test_available_fd);
	}

	if (child_stdin[0])
		close(child_stdin[0]);

	if (child_stdin[1])
		close(child_stdin[1]);

	if (child_stdout[0])
		close(child_stdout[0]);

	if (child_stdout[1])
		close(child_stdout[1]);

	if (child_stderr[0])
		close(child_stderr[0]);

	if (child_stderr[1])
		close(child_stderr[1]);

	while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
		free(entry);

	ast_module_user_remove(lu);

	return res;
}
Esempio n. 2
0
/*
 * the string is 'prefix:data' or prefix:fmt:data'
 * with ':' being invalid in strings.
 */
static int do_say(say_args_t *a, const char *s, const char *options, int depth)
{
	struct ast_variable *v;
	char *lang, *x, *rule = NULL;
	int ret = 0;   
	struct varshead head = { .first = NULL, .last = NULL };
	struct ast_var_t *n;

	ast_debug(2, "string <%s> depth <%d>\n", s, depth);
	if (depth++ > 10) {
		ast_log(LOG_WARNING, "recursion too deep, exiting\n");
		return -1;
	} else if (!say_cfg) {
		ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
		return -1;
	}

	/* scan languages same as in file.c */
	if (a->language == NULL)
		a->language = "en";     /* default */
	ast_debug(2, "try <%s> in <%s>\n", s, a->language);
	lang = ast_strdupa(a->language);
	for (;;) {
		for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
			if (ast_extension_match(v->name, s)) {
				rule = ast_strdupa(v->value);
				break;
			}
		}
		if (rule)
			break;
		if ( (x = strchr(lang, '_')) )
			*x = '\0';      /* try without suffix */
		else if (strcmp(lang, "en"))
			lang = "en";    /* last resort, try 'en' if not done yet */
		else
			break;
	}
	if (!rule)
		return 0;

	/* skip up to two prefixes to get the value */
	if ( (x = strchr(s, ':')) )
		s = x + 1;
	if ( (x = strchr(s, ':')) )
		s = x + 1;
	ast_debug(2, "value is <%s>\n", s);
	n = ast_var_assign("SAY", s);
	AST_LIST_INSERT_HEAD(&head, n, entries);

	/* scan the body, one piece at a time */
	while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
		char fn[128];
		const char *p, *fmt, *data; /* format and data pointers */

		/* prepare a decent file name */
		x = ast_skip_blanks(x);
		ast_trim_blanks(x);

		/* replace variables */
		pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
		ast_debug(2, "doing [%s]\n", fn);

		/* locate prefix and data, if any */
		fmt = strchr(fn, ':');
		if (!fmt || fmt == fn)	{	/* regular filename */
			ret = s_streamwait3(a, fn);
			continue;
		}
		fmt++;
		data = strchr(fmt, ':');	/* colon before data */
		if (!data || data == fmt) {	/* simple prefix-fmt */
			ret = do_say(a, fn, options, depth);
			continue;
		}
		/* prefix:fmt:data */
		for (p = fmt; p < data && ret <= 0; p++) {
			char fn2[sizeof(fn)];
			if (*p == ' ' || *p == '\t')	/* skip blanks */
				continue;
			if (*p == '\'') {/* file name - we trim them */
				char *y;
				strcpy(fn2, ast_skip_blanks(p+1));	/* make a full copy */
				y = strchr(fn2, '\'');
				if (!y) {
					p = data;	/* invalid. prepare to end */
					break;
				}
				*y = '\0';
				ast_trim_blanks(fn2);
				p = strchr(p+1, '\'');
				ret = s_streamwait3(a, fn2);
			} else {
				int l = fmt-fn;
				strcpy(fn2, fn); /* copy everything */
				/* after prefix, append the format */
				fn2[l++] = *p;
				strcpy(fn2 + l, data);
				ret = do_say(a, fn2, options, depth);
			}
			
			if (ret) {
				break;
			}
		}
	}
	ast_var_delete(n);
	return ret;
}
Esempio n. 3
0
static int cli_channelstats_print_body(void *obj, void *arg, int flags)
{
	struct ast_sip_cli_context *context = arg;
	const struct ast_channel_snapshot *snapshot = obj;
	struct ast_channel *channel = ast_channel_get_by_name(snapshot->name);
	struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL;
	struct ast_sip_session *session;
	struct ast_sip_session_media *media;
	struct ast_rtp_instance *rtp;
	struct ast_rtp_instance_stats stats;
	char *print_name = NULL;
	char *print_time = alloca(32);
	char codec_in_use[7];

	ast_assert(context->output_buffer != NULL);

	if (!channel) {
		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
		return -1;
	}

	ast_channel_lock(channel);

	session = cpvt->session;
	if (!session) {
		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
		ast_channel_unlock(channel);
		ao2_cleanup(channel);
		return -1;
	}

	media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
	if (!media || !media->rtp) {
		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
		ast_channel_unlock(channel);
		ao2_cleanup(channel);
		return -1;
	}

	rtp = ao2_bump(media->rtp);

	codec_in_use[0] = '\0';

	if (ast_channel_rawreadformat(channel)) {
		ast_copy_string(codec_in_use, ast_format_get_name(ast_channel_rawreadformat(channel)), sizeof(codec_in_use));
	}

	ast_channel_unlock(channel);

	print_name = ast_strdupa(snapshot->name);
	/* Skip the PJSIP/.  We know what channel type it is and we need the space. */
	print_name += 6;

	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);

	if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
		ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name);
	} else {
		ast_str_append(&context->output_buffer, 0,
			" %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n",
			snapshot->bridgeid,
			print_name,
			print_time,
			codec_in_use,
			stats.rxcount > 100000 ? stats.rxcount / 1000 : stats.rxcount,
			stats.rxcount > 100000 ? "K": " ",
			stats.rxploss > 100000 ? stats.rxploss / 1000 : stats.rxploss,
			stats.rxploss > 100000 ? "K": " ",
			stats.rxcount ? (stats.rxploss * 100) / stats.rxcount : 0,
			MIN(stats.rxjitter, 999.999),
			stats.txcount > 100000 ? stats.txcount / 1000 : stats.txcount,
			stats.txcount > 100000 ? "K": " ",
			stats.txploss > 100000 ? stats.txploss / 1000 : stats.txploss,
			stats.txploss > 100000 ? "K": " ",
			stats.txcount ? (stats.txploss * 100) / stats.txcount : 0,
			MIN(stats.txjitter, 999.999),
			MIN(stats.normdevrtt, 999.999)
		);
	}

	ao2_cleanup(rtp);
	ao2_cleanup(channel);

	return 0;
}
Esempio n. 4
0
/*! \brief Generate a Sound structure as documented in sounds.json for the specified filename */
static struct ast_json *create_sound_blob(const char *filename, struct ast_get_sounds_args *args)
{
	RAII_VAR(struct ast_json *, sound, NULL, ast_json_unref);
	RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
	const char *description;
	struct ast_json *format_lang_list;
	struct lang_format_info info;
	RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);

	if (!sounds_index) {
		return NULL;
	}

	description = ast_media_get_description(sounds_index, filename, "en");
	if (ast_strlen_zero(description)) {
		sound = ast_json_pack("{s: s, s: []}",
			"id", filename,
			"formats");
	} else {
		sound = ast_json_pack("{s: s, s: s, s: []}",
			"id", filename,
			"text", description,
			"formats");
	}
	if (!sound) {
		return NULL;
	}

	format_lang_list = ast_json_object_get(sound, "formats");
	if (!format_lang_list) {
		return NULL;
	}

	languages = ast_media_get_variants(sounds_index, filename);
	if (!languages || !ao2_container_count(languages)) {
		return NULL;
	}

	/* filter requested languages */
	if (args && !ast_strlen_zero(args->lang)) {
		char *lang_filter = ast_strdupa(args->lang);
		ao2_callback(languages, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, filter_langs_cb, lang_filter);
		if (!languages || !ao2_container_count(languages)) {
			return NULL;
		}
	}

	info.filename = filename;
	info.format_list = format_lang_list;
	info.format_filter = NULL;
	if (args) {
		info.format_filter = args->format;
	}
	ao2_callback(languages, OBJ_NODATA, add_format_information_cb, &info);

	/* no format/lang pairs for this sound so nothing to return */
	if (!ast_json_array_size(format_lang_list)) {
		return NULL;
	}

	return ast_json_ref(sound);
}
Esempio n. 5
0
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
{
    int d = 0;
    char *fmts;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;
    char prependfile[80];

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile || beep) {
        if (!beep)
            d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }
    strncpy(prependfile, recordfile, sizeof(prependfile) -1);
    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
        if (!others[x]) {
            break;
        }
    }

    sildet = ast_dsp_new(); /* Create the silence detector */
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    ast_dsp_set_threshold(sildet, silencethreshold);

    if (maxsilence > 0) {
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    if (!others[x])
                        break;
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                /* stop recording with any digit */
                if (option_verbose > 2)
                    ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                res = 't';
                outmsg = 2;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    res = 't';
                    outmsg=2;
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
#if 0
            /* delete all the prepend files */
            for (x=0; x<fmtcnt; x++) {
                if (!others[x])
                    break;
                ast_closestream(others[x]);
                ast_filedelete(prependfile, sfmt[x]);
            }
#endif
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
    }
    *duration = end - start;
#if 0
    if (outmsg > 1) {
#else
    if (outmsg) {
#endif
        struct ast_frame *fr;
        for (x=0; x<fmtcnt; x++) {
            snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
            realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
            if (!others[x] || !realfiles[x])
                break;
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
            ast_truncstream(others[x]);
            /* add the original file too */
            while ((fr = ast_readframe(realfiles[x]))) {
                ast_writestream(others[x],fr);
            }
            ast_closestream(others[x]);
            ast_closestream(realfiles[x]);
            ast_filerename(prependfile, recordfile, sfmt[x]);
#if 0
            ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
#endif
            ast_filedelete(prependfile, sfmt[x]);
        }
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg) {
        if (outmsg > 1) {
            /* Let them know it worked */
            ast_streamfile(chan, "auth-thankyou", chan->language);
            ast_waitstream(chan, "");
        }
    }
    return res;
}

int ast_lock_path(const char *path)
{
    char *s;
    char *fs;
    int res;
    int fd;
    time_t start;
    s = alloca(strlen(path) + 10);
    fs = alloca(strlen(path) + 20);
    if (!fs || !s) {
        ast_log(LOG_WARNING, "Out of memory!\n");
        return -1;
    }
    snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
    if (fd < 0) {
        fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
        return -1;
    }
    close(fd);
    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
    time(&start);
    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
        usleep(1);
    if (res < 0) {
        ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
    }
    unlink(fs);
    ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
    return res;
}
Esempio n. 6
0
/*! \brief Initiate new call, part of PBX interface
 *         dest is the dial string */
static int local_call(struct ast_channel *ast, const char *dest, int timeout)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	int pvt_locked = 0;

	struct ast_channel *owner = NULL;
	struct ast_channel *chan = NULL;
	int res;
	char *reduced_dest = ast_strdupa(dest);
	char *slash;
	const char *chan_cid;

	if (!p) {
		return -1;
	}

	/* since we are letting go of channel locks that were locked coming into
	 * this function, then we need to give the tech pvt a ref */
	ao2_ref(p, 1);
	ast_channel_unlock(ast);

	ast_unreal_lock_all(&p->base, &chan, &owner);
	pvt_locked = 1;

	if (owner != ast) {
		res = -1;
		goto return_cleanup;
	}

	if (!owner || !chan) {
		res = -1;
		goto return_cleanup;
	}

	ast_unreal_call_setup(owner, chan);

	/*
	 * If the local channel has /n on the end of it, we need to lop
	 * that off for our argument to setting up the CC_INTERFACES
	 * variable.
	 */
	if ((slash = strrchr(reduced_dest, '/'))) {
		*slash = '\0';
	}
	ast_set_cc_interfaces_chanvar(chan, reduced_dest);

	ao2_unlock(p);
	pvt_locked = 0;

	ast_channel_unlock(owner);

	chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
		ast_channel_caller(chan)->id.number.str, NULL);
	if (chan_cid) {
		chan_cid = ast_strdupa(chan_cid);
	}
	ast_channel_unlock(chan);

	res = -1;
	switch (p->type) {
	case LOCAL_CALL_ACTION_DIALPLAN:
		if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
			ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
				p->exten, p->context);
		} else {
			publish_local_bridge_message(p);

			/* Start switch on sub channel */
			res = ast_pbx_start(chan);
		}
		break;
	case LOCAL_CALL_ACTION_BRIDGE:
		publish_local_bridge_message(p);
		ast_answer(chan);
		res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
			p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT);
		ao2_ref(p->action.bridge.join, -1);
		p->action.bridge.join = NULL;
		ao2_cleanup(p->action.bridge.swap);
		p->action.bridge.swap = NULL;
		p->action.bridge.features = NULL;
		break;
	case LOCAL_CALL_ACTION_MASQUERADE:
		publish_local_bridge_message(p);
		ast_answer(chan);
		res = ast_channel_move(p->action.masq, chan);
		if (!res) {
			/* Chan is now an orphaned zombie.  Destroy it. */
			ast_hangup(chan);
		}
		p->action.masq = ast_channel_unref(p->action.masq);
		break;
	}
	if (!res) {
		ao2_lock(p);
		ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
		ao2_unlock(p);
	}

	/* we already unlocked them, clear them here so the cleanup label won't touch them. */
	owner = ast_channel_unref(owner);
	chan = ast_channel_unref(chan);

return_cleanup:
	if (p) {
		if (pvt_locked) {
			ao2_unlock(p);
		}
		ao2_ref(p, -1);
	}
	if (chan) {
		ast_channel_unlock(chan);
		ast_channel_unref(chan);
	}

	/*
	 * owner is supposed to be == to ast, if it is, don't unlock it
	 * because ast must exit locked
	 */
	if (owner) {
		if (owner != ast) {
			ast_channel_unlock(owner);
			ast_channel_lock(ast);
		}
		ast_channel_unref(owner);
	} else {
		/* we have to exit with ast locked */
		ast_channel_lock(ast);
	}

	return res;
}
Esempio n. 7
0
static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr)
{
	int recordtype = PW_STATUS_STOP;
	struct ast_tm tm;
	char timestr[128];
	char *tmp;

	if (!rc_avpair_add(rh, tosend, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0))
		return -1;

	/* Account code */
	if (!rc_avpair_add(rh, tosend, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE))
		return -1;

 	/* Source */
	if (!rc_avpair_add(rh, tosend, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE))
		return -1;

 	/* Destination */
	if (!rc_avpair_add(rh, tosend, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE))
		return -1;

 	/* Destination context */
	if (!rc_avpair_add(rh, tosend, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE))
		return -1;

	/* Caller ID */
	if (!rc_avpair_add(rh, tosend, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE))
		return -1;

	/* Channel */
	if (!rc_avpair_add(rh, tosend, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE))
		return -1;

	/* Destination Channel */
	if (!rc_avpair_add(rh, tosend, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE))
		return -1;

	/* Last Application */
	if (!rc_avpair_add(rh, tosend, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE))
		return -1;

	/* Last Data */
	if (!rc_avpair_add(rh, tosend, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE))
		return -1;


	/* Start Time */
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT,
		ast_localtime(&cdr->start, &tm,
			ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL));
	if (!rc_avpair_add(rh, tosend, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE))
		return -1;

	/* Answer Time */
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT,
		ast_localtime(&cdr->answer, &tm,
			ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL));
	if (!rc_avpair_add(rh, tosend, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE))
		return -1;

	/* End Time */
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT,
		ast_localtime(&cdr->end, &tm,
			ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL));
	if (!rc_avpair_add(rh, tosend, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE))
		return -1;

 	/* Duration */
	if (!rc_avpair_add(rh, tosend, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE))
		return -1;

	/* Billable seconds */
	if (!rc_avpair_add(rh, tosend, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE))
		return -1;

	/* Disposition */
	tmp = ast_strdupa(ast_cdr_disp2str(cdr->disposition));
	if (!rc_avpair_add(rh, tosend, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE))
		return -1;

	/* AMA Flags */
	tmp = ast_strdupa(ast_channel_amaflags2string(cdr->amaflags));
	if (!rc_avpair_add(rh, tosend, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE))
		return -1;

	if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
		/* Unique ID */
		if (!rc_avpair_add(rh, tosend, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE))
			return -1;
	}

	if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) {
		/* append the user field */
		if (!rc_avpair_add(rh, tosend, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE))
			return -1;
	}

	/* Setting Acct-Session-Id & User-Name attributes for proper generation
	 * of Acct-Unique-Session-Id on server side 
	 */
	/* Channel */
	if (!rc_avpair_add(rh, tosend, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0))
		return -1;

	/* Unique ID */
	if (!rc_avpair_add(rh, tosend, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0))
		return -1;

	return 0;
}
Esempio n. 8
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
			ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
		return 0;
	}

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(ast_channel_name(chan));
	ast_channel_unlock(chan);

	ast_channel_lock(spyee_autochan->chan);
	name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
	ast_channel_unlock(spyee_autochan->chan);

	ast_verb(2, "Spying on channel %s\n", name);
	publish_chanspy_message(chan, spyee_autochan->chan, 1);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	/* This is the audiohook which gives us the audio off the channel we are
	   spying on.
	*/
	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		/* This audiohook will let us inject audio from our channel into the
		   channel we are currently spying on.
		*/
		ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);

		if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
			ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
		}
	}

	if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(spyee_autochan->chan), ast_channel_cleanup);

		/* And this hook lets us inject audio into the channel that the spied on
		   channel is currently bridged with.
		*/
		ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);

		if ((spyee_bridge_autochan = ast_autochan_setup(bridged))) {
			ast_channel_lock(spyee_bridge_autochan->chan);
			if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
				ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
			}
			ast_channel_unlock(spyee_bridge_autochan->chan);
		}
	}
Esempio n. 9
0
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
		const char *userdefevname, const char *extra, struct ast_channel *peer2)
{
	struct timeval eventtime;
	struct ast_event *ev;
	const char *peername = "";
	struct ast_channel *peer;
	char *linkedid = ast_strdupa(ast_channel_linkedid(chan));

	/* Make sure a reload is not occurring while we're checking to see if this
	 * is an event that we care about.  We could lose an important event in this
	 * process otherwise. */
	ast_mutex_lock(&reload_lock);

	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
	if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
		if (ast_cel_linkedid_ref(linkedid)) {
			ast_mutex_unlock(&reload_lock);
			return -1;
		}
	}

	if (!cel_enabled || !ast_cel_track_event(event_type)) {
		ast_mutex_unlock(&reload_lock);
		return 0;
	}

	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
		char *app;
		if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
			ast_mutex_unlock(&reload_lock);
			return 0;
		}
		ao2_ref(app, -1);
	}

	ast_mutex_unlock(&reload_lock);

	ast_channel_lock(chan);
	peer = ast_bridged_channel(chan);
	if (peer) {
		ast_channel_ref(peer);
	}
	ast_channel_unlock(chan);

	if (peer) {
		ast_channel_lock(peer);
		peername = ast_strdupa(ast_channel_name(peer));
		ast_channel_unlock(peer);
	} else if (peer2) {
		ast_channel_lock(peer2);
		peername = ast_strdupa(ast_channel_name(peer2));
		ast_channel_unlock(peer2);
	}

	if (!userdefevname) {
		userdefevname = "";
	}

	if (!extra) {
		extra = "";
	}

	eventtime = ast_tvnow();

	ast_channel_lock(chan);

	ev = ast_event_new(AST_EVENT_CEL,
		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
			S_OR(ast_channel_dialed(chan)->number.str, ""),
		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
		AST_EVENT_IE_END);

	ast_channel_unlock(chan);

	if (peer) {
		peer = ast_channel_unref(peer);
	}

	if (ev && ast_event_queue(ev)) {
		ast_event_destroy(ev);
		return -1;
	}

	return 0;
}
Esempio n. 10
0
static int extenspy_exec(struct ast_channel *chan, const char *data)
{
	char *ptr, *exten = NULL;
	char *mygroup = NULL;
	char *recbase = NULL;
	int fd = 0;
	struct ast_flags flags;
	struct spy_dtmf_options user_options = {
		.cycle = '*',
		.volume = '#',
		.exit = '\0',
	};
	RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
	int volfactor = 0;
	int res;
	char *mailbox = NULL;
	char *name_context = NULL;
	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;
	}
	if (ast_strlen_zero(args.context))
		args.context = ast_strdupa(ast_channel_context(chan));

	if (args.options) {
		char *opts[OPT_ARG_ARRAY_SIZE];
		char tmp;

		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) &&
			!(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;

			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];
				}
			}
		}

	} else {
		/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
		ast_clear_flag(&flags, AST_FLAGS_ALL);
	}

	oldwf = ao2_bump(ast_channel_writeformat(chan));
	if (ast_set_write_format(chan, ast_format_slin) < 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);

	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;
}
Esempio n. 11
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, bridge_connected = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
			ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
		return 0;
	}

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(ast_channel_name(chan));
	ast_channel_unlock(chan);

	ast_autochan_channel_lock(spyee_autochan);
	name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
	ast_autochan_channel_unlock(spyee_autochan);

	ast_verb(2, "Spying on channel %s\n", name);
	publish_chanspy_message(chan, spyee_autochan->chan, 1);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	/* This is the audiohook which gives us the audio off the channel we are
	   spying on.
	*/
	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		/* This audiohook will let us inject audio from our channel into the
		   channel we are currently spying on.
		*/
		ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);

		if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
			ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
		}
	}

	ast_channel_lock(chan);
	ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	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;

	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.
	*/

	/* 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 a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			if (f) {
				ast_frfree(f);
			}
			break;
		}

		if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
			/* This hook lets us inject audio into the channel that the spyee is currently
			 * bridged with. If the spyee isn't bridged with anything yet, nothing will
			 * be attached and we'll need to continue attempting to attach the barge
			 * audio hook. */
			if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
					&csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
				bridge_connected = 1;
			}

			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);

			if (bridge_connected) {
				ast_audiohook_lock(&csth.bridge_whisper_audiohook);
				ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
				ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
			}

			ast_frfree(f);
			continue;
		} else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}

		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		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)) {
				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
				running = -2;
				break;
			} else {
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		} else if (res >= '0' && res <= '9') {
			if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
				change_spy_mode(res, flags);
			} else {
				inp[x++] = res;
			}
		}

		if (res == user_options->cycle) {
			running = 0;
			break;
		} else if (res == user_options->exit) {
			running = -2;
			break;
		} else if (res == user_options->volume) {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);

			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	ast_channel_lock(chan);
	ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		ast_audiohook_lock(&csth.whisper_audiohook);
		ast_audiohook_detach(&csth.whisper_audiohook);
		ast_audiohook_unlock(&csth.whisper_audiohook);
		ast_audiohook_destroy(&csth.whisper_audiohook);
	}

	if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		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);
	}

	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);

	if (spyee_bridge_autochan) {
		ast_autochan_destroy(spyee_bridge_autochan);
	}

	ast_verb(2, "Done Spying on channel %s\n", name);
	publish_chanspy_message(chan, NULL, 0);

	return running;
}
static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	static const char *mixmonitor_spy_type = "MixMonitor";
	const char *stop_message;
	const char *start_message;
	struct ast_bridge_features_automixmonitor *options = hook_pvt;
	enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
	int is_monitoring;

	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);

	ast_channel_lock(bridge_channel->chan);
	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
	ast_channel_unlock(bridge_channel->chan);
	ast_bridge_channel_lock_bridge(bridge_channel);
	peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
	ast_bridge_unlock(bridge_channel->bridge);

	if (!peer_chan) {
		ast_verb(4, "Cannot start AutoMixMonitor for %s - cannot determine peer in bridge.\n",
			ast_channel_name(bridge_channel->chan));
		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
		}
		return 0;
	}

	ast_channel_lock(bridge_channel->chan);
	start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
		"TOUCH_MIXMONITOR_MESSAGE_START");
	start_message = ast_strdupa(S_OR(start_message, ""));
	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
		"TOUCH_MIXMONITOR_MESSAGE_STOP");
	stop_message = ast_strdupa(S_OR(stop_message, ""));
	ast_channel_unlock(bridge_channel->chan);

	is_monitoring =
		0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
	switch (start_stop) {
	case AUTO_MONITOR_TOGGLE:
		if (is_monitoring) {
			stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
		} else {
			start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
		}
		return 0;
	case AUTO_MONITOR_START:
		if (!is_monitoring) {
			start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
			return 0;
		}
		ast_verb(4, "AutoMixMonitor already recording call.\n");
		break;
	case AUTO_MONITOR_STOP:
		if (is_monitoring) {
			stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
			return 0;
		}
		ast_verb(4, "AutoMixMonitor already stopped on call.\n");
		break;
	}

	/*
	 * Fake start/stop to invoker so will think it did something but
	 * was already in that mode.
	 */
	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
	}
	if (is_monitoring) {
		if (!ast_strlen_zero(start_message)) {
			ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
		}
	} else {
		if (!ast_strlen_zero(stop_message)) {
			ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
		}
	}
	return 0;
}
static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
{
	char *touch_filename;
	size_t len;
	int x;
	enum set_touch_variables_res set_touch_res;

	RAII_VAR(char *, touch_format, NULL, ast_free);
	RAII_VAR(char *, touch_monitor, NULL, ast_free);
	RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);

	set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
		&touch_monitor, &touch_monitor_prefix);
	switch (set_touch_res) {
	case SET_TOUCH_SUCCESS:
		break;
	case SET_TOUCH_UNSET:
		set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
			&touch_monitor_prefix);
		if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
			return;
		}
		break;
	case SET_TOUCH_ALLOC_FAILURE:
		return;
	}

	if (!ast_strlen_zero(touch_monitor)) {
		len = strlen(touch_monitor) + 50;
		touch_filename = ast_alloca(len);
		snprintf(touch_filename, len, "%s-%ld-%s.%s",
			S_OR(touch_monitor_prefix, "auto"),
			(long) time(NULL),
			touch_monitor,
			S_OR(touch_format, "wav"));
	} else {
		char *caller_chan_id;
		char *peer_chan_id;

		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
			ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
		peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
			ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
		len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
		touch_filename = ast_alloca(len);
		snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
			S_OR(touch_monitor_prefix, "auto"),
			(long) time(NULL),
			caller_chan_id,
			peer_chan_id,
			S_OR(touch_format, "wav"));
	}

	for (x = 0; x < strlen(touch_filename); x++) {
		if (touch_filename[x] == '/') {
			touch_filename[x] = '-';
		}
	}

	ast_verb(4, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);

	if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
		ast_verb(4, "AutoMixMonitor feature was tried by '%s' but MixMonitor failed to start.\n",
			ast_channel_name(bridge_channel->chan));

		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
		}
		return;
	}

	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
	}

	if (!ast_strlen_zero(start_message)) {
		ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
		ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
	}

	pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
}
Esempio n. 14
0
/*! \internal
 * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
 *
 * \param bridge_channel bridge channel this interval hook is being executed on
 * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
 */
static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	struct parked_user *user = hook_pvt;
	struct ast_channel *chan = user->chan;
	struct ast_context *park_dial_context;
	const char *dial_string;
	char *dial_string_flat;
	char parking_space[AST_MAX_EXTENSION];

	char returnexten[AST_MAX_EXTENSION];
	char *duplicate_returnexten;
	struct ast_exten *existing_exten;
	struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */


	/* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
	   to deal with this, lock the parked user, check and set resolution. */
	ao2_lock(user);
	if (user->resolution != PARK_UNSET) {
		/* Abandon timeout since something else has resolved the parked user before we got to it. */
		ao2_unlock(user);
		return -1;
	}
	user->resolution = PARK_TIMEOUT;
	ao2_unlock(user);

	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
		AST_CAUSE_NORMAL_CLEARING);

	dial_string = user->parker_dial_string;
	dial_string_flat = ast_strdupa(dial_string);
	flatten_dial_string(dial_string_flat);

	/* Set parking timeout channel variables */
	snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
	ast_channel_lock(chan);
	ast_channel_stage_snapshot(chan);
	pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
	pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
	pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
	pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
	pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
	parking_timeout_set_caller_features(chan, user->lot->cfg);
	ast_channel_stage_snapshot_done(chan);
	ast_channel_unlock(chan);

	/* Dialplan generation for park-dial extensions */

	if (ast_wrlock_contexts()) {
		ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
		return -1;
	}

	if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
		ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
		if (ast_unlock_contexts()) {
			ast_assert(0);
		}
		goto abandon_extension_creation;
	}

	if (ast_wrlock_context(park_dial_context)) {
		ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
		if (ast_unlock_contexts()) {
			ast_assert(0);
		}
		goto abandon_extension_creation;
	}

	if (ast_unlock_contexts()) {
		ast_assert(0);
	}

	snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
		user->lot->cfg->comebackdialtime);

	duplicate_returnexten = ast_strdup(returnexten);
	if (!duplicate_returnexten) {
		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
	}

	/* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
	if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
	    (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
		ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
			dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
	} else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
			"Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) {
			ast_free(duplicate_returnexten);
		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
	}

	if (ast_unlock_context(park_dial_context)) {
		ast_assert(0);
	}

abandon_extension_creation:

	/* async_goto the proper PBX destination - this should happen when we come out of the bridge */
	if (!ast_strlen_zero(user->comeback)) {
		ast_async_parseable_goto(chan, user->comeback);
	} else {
		comeback_goto(user, user->lot);
	}

	return -1;
}

void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
{
	unsigned int numeric_value;
	unsigned int hangup_after;

	if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
		/* If say_parking_space is called with a non-numeric string, we have a problem. */
		ast_assert(0);
		ast_bridge_channel_leave_bridge(bridge_channel,
			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
		return;
	}

	ast_say_digits(bridge_channel->chan, numeric_value, "",
		ast_channel_language(bridge_channel->chan));

	if (hangup_after) {
		ast_bridge_channel_leave_bridge(bridge_channel,
			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
	}
}
Esempio n. 15
0
static void _build_port_config (struct ast_variable *v, char *cat)
{
	int pos, i;
	union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
	int cfg_for_ports[max_ports + 1];

	if (!v || !cat)
		return;

	memset(cfg_tmp, 0, sizeof(cfg_tmp));
	memset(cfg_for_ports, 0, sizeof(cfg_for_ports));

	if (!strcasecmp(cat, "default")) {
		cfg_for_ports[0] = 1;
	}

	if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
		(_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
		CLI_ERROR(v->name, v->value, cat);
		return;
	}

	for (; v; v = v->next) {
		if (!strcasecmp(v->name, "ports")) {
			char *token, *tmp = ast_strdupa(v->value);
			char ptpbuf[BUFFERSIZE] = "";
			int start, end;
			for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) {
				if (!*token)
					continue;
				if (sscanf(token, "%30d-%30d%511s", &start, &end, ptpbuf) >= 2) {
					for (; start <= end; start++) {
						if (start <= max_ports && start > 0) {
							cfg_for_ports[start] = 1;
							ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
						} else
							CLI_ERROR(v->name, v->value, cat);
					}
				} else {
					if (sscanf(token, "%30d%511s", &start, ptpbuf)) {
						if (start <= max_ports && start > 0) {
							cfg_for_ports[start] = 1;
							ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
						} else
							CLI_ERROR(v->name, v->value, cat);
					} else
						CLI_ERROR(v->name, v->value, cat);
				}
			}
		} else {
			if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
				(_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
				CLI_ERROR(v->name, v->value, cat);
		}
	}

	for (i = 0; i < (max_ports + 1); ++i) {
		if (i > 0 && cfg_for_ports[0]) {
			/* default category, will populate the port_cfg with additional port
			categories in subsequent calls to this function */
			memset(cfg_tmp, 0, sizeof(cfg_tmp));
		}
		if (cfg_for_ports[i]) {
			memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
		}
	}
}
Esempio n. 16
0
static int _while_exec(struct ast_channel *chan, const char *data, int end)
{
	int res=0;
	const char *while_pri = NULL;
	char *my_name = NULL;
	const char *condition = NULL, *label = NULL;
	char varname[VAR_SIZE], end_varname[VAR_SIZE];
	const char *prefix = "WHILE";
	size_t size=0;
	int used_index_i = -1, x=0;
	char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";

	if (!chan) {
		/* huh ? */
		return -1;
	}

#if 0
	/* don't want run away loops if the chan isn't even up
	   this is up for debate since it slows things down a tad ......

	   Debate is over... this prevents While/EndWhile from working
	   within the "h" extension.  Not good.
	*/
	if (ast_waitfordigit(chan,1) < 0)
		return -1;
#endif

	for (x=0;;x++) {
		if (get_index(chan, prefix, x)) {
			used_index_i = x;
		} else 
			break;
	}
	
	snprintf(used_index, VAR_SIZE, "%d", used_index_i);
	snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
	
	if (!end)
		condition = ast_strdupa(data);

	size = strlen(chan->context) + strlen(chan->exten) + 32;
	my_name = alloca(size);
	memset(my_name, 0, size);
	snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
	
	ast_channel_lock(chan);
	if (end) {
		label = used_index;
	} else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
		label = new_index;
		pbx_builtin_setvar_helper(chan, my_name, label);
	}
	snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
	if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
		while_pri = ast_strdupa(while_pri);
		snprintf(end_varname,VAR_SIZE,"END_%s",varname);
	}
	ast_channel_unlock(chan);
	

	if ((!end && !pbx_checkcondition(condition)) || (end == 2)) {
		/* Condition Met (clean up helper vars) */
		const char *goto_str;
		pbx_builtin_setvar_helper(chan, varname, NULL);
		pbx_builtin_setvar_helper(chan, my_name, NULL);
		snprintf(end_varname,VAR_SIZE,"END_%s",varname);
		ast_channel_lock(chan);
		if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
			ast_parseable_goto(chan, goto_str);
			pbx_builtin_setvar_helper(chan, end_varname, NULL);
		} else {
			int pri = find_matching_endwhile(chan);
			if (pri > 0) {
				ast_verb(3, "Jumping to priority %d\n", pri);
				chan->priority = pri;
			} else {
				ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", chan->context, chan->exten, chan->priority);
			}
		}
		ast_channel_unlock(chan);
		return res;
	}

	if (!end && !while_pri) {
		char *goto_str;
		size = strlen(chan->context) + strlen(chan->exten) + 32;
		goto_str = alloca(size);
		memset(goto_str, 0, size);
		snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority);
		pbx_builtin_setvar_helper(chan, varname, goto_str);
	}

	else if (end && while_pri) {
		/* END of loop */
		snprintf(end_varname, VAR_SIZE, "END_%s", varname);
		if (! pbx_builtin_getvar_helper(chan, end_varname)) {
			char *goto_str;
			size = strlen(chan->context) + strlen(chan->exten) + 32;
			goto_str = alloca(size);
			memset(goto_str, 0, size);
			snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority+1);
			pbx_builtin_setvar_helper(chan, end_varname, goto_str);
		}
		ast_parseable_goto(chan, while_pri);
	}

	return res;
}
Esempio n. 17
0
static int _parse (union misdn_cfg_pt *dest, const char *value, enum misdn_cfg_type type, int boolint_def)
{
	int re = 0;
	int len, tmp;
	char *valtmp;
	char *tmp2 = ast_strdupa(value);

	switch (type) {
	case MISDN_CTYPE_STR:
		if (dest->str) {
			ast_free(dest->str);
		}
		if ((len = strlen(value))) {
			dest->str = ast_malloc((len + 1) * sizeof(char));
			strncpy(dest->str, value, len);
			dest->str[len] = 0;
		} else {
			dest->str = ast_malloc(sizeof(char));
			dest->str[0] = 0;
		}
		break;
	case MISDN_CTYPE_INT:
	{
		int res;

		if (strchr(value,'x')) {
			res = sscanf(value, "%30x", &tmp);
		} else {
			res = sscanf(value, "%30d", &tmp);
		}
		if (res) {
			if (!dest->num) {
				dest->num = ast_malloc(sizeof(int));
			}
			memcpy(dest->num, &tmp, sizeof(int));
		} else
			re = -1;
	}
		break;
	case MISDN_CTYPE_BOOL:
		if (!dest->num) {
			dest->num = ast_malloc(sizeof(int));
		}
		*(dest->num) = (ast_true(value) ? 1 : 0);
		break;
	case MISDN_CTYPE_BOOLINT:
		if (!dest->num) {
			dest->num = ast_malloc(sizeof(int));
		}
		if (sscanf(value, "%30d", &tmp)) {
			memcpy(dest->num, &tmp, sizeof(int));
		} else {
			*(dest->num) = (ast_true(value) ? boolint_def : 0);
		}
		break;
	case MISDN_CTYPE_MSNLIST:
		for (valtmp = strsep(&tmp2, ","); valtmp; valtmp = strsep(&tmp2, ",")) {
			if ((len = strlen(valtmp))) {
				struct msn_list *ml = ast_malloc(sizeof(*ml));
				ml->msn = ast_calloc(len+1, sizeof(char));
				strncpy(ml->msn, valtmp, len);
				ml->next = dest->ml;
				dest->ml = ml;
			}
		}
		break;
	case MISDN_CTYPE_ASTGROUP:
		if (!dest->grp) {
			dest->grp = ast_malloc(sizeof(ast_group_t));
		}
		*(dest->grp) = ast_get_group(value);
		break;
	case MISDN_CTYPE_ASTNAMEDGROUP:
		dest->namgrp = ast_get_namedgroups(value);
		break;
	}

	return re;
}
Esempio n. 18
0
static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
{
	char *s, *args[3], *varname=NULL, *delimiter=NULL, *field=NULL;
	int args_okay = 0;

	memset(buffer, 0, buflen);

	/* Check and parse arguments */
	if (data) {
		s = ast_strdupa((char *)data);
		if (s) {
			ast_app_separate_args(s, '|', args, 3);
			varname = args[0];
			delimiter = args[1];
			field = args[2];

			if (field) {
				args_okay = 1;
			}
		} else {
			return ERROR_NOMEM;
		}
	}

	if (args_okay) {
		char d, ds[2];
		char *tmp = alloca(strlen(varname) + 4);
		char varvalue[MAXRESULT], *tmp2=varvalue;

		if (tmp) {
			snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
			memset(varvalue, 0, sizeof(varvalue));
		} else {
			return ERROR_NOMEM;
		}

		if (delimiter[0])
			d = delimiter[0];
		else
			d = '-';

		/* String form of the delimiter, for use with strsep(3) */
		snprintf(ds, sizeof(ds), "%c", d);

		pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);

		if (tmp2) {
			int curfieldnum = 1;
			while ((tmp2 != NULL) && (field != NULL)) {
				char *nextgroup = strsep(&field, "&");
				int num1 = 0, num2 = MAXRESULT;
				char trashchar;

				if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
					/* range with both start and end */
				} else if (sscanf(nextgroup, "-%d", &num2) == 1) {
					/* range with end */
					num1 = 0;
				} else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
					/* range with start */
					num2 = MAXRESULT;
				} else if (sscanf(nextgroup, "%d", &num1) == 1) {
					/* single number */
					num2 = num1;
				} else {
					return ERROR_USAGE;
				}

				/* Get to start, if any */
				if (num1 > 0) {
					while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
						tmp2 = index(tmp2, d) + 1;
						curfieldnum++;
					}
				}

				/* Most frequent problem is the expectation of reordering fields */
				if ((num1 > 0) && (curfieldnum > num1)) {
					ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
				}

				/* Re-null tmp2 if we added 1 to NULL */
				if (tmp2 == (char *)NULL + 1)
					tmp2 = NULL;

				/* Output fields until we either run out of fields or num2 is reached */
				while ((tmp2 != NULL) && (curfieldnum <= num2)) {
					char *tmp3 = strsep(&tmp2, ds);
					int curlen = strlen(buffer);

					if (curlen) {
						snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3);
					} else {
						snprintf(buffer, buflen, "%s", tmp3);
					}

					curfieldnum++;
				}
			}
		}
	} else {
		return ERROR_NOARG;
	}
	return 0;
}
static int directory_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct localuser *u;
	struct ast_config *cfg;
	int last = 1;
	int fromappvm = 0;
	char *context, *dialcontext, *dirintro, *options;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	context = ast_strdupa(data);
	dialcontext = strchr(context, '|');
	if (dialcontext) {
		*dialcontext = '\0';
		dialcontext++;
		options = strchr(dialcontext, '|');
		if (options) {
			*options = '\0';
			options++; 
			if (strchr(options, 'f'))
				last = 0;
			if (strchr(options, 'v'))
				fromappvm = 1;
		}
	} else	
		dialcontext = context;

	cfg = realtime_directory(context);
	if (!cfg) {
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
	if (ast_strlen_zero(dirintro))
		dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
	if (ast_strlen_zero(dirintro)) {
		if (last)
			dirintro = "dir-intro";	
		else
			dirintro = "dir-intro-fn";
	}

	if (chan->_state != AST_STATE_UP) 
		res = ast_answer(chan);

	for (;;) {
		if (!res)
			res = ast_streamfile(chan, dirintro, chan->language);
		if (!res)
			res = ast_waitstream(chan, AST_DIGIT_ANY);
		ast_stopstream(chan);
		if (!res)
			res = ast_waitfordigit(chan, 5000);
		if (res > 0) {
			res = do_directory(chan, cfg, context, dialcontext, res, last, fromappvm);
			if (res > 0) {
				res = ast_waitstream(chan, AST_DIGIT_ANY);
				ast_stopstream(chan);
				if (res >= 0) {
					continue;
				}
			}
		}
		break;
	}
	ast_config_destroy(cfg);
	LOCAL_USER_REMOVE(u);
	return res;
}
Esempio n. 20
0
{
	char *myenforced = NULL;
	char *mygroup = NULL;
	char *recbase = NULL;
	int fd = 0;
	struct ast_flags flags;
	int oldwf = 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];

	data = ast_strdupa(data);
	AST_STANDARD_APP_ARGS(args, data);

	if (args.spec && !strcmp(args.spec, "all"))
		args.spec = NULL;

	if (args.options) {
		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) &&
			!(recbase = opts[OPT_ARG_RECORD]))
			recbase = "chanspy";

		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
Esempio n. 21
0
		pbx_builtin_setvar_helper(chan, variable, value);
	}
}

static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata)
{

	char *data;
	int dinterval = 0, duration = 0;
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(digits);
		AST_APP_ARG(dinterval);
		AST_APP_ARG(duration);
	);

	data = ast_strdupa(vdata);
	AST_STANDARD_APP_ARGS(args, data);

	if (!ast_strlen_zero(args.dinterval)) {
		ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
	}
	if (!ast_strlen_zero(args.duration)) {
		ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
	}
	ast_verb(4, "Sending DTMF: %s %d %d\n", args.digits, dinterval <= 0 ? 250 : dinterval, duration);
	ast_dtmf_stream(chan, NULL, args.digits, dinterval <= 0 ? 250 : dinterval, duration);
}

static struct playlist_entry *make_entry(const char *filename)
{
	struct playlist_entry *entry;
Esempio n. 22
0
static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
	int *volfactor, int fd, const struct ast_flags *flags, char *exitcontext) 
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	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 */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
		ast_channel_unlock(spyee);
		return 0;
	}

	name = ast_strdupa(spyee->name);
	ast_verb(2, "Spying on channel %s\n", name);

	memset(&csth, 0, sizeof(csth));

	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		ast_channel_unlock(spyee);
		return 0;
	}

	if (ast_test_flag(flags, OPTION_WHISPER)) {
		ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
		start_spying(spyee, spyer_name, &csth.whisper_audiohook);
	}

	ast_channel_unlock(spyee);
	spyee = NULL;

	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;

	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.
	*/

	/* 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 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_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}
		
		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;
		}

		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)) {
				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
				running = -2;
				break;
			} else {
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		} else if (res >= '0' && res <= '9') {
			inp[x++] = res;
		}

		if (res == '*') {
			running = 0;
			break;
		} else if (res == '#') {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);

			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	if (ast_test_flag(flags, OPTION_WHISPER)) {
		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.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);
	
	ast_verb(2, "Done Spying on channel %s\n", name);

	return running;
}
Esempio n. 23
0
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
{
    char *fmts;
    int d;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet=NULL;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile) {
        d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);

        if (!others[x]) {
            break;
        }
    }

    if (path)
        ast_unlock_path(path);


    if (maxsilence > 0) {
        sildet = ast_dsp_new(); /* Create the silence detector */
        if (!sildet) {
            ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
            return -1;
        }
        ast_dsp_set_threshold(sildet, silencethreshold);
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            ast_dsp_free(sildet);
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                if (f->subclass == '#') {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                    res = '#';
                    outmsg = 2;
                    ast_frfree(f);
                    break;
                }
            }
            if (f->subclass == '0') {
                /* Check for a '0' during message recording also, in case caller wants operator */
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
                res = '0';
                outmsg = 0;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    outmsg = 2;
                    res = 't';
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
    }

    *duration = end - start;

    for (x=0; x<fmtcnt; x++) {
        if (!others[x])
            break;
        if (res > 0) {
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
        }
        ast_truncstream(others[x]);
        ast_closestream(others[x]);
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg > 1) {
        /* Let them know recording is stopped */
        if(!ast_streamfile(chan, "auth-thankyou", chan->language))
            ast_waitstream(chan, "");
    }
    if (sildet)
        ast_dsp_free(sildet);
    return res;
}
Esempio n. 24
0
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
	int volfactor, const int fd, const char *mygroup, const char *myenforced,
	const char *spec, const char *exten, const char *context)
{
	char nameprefix[AST_NAME_STRLEN];
	char peer_name[AST_NAME_STRLEN + 5];
	char exitcontext[AST_MAX_CONTEXT] = "";
	signed char zero_volume = 0;
	int waitms;
	int res;
	char *ptr;
	int num;
	int num_spyed_upon = 1;
	struct chanspy_ds chanspy_ds;

	if (ast_test_flag(flags, OPTION_EXIT)) {
		const char *c;
		if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
			ast_copy_string(exitcontext, c, sizeof(exitcontext));
		else if (!ast_strlen_zero(chan->macrocontext))
			ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
		else
			ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
	}

	ast_mutex_init(&chanspy_ds.lock);

	snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));

	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	waitms = 100;

	for (;;) {
		struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
		struct ast_channel *prev = NULL, *peer = NULL;

		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
			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;
				else
					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
		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;
			else
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
		}

		/* reset for the next loop around, unless overridden later */
		waitms = 100;
		num_spyed_upon = 0;

		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) {
			const char *group;
			int igrp = !mygroup;
			char *groups[25];
			int num_groups = 0;
			char dup_group[512];
			int x;
			char *s;
			char *buffer;
			char *end;
			char *ext;
			char *form_enforced;
			int ienf = !myenforced;

			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);
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_channel_unlock(peer);
				chanspy_ds_free(peer_chanspy_ds);
				break;
			}

			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
				ast_channel_unlock(peer);
				continue;
			}

			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
				ast_channel_unlock(peer);
				continue;
			}

			if (mygroup) {
				if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
					ast_copy_string(dup_group, group, sizeof(dup_group));
					num_groups = ast_app_separate_args(dup_group, ':', groups,
						ARRAY_LEN(groups));
				}

				for (x = 0; x < num_groups; x++) {
					if (!strcmp(mygroup, groups[x])) {
						igrp = 1;
						break;
					}
				}
			}

			if (!igrp) {
				ast_channel_unlock(peer);
				continue;
			}

			if (myenforced) {

				/* 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));

				form_enforced = alloca(strlen(myenforced) + 3);

				strcpy(form_enforced, ":");
				strcat(form_enforced, myenforced);
				strcat(form_enforced, ":");

				buffer = ast_strdupa(peer->name);
				
				if ((end = strchr(buffer, '-'))) {
					*end++ = ':';
					*end = '\0';
				}

				strcpy(ext, ":");
				strcat(ext, buffer);

				if (strcasestr(form_enforced, ext))
					ienf = 1;
			}

			if (!ienf)
				continue;

			strcpy(peer_name, "spy-");
			strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
			ptr = strchr(peer_name, '/');
			*ptr++ = '\0';

			for (s = peer_name; s < ptr; s++)
				*s = tolower(*s);
			/* We have to unlock the peer channel here to avoid a deadlock.
			 * 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. */
			ast_channel_unlock(peer);

			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)
						res = ast_waitstream(chan, "");
					if (res) {
						chanspy_ds_free(peer_chanspy_ds);
						break;
					}
				} else
					res = ast_say_character_str(chan, peer_name, "", chan->language);
				if ((num = atoi(ptr)))
					ast_say_digits(chan, atoi(ptr), "", chan->language);
			}

			res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
			num_spyed_upon++;	

			if (res == -1) {
				chanspy_ds_free(peer_chanspy_ds);
				goto exit;
			} else if (res == -2) {
				res = 0;
				chanspy_ds_free(peer_chanspy_ds);
				goto exit;
			} else if (res > 1 && spec) {
				struct ast_channel *next;

				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);

				if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
					peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
					next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
				} else {
					/* 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;
					}
				}

				peer = NULL;
			}
		}
		if (res == -1 || ast_check_hangup(chan))
			break;
	}
exit:

	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	ast_mutex_lock(&chanspy_ds.lock);
	ast_mutex_unlock(&chanspy_ds.lock);
	ast_mutex_destroy(&chanspy_ds.lock);

	return res;
}
Esempio n. 25
0
/*!
 * \brief Excute an Select query and return ast_config list
 * \param url
 * \param unused
 * \param ap list containing one or more field/operator/value set.
 *
 * \retval struct ast_config pointer on success
 * \retval NULL on failure
*/
static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap)
{
	struct ast_str *query;
	char buf1[200], buf2[200];
	const char *newparam, *newval;
	char *stringp, *line, *pair, *key, *initfield = NULL;
	int i;
	const int EncodeSpecialChars = 1, bufsize = 256000;
	struct ast_variable *var=NULL;
	struct ast_config *cfg=NULL;
	struct ast_category *cat=NULL;
	char *buffer;

	if (!ast_custom_function_find("CURL")) {
		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
		return NULL;
	}

	if (!(query = ast_str_create(1000)))
		return NULL;

	if (!(buffer = ast_malloc(bufsize))) {
		ast_free(query);
		return NULL;
	}

	ast_str_set(&query, 0, "${CURL(%s/multi,", url);

	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
		newval = va_arg(ap, const char *);
		if (i == 0) {
			char *op;
			initfield = ast_strdupa(newparam);
			if ((op = strchr(initfield, ' ')))
				*op = '\0';
		}
		ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
		ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
	}
	va_end(ap);

	ast_str_append(&query, 0, ")}");

	/* Do the CURL query */
	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);

	if (!(cfg = ast_config_new()))
		goto exit_multi;

	/* Line oriented output */
	stringp = buffer;
	while ((line = strsep(&stringp, "\r\n"))) {
		if (ast_strlen_zero(line))
			continue;

		if (!(cat = ast_category_new("", "", 99999)))
			continue;

		while ((pair = strsep(&line, "&"))) {
			key = strsep(&pair, "=");
			ast_uri_decode(key);
			if (pair)
				ast_uri_decode(pair);

			if (!strcasecmp(key, initfield) && pair)
				ast_category_rename(cat, pair);

			if (!ast_strlen_zero(key)) {
				var = ast_variable_new(key, S_OR(pair, ""), "");
				ast_variable_append(cat, var);
			}
		}
		ast_category_append(cfg, cat);
	}

exit_multi:
	ast_free(buffer);
	ast_free(query);
	return cfg;
}
static int controlplayback_exec(struct ast_channel *chan, void *data)
{
	int res = 0, priority_jump = 0;
	int skipms = 0;
	struct localuser *u;
	char *tmp;
	int argc;
	char *argv[8];
	enum arg_ids {
		arg_file = 0,
		arg_skip = 1,
		arg_fwd = 2,
		arg_rev = 3,
		arg_stop = 4,
		arg_pause = 5,
		arg_restart = 6,
		options = 7,
	};
	
	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
		return -1;
	}

	LOCAL_USER_ADD(u);
	
	tmp = ast_strdupa(data);
	memset(argv, 0, sizeof(argv));

	argc = ast_app_separate_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0]));

	if (argc < 1) {
		ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	skipms = argv[arg_skip] ? atoi(argv[arg_skip]) : 3000;
	if (!skipms)
		skipms = 3000;

	if (!argv[arg_fwd] || !is_on_phonepad(*argv[arg_fwd]))
		argv[arg_fwd] = "#";
	if (!argv[arg_rev] || !is_on_phonepad(*argv[arg_rev]))
		argv[arg_rev] = "*";
	if (argv[arg_stop] && !is_on_phonepad(*argv[arg_stop]))
		argv[arg_stop] = NULL;
	if (argv[arg_pause] && !is_on_phonepad(*argv[arg_pause]))
		argv[arg_pause] = NULL;
	if (argv[arg_restart] && !is_on_phonepad(*argv[arg_restart]))
		argv[arg_restart] = NULL;

	if (argv[options]) {
		if (strchr(argv[options], 'j'))
			priority_jump = 1;
	}

	res = ast_control_streamfile(chan, argv[arg_file], argv[arg_fwd], argv[arg_rev], argv[arg_stop], argv[arg_pause], argv[arg_restart], skipms);

	/* If we stopped on one of our stop keys, return 0  */
	if (argv[arg_stop] && strchr(argv[arg_stop], res)) {
		res = 0;
		pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
	} else {
		if (res < 0) {
			if (priority_jump || ast_opt_priority_jumping) {
				if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
					ast_log(LOG_WARNING, "ControlPlayback tried to jump to priority n+101 as requested, but priority didn't exist\n");
				}
			}
			res = 0;
			pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
		} else
			pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
	}

	LOCAL_USER_REMOVE(u);

	return res;
}
Esempio n. 27
0
	return 0;
}

static int cut_internal(struct ast_channel *chan, char *data, struct ast_str **buf, ssize_t buflen)
{
	char *parse, ds[2], *var_expr;
	size_t delim_consumed;
	struct ast_str *var_value;
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(varname);
		AST_APP_ARG(delimiter);
		AST_APP_ARG(field);
	);

	parse = ast_strdupa(data);

	AST_STANDARD_APP_ARGS(args, parse);

	/* Check arguments */
	if (args.argc < 3) {
		return ERROR_NOARG;
	} else if (!(var_expr = alloca(strlen(args.varname) + 4))) {
		return ERROR_NOMEM;
	}

	/* Get the value of the variable named in the 1st argument */
	snprintf(var_expr, strlen(args.varname) + 4, "${%s}", args.varname);
	var_value = ast_str_create(16);
	ast_str_substitute_variables(&var_value, 0, chan, var_expr);
Esempio n. 28
0
void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
	const char *uri, enum ast_http_method method,
	struct ast_variable *get_params, struct ast_variable *headers,
	struct ast_ari_response *response)
{
	RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
	struct stasis_rest_handlers *handler;
	RAII_VAR(struct ast_variable *, path_vars, NULL, ast_variables_destroy);
	char *path = ast_strdupa(uri);
	char *path_segment;
	stasis_rest_callback callback;

	root = handler = get_root_handler();
	ast_assert(root != NULL);

	while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
		struct stasis_rest_handlers *found_handler = NULL;
		int i;
		ast_uri_decode(path_segment, ast_uri_http_legacy);
		ast_debug(3, "Finding handler for %s\n", path_segment);
		for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
			struct stasis_rest_handlers *child = handler->children[i];

			ast_debug(3, "  Checking %s\n", child->path_segment);
			if (child->is_wildcard) {
				/* Record the path variable */
				struct ast_variable *path_var = ast_variable_new(child->path_segment, path_segment, __FILE__);
				path_var->next = path_vars;
				path_vars = path_var;
				found_handler = child;
			} else if (strcmp(child->path_segment, path_segment) == 0) {
				found_handler = child;
			}
		}

		if (found_handler == NULL) {
			/* resource not found */
			ast_debug(3, "  Handler not found\n");
			ast_ari_response_error(
				response, 404, "Not Found",
				"Resource not found");
			return;
		} else {
			ast_debug(3, "  Got it!\n");
			handler = found_handler;
		}
	}

	ast_assert(handler != NULL);
	if (method == AST_HTTP_OPTIONS) {
		handle_options(handler, headers, response);
		return;
	}

	if (method < 0 || method >= AST_HTTP_MAX_METHOD) {
		add_allow_header(handler, response);
		ast_ari_response_error(
			response, 405, "Method Not Allowed",
			"Invalid method");
		return;
	}

	if (handler->ws_server && method == AST_HTTP_GET) {
		/* WebSocket! */
		ari_handle_websocket(handler->ws_server, ser, uri, method,
			get_params, headers);
		/* Since the WebSocket code handles the connection, we shouldn't
		 * do anything else; setting no_response */
		response->no_response = 1;
		return;
	}

	callback = handler->callbacks[method];
	if (callback == NULL) {
		add_allow_header(handler, response);
		ast_ari_response_error(
			response, 405, "Method Not Allowed",
			"Invalid method");
		return;
	}

	callback(ser, get_params, path_vars, headers, response);
	if (response->message == NULL && response->response_code == 0) {
		/* Really should not happen */
		ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
			ast_get_http_method(method), uri);
		ast_ari_response_error(
			response, 501, "Not Implemented",
			"Method not implemented");
	}
}
static int conf_exec(struct ast_channel *chan, void *data)
{
	int res=-1;
	struct localuser *u;
	int confflags = 0;
	int confno = 0;
	char confstr[80] = "", *tmp = NULL;
	struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL;
	struct ast_frame *f;
	char *mygroup;
	char *desired_group;
	int input=0,search_group=0;
	
	LOCAL_USER_ADD(u);
	
	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);
	
	desired_group = ast_strdupa((char *) data);
	if(!ast_strlen_zero(desired_group)) {
		ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group);
		search_group = 1;
	}

	for (;;) {
		if (ast_waitfor(chan, 100) < 0)
			break;
		
		f = ast_read(chan);
		if (!f)
			break;
		if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
			ast_frfree(f);
			break;
		}
		ast_frfree(f);
		ichan = NULL;
		if(input) {
			ichan = get_zap_channel_locked(input);
			input = 0;
		}
		
		tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
		
		if ( !tempchan && !lastchan )
			break;
		
		if (tempchan && search_group) {
			if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
				ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
			} else {
				ast_mutex_unlock(&tempchan->lock);
				lastchan = tempchan;
				continue;
			}
		}
		if ( tempchan && tempchan->type && (!strcmp(tempchan->type, "Zap")) && (tempchan != chan) ) {
			ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name);
			ast_copy_string(confstr, tempchan->name, sizeof(confstr));
			ast_mutex_unlock(&tempchan->lock);
			if ((tmp = strchr(confstr,'-'))) {
				*tmp = '\0';
			}
			confno = atoi(strchr(confstr,'/') + 1);
			ast_stopstream(chan);
			ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
			res = conf_run(chan, confno, confflags);
			if (res<0) break;
			input = res;
		} else if (tempchan)
			ast_mutex_unlock(&tempchan->lock);
		lastchan = tempchan;
	}
	LOCAL_USER_REMOVE(u);
	return res;
}
Esempio n. 30
0
static int chanspy_exec(struct ast_channel *chan, const char *data)
{
	char *myenforced = NULL;
	char *mygroup = NULL;
	char *recbase = NULL;
	int fd = 0;
	struct ast_flags flags;
	struct spy_dtmf_options user_options = {
		.cycle = '*',
		.volume = '#',
		.exit = '\0',
	};
	struct ast_format oldwf;
	int volfactor = 0;
	int res;
	char *mailbox = NULL;
	char *name_context = NULL;
	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);
	ast_format_clear(&oldwf);

	if (args.spec && !strcmp(args.spec, "all"))
		args.spec = NULL;

	if (args.options) {
		char tmp;
		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) &&
			!(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.");
			}
		}

		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.");
			}
		}

		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
			int vol;

			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];
				}
			}
		}
	} else {
		ast_clear_flag(&flags, AST_FLAGS_ALL);
	}

	ast_format_copy(&oldwf, &chan->writeformat);
	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 (fd)
		close(fd);

	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");
	}

	return res;
}