示例#1
0
static char *complete_context_add_ignorepat(char *line, char *word,
	int pos, int state)
{
	if (pos == 3) return state == 0 ? strdup("into") : NULL;

	if (pos == 4) {
		struct ast_context *c;
		int which = 0;
		char *dupline, *duplinet, *ignorepat = NULL;

		dupline = strdup(line);
		duplinet = dupline;

		if (duplinet) {
			strsep(&duplinet, " "); /* skip 'add' */
			strsep(&duplinet, " "); /* skip 'ignorepat' */
			ignorepat = strsep(&duplinet, " ");
		}

		if (ast_lock_contexts()) {
			ast_log(LOG_ERROR, "Failed to lock contexts list\n");
			return NULL;
		}

		c = ast_walk_contexts(NULL);
		while (c) {
			if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
				int serve_context = 1;
				if (ignorepat) {
					if (!ast_lock_context(c)) {
						struct ast_ignorepat *ip;
						ip = ast_walk_context_ignorepats(c, NULL);
						while (ip && serve_context) {
							if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
								serve_context = 0;
							ip = ast_walk_context_ignorepats(c, ip);
						}
						ast_unlock_context(c);
					}
				}
				if (serve_context) {
					if (++which > state) {
						char *context = strdup(ast_get_context_name(c));
						if (dupline) free(dupline);
						ast_unlock_contexts();
						return context;
					}
				}
			}
			c = ast_walk_contexts(c);
		}

		if (dupline) free(dupline);
		ast_unlock_contexts();
		return NULL;
	}

	return NULL;
}
示例#2
0
static int find_matching_endwhile(struct ast_channel *chan)
{
	struct ast_context *c;
	int res=-1;

	if (ast_rdlock_contexts()) {
		ast_log(LOG_ERROR, "Failed to lock contexts list\n");
		return -1;
	}

	for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {
		struct ast_exten *e;

		if (!ast_rdlock_context(c)) {
			if (!strcmp(ast_get_context_name(c), chan->context)) {
				/* This is the matching context we want */
				int cur_priority = chan->priority + 1, level=1;

				for (e = find_matching_priority(c, chan->exten, cur_priority,
					S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
					e;
					e = find_matching_priority(c, chan->exten, ++cur_priority,
						S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
					if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
						level++;
					} else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
						level--;
					}

					if (level == 0) {
						res = cur_priority;
						break;
					}
				}
			}
			ast_unlock_context(c);
			if (res > 0) {
				break;
			}
		}
	}
	ast_unlock_contexts();
	return res;
}
示例#3
0
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
{
	const char *s;
	char *tmp;
	char *cur, *rest;
	char *macro;
	char fullmacro[80];
	char varname[80];
	char runningapp[80], runningdata[1024];
	char *oldargs[MAX_ARGS + 1] = { NULL, };
	int argc, x;
	int res=0;
	char oldexten[256]="";
	int oldpriority, gosub_level = 0;
	char pc[80], depthc[12];
	char oldcontext[AST_MAX_CONTEXT] = "";
	const char *inhangupc;
	int offset, depth = 0, maxdepth = 7;
	int setmacrocontext=0;
	int autoloopflag, inhangup = 0;
	struct ast_str *tmp_subst = NULL;
  
	char *save_macro_exten;
	char *save_macro_context;
	char *save_macro_priority;
	char *save_macro_offset;
	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
		return -1;
	}

	do {
		if (macro_store) {
			break;
		}
		if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
			ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
			break;
		}
		/* Just the existence of this datastore is enough. */
		macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
		ast_channel_datastore_add(chan, macro_store);
	} while (0);

	/* does the user want a deeper rabbit hole? */
	ast_channel_lock(chan);
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
		sscanf(s, "%30d", &maxdepth);
	}
	
	/* Count how many levels deep the rabbit hole goes */
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
		sscanf(s, "%30d", &depth);
	}
	
	/* Used for detecting whether to return when a Macro is called from another Macro after hangup */
	if (strcmp(ast_channel_exten(chan), "h") == 0)
		pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
	
	if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
		sscanf(inhangupc, "%30d", &inhangup);
	}
	ast_channel_unlock(chan);

	if (depth >= maxdepth) {
		ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
		return 0;
	}
	snprintf(depthc, sizeof(depthc), "%d", depth + 1);

	tmp = ast_strdupa(data);
	rest = tmp;
	macro = strsep(&rest, ",");
	if (ast_strlen_zero(macro)) {
		ast_log(LOG_WARNING, "Invalid macro name specified\n");
		return 0;
	}

	snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
	if (!ast_exists_extension(chan, fullmacro, "s", 1,
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		if (!ast_context_find(fullmacro)) 
			ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
		else
			ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
		return 0;
	}

	/* If we are to run the macro exclusively, take the mutex */
	if (exclusive) {
		ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
		ast_autoservice_start(chan);
		if (ast_context_lockmacro(fullmacro)) {
			ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
			ast_autoservice_stop(chan);
			return 0;
		}
		ast_autoservice_stop(chan);
	}

	if (!(tmp_subst = ast_str_create(16))) {
		return -1;
	}

	/* Save old info */
	oldpriority = ast_channel_priority(chan);
	ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
	ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
	if (ast_strlen_zero(ast_channel_macrocontext(chan))) {
		ast_channel_macrocontext_set(chan, ast_channel_context(chan));
		ast_channel_macroexten_set(chan, ast_channel_exten(chan));
		ast_channel_macropriority_set(chan, ast_channel_priority(chan));
		setmacrocontext=1;
	}
	argc = 1;
	/* Save old macro variables */
	save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);

	save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);

	save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
	snprintf(pc, sizeof(pc), "%d", oldpriority);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
  
	save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);

	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

	/* Setup environment for new run */
	ast_channel_exten_set(chan, "s");
	ast_channel_context_set(chan, fullmacro);
	ast_channel_priority_set(chan, 1);

	ast_channel_lock(chan);
	while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
		const char *argp;
  		/* Save copy of old arguments if we're overwriting some, otherwise
	   	let them pass through to the other macro */
  		snprintf(varname, sizeof(varname), "ARG%d", argc);
		if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
			oldargs[argc] = ast_strdup(argp);
		}
		pbx_builtin_setvar_helper(chan, varname, cur);
		argc++;
	}
	ast_channel_unlock(chan);
	autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		struct ast_context *c;
		struct ast_exten *e;
		int foundx;
		runningapp[0] = '\0';
		runningdata[0] = '\0';

		/* What application will execute? */
		if (ast_rdlock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
		} else {
			for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
				if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
					if (ast_rdlock_context(c)) {
						ast_log(LOG_WARNING, "Unable to lock context?\n");
					} else {
						e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
							S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
						if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
							ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
							ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
						}
						ast_unlock_context(c);
					}
					break;
				}
			}
		}
		ast_unlock_contexts();

		/* Reset the macro depth, if it was changed in the last iteration */
		pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

		res = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
			&foundx, 1);
		if (res) {
			/* Something bad happened, or a hangup has been requested. */
			if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
		    	(res == '*') || (res == '#')) {
				/* Just return result as to the previous application as if it had been dialed */
				ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
				break;
			}
			switch(res) {
			case MACRO_EXIT_RESULT:
				res = 0;
				goto out;
			default:
				ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				goto out;
			}
		}

		ast_debug(1, "Executed application: %s\n", runningapp);

		if (!strcasecmp(runningapp, "GOSUB")) {
			gosub_level++;
			ast_debug(1, "Incrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "GOSUBIF")) {
			char *cond, *app_arg;
			char *app2;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			app2 = ast_str_buffer(tmp_subst);
			cond = strsep(&app2, "?");
			app_arg = strsep(&app2, ":");
			if (pbx_checkcondition(cond)) {
				if (!ast_strlen_zero(app_arg)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			} else {
				if (!ast_strlen_zero(app2)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			}
		} else if (!strcasecmp(runningapp, "RETURN")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "STACKPOP")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strncasecmp(runningapp, "EXEC", 4)) {
			/* Must evaluate args to find actual app */
			char *tmp2, *tmp3 = NULL;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			tmp2 = ast_str_buffer(tmp_subst);
			if (!strcasecmp(runningapp, "EXECIF")) {
				if ((tmp3 = strchr(tmp2, '|'))) {
					*tmp3++ = '\0';
				}
				if (!pbx_checkcondition(tmp2)) {
					tmp3 = NULL;
				}
			} else {
				tmp3 = tmp2;
			}

			if (tmp3) {
				ast_debug(1, "Last app: %s\n", tmp3);
			}

			if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
				gosub_level++;
				ast_debug(1, "Incrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			}
		}

		if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
			ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
			break;
		}

		/* don't stop executing extensions when we're in "h" */
		if (ast_check_hangup(chan) && !inhangup) {
			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", ast_channel_exten(chan), ast_channel_macroexten(chan), ast_channel_priority(chan));
			goto out;
		}
		ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
  	}
	out:

	/* Don't let the channel change now. */
	ast_channel_lock(chan);

	/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
	snprintf(depthc, sizeof(depthc), "%d", depth);
	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
	ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);

  	for (x = 1; x < argc; x++) {
  		/* Restore old arguments and delete ours */
		snprintf(varname, sizeof(varname), "ARG%d", x);
  		if (oldargs[x]) {
			pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
			ast_free(oldargs[x]);
		} else {
			pbx_builtin_setvar_helper(chan, varname, NULL);
		}
  	}

	/* Restore macro variables */
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
	if (save_macro_exten)
		ast_free(save_macro_exten);
	if (save_macro_context)
		ast_free(save_macro_context);
	if (save_macro_priority)
		ast_free(save_macro_priority);

	if (setmacrocontext) {
		ast_channel_macrocontext_set(chan, "");
		ast_channel_macroexten_set(chan, "");
		ast_channel_macropriority_set(chan, 0);
	}

	if (!strcasecmp(ast_channel_context(chan), fullmacro)) {
		const char *offsets;

  		/* If we're leaving the macro normally, restore original information */
		ast_channel_priority_set(chan, oldpriority);
		ast_channel_context_set(chan, oldcontext);
		ast_channel_exten_set(chan, oldexten);
		if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
			/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
			normally if there is any problem */
			if (sscanf(offsets, "%30d", &offset) == 1) {
				if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
					ast_channel_priority(chan) + offset + 1,
					S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
					ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
				}
			}
		}
	}

	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
	if (save_macro_offset)
		ast_free(save_macro_offset);

	/* Unlock the macro */
	if (exclusive) {
		ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
		if (ast_context_unlockmacro(fullmacro)) {
			ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
			res = 0;
		}
	}
	ast_channel_unlock(chan);
	ast_free(tmp_subst);

	return res;
}
/*! \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);
	}
}
示例#5
0
/*
 * 'save dialplan' CLI command implementation functions ...
 */
static int handle_save_dialplan(int fd, int argc, char *argv[])
{
	char filename[256];
	struct ast_context *c;
	struct ast_config *cfg;
	struct ast_variable *v;
	int context_header_written;
	int incomplete = 0; /* incomplete config write? */
	FILE *output;

	if (! (static_config && !write_protect_config)) {
		ast_cli(fd,
			"I can't save dialplan now, see '%s' example file.\n",
			config);
		return RESULT_FAILURE;
	}

	if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;

	if (ast_mutex_lock(&save_dialplan_lock)) {
		ast_cli(fd,
			"Failed to lock dialplan saving (another proccess saving?)\n");
		return RESULT_FAILURE;
	}

	/* have config path? */
	if (argc == 3) {
		/* is there extension.conf too? */
		if (!strstr(argv[2], ".conf")) {
			/* no, only directory path, check for last '/' occurence */
			if (*(argv[2] + strlen(argv[2]) -1) == '/')
				snprintf(filename, sizeof(filename), "%s%s",
					argv[2], config);
			else
				/* without config extensions.conf, add it */
				snprintf(filename, sizeof(filename), "%s/%s",
					argv[2], config);
		} else
			/* there is an .conf */
			snprintf(filename, sizeof(filename), argv[2]);
	} else
		/* no config file, default one */
		snprintf(filename, sizeof(filename), "%s/%s",
			(char *)ast_config_AST_CONFIG_DIR, config);

	cfg = ast_load("extensions.conf");

	/* try to lock contexts list */
	if (ast_lock_contexts()) {
		ast_cli(fd, "Failed to lock contexts list\n");
		ast_mutex_unlock(&save_dialplan_lock);
		ast_destroy(cfg);
		return RESULT_FAILURE;
	}

	/* create new file ... */
	if (!(output = fopen(filename, "wt"))) {
		ast_cli(fd, "Failed to create file '%s'\n",
			filename);
		ast_unlock_contexts();
		ast_mutex_unlock(&save_dialplan_lock);
		ast_destroy(cfg);
		return RESULT_FAILURE;
	}

	/* fireout general info */
	fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\n\n",
		static_config ? "yes" : "no",
		write_protect_config ? "yes" : "no");

	if ((v = ast_variable_browse(cfg, "globals"))) {
		fprintf(output, "[globals]\n");
		while(v) {
			fprintf(output, "%s => %s\n", v->name, v->value);
			v = v->next;
		}
		fprintf(output, "\n");
	}

	ast_destroy(cfg);
	
	/* walk all contexts */
	c = ast_walk_contexts(NULL);
	while (c) {
		context_header_written = 0;
	
		/* try to lock context and fireout all info */	
		if (!ast_lock_context(c)) {
			struct ast_exten *e, *last_written_e = NULL;
			struct ast_include *i;
			struct ast_ignorepat *ip;
			struct ast_sw *sw;

			/* registered by this module? */
			if (!strcmp(ast_get_context_registrar(c), registrar)) {
				fprintf(output, "[%s]\n", ast_get_context_name(c));
				context_header_written = 1;
			}

			/* walk extensions ... */
			e = ast_walk_context_extensions(c, NULL);
			while (e) {
				struct ast_exten *p;

				/* fireout priorities */
				p = ast_walk_extension_priorities(e, NULL);
				while (p) {
					if (!strcmp(ast_get_extension_registrar(p),
						registrar)) {
			
						/* make empty line between different extensions */	
						if (last_written_e != NULL &&
							strcmp(ast_get_extension_name(last_written_e),
								ast_get_extension_name(p)))
							fprintf(output, "\n");
						last_written_e = p;
				
						if (!context_header_written) {
							fprintf(output, "[%s]\n", ast_get_context_name(c));
							context_header_written = 1;
						}

						if (ast_get_extension_priority(p)!=PRIORITY_HINT) {
							char *tempdata = NULL, *startdata;
							tempdata = strdup((char *)ast_get_extension_app_data(p));
							if (tempdata) {
								startdata = tempdata;
								while (*tempdata) {
									if (*tempdata == '|')
										*tempdata = ',';
									tempdata++;
								}
								tempdata = startdata;
							}
							if (ast_get_extension_matchcid(p))
								fprintf(output, "exten => %s/%s,%d,%s(%s)\n",
								    ast_get_extension_name(p),
								    ast_get_extension_cidmatch(p),
								    ast_get_extension_priority(p),
								    ast_get_extension_app(p),
								    tempdata);
							else
								fprintf(output, "exten => %s,%d,%s(%s)\n",
								    ast_get_extension_name(p),
								    ast_get_extension_priority(p),
								    ast_get_extension_app(p),
								    tempdata);
							if (tempdata)
								free(tempdata);
						} else
							fprintf(output, "exten => %s,hint,%s\n",
							    ast_get_extension_name(p),
							    ast_get_extension_app(p));
						
					}
					p = ast_walk_extension_priorities(e, p);
				}

				e = ast_walk_context_extensions(c, e);
			}

			/* written any extensions? ok, write space between exten & inc */
			if (last_written_e) fprintf(output, "\n");

			/* walk through includes */
			i = ast_walk_context_includes(c, NULL);
			while (i) {
				if (!strcmp(ast_get_include_registrar(i), registrar)) {
					if (!context_header_written) {
						fprintf(output, "[%s]\n", ast_get_context_name(c));
						context_header_written = 1;
					}
					fprintf(output, "include => %s\n",
						ast_get_include_name(i));
				}
				i = ast_walk_context_includes(c, i);
			}

			if (ast_walk_context_includes(c, NULL))
				fprintf(output, "\n");

			/* walk through switches */
			sw = ast_walk_context_switches(c, NULL);
			while (sw) {
				if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
					if (!context_header_written) {
						fprintf(output, "[%s]\n", ast_get_context_name(c));
						context_header_written = 1;
					}
					fprintf(output, "switch => %s/%s\n",
						ast_get_switch_name(sw),
						ast_get_switch_data(sw));
				}
				sw = ast_walk_context_switches(c, sw);
			}

			if (ast_walk_context_switches(c, NULL))
				fprintf(output, "\n");

			/* fireout ignorepats ... */
			ip = ast_walk_context_ignorepats(c, NULL);
			while (ip) {
				if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
					if (!context_header_written) {
						fprintf(output, "[%s]\n", ast_get_context_name(c));
						context_header_written = 1;
					}

					fprintf(output, "ignorepat => %s\n",
						ast_get_ignorepat_name(ip));
				}
				ip = ast_walk_context_ignorepats(c, ip);
			}

			ast_unlock_context(c);
		} else
			incomplete = 1;

		c = ast_walk_contexts(c);
	}	

	ast_unlock_contexts();
	ast_mutex_unlock(&save_dialplan_lock);
	fclose(output);

	if (incomplete) {
		ast_cli(fd, "Saved dialplan is incomplete\n");
		return RESULT_FAILURE;
	}

	ast_cli(fd, "Dialplane successfully saved into '%s'\n",
		filename);
	return RESULT_SUCCESS;
}
示例#6
0
static char *complete_context_add_include(char *line, char *word, int pos,
    int state)
{
	struct ast_context *c;
	int which = 0;

	/* server context for inclusion ... */
	if (pos == 1)
	{
		if (ast_lock_contexts()) {
			ast_log(LOG_ERROR, "Failed to lock context list\n");
			return NULL;
		}

		/* server all contexts */ 
		c = ast_walk_contexts(NULL); 
		while (c) {
			if ((!strlen(word) || 
				 !strncmp(ast_get_context_name(c), word, strlen(word))) &&
				++which > state)
			{
				char *context = strdup(ast_get_context_name(c));
				ast_unlock_contexts();
				return context;
			}
			c = ast_walk_contexts(c);
		}

		ast_unlock_contexts();
	}

	/* complete 'in' only if context exist ... */
	if (pos == 2)
	{
		char *context, *dupline, *duplinet;

		if (state != 0) return NULL;

		/* parse context from line ... */
		if (!(dupline = strdup(line))) {
			ast_log(LOG_ERROR, "Out of free memory\n");
			if (state == 0) return strdup("in");
			return NULL;
		}

		duplinet = dupline;

		strsep(&duplinet, " ");
		context = strsep(&duplinet, " ");
		if (context) {
			struct ast_context *c;
			int context_existence = 0;

			/* check for context existence ... */
			if (ast_lock_contexts()) {
				ast_log(LOG_ERROR, "Failed to lock context list\n");
				free(dupline);
				/* our fault, we can't check, so complete 'in' ... */
				return strdup("in");
			}

			c = ast_walk_contexts(NULL);
			while (c && !context_existence) {
				if (!strcmp(context, ast_get_context_name(c))) {
					context_existence = 1;
					continue;
				}
				c = ast_walk_contexts(c);
			}

			/* if context exists, return 'into' ... */
			if (context_existence) {
				free(dupline);
				ast_unlock_contexts();
				return strdup("into");
			}

			ast_unlock_contexts();
		}	

		free(dupline);
		return NULL;
	}

	/* serve context into which we include another context */
	if (pos == 3)
	{
		char *context, *dupline, *duplinet, *in;
		int context_existence = 0;

		if (!(dupline = strdup(line))) {
			ast_log(LOG_ERROR, "Out of free memory\n");
			return NULL;
		}

		duplinet = dupline;

		strsep(&duplinet, " "); /* skip 'include' */
		context = strsep(&duplinet, " ");
		in = strsep(&duplinet, " ");

		/* given some context and third word is in? */
		if (!strlen(context) || strcmp(in, "in")) {
			free(dupline);
			return NULL;
		}

		if (ast_lock_contexts()) {
			ast_log(LOG_ERROR, "Failed to lock context list\n");
			free(dupline);
			return NULL;
		}

		/* check for context existence ... */
		c = ast_walk_contexts(NULL);
		while (c && !context_existence) {
			if (!strcmp(context, ast_get_context_name(c))) {
				context_existence = 1;
				continue;
			}
			c = ast_walk_contexts(c);
		}

		if (!context_existence) {
			free(dupline);
			ast_unlock_contexts();
			return NULL;
		}

		/* go through all contexts ... */
		c = ast_walk_contexts(NULL);
		while (c) {
			/* must be different contexts ... */
			if (strcmp(context, ast_get_context_name(c))) {
				if (!ast_lock_context(c)) {
					struct ast_include *i;
					int included = 0;

					/* check for duplicity inclusion ... */
					i = ast_walk_context_includes(c, NULL);
					while (i && !included) {
						if (!strcmp(ast_get_include_name(i), context))
							included = 1;
						i = ast_walk_context_includes(c, i);
					}
					ast_unlock_context(c);

					/* not included yet, so show possibility ... */
					if (!included &&
						!strncmp(ast_get_context_name(c), word, strlen(word))){
						
						if (++which > state) {
							char *res = strdup(ast_get_context_name(c));
							free(dupline);
							ast_unlock_contexts();
							return res;
						}
					}	
				}
			}
			c = ast_walk_contexts(c);
		}

		ast_unlock_contexts();
		free(dupline);
		return NULL;
	}

	return NULL;
}
示例#7
0
static char *complete_context_dont_include(char *line, char *word,
	int pos, int state)
{
	int which = 0;

	/*
	 * Context completion ...
	 */
	if (pos == 2) {
		struct ast_context *c;

		if (ast_lock_contexts()) {
			ast_log(LOG_ERROR, "Failed to lock context list\n");
			return NULL;
		}

		/* walk pbx_get_contexts ... */
		c = ast_walk_contexts(NULL); 
		while (c) {
			struct ast_include *i;

			if (ast_lock_context(c)) {
				c = ast_walk_contexts(c);
				continue;
			}

			i = ast_walk_context_includes(c, NULL);
			while (i) {
				if (!strlen(word) ||
					!strncmp(ast_get_include_name(i), word, strlen(word))) {
					struct ast_context *nc;
					int already_served = 0;

					/* check if this include is already served or not */

					/* go through all contexts again till we reach actuall
					 * context or already_served = 1
					 */
					nc = ast_walk_contexts(NULL);
					while (nc && nc != c && !already_served) {
						if (!ast_lock_context(nc)) {
							struct ast_include *ni;

							ni = ast_walk_context_includes(nc, NULL);
							while (ni && !already_served) {
								if (!strcmp(ast_get_include_name(i),
									ast_get_include_name(ni)))
									already_served = 1;
								ni = ast_walk_context_includes(nc, ni);
							}	
							
							ast_unlock_context(nc);
						}
						nc = ast_walk_contexts(nc);
					}

					if (!already_served) {
						if (++which > state) {
							char *res =
								strdup(ast_get_include_name(i));
							ast_unlock_context(c);
							ast_unlock_contexts();
							return res;
						}
					}
				}
				i = ast_walk_context_includes(c, i);
			}

			ast_unlock_context(c);
			c = ast_walk_contexts(c);
		}

		ast_unlock_contexts();
		return NULL;
	}

	/*
	 * 'in' completion ... (complete only if previous context is really
	 * included somewhere)
	 */
	if (pos == 3) {
		struct ast_context *c;
		char *context, *dupline, *duplinet;

		if (state > 0) return NULL;

		/* take 'context' from line ... */
		if (!(dupline = strdup(line))) {
			ast_log(LOG_ERROR, "Out of free memory\n");
			return NULL;
		}

		duplinet = dupline;
		strsep(&duplinet, " "); /* skip 'dont' */
		strsep(&duplinet, " "); /* skip 'include' */
		context = strsep(&duplinet, " ");

		if (!context) {
			free(dupline);
			return NULL;
		}

		if (ast_lock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
			free(dupline);
			return NULL;
		}

		/* go through all contexts and check if is included ... */
		c = ast_walk_contexts(NULL);
		while (c) {
			struct ast_include *i;
			if (ast_lock_context(c)) {
				free(dupline);
				ast_unlock_contexts();
				return NULL;
			}

			i = ast_walk_context_includes(c, NULL);
			while (i) {
				/* is it our context? */
				if (!strcmp(ast_get_include_name(i), context)) {
					/* yes, it is, context is really included, so
					 * complete "in" command
					 */
					free(dupline);
					ast_unlock_context(c);
					ast_unlock_contexts();
					return strdup("in");
				}
				i = ast_walk_context_includes(c, i);
			}
			ast_unlock_context(c);
			c = ast_walk_contexts(c);
		}
		free(dupline);
		ast_unlock_contexts();
		return NULL;
	}

	/*
	 * Context from which we removing include ... 
	 */
	if (pos == 4) {
		struct ast_context *c;
		char *context, *dupline, *duplinet, *in;

		if (!(dupline = strdup(line))) {
			ast_log(LOG_ERROR, "Out of free memory\n");
			return NULL;
		}

		duplinet = dupline;

		strsep(&duplinet, " "); /* skip 'dont' */
		strsep(&duplinet, " "); /* skip 'include' */

		if (!(context = strsep(&duplinet, " "))) {
			free(dupline);
			return NULL;
		}

		/* third word must be in */
		in = strsep(&duplinet, " ");
		if (!in ||
			strcmp(in, "in")) {
			free(dupline);
			return NULL;
		}

		if (ast_lock_contexts()) {
			ast_log(LOG_ERROR, "Failed to lock context list\n");
			free(dupline);
			return NULL;
		}

		/* walk through all contexts ... */
		c = ast_walk_contexts(NULL);
		while (c) {
			struct ast_include *i;
			if (ast_lock_context(c)) {
				free(dupline);
				return NULL;
			}
	
			/* walk through all includes and check if it is our context */	
			i = ast_walk_context_includes(c, NULL);
			while (i) {
				/* is in this context included another on which we want to
				 * remove?
				 */
				if (!strcmp(context, ast_get_include_name(i))) {
					/* yes, it's included, is matching our word too? */
					if (!strncmp(ast_get_context_name(c),
							word, strlen(word))) {
						/* check state for completion */
						if (++which > state) {
							char *res = strdup(ast_get_context_name(c));
							free(dupline);
							ast_unlock_context(c);
							ast_unlock_contexts();
							return res;
						}
					}
					break;
				}
				i = ast_walk_context_includes(c, i);
			}	
			ast_unlock_context(c);
			c = ast_walk_contexts(c);
		}

		free(dupline);
		ast_unlock_contexts();
		return NULL;
	}

	return NULL;
}
示例#8
0
static char *complete_context_remove_ignorepat(char *line, char *word,
	int pos, int state)
{
	struct ast_context *c;
	int which = 0;

	if (pos == 2) {
		if (ast_lock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
			return NULL;
		}

		c = ast_walk_contexts(NULL);
		while (c) {
			if (!ast_lock_context(c)) {
				struct ast_ignorepat *ip;
			
				ip = ast_walk_context_ignorepats(c, NULL);
				while (ip) {
					if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
						if (which + 1 > state) {
							struct ast_context *cw;
							int already_served = 0;
							cw = ast_walk_contexts(NULL);
							while (cw && cw != c && !already_served) {
								if (!ast_lock_context(cw)) {
									struct ast_ignorepat *ipw;
									ipw = ast_walk_context_ignorepats(cw, NULL);
									while (ipw) {
										if (!strcmp(ast_get_ignorepat_name(ipw),
											ast_get_ignorepat_name(ip))) already_served = 1;
										ipw = ast_walk_context_ignorepats(cw, ipw);
									}
									ast_unlock_context(cw);
								}
								cw = ast_walk_contexts(cw);
							}
							if (!already_served) {
								char *ret = strdup(ast_get_ignorepat_name(ip));
								ast_unlock_context(c);
								ast_unlock_contexts();
								return ret;
							}
						} else
							which++;
					}
					ip = ast_walk_context_ignorepats(c, ip);
				}

				ast_unlock_context(c);
			}
			c = ast_walk_contexts(c);
		}

		ast_unlock_contexts();
		return NULL;
	}
 
	if (pos == 3) return state == 0 ? strdup("from") : NULL;

	if (pos == 4) {
		char *dupline, *duplinet, *ignorepat;

		dupline = strdup(line);
		if (!dupline) {
			ast_log(LOG_WARNING, "Out of free memory\n");
			return NULL;
		}

		duplinet = dupline;
		strsep(&duplinet, " ");
		strsep(&duplinet, " ");
		ignorepat = strsep(&duplinet, " ");

		if (!ignorepat) {
			free(dupline);
			return NULL;
		}

		if (ast_lock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
			free(dupline);
			return NULL;
		}

		c = ast_walk_contexts(NULL);
		while (c) {
			if (!ast_lock_context(c)) {
				struct ast_ignorepat *ip;
				ip = ast_walk_context_ignorepats(c, NULL);
				while (ip) {
					if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
						if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
							if (++which > state) {
								char *ret = strdup(ast_get_context_name(c));
								free(dupline);
								ast_unlock_context(c);
								ast_unlock_contexts();
								return ret;
							}
						}
					}
					ip = ast_walk_context_ignorepats(c, ip);
				}

				ast_unlock_context(c);
			}
			c = ast_walk_contexts(c);
		}

		free(dupline);
		ast_unlock_contexts();
		return NULL;
	}

	return NULL;
}