Skip to content
Snippets Groups Projects
pbx.c 100 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    							ast_get_extension_app(p),
    							(char *)ast_get_extension_app_data(p));
    
    						ast_cli(fd,"  %-17s %-45s [%s]\n",
    							"", buf2,
    							ast_get_extension_registrar(p));	
    
    						p = ast_walk_extension_priorities(e, p);
    
    Mark Spencer's avatar
    Mark Spencer committed
    					}
    
    Mark Spencer's avatar
    Mark Spencer committed
    					e = ast_walk_context_extensions(c, e);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    				/* include & ignorepat we all printing if we are not
    				 * looking for exact extension
    				 */
    				if (!exten) {
    					if (ast_walk_context_extensions(c, NULL))
    						ast_cli(fd, "\n");
    
    					/* walk included and write info ... */
    					i = ast_walk_context_includes(c, NULL);
    					while (i) {
    						bzero(buf, sizeof(buf));
    						snprintf(buf, sizeof(buf), "'%s'",
    							ast_get_include_name(i));
    						ast_cli(fd, "  Include =>        %-45s [%s]\n",
    							buf, ast_get_include_registrar(i));
    						i = ast_walk_context_includes(c, i);
    					}
    
    					/* walk ignore patterns and write info ... */
    					ip = ast_walk_context_ignorepats(c, NULL);
    					while (ip) {
    						bzero(buf, sizeof(buf));
    						snprintf(buf, sizeof(buf), "'%s'",
    							ast_get_ignorepat_name(ip));
    						ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
    							buf, ast_get_ignorepat_registrar(ip));	
    						ip = ast_walk_context_ignorepats(c, ip);
    					}
    					sw = ast_walk_context_switches(c, NULL);
    					while(sw) {
    						bzero(buf, sizeof(buf));
    						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));	
    						sw = ast_walk_context_switches(c, sw);
    					}
    				}
    	
    				ast_unlock_context(c);
    
    				/* if we print something in context, make an empty line */
    				if (context_info_printed) ast_cli(fd, "\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		c = ast_walk_contexts(c);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_unlock_contexts();
    
    	/* check for input failure and throw some error messages */
    	if (context && !context_existence) {
    		ast_cli(fd, "There is no existence of '%s' context\n",
    			context);
    		return RESULT_FAILURE;
    	}
    
    	if (exten && !extension_existence) {
    		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;
    	}
    
    	/* everything ok */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return RESULT_SUCCESS;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * CLI entries for upper commands ...
     */
    static struct ast_cli_entry show_applications_cli = 
    	{ { "show", "applications", NULL }, 
    	handle_show_applications, "Shows registered applications",
    	show_applications_help };
    
    static struct ast_cli_entry show_application_cli =
    	{ { "show", "application", NULL }, 
    	handle_show_application, "Describe a specific application",
    	show_application_help, complete_show_application };
    
    static struct ast_cli_entry show_dialplan_cli =
    	{ { "show", "dialplan", NULL },
    		handle_show_dialplan, "Show dialplan",
    		show_dialplan_help, complete_show_dialplan_context };
    
    static struct ast_cli_entry show_switches_cli =
    	{ { "show", "switches", NULL },
    		handle_show_switches, "Show alternative switches",
    		show_switches_help, NULL };
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_unregister_application(char *app) {
    	struct ast_app *tmp, *tmpl = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ast_pthread_mutex_lock(&applock)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_ERROR, "Unable to lock application list\n");
    		return -1;
    	}
    	tmp = apps;
    	while(tmp) {
    		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
    			ast_pthread_mutex_unlock(&applock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return 0;
    		}
    		tmpl = tmp;
    		tmp = tmp->next;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_pthread_mutex_unlock(&applock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return -1;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct ast_context *ast_context_create(char *name, char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_context *tmp;
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_pthread_mutex_lock(&conlock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	tmp = contexts;
    	while(tmp) {
    		if (!strcasecmp(tmp->name, name)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_pthread_mutex_unlock(&conlock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
    			return NULL;
    		}
    		tmp = tmp->next;
    	}
    	tmp = malloc(sizeof(struct ast_context));
    	if (tmp) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		memset(tmp, 0, sizeof(struct ast_context));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_pthread_mutex_init(&tmp->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(tmp->name, name, sizeof(tmp->name)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->root = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->registrar = registrar;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->next = contexts;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->includes = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->ignorepats = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		contexts = tmp;
    		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);
    	} else
    		ast_log(LOG_WARNING, "Out of memory\n");
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_pthread_mutex_unlock(&conlock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return tmp;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * errno values
     *  EBUSY  - can't lock
     *  ENODATA - no existence of context
     */
    int ast_context_add_include(char *context, char *include, char *registrar)
    {
    	struct ast_context *c;
    
    	if (ast_lock_contexts()) {
    		errno = EBUSY;
    		return -1;
    	}
    
    	/* walk contexts ... */
    	c = ast_walk_contexts(NULL);
    	while (c) {
    		/* ... search for the right one ... */
    		if (!strcmp(ast_get_context_name(c), context)) {
    			int ret = ast_context_add_include2(c, include, registrar);
    			/* ... unlock contexts list and return */
    			ast_unlock_contexts();
    			return ret;
    		}
    		c = ast_walk_contexts(c);
    	}
    
    	/* we can't find the right context */
    	ast_unlock_contexts();
    	errno = ENODATA;
    	return -1;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define FIND_NEXT \
    do { \
    	c = info; \
    	while(*c && (*c != '|')) c++; \
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (*c) { *c = '\0'; c++; } else c = NULL; \
    
    Mark Spencer's avatar
    Mark Spencer committed
    } while(0)
    
    static void get_timerange(struct ast_include *i, char *times)
    {
    	char *e;
    	int x;
    	int s1, s2;
    	int e1, e2;
    	/* Star is all times */
    	if (!strlen(times) || !strcmp(times, "*")) {
    		for (x=0;x<24;x++)
    			i->minmask[x] = (1 << 30) - 1;
    		return;
    	}
    	/* Otherwise expect a range */
    	e = strchr(times, '-');
    	if (!e) {
    		ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
    		return;
    	}
    	*e = '\0';
    	e++;
    	while(*e && !isdigit(*e)) e++;
    	if (!*e) {
    		ast_log(LOG_WARNING, "Invalid time range.  Assuming no time.\n");
    		return;
    	}
    	if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
    		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", times);
    		return;
    	}
    	if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
    		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", e);
    		return;
    	}
    	s1 = s1 * 30 + s2/2;
    	if ((s1 < 0) || (s1 >= 24*30)) {
    		ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
    		return;
    	}
    	e1 = e1 * 30 + e2/2;
    	if ((e1 < 0) || (e2 >= 24*30)) {
    		ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
    		return;
    	}
    	/* Go through the time and enable each appropriate bit */
    	for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
    		i->minmask[x/30] |= (1 << (x % 30));
    	}
    	/* Do the last one */
    	i->minmask[x/30] |= (1 << (x % 30));
    	/* All done */
    }
    
    static char *days[] =
    {
    	"sun",
    	"mon",
    	"tue",
    	"wed",
    	"thu",
    	"fri",
    	"sat",
    };
    
    static unsigned int get_dow(char *dow)
    {
    	char *c;
    	/* The following line is coincidence, really! */
    	int s, e, x;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	unsigned int mask;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Check for all days */
    	if (!strlen(dow) || !strcmp(dow, "*"))
    		return (1 << 7) - 1;
    	/* Get start and ending days */
    	c = strchr(dow, '-');
    	if (c) {
    		*c = '\0';
    		c++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else
    		c = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Find the start */
    	s = 0;
    	while((s < 7) && strcasecmp(dow, days[s])) s++;
    	if (s >= 7) {
    		ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
    		return 0;
    	}
    	if (c) {
    		e = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		while((e < 7) && strcasecmp(c, days[e])) e++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (e >= 7) {
    			ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
    			return 0;
    		}
    	} else
    		e = s;
    	mask = 0;
    	for (x=s;x!=e;x = (x + 1) % 7) {
    		mask |= (1 << x);
    	}
    	/* One last one */
    	mask |= (1 << x);
    	return mask;
    }
    
    static unsigned int get_day(char *day)
    {
    	char *c;
    	/* The following line is coincidence, really! */
    	int s, e, x;
    	unsigned int mask;
    	/* Check for all days */
    	if (!strlen(day) || !strcmp(day, "*")) {
    		mask = (1 << 30)  + ((1 << 30) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return mask;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	/* Get start and ending days */
    	c = strchr(day, '-');
    	if (c) {
    		*c = '\0';
    		c++;
    	}
    	/* Find the start */
    	if (sscanf(day, "%d", &s) != 1) {
    		ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
    		return 0;
    	}
    	if ((s < 1) || (s > 31)) {
    		ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
    		return 0;
    	}
    	s--;
    	if (c) {
    		if (sscanf(c, "%d", &e) != 1) {
    			ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
    			return 0;
    		}
    		if ((e < 1) || (e > 31)) {
    			ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
    			return 0;
    		}
    		e--;
    	} else
    		e = s;
    	mask = 0;
    	for (x=s;x!=e;x = (x + 1) % 31) {
    		mask |= (1 << x);
    	}
    	mask |= (1 << x);
    	return mask;
    }
    
    static char *months[] =
    {
    	"jan",
    	"feb",
    	"mar",
    	"apr",
    	"may",
    	"jun",
    	"jul",
    	"aug",
    	"sep",
    	"oct",
    	"nov",
    	"dec",
    };
    
    static unsigned int get_month(char *mon)
    {
    	char *c;
    	/* The following line is coincidence, really! */
    	int s, e, x;
    	unsigned int mask;
    	/* Check for all days */
    	if (!strlen(mon) || !strcmp(mon, "*")) 
    		return (1 << 12) - 1;
    	/* Get start and ending days */
    	c = strchr(mon, '-');
    	if (c) {
    		*c = '\0';
    		c++;
    	}
    	/* Find the start */
    	s = 0;
    	while((s < 12) && strcasecmp(mon, months[s])) s++;
    	if (s >= 12) {
    		ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
    		return 0;
    	}
    	if (c) {
    		e = 0;
    		while((e < 12) && strcasecmp(mon, months[e])) e++;
    		if (e >= 12) {
    			ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
    			return 0;
    		}
    	} else
    		e = s;
    	mask = 0;
    	for (x=s;x!=e;x = (x + 1) % 12) {
    		mask |= (1 << x);
    	}
    	/* One last one */
    	mask |= (1 << x);
    	return mask;
    }
    
    static void build_timing(struct ast_include *i, char *info)
    {
    	char *c;
    	/* Check for empty just in case */
    	if (!strlen(info))
    		return;
    	i->hastime = 1;
    	/* Assume everything except time */
    	i->monthmask = (1 << 12) - 1;
    	i->daymask = (1 << 30) - 1 + (1 << 30);
    	i->dowmask = (1 << 7) - 1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Avoid using str tok */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	FIND_NEXT;
    	/* Info has the time range, start with that */
    	get_timerange(i, info);
    	info = c;
    	if (!info)
    		return;
    	FIND_NEXT;
    	/* Now check for day of week */
    	i->dowmask = get_dow(info);
    
    	info = c;
    	if (!info)
    		return;
    	FIND_NEXT;
    	/* Now check for the day of the month */
    	i->daymask = get_day(info);
    	info = c;
    	if (!info)
    		return;
    	FIND_NEXT;
    	/* And finally go for the month */
    	i->monthmask = get_month(info);
    }
    
    
    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, char *value,
    	char *registrar)
    {
    	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 */
    
    	/* allocate new include structure ... */
    	if (!(new_include = malloc(sizeof(struct ast_include)))) {
    		ast_log(LOG_WARNING, "Out of memory\n");
    		errno = ENOMEM;
    		return -1;
    	}
    	
    	/* ... fill in this structure ... */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	memset(new_include, 0, sizeof(struct ast_include));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(new_include->name, value, sizeof(new_include->name)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
    	c = new_include->rname;
    	/* Strip off timing info */
    	while(*c && (*c != '|')) c++; 
    	/* Process if it's there */
    	if (*c) {
    		build_timing(new_include, c+1);
    		*c = '\0';
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	new_include->next      = NULL;
    	new_include->registrar = registrar;
    
    	/* ... try to lock this context ... */
    	if (ast_pthread_mutex_lock(&con->lock)) {
    		free(new_include);
    		errno = EBUSY;
    		return -1;
    	}
    
    	/* ... go to last include and check if context is already included too... */
    	i = con->includes;
    	while (i) {
    		if (!strcasecmp(i->name, new_include->name)) {
    			free(new_include);
    			ast_pthread_mutex_unlock(&con->lock);
    			errno = EEXIST;
    			return -1;
    		}
    		il = i;
    		i = i->next;
    	}
    
    	/* ... 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)); 
    	ast_pthread_mutex_unlock(&con->lock);
    
    	return 0;
    }
    
    /*
     * errno values
     *  EBUSY  - can't lock
     *  ENODATA - no existence of context
     */
    int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
    {
    	struct ast_context *c;
    
    	if (ast_lock_contexts()) {
    		errno = EBUSY;
    		return -1;
    	}
    
    	/* walk contexts ... */
    	c = ast_walk_contexts(NULL);
    	while (c) {
    		/* ... search for the right one ... */
    		if (!strcmp(ast_get_context_name(c), context)) {
    			int ret = ast_context_add_switch2(c, sw, data, registrar);
    			/* ... unlock contexts list and return */
    			ast_unlock_contexts();
    			return ret;
    		}
    		c = ast_walk_contexts(c);
    	}
    
    	/* we can't find the right context */
    	ast_unlock_contexts();
    	errno = ENODATA;
    	return -1;
    }
    
    /*
     * 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, char *value,
    	char *data, 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 */
    
    	/* allocate new sw structure ... */
    	if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Out of memory\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		errno = ENOMEM;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	/* ... fill in this structure ... */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	memset(new_sw, 0, sizeof(struct ast_sw));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	else
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	new_sw->next      = NULL;
    	new_sw->registrar = registrar;
    
    	/* ... try to lock this context ... */
    	if (ast_pthread_mutex_lock(&con->lock)) {
    		free(new_sw);
    		errno = EBUSY;
    		return -1;
    	}
    
    	/* ... go to last sw and check if context is already swd too... */
    	i = con->alts;
    	while (i) {
    		if (!strcasecmp(i->name, new_sw->name)) {
    			free(new_sw);
    			ast_pthread_mutex_unlock(&con->lock);
    			errno = EEXIST;
    			return -1;
    		}
    		il = i;
    		i = i->next;
    	}
    
    	/* ... 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)); 
    	ast_pthread_mutex_unlock(&con->lock);
    
    	return 0;
    }
    
    /*
     * EBUSY  - can't lock
     * ENODATA - there is not context existence
     */
    int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
    {
    	struct ast_context *c;
    
    	if (ast_lock_contexts()) {
    		errno = EBUSY;
    		return -1;
    	}
    
    	c = ast_walk_contexts(NULL);
    	while (c) {
    		if (!strcmp(ast_get_context_name(c), context)) {
    			int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
    			ast_unlock_contexts();
    			return ret;
    		}
    		c = ast_walk_contexts(c);
    	}
    
    	ast_unlock_contexts();
    	errno = ENODATA;
    	return -1;
    }
    
    int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
    {
    	struct ast_ignorepat *ip, *ipl = NULL;
    
    	if (ast_pthread_mutex_lock(&con->lock)) {
    		errno = EBUSY;
    		return -1;
    	}
    
    	ip = con->ignorepats;
    	while (ip) {
    		if (!strcmp(ip->pattern, ignorepat) &&
    			(registrar == ip->registrar || !registrar)) {
    			if (ipl) {
    				ipl->next = ip->next;
    				free(ip);
    			} else {
    				con->ignorepats = ip->next;
    				free(ip);
    			}
    			ast_pthread_mutex_unlock(&con->lock);
    			return 0;
    		}
    		ipl = ip; ip = ip->next;
    	}
    
    	ast_pthread_mutex_unlock(&con->lock);
    	errno = EINVAL;
    	return -1;
    }
    
    /*
     * EBUSY - can't lock
     * ENODATA - there is no existence of context
     */
    int ast_context_add_ignorepat(char *con, char *value, char *registrar)
    {
    	struct ast_context *c;
    
    	if (ast_lock_contexts()) {
    		errno = EBUSY;
    		return -1;
    	}
    
    	c = ast_walk_contexts(NULL);
    	while (c) {
    		if (!strcmp(ast_get_context_name(c), con)) {
    			int ret = ast_context_add_ignorepat2(c, value, registrar);
    			ast_unlock_contexts();
    			return ret;
    		} 
    		c = ast_walk_contexts(c);
    	}
    
    	ast_unlock_contexts();
    	errno = ENODATA;
    	return -1;
    }
    
    int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
    {
    	struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
    	ignorepat = malloc(sizeof(struct ast_ignorepat));
    	if (!ignorepat) {
    		ast_log(LOG_WARNING, "Out of memory\n");
    		errno = ENOMEM;
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	memset(ignorepat, 0, sizeof(struct ast_ignorepat));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ignorepat->next = NULL;
    	ignorepat->registrar = registrar;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_pthread_mutex_lock(&con->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ignorepatc = con->ignorepats;
    	while(ignorepatc) {
    		ignorepatl = ignorepatc;
    		if (!strcasecmp(ignorepatc->pattern, value)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Already there */
    			pthread_mutex_unlock(&con->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			errno = EEXIST;
    			return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ignorepatc = ignorepatc->next;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ignorepatl) 
    		ignorepatl->next = ignorepat;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	else
    
    Mark Spencer's avatar
    Mark Spencer committed
    		con->ignorepats = ignorepat;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	pthread_mutex_unlock(&con->lock);
    	return 0;
    	
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_ignore_pattern(char *context, char *pattern)
    {
    	struct ast_context *con;
    	struct ast_ignorepat *pat;
    	con = ast_context_find(context);
    	if (con) {
    		pat = con->ignorepats;
    		while (pat) {
    			if (ast_extension_match(pat->pattern, pattern))
    				return 1;
    			pat = pat->next;
    		}
    	} 
    	return 0;
    }
    
    /*
     * EBUSY   - can't lock
     * ENODATA  - no existence of context
     *
     */
    int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
    	char *application, void *data, void (*datad)(void *), char *registrar)
    {
    	struct ast_context *c;
    
    	if (ast_lock_contexts()) {
    		errno = EBUSY;
    		return -1;
    	}
    
    	c = ast_walk_contexts(NULL);
    	while (c) {
    		if (!strcmp(context, ast_get_context_name(c))) {
    			int ret = ast_add_extension2(c, replace, extension, priority, callerid,
    				application, data, datad, registrar);
    			ast_unlock_contexts();
    			return ret;
    		}
    		c = ast_walk_contexts(c);
    	}
    
    	ast_unlock_contexts();
    	errno = ENODATA;
    	return -1;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority, int needlock)
    {
    	int res = 0;
    	if (needlock)
    		ast_pthread_mutex_lock(&chan->lock);
    	if (chan->pbx) {
    		/* This channel is currently in the PBX */
    		if (context && strlen(context))
    			strncpy(chan->context, context, sizeof(chan->context) - 1);
    		if (exten && strlen(exten))
    			strncpy(chan->exten, exten, sizeof(chan->context) - 1);
    		if (priority)
    			chan->priority = priority - 1;
    		ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
    		if (needlock)
    			ast_pthread_mutex_unlock(&chan->lock);
    	} else {
    		/* In order to do it when the channel doesn't really exist within
    		   the PBX, we have to make a new channel, masquerade, and start the PBX
    		   at the new location */
    		struct ast_channel *tmpchan;
    		struct ast_frame *f;
    		tmpchan = ast_channel_alloc(0);
    		if (tmpchan) {
    			snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
    
    			ast_setstate(tmpchan, chan->_state);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Make formats okay */
    			tmpchan->readformat = chan->readformat;
    			tmpchan->writeformat = chan->writeformat;
    			/* Setup proper location */
    			if (context && strlen(context))
    				strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
    			else
    				strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
    			if (exten && strlen(exten))
    				strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
    			else
    				strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
    			if (priority)
    				tmpchan->priority = priority;
    			else
    				tmpchan->priority = chan->priority;
    			if (needlock)
    				ast_pthread_mutex_unlock(&chan->lock);
    			
    			/* Masquerade into temp channel */
    			ast_channel_masquerade(tmpchan, chan);
    			
    			/* Make the masquerade happen by reading a frame from the tmp channel */
    			f = ast_read(tmpchan);
    			if (f)
    				ast_frfree(f);
    			/* Start the PBX going on our stolen channel */
    			if (ast_pbx_start(tmpchan)) {
    				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
    				ast_hangup(tmpchan);
    				res = -1;
    			}
    		} else {
    			res = -1;
    			if (needlock)
    				ast_pthread_mutex_unlock(&chan->lock);
    		}
    	}
    	return res;
    }
    
    int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
    {
    	struct ast_channel *chan;
    	chan = ast_channel_walk(NULL);
    	while(chan) {
    		if (!strcasecmp(channame, chan->name))
    			break;
    		chan = ast_channel_walk(chan);
    	}
    	if (chan)
    		return ast_async_goto(chan, context, exten, priority, 1);
    	return -1;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void ext_strncpy(char *dst, char *src, int len)
    {
    	int count=0;
    	while(*src && (count < len - 1)) {
    		switch(*src) {
    		case ' ':
    
    //otherwise exten => [a-b],1,... doesn't work
    //		case '-':
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Ignore */
    			break;
    		default:
    			*dst = *src;
    			dst++;
    		}
    		src++;
    		count++;
    	}
    	*dst = '\0';
    }
    
    /*
     * EBUSY - can't lock
     * EEXIST - extension with the same priority exist and no replace is set
     *
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_add_extension2(struct ast_context *con,
    
    Mark Spencer's avatar
    Mark Spencer committed
    					  int replace, char *extension, int priority, char *callerid,
    
    Mark Spencer's avatar
    Mark Spencer committed
    					  char *application, void *data, void (*datad)(void *),
    					  char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define LOG do { 	if (option_debug) {\
    		if (tmp->matchcid) { \
    			ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
    		} else { \
    			ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
    		} \
    	} else if (option_verbose > 2) { \
    		if (tmp->matchcid) { \
    			ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
    		} else {  \
    			ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
    		} \
    	} } while(0)
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/*
    	 * This is a fairly complex routine.  Different extensions are kept
    	 * in order by the extension number.  Then, extensions of different
    	 * priorities (same extension) are kept in a list, according to the
    	 * peer pointer.
    	 */
    	struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
    	int res;
    	/* Be optimistic:  Build the extension structure first */
    	tmp = malloc(sizeof(struct ast_exten));
    	if (tmp) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		memset(tmp, 0, sizeof(struct ast_exten));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->priority = priority;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (callerid) {
    			ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
    			tmp->matchcid = 1;
    		} else {
    			strcpy(tmp->cidmatch, "");
    			tmp->matchcid = 0;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(tmp->app, application, sizeof(tmp->app)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->data = data;
    		tmp->datad = datad;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->registrar = registrar;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		tmp->peer = NULL;
    		tmp->next =  NULL;
    	} else {
    		ast_log(LOG_WARNING, "Out of memory\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		errno = ENOMEM;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ast_pthread_mutex_lock(&con->lock)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		free(tmp);
    		/* And properly destroy the data */
    		datad(data);
    		ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		errno = EBUSY;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    	e = con->root;
    	while(e) {
    		res= strcasecmp(e->exten, extension);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!res) {
    			if (!e->matchcid && !tmp->matchcid)
    				res = 0;
    			else if (tmp->matchcid && !e->matchcid)
    				res = 1;
    			else if (e->matchcid && !tmp->matchcid)
    				res = -1;
    			else
    				res = strcasecmp(e->cidmatch, tmp->cidmatch);
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (res == 0) {
    			/* We have an exact match, now we find where we are
    			   and be sure there's no duplicates */
    			while(e) {
    				if (e->priority == tmp->priority) {
    					/* Can't have something exactly the same.  Is this a
    					   replacement?  If so, replace, otherwise, bonk. */
    					if (replace) {
    						if (ep) {
    							/* We're in the peer list, insert ourselves */
    							ep->peer = tmp;
    							tmp->peer = e->peer;
    						} else if (el) {
    							/* We're the first extension. Take over e's functions */
    							el->next = tmp;
    							tmp->next = e->next;
    							tmp->peer = e->peer;
    						} else {
    							/* We're the very first extension.  */
    							con->root = tmp;
    							tmp->next = e->next;
    							tmp->peer = e->peer;
    						}
    						/* Destroy the old one */
    						e->datad(e->data);
    						free(e);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_pthread_mutex_unlock(&con->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						/* And immediately return success. */
    						LOG;
    						return 0;
    					} else {
    						ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
    						tmp->datad(tmp->data);
    						free(tmp);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_pthread_mutex_unlock(&con->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						errno = EEXIST;
    
    Mark Spencer's avatar
    Mark Spencer committed
    						return -1;
    					}
    				} else if (e->priority > tmp->priority) {