Index: pbx.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx.c,v retrieving revision 1.208 diff -u -r1.208 pbx.c --- pbx.c 26 Feb 2005 03:57:10 -0000 1.208 +++ pbx.c 4 Mar 2005 01:09:32 -0000 @@ -11,6 +11,8 @@ * the GNU General Public License */ +#include +#include #include #include #include @@ -196,6 +198,8 @@ static int autofallthrough = 0; +static struct ast_custom_function_obj *acf_root = NULL; + static struct pbx_builtin { char name[AST_MAX_APP]; int (*execute)(struct ast_channel *chan, void *data); @@ -1085,6 +1089,133 @@ } } +static int handle_show_functions(int fd, int argc, char *argv[]) +{ + struct ast_custom_function_obj *acfptr; + + ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n"); + for (acfptr = acf_root ; acfptr ; acfptr = acfptr->next) { + ast_cli(fd, "%s\t(%s)\t[%s]\n", acfptr->name, acfptr->desc, acfptr->syntax); + } + ast_cli(fd, "\n"); + return 0; +} + +struct ast_custom_function_obj* ast_custom_function_find_obj(char *name) +{ + struct ast_custom_function_obj *acfptr; + + for (acfptr = acf_root ; acfptr ; acfptr = acfptr->next) { + if (!strcmp(name, acfptr->name)) { + break; + } + } + + return acfptr; +} + +int ast_custom_function_unregister(struct ast_custom_function_obj *acf) +{ + struct ast_custom_function_obj *acfptr, *lastacf = NULL; + + if (acf) { + for (acfptr = acf_root ; acfptr ; acfptr = acfptr->next) { + if (acfptr == acf) { + if (lastacf) { + lastacf->next = acf->next; + } else { + acf_root = acf->next; + } + ast_verbose(VERBOSE_PREFIX_1 "Unregistered custom function %s\n", acf->name); + return 0; + } + lastacf = acfptr; + } + } + return -1; +} + +int ast_custom_function_register(struct ast_custom_function_obj *acf) +{ + struct ast_custom_function_obj *acfptr; + + if (acf) { + if((acfptr = ast_custom_function_find_obj(acf->name))) { + ast_log(LOG_ERROR, "Function %s already in use.\n", acf->name); + return -1; + } + acf->next = acf_root; + acf_root = acf; + ast_verbose(VERBOSE_PREFIX_1 "Registered custom function %s\n", acf->name); + return 0; + } + + return -1; +} + +static char *ast_func(struct ast_channel *chan, char *in, char *workspace, size_t len) { + char *out = NULL; + static char *ret = "0"; + struct ast_custom_function_obj *acfptr; + + if ((out = strchr(in, ' '))) { + *out = '\0'; + out++; + + if((acfptr = ast_custom_function_find_obj(in))) { + /* run the custom function */ + return acfptr->function(chan, in, out, workspace, len); + } + } + return strdup(ret); +} + +static char *builtin_function_isnull(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + char *ret_true = "1", *ret_false = "0"; + return cmd ? ret_false : ret_true; +} + +static char *builtin_function_exists(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + char *ret_true = "1", *ret_false = "0"; + return cmd ? ret_true : ret_false; +} + +static char *builtin_function_regex(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + char *ret_true = "1", *ret_false = "0", *ret; + char *arg, *tmp; + regex_t regexbuf; + + ret = ret_false; /* convince me otherwise */ + if ((tmp = ast_strdupa(data)) && (arg = strchr(tmp, '"')) && (data = strchr(arg+1, '"'))) { + arg++; + *data = '\0'; + data++; + + if(data[0] == ' ') { + data++; + } else { + ast_log(LOG_WARNING, "Malformed input missing space in %s\n", cmd); + ret = ret_false; + } + + if (regcomp(®exbuf, arg, REG_EXTENDED | REG_NOSUB)) { + ast_log(LOG_WARNING, "Malformed regex input %s\n", cmd); + ret = NULL; + } + ret = regexec(®exbuf, data, 0, NULL, 0) ? ret_false : ret_true; + regfree(®exbuf); + + + } else { + ast_log(LOG_WARNING, "Malformed input %s\n", cmd); + } + + return ret; +} + static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp) { char *cp4; @@ -1092,9 +1223,9 @@ int length; char workspace[4096]; char ltmp[4096], var[4096]; - char *nextvar, *nextexp; + char *nextvar, *nextexp, *nextfunc; char *vars, *vare; - int pos, brackets, needsub, len; + int pos, brackets, needsub, len, needfunc; /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be zero-filled */ @@ -1108,13 +1239,27 @@ /* Look for an expression */ nextexp = strstr(whereweare, "$["); + + /* Look for a function */ + nextfunc = strstr(whereweare, "$("); /* Pick the first one only */ - if (nextvar && nextexp) { - if (nextvar < nextexp) - nextexp = NULL; - else - nextvar = NULL; + len = 0; + if (nextvar) + len++; + if(nextexp) + len++; + if(nextfunc) + len++; + + if (len > 1) { + if(nextfunc) { + nextvar = nextexp = NULL; + } else if (nextvar) { + nextexp = nextfunc = NULL; + } else if (nextexp) { + nextvar = nextfunc = NULL; + } } /* If there is one, we only go that far */ @@ -1122,7 +1267,9 @@ pos = nextvar - whereweare; else if (nextexp) pos = nextexp - whereweare; - + else if (nextfunc) { + pos = nextfunc - whereweare; + } /* Can't copy more than 'count' bytes */ if (pos > count) pos = count; @@ -1193,7 +1340,8 @@ vars = vare = nextexp + 2; brackets = 1; needsub = 0; - + needfunc = 0; + /* Find the end of it */ while(brackets && *vare) { if ((vare[0] == '$') && (vare[1] == '[')) { @@ -1207,6 +1355,9 @@ } else if ((vare[0] == '$') && (vare[1] == '{')) { needsub++; vare++; + } else if ((vare[0] == '$') && (vare[1] == '(')) { + needfunc++; + vare++; } vare++; } @@ -1223,7 +1374,7 @@ var[len] = '\0'; /* Substitute if necessary */ - if (needsub) { + if (needsub || needfunc) { memset(ltmp, 0, sizeof(ltmp)); pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1); vars = ltmp; @@ -1245,6 +1396,63 @@ cp2 += length; free(cp4); } + } else if (nextfunc) { + /* We have a function. Find the start and end */ + vars = vare = nextfunc + 2; + brackets = 1; + needsub = 0; + + /* Find the end of it */ + while(brackets && *vare) { + if ((vare[0] == '$') && (vare[1] == '(')) { + needsub++; + brackets++; + vare++; + } else if (vare[0] == '(') { + brackets++; + } else if (vare[0] == ')') { + brackets--; + } else if ((vare[0] == '$') && (vare[1] == '{')) { + needsub++; + vare++; + } + vare++; + } + if (brackets) + ast_log(LOG_NOTICE, "Error in extension logic (missing ')')\n"); + len = vare - vars - 1; + + /* Skip totally over variable name */ + whereweare += ( len + 3); + + /* Store variable name (and truncate) */ + memset(var, 0, sizeof(var)); + strncpy(var, vars, sizeof(var) - 1); + var[len] = '\0'; + + /* Substitute if necessary */ + if (needsub) { + memset(ltmp, 0, sizeof(ltmp)); + pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1); + vars = ltmp; + } else { + vars = var; + } + + /* Evaluate expression */ + cp4 = ast_func(c, vars, workspace, sizeof(workspace)); + + ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4); + + if (cp4) { + length = strlen(cp4); + if (length > count) + length = count; + memcpy(cp2, cp4, length); + count -= length; + cp2 += length; + free(cp4); + } } else break; @@ -1266,7 +1474,7 @@ memset(passdata, 0, datalen); /* No variables or expressions in e->data, so why scan it? */ - if (!strstr(e->data,"${") && !strstr(e->data,"$[")) { + if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) { strncpy(passdata, e->data, datalen - 1); passdata[datalen-1] = '\0'; return; @@ -2593,6 +2801,10 @@ "Usage: show application [ [ [...]]]\n" " Describes a particular application.\n"; +static char show_functions_help[] = +" Usage: show functions\n" +""; + static char show_applications_help[] = "Usage: show applications [{like|describing} ]\n" " List applications which are currently available.\n" @@ -3169,6 +3381,30 @@ return RESULT_SUCCESS; } + +/* custom commands */ + +static struct ast_custom_function_obj regex_function = { + .name = "regex", + .desc = "Regular Expression", + .syntax = "$(regex \"\" )", + .function = builtin_function_regex, +}; + +static struct ast_custom_function_obj isnull_function = { + .name = "isnull", + .desc = "NULL Test", + .syntax = "$(isnull