Newer
Older
brokentime.tm_year+1900,
brokentime.tm_mon+1,
brokentime.tm_mday,
brokentime.tm_hour,
brokentime.tm_min,
brokentime.tm_sec
);
*ret = workspace;
} else if (c && !strcmp(var, "UNIQUEID")) {
snprintf(workspace, workspacelen, "%s", c->uniqueid);
*ret = workspace;
} else if (c && !strcmp(var, "HANGUPCAUSE")) {
snprintf(workspace, workspacelen, "%i", c->hangupcause);
*ret = workspace;
} else if (c && !strcmp(var, "ACCOUNTCODE")) {
strncpy(workspace, c->accountcode, workspacelen - 1);
*ret = workspace;
} else if (c && !strcmp(var, "LANGUAGE")) {
strncpy(workspace, c->language, workspacelen - 1);
*ret = workspace;
icky:
AST_LIST_TRAVERSE(headp,variables,entries) {
ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
if (strcasecmp(ast_var_name(variables),var)==0) {
*ret=ast_var_value(variables);
if (*ret) {
strncpy(workspace, *ret, workspacelen - 1);
*ret = workspace;
}
/* Try globals */
AST_LIST_TRAVERSE(&globals,variables,entries) {
#if 0
ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
if (strcasecmp(ast_var_name(variables),var)==0) {
*ret=ast_var_value(variables);
if (*ret) {
strncpy(workspace, *ret, workspacelen - 1);
*ret = workspace;
}
}
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
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;
}
if (option_verbose)
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;
if (option_verbose)
ast_verbose(VERBOSE_PREFIX_1 "Registered custom function %s\n", acf->name);
return 0;
}
return -1;
}
char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
{
char *args = NULL, *function, *p;
char *ret = "0";
struct ast_custom_function_obj *acfptr;
function = ast_strdupa(in);
if (function) {
if ((args = strchr(function, '('))) {
*args = '\0';
args++;
if ((p = strrchr(args, ')'))) {
*p = '\0';
} else {
ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
}
} else {
ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
}
if ((acfptr = ast_custom_function_find_obj(function))) {
/* run the custom function */
if (acfptr->read) {
return acfptr->read(chan, function, args, workspace, len);
} else {
ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
}
} else {
ast_log(LOG_ERROR, "Function %s not registered\n", function);
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
} else {
ast_log(LOG_ERROR, "Out of memory\n");
}
return ret;
}
static void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
{
char *args = NULL, *function, *p;
struct ast_custom_function_obj *acfptr;
function = ast_strdupa(in);
if (function) {
if ((args = strchr(function, '('))) {
*args = '\0';
args++;
if ((p = strrchr(args, ')'))) {
*p = '\0';
} else {
ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
}
} else {
ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
}
if ((acfptr = ast_custom_function_find_obj(function))) {
/* run the custom function */
if (acfptr->write) {
acfptr->write(chan, function, args, value);
} else {
ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
}
} else {
ast_log(LOG_ERROR, "Function %s not registered\n", function);
}
} else {
ast_log(LOG_ERROR, "Out of memory\n");
}
}
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 data && *data ? 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 data && *data ? ret_true : ret_false;
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
static char *builtin_function_if(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
char *ret = NULL;
char *mydata = NULL;
char *expr = NULL;
char *iftrue = NULL;
char *iffalse = NULL;
if((mydata = ast_strdupa(data))) {
expr = mydata;
if ((iftrue = strchr(mydata, '?'))) {
*iftrue = '\0';
iftrue++;
if ((iffalse = strchr(iftrue, ':'))) {
*iffalse = '\0';
iffalse++;
}
} else
iffalse = "";
if (expr && iftrue) {
ret = ast_true(expr) ? iftrue : iffalse;
strncpy(buf, ret, len);
ret = buf;
} else {
ast_log(LOG_WARNING, "Syntax $(if <expr>?[<truecond>][:<falsecond>])\n");
ret = NULL;
}
} else {
ast_log(LOG_WARNING, "Memory Error!\n");
ret = NULL;
}
return ret;
}
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
static char *builtin_function_env_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
char *ret = "";
if (data) {
ret = getenv(data);
if (!ret)
ret = "";
}
strncpy(buf, ret, len);
buf[len - 1] = '\0';
return buf;
}
static void builtin_function_env_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
{
if (data && !ast_strlen_zero(data)) {
if (value && !ast_strlen_zero(value)) {
setenv(data, value, 1);
} else {
unsetenv(data);
}
}
}
static char *builtin_function_len(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
int length = 0;
if (data) {
length = strlen(data);
}
snprintf(buf, len, "%d", length);
return buf;
}
static char *builtin_function_cdr_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
char *ret;
if (chan && chan->cdr && data) {
ast_cdr_getvar(chan->cdr, data, &ret, buf, len, 1);
}
return ret;
}
static void builtin_function_cdr_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
{
if (chan && chan->cdr && data) {
ast_cdr_setvar(chan->cdr, data, value, 1);
}
}
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, *earg, *tmp, errstr[256] = "";
int errcode;
regex_t regexbuf;
ret = ret_false; /* convince me otherwise */
tmp = ast_strdupa(data);
if (tmp) {
/* Regex in quotes */
arg = strchr(tmp, '"');
if (arg) {
arg++;
earg = strrchr(arg, '"');
if (earg) {
*earg = '\0';
}
} else {
if ((errcode = regcomp(®exbuf, arg, REG_EXTENDED | REG_NOSUB))) {
regerror(errcode, ®exbuf, errstr, sizeof(errstr));
ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, data, errstr);
ret = NULL;
} else {
ret = regexec(®exbuf, data, 0, NULL, 0) ? ret_false : ret_true;
}
regfree(®exbuf);
} else {
ast_log(LOG_ERROR, "Out of memory in %s(%s)\n", cmd, data);
}
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;
const char *tmp, *whereweare;
int length;
char workspace[4096];
char ltmp[4096], var[4096];
char *nextvar, *nextexp, *nextthing;
int pos, brackets, needsub, len;
/* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
zero-filled */
whereweare=tmp=cp1;
while(!ast_strlen_zero(whereweare) && count) {
/* Assume we're copying the whole remaining string */
pos = strlen(whereweare);
nextvar = NULL;
nextexp = NULL;
nextthing = strchr(whereweare, '$');
if (nextthing) {
switch(nextthing[1]) {
case '{':
nextvar = nextthing;
break;
case '[':
nextexp = nextthing;
break;
}
/* If there is one, we only go that far */
if (nextvar)
pos = nextvar - whereweare;
else if (nextexp)
pos = nextexp - whereweare;
/* Can't copy more than 'count' bytes */
if (pos > count)
pos = count;
/* Copy that many bytes */
memcpy(cp2, whereweare, pos);
count -= pos;
cp2 += pos;
whereweare += pos;
/* We have a variable. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextvar + 2;
/* Find the end of it */
while(brackets && *vare) {
if ((vare[0] == '$') && (vare[1] == '{')) {
needsub++;
brackets++;
} else if (vare[0] == '}') {
brackets--;
} else if ((vare[0] == '$') && (vare[1] == '['))
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;
workspace[0] = '\0';
if (var[len - 1] == ')') {
/* Evaluate function */
cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4);
} else {
/* Retrieve variable value */
pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
}
if (cp4) {
length = strlen(cp4);
if (length > count)
length = count;
memcpy(cp2, cp4, length);
count -= length;
cp2 += length;
} else if (nextexp) {
/* We have an expression. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextexp + 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] == '{')) {
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 */
memset(ltmp, 0, sizeof(ltmp));
pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
vars = ltmp;
} else {
vars = var;
}
/* Evaluate expression */
cp4 = ast_expr(vars);
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);
}
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
{
pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
}
void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
{
pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
}
static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
{
memset(passdata, 0, datalen);
/* No variables or expressions in e->data, so why scan it? */
if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
strncpy(passdata, e->data, datalen - 1);
passdata[datalen-1] = '\0';
return;
}
pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
const char *foundcontext=NULL;
int status = 0;
char *incstack[AST_PBX_MAX_STACK];
char passdata[EXT_DATA_SIZE];
char tmp3[EXT_DATA_SIZE];
char atmp[80];
char atmp2[EXT_DATA_SIZE+100];
if (ast_mutex_lock(&conlock)) {
if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
if (e) {
switch(action) {
case HELPER_CANMATCH:
ast_mutex_unlock(&conlock);
ast_mutex_unlock(&conlock);
case HELPER_FINDLABEL:
res = e->priority;
ast_mutex_unlock(&conlock);
return res;
ast_mutex_unlock(&conlock);
case HELPER_SPAWN:
newstack++;
/* Fall through */
case HELPER_EXEC:
app = pbx_findapp(e->app);
ast_mutex_unlock(&conlock);
strncpy(c->context, context, sizeof(c->context)-1);
if (c->exten != exten)
strncpy(c->exten, exten, sizeof(c->exten)-1);
pbx_substitute_variables(passdata, sizeof(passdata), c, e);
if (option_debug) {
ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
pbx_builtin_setvar_helper(c, atmp, atmp2);
}
ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
manager_event(EVENT_FLAG_CALL, "Newexten",
"Channel: %s\r\n"
"Context: %s\r\n"
"Extension: %s\r\n"
"Priority: %d\r\n"
"Application: %s\r\n"
"AppData: %s\r\n"
"Uniqueid: %s\r\n",
c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
res = pbx_exec(c, app, passdata, newstack);
return res;
} else {
ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
return -1;
}
default:
ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
} else if (sw) {
switch(action) {
case HELPER_CANMATCH:
ast_mutex_unlock(&conlock);
ast_mutex_unlock(&conlock);
ast_mutex_unlock(&conlock);
case HELPER_FINDLABEL:
ast_mutex_unlock(&conlock);
return -1;
case HELPER_SPAWN:
newstack++;
/* Fall through */
case HELPER_EXEC:
ast_mutex_unlock(&conlock);
res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
else {
ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
res = -1;
}
return res;
default:
ast_log(LOG_WARNING, "Huh (%d)?\n", action);
return -1;
}
ast_mutex_unlock(&conlock);
if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
break;
case STATUS_NO_EXTENSION:
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
break;
case STATUS_NO_PRIORITY:
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
break;
case STATUS_NO_LABEL:
if (context)
ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
default:
ast_log(LOG_DEBUG, "Shouldn't happen!\n");
}
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
/*--- ast_hint_extension: Find hint for given extension in context */
static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
{
struct ast_exten *e;
struct ast_switch *sw;
char *data;
const char *foundcontext = NULL;
int status = 0;
char *incstack[AST_PBX_MAX_STACK];
int stacklen = 0;
if (ast_mutex_lock(&conlock)) {
ast_log(LOG_WARNING, "Unable to obtain lock\n");
return NULL;
}
e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
ast_mutex_unlock(&conlock);
return e;
}
/*--- ast_extensions_state2: Check state of extension by using hints */
static int ast_extension_state2(struct ast_exten *e)
{
char hint[AST_MAX_EXTENSION] = "";
char *cur, *rest;
int res = -1;
int allunavailable = 1, allbusy = 1, allfree = 1;
int busy = 0;
strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
cur = hint; /* On or more devices separated with a & character */
do {
rest = strchr(cur, '&');
if (rest) {
*rest = 0;
rest++;
}
res = ast_device_state(cur);
switch (res) {
case AST_DEVICE_NOT_INUSE:
allunavailable = 0;
allbusy = 0;
break;
case AST_DEVICE_INUSE:
case AST_DEVICE_BUSY:
allunavailable = 0;
allfree = 0;
busy = 1;
break;
case AST_DEVICE_UNAVAILABLE:
case AST_DEVICE_INVALID:
allbusy = 0;
allfree = 0;
break;
allunavailable = 0;
allbusy = 0;
allfree = 0;
}
/*--- ast_extension_state: Check extension state for an extension by using hint */
int ast_extension_state(struct ast_channel *c, char *context, char *exten)
{
e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
return ast_extension_state2(e); /* Check all devices in the hint */
/*--- ast_device_state_changed: If device state in cblist is changed - then notify callback function */
int ast_device_state_changed(const char *fmt, ...)
struct ast_hint *list;
struct ast_state_cb *cblist;
char hint[AST_MAX_EXTENSION] = "";
char device[AST_MAX_EXTENSION];
char *cur, *rest;
int state;
va_start(ap, fmt);
vsnprintf(device, sizeof(device), fmt, ap);
va_end(ap);
rest = strchr(device, '-');
if (rest) {
if (option_debug > 2)
ast_log(LOG_DEBUG, "Changing state for %s\n", device);
ast_mutex_lock(&hintlock);
devcb = devcbs;
while(devcb) {
if (devcb->callback)
devcb->callback(device, state, devcb->data);
devcb = devcb->next;
}
/* Then check callbacks in hints */
list = hints;
while (list) {
strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
cur = hint;
do {
rest = strchr(cur, '&');
if (rest) {
*rest = 0;
rest++;
}
if (!strcmp(cur, device)) { /* Is this device referred to in this hint? */
/* Get device state for this hint */
state = ast_extension_state2(list->exten);
if ((state != -1) && (state != list->laststate)) {
/* Device state changed since last check - notify the watcher */
cblist = statecbs;
while (cblist) {
cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
cblist = cblist->next;
}
cblist = list->callbacks;
while (cblist) {
cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
cblist = cblist->next;
}
list->laststate = state;
}
break;
}
cur = rest;
} while (cur);
list = list->next;
}
ast_mutex_unlock(&hintlock);
return 1;
/*--- ast_devstate_add: Add device state watcher */
int ast_devstate_add(ast_devstate_cb_type callback, void *data)
{
struct ast_devstate_cb *devcb;
devcb = malloc(sizeof(struct ast_devstate_cb));
if (devcb) {
memset(devcb, 0, sizeof(struct ast_devstate_cb));
ast_mutex_lock(&hintlock);
devcb->data = data;
devcb->callback = callback;
devcb->next = devcbs;
devcbs = devcb;
ast_mutex_unlock(&hintlock);
}
return 0;
}
/*--- ast_devstate_del: Remove device state watcher */
void ast_devstate_del(ast_devstate_cb_type callback, void *data)
{
struct ast_devstate_cb *devcb, *prev = NULL, *next;
ast_mutex_lock(&hintlock);
devcb = devcbs;
while(devcb) {
next = devcb->next;
if ((devcb->data == data) && (devcb->callback == callback)) {
if (prev)
prev->next = next;
else
devcbs = next;
free(devcb);
} else
prev = devcb;
devcb = next;
}
ast_mutex_unlock(&hintlock);
}
/*--- ast_extension_state_add: Add watcher for extension states */
int ast_extension_state_add(const char *context, const char *exten,
ast_state_cb_type callback, void *data)
struct ast_hint *list;
struct ast_state_cb *cblist;
struct ast_exten *e;
/* If there's no context and extension: add callback to statecbs list */
if (!context && !exten) {
ast_mutex_lock(&hintlock);
cblist = statecbs;
while (cblist) {
if (cblist->callback == callback) {
cblist->data = data;
ast_mutex_unlock(&hintlock);
}
cblist = cblist->next;
}
/* Now inserts the callback */
cblist = malloc(sizeof(struct ast_state_cb));
if (!cblist) {
ast_mutex_unlock(&hintlock);
return -1;
}
memset(cblist, 0, sizeof(struct ast_state_cb));
cblist->id = 0;
cblist->callback = callback;
cblist->data = data;
cblist->next = statecbs;
ast_mutex_unlock(&hintlock);
if (!context || !exten)
return -1;
/* This callback type is for only one hint, so get the hint */
e = ast_hint_extension(NULL, context, exten);
if (!e) {
return -1;
/* Find the hint in the list of hints */
ast_mutex_lock(&hintlock);
list = hints;
while (list) {
if (list->exten == e)
break;
list = list->next;
}
if (!list) {
ast_mutex_unlock(&hintlock);
return -1;
}
/* Now insert the callback in the callback list */
cblist = malloc(sizeof(struct ast_state_cb));
if (!cblist) {
ast_mutex_unlock(&hintlock);
return -1;
}
memset(cblist, 0, sizeof(struct ast_state_cb));
cblist->id = stateid++; /* Unique ID for this callback */
cblist->callback = callback; /* Pointer to callback routine */
cblist->data = data; /* Data for the callback */
cblist->next = list->callbacks;
list->callbacks = cblist;
ast_mutex_unlock(&hintlock);
/*--- ast_extension_state_del: Remove a watcher from the callback list */
int ast_extension_state_del(int id, ast_state_cb_type callback)
{
struct ast_hint *list;
struct ast_state_cb *cblist, *cbprev;
if (!id && !callback)
return -1;
/* id is zero is a callback without extension */
if (!id) {
cbprev = NULL;
cblist = statecbs;
while (cblist) {
if (cblist->callback == callback) {
if (!cbprev)
statecbs = cblist->next;
else
cbprev->next = cblist->next;
free(cblist);
ast_mutex_unlock(&hintlock);
return 0;
}
cbprev = cblist;
cblist = cblist->next;
}
ast_mutex_lock(&hintlock);