diff -urN asterisk-SVN_branch_1.4_r138685/apps/app_followme.c asterisk-SVN_branch_1.4_r138685.followme_realtime/apps/app_followme.c --- asterisk-SVN_branch_1.4_r138685/apps/app_followme.c 2008-08-18 16:59:41.000000000 -0300 +++ asterisk-SVN_branch_1.4_r138685.followme_realtime/apps/app_followme.c 2008-08-19 22:45:49.000000000 -0300 @@ -94,6 +94,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 */ @@ -239,17 +240,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) @@ -916,6 +917,70 @@ } +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; + char *str; + + 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"); + if (!(str = ast_malloc(strlen(numstr)+1))) { + ast_log(LOG_ERROR, "Can't allocate %d bytes to read phonenumber\n", strlen(numstr)+1); + return NULL; + } + ast_copy_string(str, numstr, strlen(numstr)+1); + if ((cur = create_followme_number(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; @@ -962,6 +1027,10 @@ if (option_debug) ast_log(LOG_DEBUG, "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); res = 0; } else { @@ -1068,6 +1137,12 @@ ast_module_user_remove(u); + if (f && f->realtime) { + /* Not in list */ + free_numbers(f); + ast_free(f); + } + return res; } diff -urN asterisk-SVN_branch_1.4_r138685/doc/followme.txt asterisk-SVN_branch_1.4_r138685.followme_realtime/doc/followme.txt --- asterisk-SVN_branch_1.4_r138685/doc/followme.txt 1969-12-31 21:00:00.000000000 -0300 +++ asterisk-SVN_branch_1.4_r138685.followme_realtime/doc/followme.txt 2008-08-19 22:17:21.000000000 -0300 @@ -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. +