Skip to content
Snippets Groups Projects
app.c 39 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* Channel group core functions */
    
    
    int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
    
    	char *grp=NULL, *cat=NULL;
    
    
    		ast_copy_string(tmp, data, sizeof(tmp));
    
    		grp = tmp;
    		cat = strchr(tmp, '@');
    		if (cat) {
    			*cat = '\0';
    			cat++;
    		}
    	}
    
    
    		ast_copy_string(group, grp, group_max);
    
    	else
    		res = -1;
    
    	if (cat)
    		snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat);
    	else
    
    		ast_copy_string(category, GROUP_CATEGORY_PREFIX, category_max);
    
    int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
    
    {
    	int res=0;
    	char group[80] = "";
    	char category[80] = "";
    
    	if (!ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
    		pbx_builtin_setvar_helper(chan, category, group);
    	} else
    		res = -1;
    
    	return res;
    }
    
    
    int ast_app_group_get_count(const char *group, const char *category)
    
    {
    	struct ast_channel *chan;
    	int count = 0;
    
     	s = S_OR(category, GROUP_CATEGORY_PREFIX);
    
    	ast_copy_string(cat, s, sizeof(cat));
    
    	chan = NULL;
    	while ((chan = ast_channel_walk_locked(chan)) != NULL) {
     		test = pbx_builtin_getvar_helper(chan, cat);
    		if (test && !strcasecmp(test, group))
     			count++;
    		ast_mutex_unlock(&chan->lock);
    
    int ast_app_group_match_get_count(const char *groupmatch, const char *category)
    
    {
    	regex_t regexbuf;
    	struct ast_channel *chan;
    	int count = 0;
    
    	if (ast_strlen_zero(groupmatch))
    
    		return 0;
    
    	/* if regex compilation fails, return zero matches */
    	if (regcomp(&regexbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
    		return 0;
    
    
    	s = S_OR(category, GROUP_CATEGORY_PREFIX);
    
    	chan = NULL;
    	while ((chan = ast_channel_walk_locked(chan)) != NULL) {
    
    		test = pbx_builtin_getvar_helper(chan, cat);
    		if (test && !regexec(&regexbuf, test, 0, NULL, 0))
    			count++;
    		ast_mutex_unlock(&chan->lock);
    	}
    
    	regfree(&regexbuf);
    
    	return count;
    }
    
    unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
    
    
    	for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
    		array[argc] = scan;
    		for (; *scan; scan++) {
    			if (*scan == '(')
    				paren++;
    			else if (*scan == ')') {
    				if (paren)
    					paren--;
    
    			} else if (*scan == '"') {
    				quote = quote ? 0 : 1;
    				/* Remove quote character from argument */
    				memmove(scan, scan + 1, strlen(scan));
    				scan--;
    			} else if (*scan == '\\') {
    				/* Literal character, don't parse */
    				memmove(scan, scan + 1, strlen(scan));
    			} else if ((*scan == delim) && !paren && !quote) {
    
    enum AST_LOCK_RESULT ast_lock_path(const char *path)
    
    	if (!(s = alloca(lp + 10)) || !(fs = alloca(lp + 20))) {
    
    		ast_log(LOG_WARNING, "Out of memory!\n");
    
    		return AST_LOCK_FAILURE;
    
    	snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
    
    	fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
    	if (fd < 0) {
    
    		fprintf(stderr, "Unable to create lock file '%s': %s\n", path, strerror(errno));
    		return AST_LOCK_PATH_NOT_FOUND;
    
    
    	snprintf(s, strlen(path) + 9, "%s/.lock", path);
    
    	time(&start);
    	while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
    		usleep(1);
    
    		ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
    
    		return AST_LOCK_TIMEOUT;
    	} else {
    		unlink(fs);
    		ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
    		return AST_LOCK_SUCCESS;
    
    	if (!(s = alloca(strlen(path) + 10)))
    
    		return -1;
    	snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
    	ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
    	return unlink(s);
    }
    
    int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) 
    
    {
    	int silencethreshold = 128; 
    	int maxsilence=0;
    	int res = 0;
    	int cmd = 0;
    	int max_attempts = 3;
    	int attempts = 0;
    	int recorded = 0;
    	int message_exists = 0;
    	/* Note that urgent and private are for flagging messages as such in the future */
    
    	/* barf if no pointer passed to store duration in */
    	if (duration == NULL) {
    		ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
    		return -1;
    	}
    
    	cmd = '3';	 /* Want to start by recording */
    
    	while ((cmd >= 0) && (cmd != 't')) {
    		switch (cmd) {
    		case '1':
    			if (!message_exists) {
    				/* In this case, 1 is to record a message */
    				cmd = '3';
    				break;
    			} else {
    				ast_streamfile(chan, "vm-msgsaved", chan->language);
    				ast_waitstream(chan, "");
    				cmd = 't';
    				return res;
    			}
    		case '2':
    			/* Review */
    			ast_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n");
    			ast_streamfile(chan, recordfile, chan->language);
    			cmd = ast_waitstream(chan, AST_DIGIT_ANY);
    			break;
    		case '3':
    			message_exists = 0;
    			/* Record */
    			if (recorded == 1)
    				ast_verbose(VERBOSE_PREFIX_3 "Re-recording\n");
    			else	
    				ast_verbose(VERBOSE_PREFIX_3 "Recording\n");
    			recorded = 1;
    
    			cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
    
    			if (cmd == -1) {
    			/* User has hung up, no options to give */
    				return cmd;
    			}
    			if (cmd == '0') {
    				break;
    			} else if (cmd == '*') {
    				break;
    			} 
    			else {
    				/* If all is well, a message exists */
    				message_exists = 1;
    				cmd = 0;
    			}
    			break;
    		case '4':
    		case '5':
    		case '6':
    		case '7':
    		case '8':
    		case '9':
    		case '*':
    		case '#':
    			cmd = ast_play_and_wait(chan, "vm-sorry");
    			break;
    		default:
    			if (message_exists) {
    				cmd = ast_play_and_wait(chan, "vm-review");
    			}
    			else {
    				cmd = ast_play_and_wait(chan, "vm-torerecord");
    				if (!cmd)
    					cmd = ast_waitfordigit(chan, 600);
    			}
    			
    			if (!cmd)
    				cmd = ast_waitfordigit(chan, 6000);
    			if (!cmd) {
    				attempts++;
    			}
    			if (attempts > max_attempts) {
    				cmd = 't';
    			}
    		}
    	}
    	if (cmd == 't')
    		cmd = 0;
    	return cmd;
    }
    
    
    #define RES_UPONE (1 << 16)
    #define RES_EXIT  (1 << 17)
    #define RES_REPEAT (1 << 18)
    #define RES_RESTART ((1 << 19) | RES_REPEAT)
    
    static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
    static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
    {
    	int res;
    
    	int (*ivr_func)(struct ast_channel *, void *);
    	char *c;
    	char *n;
    	
    
    	switch(option->action) {
    	case AST_ACTION_UPONE:
    		return RES_UPONE;
    	case AST_ACTION_EXIT:
    		return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
    	case AST_ACTION_REPEAT:
    		return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
    	case AST_ACTION_RESTART:
    		return RES_RESTART ;
    	case AST_ACTION_NOOP:
    		return 0;
    	case AST_ACTION_BACKGROUND:
    		res = ast_streamfile(chan, (char *)option->adata, chan->language);
    		if (!res) {
    			res = ast_waitstream(chan, AST_DIGIT_ANY);
    		} else {
    			ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
    			res = 0;
    		}
    		return res;
    	case AST_ACTION_PLAYBACK:
    		res = ast_streamfile(chan, (char *)option->adata, chan->language);
    		if (!res) {
    			res = ast_waitstream(chan, "");
    		} else {
    			ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
    			res = 0;
    		}
    		return res;
    	case AST_ACTION_MENU:
    		res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
    
    		/* Do not pass entry errors back up, treaat ast though ti was an "UPONE" */
    		if (res == -2)
    			res = 0;
    		return res;
    	case AST_ACTION_WAITOPTION:
    		res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
    		if (!res)
    			return 't';
    
    		return res;
    	case AST_ACTION_CALLBACK:
    
    		ivr_func = option->adata;
    		res = ivr_func(chan, cbdata);
    		return res;
    
    	case AST_ACTION_TRANSFER:
    
    		res = ast_parseable_goto(chan, option->adata);
    
    	case AST_ACTION_PLAYLIST:
    	case AST_ACTION_BACKLIST:
    		res = 0;
    		c = ast_strdupa(option->adata);
    
    		if (c) {
    			while((n = strsep(&c, ";")))
    				if ((res = ast_streamfile(chan, n, chan->language)) || (res = ast_waitstream(chan, (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
    					break;
    			ast_stopstream(chan);
    
    	default:
    		ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
    		return 0;
    	};
    	return -1;
    }
    
    static int option_exists(struct ast_ivr_menu *menu, char *option)
    {
    	int x;
    	for (x=0;menu->options[x].option;x++)
    		if (!strcasecmp(menu->options[x].option, option))
    			return x;
    	return -1;
    }
    
    static int option_matchmore(struct ast_ivr_menu *menu, char *option)
    {
    	int x;
    	for (x=0;menu->options[x].option;x++)
    		if ((!strncasecmp(menu->options[x].option, option, strlen(option))) && 
    				(menu->options[x].option[strlen(option)]))
    			return x;
    	return -1;
    }
    
    static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
    {
    	int res=0;
    	int ms;
    	while(option_matchmore(menu, exten)) {
    		ms = chan->pbx ? chan->pbx->dtimeout : 5000;
    		if (strlen(exten) >= maxexten - 1) 
    			break;
    		res = ast_waitfordigit(chan, ms);
    		if (res < 1)
    			break;
    		exten[strlen(exten) + 1] = '\0';
    		exten[strlen(exten)] = res;
    	}
    	return res > 0 ? 0 : res;
    }
    
    static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
    {
    	/* Execute an IVR menu structure */
    	int res=0;
    	int pos = 0;
    	int retries = 0;
    	char exten[AST_MAX_EXTENSION] = "s";
    	if (option_exists(menu, "s") < 0) {
    		strcpy(exten, "g");
    		if (option_exists(menu, "g") < 0) {
    			ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
    			return -1;
    		}
    	}
    	while(!res) {
    		while(menu->options[pos].option) {
    			if (!strcasecmp(menu->options[pos].option, exten)) {
    				res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
    
    				ast_log(LOG_DEBUG, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
    
    				if (res < 0)
    					break;
    				else if (res & RES_UPONE)
    					return 0;
    				else if (res & RES_EXIT)
    					return res;
    				else if (res & RES_REPEAT) {
    					int maxretries = res & 0xffff;
    
    					if ((res & RES_RESTART) == RES_RESTART) {
    
    						retries++;
    					if (!maxretries)
    						maxretries = 3;
    
    					if ((maxretries > 0) && (retries >= maxretries)) {
    						ast_log(LOG_DEBUG, "Max retries %d exceeded\n", maxretries);
    
    						if (option_exists(menu, "g") > -1) 
    							strcpy(exten, "g");
    						else if (option_exists(menu, "s") > -1)
    							strcpy(exten, "s");
    					}
    					pos=0;
    
    				} else if (res && strchr(AST_DIGIT_ANY, res)) {
    					ast_log(LOG_DEBUG, "Got start of extension, %c\n", res);
    					exten[1] = '\0';
    					exten[0] = res;
    					if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
    						break;
    
    					if (option_exists(menu, exten) < 0) {
    
    						if (option_exists(menu, "i")) {
    
    							ast_log(LOG_DEBUG, "Invalid extension entered, going to 'i'!\n");
    
    							strcpy(exten, "i");
    							pos = 0;
    							continue;
    						} else {
    							ast_log(LOG_DEBUG, "Aborting on invalid entry, with no 'i' option!\n");
    							res = -2;
    							break;
    						}
    					} else {
    
    						ast_log(LOG_DEBUG, "New existing extension: %s\n", exten);
    
    						pos = 0;
    						continue;
    					}
    				}
    			}
    			pos++;
    		}
    		ast_log(LOG_DEBUG, "Stopping option '%s', res is %d\n", exten, res);
    		pos = 0;
    		if (!strcasecmp(exten, "s"))
    			strcpy(exten, "g");
    		else
    			break;
    	}
    	return res;
    }
    
    int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
    {
    	int res;
    	res = ast_ivr_menu_run_internal(chan, menu, cbdata);
    	/* Hide internal coding */
    	if (res > 0)
    		res = 0;
    	return res;
    }
    
    	
    char *ast_read_textfile(const char *filename)
    {
    	int fd;
    	char *output=NULL;
    	struct stat filesize;
    	int count=0;
    	int res;
    	if(stat(filename,&filesize)== -1){
    		ast_log(LOG_WARNING,"Error can't stat %s\n", filename);
    		return NULL;
    	}
    	count=filesize.st_size + 1;
    	fd = open(filename, O_RDONLY);
    	if (fd < 0) {
    		ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
    		return NULL;
    
    	if ((output = ast_malloc(count))) {
    
    		res = read(fd, output, count - 1);
    		if (res == count - 1) {
    			output[res] = '\0';
    		} else {
    			ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count -  1, strerror(errno));
    			free(output);
    			output = NULL;
    		}
    
    int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
    
    	ast_clear_flag(flags, AST_FLAGS_ALL);
    
    		curarg = *s++ & 0x7f;	/* the array (in app.h) has 128 entries */
    
    		ast_set_flag(flags, options[curarg].flag);
    
    		if (*s == '(') {
    			/* Has argument */
    
    			if (*s) {
    				if (argloc)
    					args[argloc - 1] = arg;
    
    				ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);