Skip to content
Snippets Groups Projects
pbx.c 162 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		total_apps++;
    
    			if (strcasestr(a->name, argv[3])) {
    
    				total_match++;
    
    			}
    		} else if (describing) {
    			if (a->description) {
    				/* Match all words on command line */
    				int i;
    				printapp = 1;
    
    Russell Bryant's avatar
    Russell Bryant committed
    				for (i = 3; i < argc; i++) {
    
    					if (!strcasestr(a->description, argv[i])) {
    
    					} else {
    						total_match++;
    
    					}
    				}
    			}
    		} else {
    			printapp = 1;
    		}
    
    		if (printapp) {
    			ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if ((!like) && (!describing)) {
    
    		ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
    	} else {
    		ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
    	}
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* ... unlock and return */
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	return RESULT_SUCCESS;
    }
    
    
    static char *complete_show_applications(const char *line, const char *word, int pos, int state)
    
    	static char* choices[] = { "like", "describing", NULL };
    
    	return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * 'show dialplan' CLI command implementation functions ...
     */
    
    static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int state)
    {
    
    Russell Bryant's avatar
    Russell Bryant committed
    	struct ast_context *c = NULL;
    	char *ret = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int which = 0;
    
    Russell Bryant's avatar
    Russell Bryant committed
    	int wordlen;
    
    	/* we are do completion of [exten@]context on second position only */
    
    Russell Bryant's avatar
    Russell Bryant committed
    	if (pos != 2)
    		return NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* try to lock contexts list ... */
    	if (ast_lock_contexts()) {
    		ast_log(LOG_ERROR, "Unable to lock context list\n");
    		return NULL;
    	}
    
    
    Russell Bryant's avatar
    Russell Bryant committed
    	wordlen = strlen(word);
    
    
    	/* walk through all contexts and return the n-th match */
    
    Russell Bryant's avatar
    Russell Bryant committed
    	while ( (c = ast_walk_contexts(c)) ) {
    
    		if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
    			ret = ast_strdup(ast_get_context_name(c));
    			break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* ... unlock and return */
    	ast_unlock_contexts();
    
    Russell Bryant's avatar
    Russell Bryant committed
    	return ret;
    
    struct dialplan_counters {
    	int total_context;
    	int total_exten;
    	int total_prio;
    	int context_existence;
    	int extension_existence;
    };
    
    
    static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, char *includes[])
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Russell Bryant's avatar
    Russell Bryant committed
    	struct ast_context *c = NULL;
    
    Russell Bryant's avatar
    Russell Bryant committed
    	int res = 0, old_total_exten = dpc->total_exten;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* try to lock contexts */
    	if (ast_lock_contexts()) {
    
    		ast_log(LOG_WARNING, "Failed to lock contexts list\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* walk all contexts ... */
    
    Russell Bryant's avatar
    Russell Bryant committed
    	while ( (c = ast_walk_contexts(c)) ) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* show this context? */
    		if (!context ||
    			!strcmp(ast_get_context_name(c), context)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    			/* try to lock context before walking in ... */
    			if (!ast_lock_context(c)) {
    				struct ast_exten *e;
    				struct ast_include *i;
    				struct ast_ignorepat *ip;
    				struct ast_sw *sw;
    				char buf[256], buf2[256];
    				int context_info_printed = 0;
    
    				/* are we looking for exten too? if yes, we print context
    				 * if we our extension only
    				 */
    				if (!exten) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
    						ast_get_context_name(c), ast_get_context_registrar(c));
    					context_info_printed = 1;
    				}
    
    				/* walk extensions ... */
    
    				for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					struct ast_exten *p;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    					/* looking for extension? is this our extension? */
    					if (exten &&
    
    						!ast_extension_match(ast_get_extension_name(e), exten))
    
    Mark Spencer's avatar
    Mark Spencer committed
    					{
    						/* we are looking for extension and it's not our
     						 * extension, so skip to next extension */
    						continue;
    					}
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    					/* may we print context info? */	
    					if (!context_info_printed) {
    
    						dpc->total_context++;
    						if (rinclude) {
    							/* TODO Print more info about rinclude */
    							ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
    								ast_get_context_name(c),
    								ast_get_context_registrar(c));
    						} else {
    							ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
    								ast_get_context_name(c),
    								ast_get_context_registrar(c));
    						}
    
    Mark Spencer's avatar
    Mark Spencer committed
    						context_info_printed = 1;
    					}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    					/* write extension name and first peer */	
    					bzero(buf, sizeof(buf));		
    					snprintf(buf, sizeof(buf), "'%s' =>",
    						ast_get_extension_name(e));
    
    
    					prio = ast_get_extension_priority(e);
    					if (prio == PRIORITY_HINT) {
    						snprintf(buf2, sizeof(buf2),
    							"hint: %s",
    							ast_get_extension_app(e));
    					} else {
    						snprintf(buf2, sizeof(buf2),
    							"%d. %s(%s)",
    							prio,
    							ast_get_extension_app(e),
    							(char *)ast_get_extension_app_data(e));
    					}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    					ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
    						ast_get_extension_registrar(e));
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    					/* walk next extension peers */
    
    					for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
    						dpc->total_prio++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    						bzero((void *)buf2, sizeof(buf2));
    
    						bzero((void *)buf, sizeof(buf));
    						if (ast_get_extension_label(p))
    							snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
    
    						prio = ast_get_extension_priority(p);
    						if (prio == PRIORITY_HINT) {
    							snprintf(buf2, sizeof(buf2),
    								"hint: %s",
    								ast_get_extension_app(p));
    						} else {
    							snprintf(buf2, sizeof(buf2),
    								"%d. %s(%s)",
    								prio,
    								ast_get_extension_app(p),
    								(char *)ast_get_extension_app_data(p));
    						}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    						ast_cli(fd,"  %-17s %-45s [%s]\n",
    
    				/* walk included and write info ... */
    				for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
    					bzero(buf, sizeof(buf));
    					snprintf(buf, sizeof(buf), "'%s'",
    						ast_get_include_name(i));
    					if (exten) {
    						/* Check all includes for the requested extension */
    
    						if (includecount >= AST_PBX_MAX_STACK) {
    							ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
    						} else {
    							int dupe=0;
    							int x;
    							for (x=0;x<includecount;x++) {
    								if (!strcasecmp(includes[x], ast_get_include_name(i))) {
    									dupe++;
    									break;
    								}
    							}
    							if (!dupe) {
    								includes[includecount] = (char *)ast_get_include_name(i);
    								show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
    							} else {
    								ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
    							}
    						}
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_cli(fd, "  Include =>        %-45s [%s]\n",
    							buf, ast_get_include_registrar(i));
    					}
    
    Russell Bryant's avatar
    Russell Bryant committed
    				for (ip = ast_walk_context_ignorepats(c, NULL); ip; ip = ast_walk_context_ignorepats(c, ip)) {
    
    					const char *ipname = ast_get_ignorepat_name(ip);
    					char ignorepat[AST_MAX_EXTENSION];
    					snprintf(buf, sizeof(buf), "'%s'", ipname);
    					snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
    					if ((!exten) || ast_extension_match(ignorepat, exten)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
    
    Mark Spencer's avatar
    Mark Spencer committed
    					}
    
    				}
    				if (!rinclude) {
    					for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						snprintf(buf, sizeof(buf), "'%s/%s'",
    							ast_get_switch_name(sw),
    							ast_get_switch_data(sw));
    						ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
    							buf, ast_get_switch_registrar(sw));	
    					}
    				}
    	
    				ast_unlock_context(c);
    
    				/* if we print something in context, make an empty line */
    
    				if (context_info_printed) ast_cli(fd, "\r\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_unlock_contexts();
    
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	return (dpc->total_exten == old_total_exten) ? -1 : res;
    
    }
    
    static int handle_show_dialplan(int fd, int argc, char *argv[])
    {
    	char *exten = NULL, *context = NULL;
    	/* Variables used for different counters */
    	struct dialplan_counters counters;
    
    	char *incstack[AST_PBX_MAX_STACK];
    
    	if (argc != 2 && argc != 3) 
    		return RESULT_SHOWUSAGE;
    
    
    	/* we obtain [exten@]context? if yes, split them ... */
    	if (argc == 3) {
    		char *splitter = ast_strdupa(argv[2]);
    		/* is there a '@' character? */
    
    		if (splitter && strchr(argv[2], '@')) {
    
    			/* yes, split into exten & context ... */
    			exten   = strsep(&splitter, "@");
    			context = splitter;
    
    			/* check for length and change to NULL if ast_strlen_zero() */
    
    			if (ast_strlen_zero(exten))
    				exten = NULL;
    			if (ast_strlen_zero(context))
    				context = NULL;
    
    			show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
    
    		} else {
    			/* no '@' char, only context given */
    			context = argv[2];
    
    			if (ast_strlen_zero(context))
    				context = NULL;
    
    			show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
    
    		show_dialplan_helper(fd, NULL, NULL, &counters, NULL, 0, incstack);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* check for input failure and throw some error messages */
    
    	if (context && !counters.context_existence) {
    		ast_cli(fd, "There is no existence of '%s' context\n", context);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return RESULT_FAILURE;
    	}
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (context)
    			ast_cli(fd, "There is no existence of %s@%s extension\n",
    				exten, context);
    		else
    			ast_cli(fd,
    				"There is no existence of '%s' extension in all contexts\n",
    				exten);
    		return RESULT_FAILURE;
    	}
    
    	ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
    				counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
    				counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
    				counters.total_context, counters.total_context == 1 ? "context" : "contexts");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* everything ok */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return RESULT_SUCCESS;
    }
    
    
    /*! \brief CLI support for listing global variables in a parseable way */
    static int handle_show_globals(int fd, int argc, char *argv[])
    {
    	int i = 0;
    	struct ast_var_t *newvariable;
    
    
    	AST_LIST_TRAVERSE (&globals, newvariable, entries) {
    		i++;
    		ast_cli(fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
    	}
    
    	ast_cli(fd, "\n    -- %d variables\n", i);
    
    	return RESULT_SUCCESS;
    }
    
    /*! \brief  CLI support for setting global variables */
    static int handle_set_global(int fd, int argc, char *argv[])
    {
    	if (argc != 4) 
    		return RESULT_SHOWUSAGE;
    
    	pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[2], argv[3]);
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * CLI entries for upper commands ...
     */
    
    static struct ast_cli_entry pbx_cli[] = {
    	{ { "show", "applications", NULL }, handle_show_applications,
    	  "Shows registered dialplan applications", show_applications_help, complete_show_applications },
    	{ { "show", "functions", NULL }, handle_show_functions,
    	  "Shows registered dialplan functions", show_functions_help },
    	{ { "show" , "function", NULL }, handle_show_function,
    	  "Describe a specific dialplan function", show_function_help, complete_show_function },
    	{ { "show", "application", NULL }, handle_show_application,
    	  "Describe a specific dialplan application", show_application_help, complete_show_application },
    	{ { "show", "dialplan", NULL }, handle_show_dialplan,
    	  "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
    	{ { "show", "switches", NULL },	handle_show_switches,
    	  "Show alternative switches", show_switches_help },
    	{ { "show", "hints", NULL }, handle_show_hints,
    	  "Show dialplan hints", show_hints_help },
    
    	{ { "show", "globals", NULL }, handle_show_globals,
    	  "Show global dialplan variables", show_globals_help },
    	{ { "set", "global", NULL }, handle_set_global,
    	  "Set global dialplan variable", set_global_help },
    
    int ast_unregister_application(const char *app) 
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_app *tmp, *tmpl = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_ERROR, "Unable to lock application list\n");
    		return -1;
    	}
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (tmp = apps; tmp; tmpl = tmp, tmp = tmp->next) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!strcasecmp(app, tmp->name)) {
    			if (tmpl)
    				tmpl->next = tmp->next;
    			else
    				apps = tmp->next;
    			if (option_verbose > 1)
    				ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return 0;
    		}
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return -1;
    }
    
    
    struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	struct ast_context *tmp, **local_contexts;
    
    	int length;
    	length = sizeof(struct ast_context);
    	length += strlen(name) + 1;
    
    	if (!extcontexts) {
    		local_contexts = &contexts;
    
    	} else
    		local_contexts = extcontexts;
    
    
    Russell Bryant's avatar
    Russell Bryant committed
    	for (tmp = *local_contexts; tmp; tmp = tmp->next) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!strcasecmp(tmp->name, name)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
    
    			if (!extcontexts)
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return NULL;
    		}
    	}
    
    		strcpy(tmp->name, name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->root = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->registrar = registrar;
    
    		tmp->next = *local_contexts;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->includes = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->ignorepats = NULL;
    
    		*local_contexts = tmp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (option_debug)
    			ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
    		else if (option_verbose > 2)
    			ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
    
    	if (!extcontexts)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return tmp;
    }
    
    
    void __ast_context_destroy(struct ast_context *con, const char *registrar);
    
    struct store_hint {
    	char *context;
    	char *exten;
    	struct ast_state_cb *callbacks;
    	int laststate;
    	AST_LIST_ENTRY(store_hint) list;
    	char data[1];
    };
    
    AST_LIST_HEAD(store_hints, store_hint);
    
    void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
    {
    
    	struct ast_context *tmp, *lasttmp = NULL;
    
    	struct store_hints store;
    	struct store_hint *this;
    	struct ast_hint *hint;
    	struct ast_exten *exten;
    	int length;
    	struct ast_state_cb *thiscb, *prevcb;
    
    	AST_LIST_HEAD_INIT(&store);
    
    
    	/* it is very important that this function hold the hint list lock _and_ the conlock
    	   during its operation; not only do we need to ensure that the list of contexts
    	   and extensions does not change, but also that no hint callbacks (watchers) are
    	   added or removed during the merge/delete process
    
    	   in addition, the locks _must_ be taken in this order, because there are already
    	   other code paths that use this order
    	*/
    	ast_mutex_lock(&conlock);
    
    
    	/* preserve all watchers for hints associated with this registrar */
    
    		if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
    			length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
    
    				continue;
    			this->callbacks = hint->callbacks;
    			hint->callbacks = NULL;
    			this->laststate = hint->laststate;
    			this->context = this->data;
    			strcpy(this->data, hint->exten->parent->name);
    			this->exten = this->data + strlen(this->context) + 1;
    			strcpy(this->exten, hint->exten->exten);
    			AST_LIST_INSERT_HEAD(&store, this, list);
    		}
    	}
    
    
    	tmp = *extcontexts;
    
    Martin Pycko's avatar
    Martin Pycko committed
    	if (registrar) {
    
    Martin Pycko's avatar
    Martin Pycko committed
    		while (tmp) {
    			lasttmp = tmp;
    			tmp = tmp->next;
    		}
    	} else {
    		while (tmp) {
    
    			__ast_context_destroy(tmp,tmp->registrar);
    
    Martin Pycko's avatar
    Martin Pycko committed
    			lasttmp = tmp;
    			tmp = tmp->next;
    		}
    
    	}
    	if (lasttmp) {
    		lasttmp->next = contexts;
    		contexts = *extcontexts;
    		*extcontexts = NULL;
    	} else 
    		ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
    
    
    	/* restore the watchers for hints that can be found; notify those that
    	   cannot be restored
    	*/
    	while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
    		exten = ast_hint_extension(NULL, this->context, this->exten);
    		/* Find the hint in the list of hints */
    
    			if (hint->exten == exten)
    				break;
    		}
    		if (!exten || !hint) {
    			/* this hint has been removed, notify the watchers */
    			prevcb = NULL;
    			thiscb = this->callbacks;
    			while (thiscb) {
    				prevcb = thiscb;	    
    				thiscb = thiscb->next;
    				prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
    				free(prevcb);
    	    		}
    		} else {
    			thiscb = this->callbacks;
    			while (thiscb->next)
    				thiscb = thiscb->next;
    			thiscb->next = hint->callbacks;
    			hint->callbacks = this->callbacks;
    			hint->laststate = this->laststate;
    		}
    		free(this);
    	}
    
    
    	AST_LIST_UNLOCK(&hints);
    	ast_mutex_unlock(&conlock);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * errno values
     *  EBUSY  - can't lock
    
    Mark Spencer's avatar
    Mark Spencer committed
     *  ENOENT - no existence of context
    
    Mark Spencer's avatar
    Mark Spencer committed
     */
    
    int ast_context_add_include(const char *context, const char *include, const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	int ret = -1;
    	struct ast_context *c = find_context_locked(context);
    
    	if (c) {
    		ret = ast_context_add_include2(c, include, registrar);
    		ast_unlock_contexts();
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    /*! \brief Helper for get_range.
     * return the index of the matching entry, starting from 1.
     * If names is not supplied, try numeric values.
     */
    static int lookup_name(const char *s, char *const names[], int max)
    {
    	int i;
    
    	if (names) {
    		for (i = 0; names[i]; i++) {
    			if (!strcasecmp(s, names[i]))
    				return i+1;
    		}
    	} else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
    		return i;
    	}
    	return 0; /* error return */
    }
    
    /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
     * names, if supplied, is an array of names that should be mapped to numbers.
     */
    static unsigned get_range(char *src, int max, char *const names[], const char *msg)
    {
    	int s, e; /* start and ending position */
    	unsigned int mask = 0;
    
    	/* Check for whole range */
    	if (ast_strlen_zero(src) || !strcmp(src, "*")) {
    		s = 0;
    		e = max - 1;
    	} else {
    		/* Get start and ending position */
    		char *c = strchr(src, '-');
    		if (c)
    			*c++ = '\0';
    		/* Find the start */
    		s = lookup_name(src, names, max);
    		if (!s) {
    			ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
    			return 0;
    		}
    		s--;
    		if (c) { /* find end of range */
    			e = lookup_name(c, names, max);
    			if (!e) {
    				ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
    				return 0;
    			}
    			e--;
    		} else
    			e = s;
    	}
    	/* Fill the mask. Remember that ranges are cyclic */
    
    	mask = 1 << e;	/* initialize with last element */
    
    	while (s != e) {
    		if (s >= max) {
    			s = 0;
    			mask |= (1 << s);
    		} else {
    			mask |= (1 << s);
    			s++;
    		}
    
    	}
    	return mask;
    }
    
    /*! \brief store a bitmask of valid times, one bit each 2 minute */
    
    static void get_timerange(struct ast_timing *i, char *times)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char *e;
    	int x;
    	int s1, s2;
    	int e1, e2;
    
    	/*	int cth, ctm; */
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    	/* start disabling all times, fill the fields with 0's, as they may contain garbage */
    
    	memset(i->minmask, 0, sizeof(i->minmask));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    
    	/* 2-minutes per bit, since the mask has only 32 bits :( */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Star is all times */
    
    	if (ast_strlen_zero(times) || !strcmp(times, "*")) {
    
    			i->minmask[x] = 0x3fffffff; /* 30 bits */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    	/* Otherwise expect a range */
    	e = strchr(times, '-');
    	if (!e) {
    
    		ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    
    	*e++ = '\0';
    	/* XXX why skip non digits ? */
    
    Russell Bryant's avatar
    Russell Bryant committed
    	while (*e && !isdigit(*e)) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!*e) {
    
    		ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    	if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
    
    		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    	if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
    
    		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    
    	/* XXX this needs to be optimized */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	s1 = s1 * 30 + s2/2;
    	if ((s1 < 0) || (s1 >= 24*30)) {
    
    		ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    	e1 = e1 * 30 + e2/2;
    
    	if ((e1 < 0) || (e1 >= 24*30)) {
    		ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    	/* Go through the time and enable each appropriate bit */
    
    	for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		i->minmask[x/30] |= (1 << (x % 30));
    	}
    	/* Do the last one */
    	i->minmask[x/30] |= (1 << (x % 30));
    
    	for (cth=0; cth<24; cth++) {
    
    		/* Initialize masks to blank */
    		i->minmask[cth] = 0;
    
    		for (ctm=0; ctm<30; ctm++) {
    
    			if (
    			/* First hour with more than one hour */
    			      (((cth == s1) && (ctm >= s2)) &&
    			       ((cth < e1)))
    			/* Only one hour */
    			||    (((cth == s1) && (ctm >= s2)) &&
    			       ((cth == e1) && (ctm <= e2)))
    			/* In between first and last hours (more than 2 hours) */
    			||    ((cth > s1) &&
    			       (cth < e1))
    			/* Last hour with more than one hour */
    			||    ((cth > s1) &&
    			       ((cth == e1) && (ctm <= e2)))
    			)
    				i->minmask[cth] |= (1 << (ctm / 2));
    		}
    	}
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* All done */
    
    	return;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static char *days[] =
    {
    	"sun",
    	"mon",
    	"tue",
    	"wed",
    	"thu",
    	"fri",
    	"sat",
    
    Mark Spencer's avatar
    Mark Spencer committed
    };
    
    static char *months[] =
    {
    	"jan",
    	"feb",
    	"mar",
    	"apr",
    	"may",
    	"jun",
    	"jul",
    	"aug",
    	"sep",
    	"oct",
    	"nov",
    	"dec",
    
    int ast_build_timing(struct ast_timing *i, const char *info_in)
    
    	char info_save[256];
    	char *info;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Check for empty just in case */
    
    	if (ast_strlen_zero(info_in))
    		return 0;
    	/* make a copy just in case we were passed a static string */
    
    	ast_copy_string(info_save, info_in, sizeof(info_save));
    
    	info = info_save;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Assume everything except time */
    
    	i->monthmask = 0xfff;	/* 12 bits */
    	i->daymask = 0x7fffffffU; /* 31 bits */
    	i->dowmask = 0x7f; /* 7 bits */
    	/* on each call, use strsep() to move info to the next argument */
    	get_timerange(i, strsep(&info, "|"));
    	if (info)
    		i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
    	if (info)
    		i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
    	if (info)
    		i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
    
    int ast_check_timing(const struct ast_timing *i)
    
    	time_t t = time(NULL);
    
    
    	localtime_r(&t,&tm);
    
    	/* If it's not the right month, return */
    
    	if (!(i->monthmask & (1 << tm.tm_mon)))
    
    		return 0;
    
    	/* If it's not that time of the month.... */
    	/* Warning, tm_mday has range 1..31! */
    	if (!(i->daymask & (1 << (tm.tm_mday-1))))
    		return 0;
    
    	/* If it's not the right day of the week */
    	if (!(i->dowmask & (1 << tm.tm_wday)))
    		return 0;
    
    	/* Sanity check the hour just to be safe */
    	if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
    		ast_log(LOG_WARNING, "Insane time...\n");
    		return 0;
    	}
    
    	/* Now the tough part, we calculate if it fits
    	   in the right time based on min/hour */
    	if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
    		return 0;
    
    	/* If we got this far, then we're good */
    	return 1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * errno values
     *  ENOMEM - out of memory
     *  EBUSY  - can't lock
     *  EEXIST - already included
     *  EINVAL - there is no existence of context for inclusion
     */
    
    int ast_context_add_include2(struct ast_context *con, const char *value,
    	const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_include *new_include;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *c;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_include *i, *il = NULL; /* include, include_last */
    
    	int length;
    	char *p;
    	
    	length = sizeof(struct ast_include);
    	length += 2 * (strlen(value) + 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* allocate new include structure ... */
    
    	if (!(new_include = ast_calloc(1, length)))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	
    
    	/* Fill in this structure. Use 'p' for assignments, as the fields
    	 * in the structure are 'const char *'
    	 */
    
    	p = new_include->stuff;
    	new_include->name = p;
    
    	p += strlen(value) + 1;
    	new_include->rname = p;
    
    	strcpy(p, value);
    	/* Strip off timing info, and process if it is there */
    	if ( (c = strchr(p, '|')) ) {
    		*c++ = '\0';
    	        new_include->hastime = ast_build_timing(&(new_include->timing), c);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	new_include->next      = NULL;
    	new_include->registrar = registrar;
    
    	/* ... try to lock this context ... */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		free(new_include);
    		errno = EBUSY;
    		return -1;
    	}
    
    	/* ... go to last include and check if context is already included too... */
    
    Russell Bryant's avatar
    Russell Bryant committed
    	for (i = con->includes; i; i = i->next) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!strcasecmp(i->name, new_include->name)) {
    			free(new_include);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			errno = EEXIST;
    			return -1;
    		}
    		il = i;
    	}
    
    	/* ... include new context into context list, unlock, return */
    	if (il)
    		il->next = new_include;
    	else
    		con->includes = new_include;
    	if (option_verbose > 2)
    		ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	return 0;
    }
    
    /*
     * errno values
     *  EBUSY  - can't lock
    
    Mark Spencer's avatar
    Mark Spencer committed
     *  ENOENT - no existence of context
    
    Mark Spencer's avatar
    Mark Spencer committed
     */
    
    int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	int ret = -1;
    	struct ast_context *c = find_context_locked(context);
    
    	if (c) { /* found, add switch to this context */
    		ret = ast_context_add_switch2(c, sw, data, eval, registrar);
    		ast_unlock_contexts();
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    /*
     * errno values
     *  ENOMEM - out of memory
     *  EBUSY  - can't lock
     *  EEXIST - already included
     *  EINVAL - there is no existence of context for inclusion
     */
    
    int ast_context_add_switch2(struct ast_context *con, const char *value,
    
    	const char *data, int eval, const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_sw *new_sw;
    	struct ast_sw *i, *il = NULL; /* sw, sw_last */
    
    	int length;
    	char *p;
    	
    	length = sizeof(struct ast_sw);
    	length += strlen(value) + 1;
    	if (data)
    		length += strlen(data);
    	length++;
    
    	if (eval) {
    		/* Create buffer for evaluation of variables */
    		length += SWITCH_DATA_LENGTH;
    		length++;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* allocate new sw structure ... */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	/* ... fill in this structure ... */
    
    	p = new_sw->stuff;
    	new_sw->name = p;
    	strcpy(new_sw->name, value);
    	p += strlen(value) + 1;
    	new_sw->data = p;
    
    		strcpy(new_sw->data, data);
    
    		strcpy(new_sw->data, "");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	new_sw->next      = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	new_sw->registrar = registrar;
    
    	/* ... try to lock this context ... */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		free(new_sw);
    		errno = EBUSY;
    		return -1;
    	}
    
    	/* ... go to last sw and check if context is already swd too... */
    
    Russell Bryant's avatar
    Russell Bryant committed
    	for (i = con->alts; i; i = i->next) {
    
    		if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			free(new_sw);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			errno = EEXIST;
    			return -1;
    		}
    		il = i;
    	}
    
    	/* ... sw new context into context list, unlock, return */
    	if (il)
    		il->next = new_sw;
    	else
    		con->alts = new_sw;
    	if (option_verbose > 2)
    		ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	return 0;
    }
    
    /*
     * EBUSY  - can't lock
    
    Mark Spencer's avatar
    Mark Spencer committed
     * ENOENT - there is not context existence
    
    Mark Spencer's avatar
    Mark Spencer committed
     */
    
    int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {