Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (revision 137138) +++ channels/chan_iax2.c (working copy) @@ -1427,8 +1427,8 @@ ast_clear_flag(pvt, IAX_MAXAUTHREQ); } /* No more pings or lagrq's */ - AST_SCHED_DEL(sched, pvt->pingid); - AST_SCHED_DEL(sched, pvt->lagid); + AST_SCHED_DEL_SPINLOCK(sched, pvt->pingid, &iaxsl[PTR_TO_CALLNO(pvt)]); + AST_SCHED_DEL_SPINLOCK(sched, pvt->lagid, &iaxsl[PTR_TO_CALLNO(pvt)]); AST_SCHED_DEL(sched, pvt->autoid); AST_SCHED_DEL(sched, pvt->authid); AST_SCHED_DEL(sched, pvt->initid); Index: apps/app_followme.c =================================================================== --- apps/app_followme.c (revision 137138) +++ apps/app_followme.c (working copy) @@ -89,6 +89,7 @@ char moh[AST_MAX_CONTEXT]; /*!< Music On Hold Class to be used */ char context[AST_MAX_CONTEXT]; /*!< Context to dial from */ unsigned int active; /*!< Profile is active (1), or disabled (0). */ + int realtime; /*!< Cached from realtime */ char takecall[20]; /*!< Digit mapping to take a call */ char nextindp[20]; /*!< Digit mapping to decline a call */ char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */ @@ -233,17 +234,17 @@ ast_copy_string(f->takecall, val, sizeof(f->takecall)); else if (!strcasecmp(param, "declinecall")) ast_copy_string(f->nextindp, val, sizeof(f->nextindp)); - else if (!strcasecmp(param, "call-from-prompt")) + else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt")) ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt)); - else if (!strcasecmp(param, "followme-norecording-prompt")) + else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt")) ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt)); - else if (!strcasecmp(param, "followme-options-prompt")) + else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt")) ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt)); - else if (!strcasecmp(param, "followme-pls-hold-prompt")) + else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "hold_prompt")) ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt)); - else if (!strcasecmp(param, "followme-status-prompt")) + else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt")) ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt)); - else if (!strcasecmp(param, "followme-sorry-prompt")) + else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt")) ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt)); else if (failunknown) { if (linenum >= 0) @@ -873,6 +874,67 @@ return; } +static struct call_followme *find_realtime(const char *name) +{ + struct ast_variable *var = ast_load_realtime("followme", "name", name, NULL), *v; + struct ast_config *cfg; + const char *catg; + struct call_followme *new; + struct ast_str *str = ast_str_create(16); + + if (!var) { + return NULL; + } + + if (!(new = alloc_profile(name))) { + return NULL; + } + + for (v = var; v; v = v->next) { + if (!strcasecmp(v->name, "active")) { + if (ast_false(v->value)) { + ast_mutex_destroy(&new->lock); + ast_free(new); + return NULL; + } + } else { + profile_set_param(new, v->name, v->value, 0, 0); + } + } + + ast_variables_destroy(var); + new->realtime = 1; + + /* Load numbers */ + if (!(cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name", name, NULL))) { + ast_mutex_destroy(&new->lock); + ast_free(new); + return NULL; + } + + for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) { + const char *numstr, *timeoutstr, *ordstr; + int timeout; + struct number *cur; + if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) { + continue; + } + if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout")) || sscanf(timeoutstr, "%d", &timeout) != 1 || timeout < 1) { + timeout = 25; + } + /* This one has to exist; it was part of the query */ + ordstr = ast_variable_retrieve(cfg, catg, "ordinal"); + ast_str_make_space(&str, strlen(numstr) + 1); + ast_copy_string(str->str, numstr, str->len); + if ((cur = create_followme_number(str->str, timeout, atoi(ordstr)))) { + AST_LIST_INSERT_TAIL(&new->numbers, cur, entry); + } + } + ast_config_destroy(cfg); + + return new; +} + static int app_exec(struct ast_channel *chan, void *data) { struct fm_args targs; @@ -918,6 +980,10 @@ ast_debug(1, "New profile %s.\n", args.followmeid); if (!f) { + f = find_realtime(args.followmeid); + } + + if (!f) { ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid); return 0; } @@ -1016,6 +1082,12 @@ outrun: + if (f->realtime) { + /* Not in list */ + free_numbers(f); + ast_free(f); + } + return res; } Index: doc/followme.txt =================================================================== --- doc/followme.txt (revision 0) +++ doc/followme.txt (revision 0) @@ -0,0 +1,32 @@ +Followme is now realtime-enabled: + +To use, you must define two backend data structures, with the following fields: + +followme: + name Name of this followme entry. Specified when invoking the FollowMe + application in the dialplan. This field is the only one which is + mandatory. All of the other fields will inherit the default from + followme.conf, if not specified in this data resource. + musicclass OR The musiconhold class used for the caller while waiting to be + musiconhold OR connected. + music + context Dialplan context from which to dial numbers + takecall DTMF used to accept the call and be connected. For obvious reasons, + this needs to be a single digit, '*', or '#'. + declinecall DTMF used to refuse the call, sending it onto the next step, if any. + call_from_prompt Prompt to play to the callee, announcing the call. + norecording_prompt The alternate prompt to play to the callee, when the caller + refuses to leave a name (or the option isn't set to allow them). + options_prompt Normally, "press 1 to accept, 2 to decline". + hold_prompt Message played to the caller while dialing the followme steps. + status_prompt Normally, "Party is not at their desk". + sorry_prompt Normally, "Unable to locate party". + +followme_numbers: + name Name of this followme entry. Must match the name above. + ordinal An integer, specifying the order in which these numbers will be + followed. + phonenumber The telephone number(s) you would like to call, separated by '&'. + timeout Timeout associated with this step. See the followme documentation + for more information on how this value is handled. + Index: include/asterisk/sched.h =================================================================== --- include/asterisk/sched.h (revision 137138) +++ include/asterisk/sched.h (working copy) @@ -59,6 +59,22 @@ id = -1; \ } while (0); +#define AST_SCHED_DEL_SPINLOCK(sched, id, lock) \ + ({ \ + int _count = 0; \ + int _sched_res = -1; \ + while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) { \ + ast_mutex_unlock(lock); \ + usleep(1); \ + ast_mutex_lock(lock); \ + } \ + if (_count == 10 && option_debug > 2) { \ + ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \ + } \ + id = -1; \ + (_sched_res); \ + }) + #define AST_SCHED_DEL_UNREF(sched, id, refcall) \ do { \ int _count = 0; \