static int change_monitor_action(struct mansession *s, struct message *m)
{
	struct ast_channel *c = NULL;
	char *name = astman_get_header(m, "Channel");
	char *fname = astman_get_header(m, "File");
	if (ast_strlen_zero(name)) {
		astman_send_error(s, m, "No channel specified");
		return 0;
	}
	if (ast_strlen_zero(fname)) {
		astman_send_error(s, m, "No filename specified");
		return 0;
	}
	c = ast_get_channel_by_name_locked(name);
	if (!c) {
		astman_send_error(s, m, "No such channel");
		return 0;
	}
	if (ast_monitor_change_fname(c, fname, 1)) {
		astman_send_error(s, m, "Could not change monitored filename of channel");
		ast_channel_unlock(c);
		return 0;
	}
	ast_channel_unlock(c);
	astman_send_ack(s, m, "Changed monitor filename");
	return 0;
}
static int start_monitor_action(struct mansession *s, struct message *m)
{
	struct ast_channel *c = NULL;
	char *name = astman_get_header(m, "Channel");
	char *fname = astman_get_header(m, "File");
	char *format = astman_get_header(m, "Format");
	char *mix = astman_get_header(m, "Mix");
	char *d;
	
	if (ast_strlen_zero(name)) {
		astman_send_error(s, m, "No channel specified");
		return 0;
	}
	c = ast_get_channel_by_name_locked(name);
	if (!c) {
		astman_send_error(s, m, "No such channel");
		return 0;
	}

	if (ast_strlen_zero(fname)) {
		/* No filename base specified, default to channel name as per CLI */
		fname = malloc (FILENAME_MAX);
		if (!fname) {
			astman_send_error(s, m, "Could not start monitoring channel");
			ast_mutex_unlock(&c->lock);
			return 0;
		}
		memset(fname, 0, FILENAME_MAX);
		ast_copy_string(fname, c->name, FILENAME_MAX);
		/* Channels have the format technology/channel_name - have to replace that /  */
		if ((d=strchr(fname, '/'))) *d='-';
	}
	
	if (ast_monitor_start(c, format, fname, 1)) {
		if (ast_monitor_change_fname(c, fname, 1)) {
			astman_send_error(s, m, "Could not start monitoring channel");
			ast_mutex_unlock(&c->lock);
			return 0;
		}
	}

	if (ast_true(mix)) {
		ast_monitor_setjoinfiles(c, 1);
	}

	ast_mutex_unlock(&c->lock);
	astman_send_ack(s, m, "Started monitoring channel");
	return 0;
}
static int change_monitor_exec(struct ast_channel *chan, void *data)
{
	return ast_monitor_change_fname(chan, (const char*)data, 1);
}
static int start_monitor_exec(struct ast_channel *chan, void *data)
{
	char *arg = NULL;
	char *format = NULL;
	char *fname_base = NULL;
	char *options = NULL;
	char *delay = NULL;
	char *urlprefix = NULL;
	char tmp[256];
	int joinfiles = 0;
	int waitforbridge = 0;
	int res = 0;
	
	/* Parse arguments. */
	if (!ast_strlen_zero((char*)data)) {
		arg = ast_strdupa((char*)data);
		format = arg;
		fname_base = strchr(arg, '|');
		if (fname_base) {
			*fname_base = 0;
			fname_base++;
			if ((options = strchr(fname_base, '|'))) {
				*options = 0;
				options++;
				if (strchr(options, 'm'))
					joinfiles = 1;
				if (strchr(options, 'b'))
					waitforbridge = 1;
			}
		}
		arg = strchr(format,':');
		if (arg) {
			*arg++ = 0;
			urlprefix = arg;
		}
	}
	if (urlprefix) {
		snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
			((strcmp(format,"gsm")) ? "wav" : "gsm"));
		if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
			return -1;
		ast_cdr_setuserfield(chan, tmp);
	}
	if (waitforbridge) {
		/* We must remove the "b" option if listed.  In principle none of
		   the following could give NULL results, but we check just to
		   be pedantic. Reconstructing with checks for 'm' option does not
		   work if we end up adding more options than 'm' in the future. */
		delay = ast_strdupa(data);
		options = strrchr(delay, '|');
		if (options) {
			arg = strchr(options, 'b');
			if (arg) {
				*arg = 'X';
				pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
			}
		}
		return 0;
	}

	res = ast_monitor_start(chan, format, fname_base, 1);
	if (res < 0)
		res = ast_monitor_change_fname(chan, fname_base, 1);
	ast_monitor_setjoinfiles(chan, joinfiles);

	return res;
}