Find-Me Follow-Me application. More...
#include "asterisk.h"
#include <signal.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
Go to the source code of this file.
Data Structures | |
struct | call_followme::blnumbers |
struct | call_followme |
Data structure for followme scripts. More... | |
struct | fm_args::cnumbers |
struct | findme_user |
struct | findme_user_listptr |
struct | fm_args |
struct | followmes |
struct | number |
Number structure. More... | |
struct | call_followme::numbers |
struct | call_followme::wlnumbers |
Enumerations | |
enum | { FOLLOWMEFLAG_STATUSMSG = (1 << 0), FOLLOWMEFLAG_RECORDNAME = (1 << 1), FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2) } |
Functions | |
static void | __fini_followmes (void) |
static void | __init_followmes (void) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static struct call_followme * | alloc_profile (const char *fmname) |
Allocate and initialize followme profile. | |
static int | app_exec (struct ast_channel *chan, void *data) |
static void | clear_caller (struct findme_user *tmpuser) |
static void | clear_calling_tree (struct findme_user_listptr *findme_user_list) |
static struct number * | create_followme_number (char *number, int timeout, int numorder) |
Add a new number. | |
static void | end_bridge_callback (void *data) |
static void | end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) |
static struct call_followme * | find_realtime (const char *name) |
static void | findmeexec (struct fm_args *tpargs) |
static void | free_numbers (struct call_followme *f) |
static void | init_profile (struct call_followme *f) |
static int | load_module (void) |
static void | profile_set_param (struct call_followme *f, const char *param, const char *val, int linenum, int failunknown) |
Set parameter in profile from configuration file. | |
static int | reload (void) |
static int | reload_followme (int reload) |
Reload followme application module. | |
static int | unload_module (void) |
static struct ast_channel * | wait_for_winner (struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, char *namerecloc, int *status, struct fm_args *tpargs) |
Variables | |
static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Find-Me/Follow-Me Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
static char * | app = "FollowMe" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char | callfromprompt [PATH_MAX] = "followme/call-from" |
static const char * | defaultmoh = "default" |
static int | featuredigittimeout = 5000 |
static const char * | featuredigittostr |
static struct ast_app_option | followme_opts [128] = { [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG },} |
static struct followmes | followmes |
static char | nextindp [20] = "2" |
static char | norecordingprompt [PATH_MAX] = "followme/no-recording" |
static char | optionsprompt [PATH_MAX] = "followme/options" |
static char | plsholdprompt [PATH_MAX] = "followme/pls-hold-while-try" |
static char | sorryprompt [PATH_MAX] = "followme/sorry" |
static char | statusprompt [PATH_MAX] = "followme/status" |
static char | takecall [20] = "1" |
static int | ynlongest = 0 |
Find-Me Follow-Me application.
Definition in file app_followme.c.
anonymous enum |
Definition at line 159 of file app_followme.c.
{ FOLLOWMEFLAG_STATUSMSG = (1 << 0), FOLLOWMEFLAG_RECORDNAME = (1 << 1), FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2) };
static void __fini_followmes | ( | void | ) | [static] |
Definition at line 186 of file app_followme.c.
{
static void __init_followmes | ( | void | ) | [static] |
Definition at line 186 of file app_followme.c.
{
static void __reg_module | ( | void | ) | [static] |
Definition at line 1203 of file app_followme.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1203 of file app_followme.c.
static struct call_followme* alloc_profile | ( | const char * | fmname | ) | [static, read] |
Allocate and initialize followme profile.
Definition at line 212 of file app_followme.c.
References ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, ast_mutex_init(), call_followme::blnumbers, call_followme::callfromprompt, call_followme::context, f, call_followme::lock, call_followme::moh, call_followme::name, call_followme::nextindp, call_followme::norecordingprompt, call_followme::numbers, call_followme::optionsprompt, call_followme::plsholdprompt, call_followme::sorryprompt, call_followme::statusprompt, call_followme::takecall, and call_followme::wlnumbers.
Referenced by find_realtime(), and reload_followme().
{ struct call_followme *f; if (!(f = ast_calloc(1, sizeof(*f)))) return NULL; ast_mutex_init(&f->lock); ast_copy_string(f->name, fmname, sizeof(f->name)); f->moh[0] = '\0'; f->context[0] = '\0'; ast_copy_string(f->takecall, takecall, sizeof(f->takecall)); ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp)); ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt)); ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt)); ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt)); ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt)); ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt)); ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt)); AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); return f; }
static int app_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 1009 of file app_followme.c.
References ast_channel::_state, call_followme::active, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_make_compatible(), ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_get_threshold_from_settings(), AST_FEATURE_AUTOMON, AST_FEATURE_REDIRECT, ast_fileexists(), ast_free, ast_hangup(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_play_and_record(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), call_followme::callfromprompt, fm_args::callfromprompt, chan, fm_args::chan, fm_args::cnumbers, call_followme::context, fm_args::context, create_followme_number(), end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, f, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_realtime(), findmeexec(), followme_opts, FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, fm_args::followmeflags, free_numbers(), ast_channel::language, call_followme::lock, LOG_ERROR, LOG_WARNING, call_followme::moh, fm_args::mohclass, ast_channel::name, call_followme::name, fm_args::namerecloc, call_followme::nextindp, fm_args::nextindp, call_followme::norecordingprompt, fm_args::norecordingprompt, number::number, call_followme::numbers, call_followme::optionsprompt, fm_args::optionsprompt, number::order, fm_args::outbound, call_followme::plsholdprompt, fm_args::plsholdprompt, call_followme::realtime, S_OR, call_followme::sorryprompt, fm_args::sorryprompt, fm_args::status, call_followme::statusprompt, fm_args::statusprompt, call_followme::takecall, fm_args::takecall, THRESHOLD_SILENCE, number::timeout, and ast_channel::uniqueid.
Referenced by load_module().
{ struct fm_args targs = { 0, }; struct ast_bridge_config config; struct call_followme *f; struct number *nm, *newnm; int res = 0; char *argstr; char namerecloc[255]; int duration = 0; struct ast_channel *caller; struct ast_channel *outbound; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(followmeid); AST_APP_ARG(options); ); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); return -1; } if (!(argstr = ast_strdupa((char *)data))) { ast_log(LOG_ERROR, "Out of memory!\n"); return -1; } AST_STANDARD_APP_ARGS(args, argstr); if (ast_strlen_zero(args.followmeid)) { ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); return -1; } AST_RWLIST_RDLOCK(&followmes); AST_RWLIST_TRAVERSE(&followmes, f, entry) { if (!strcasecmp(f->name, args.followmeid) && (f->active)) break; } AST_RWLIST_UNLOCK(&followmes); 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; } /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */ if (args.options) ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options); /* Lock the profile lock and copy out everything we need to run with before unlocking it again */ ast_mutex_lock(&f->lock); targs.mohclass = ast_strdupa(f->moh); ast_copy_string(targs.context, f->context, sizeof(targs.context)); ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall)); ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp)); ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt)); ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt)); ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt)); ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt)); ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt)); ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt)); /* Copy the numbers we're going to use into another list in case the master list should get modified (and locked) while we're trying to do a follow-me */ AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers); AST_LIST_TRAVERSE(&f->numbers, nm, entry) { newnm = create_followme_number(nm->number, nm->timeout, nm->order); AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry); } ast_mutex_unlock(&f->lock); /* Answer the call */ if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) ast_stream_and_wait(chan, targs.statusprompt, ""); snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid); duration = 5; if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) goto outrun; if (!ast_fileexists(namerecloc, NULL, chan->language)) ast_copy_string(namerecloc, "", sizeof(namerecloc)); if (ast_streamfile(chan, targs.plsholdprompt, chan->language)) goto outrun; if (ast_waitstream(chan, "") < 0) goto outrun; ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL); targs.status = 0; targs.chan = chan; ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc)); findmeexec(&targs); while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) ast_free(nm); if (!ast_strlen_zero(namerecloc)) unlink(namerecloc); if (targs.status != 100) { ast_moh_stop(chan); if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) ast_stream_and_wait(chan, targs.sorryprompt, ""); res = 0; } else { caller = chan; outbound = targs.outbound; /* Bridge the two channels. */ memset(&config, 0, sizeof(config)); ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); config.end_bridge_callback = end_bridge_callback; config.end_bridge_callback_data = chan; config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; ast_moh_stop(caller); /* Be sure no generators are left on it */ ast_deactivate_generator(caller); /* Make sure channels are compatible */ res = ast_channel_make_compatible(caller, outbound); if (res < 0) { ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name); ast_hangup(outbound); goto outrun; } res = ast_bridge_call(caller, outbound, &config); if (outbound) ast_hangup(outbound); } outrun: if (f->realtime) { /* Not in list */ free_numbers(f); ast_free(f); } return res; }
static void clear_caller | ( | struct findme_user * | tmpuser | ) | [static] |
Definition at line 468 of file app_followme.c.
References ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_hangup(), ast_log(), ast_channel::cdr, findme_user::dialarg, ast_channel::hangupcause, LOG_WARNING, findme_user::ochan, and findme_user::state.
Referenced by clear_calling_tree(), and findmeexec().
{ struct ast_channel *outbound; if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) { outbound = tmpuser->ochan; if (!outbound->cdr) { outbound->cdr = ast_cdr_alloc(); if (outbound->cdr) ast_cdr_init(outbound->cdr, outbound); } if (outbound->cdr) { char tmp[256]; snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg); ast_cdr_setapp(outbound->cdr, "FollowMe", tmp); ast_cdr_update(outbound); ast_cdr_start(outbound->cdr); ast_cdr_end(outbound->cdr); /* If the cause wasn't handled properly */ if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) ast_cdr_failed(outbound->cdr); } else ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); ast_hangup(tmpuser->ochan); } }
static void clear_calling_tree | ( | struct findme_user_listptr * | findme_user_list | ) | [static] |
Definition at line 497 of file app_followme.c.
References AST_LIST_TRAVERSE, clear_caller(), and findme_user::cleared.
Referenced by wait_for_winner().
{ struct findme_user *tmpuser; AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { clear_caller(tmpuser); tmpuser->cleared = 1; } }
static struct number* create_followme_number | ( | char * | number, |
int | timeout, | ||
int | numorder | ||
) | [static, read] |
Add a new number.
Definition at line 278 of file app_followme.c.
References ast_calloc, ast_copy_string(), ast_debug, number::number, number::order, and number::timeout.
Referenced by app_exec(), find_realtime(), and reload_followme().
{ struct number *cur; char *tmp; if (!(cur = ast_calloc(1, sizeof(*cur)))) return NULL; cur->timeout = timeout; if ((tmp = strchr(number, ','))) *tmp = '\0'; ast_copy_string(cur->number, number, sizeof(cur->number)); cur->order = numorder; ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout); return cur; }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 983 of file app_followme.c.
References ast_cdr::answer, ast_channel_lock, ast_channel_unlock, buf, ast_channel::cdr, ast_channel::data, pbx_builtin_setvar_helper(), and ast_cdr::start.
Referenced by app_exec().
{ char buf[80]; time_t end; struct ast_channel *chan = data; time(&end); ast_channel_lock(chan); if (chan->cdr->answer.tv_sec) { snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec); pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); } if (chan->cdr->start.tv_sec) { snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec); pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); } ast_channel_unlock(chan); }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, |
struct ast_channel * | originator, | ||
struct ast_channel * | terminator | ||
) | [static] |
Definition at line 1004 of file app_followme.c.
References ast_bridge_config::end_bridge_callback_data.
Referenced by app_exec().
{ bconfig->end_bridge_callback_data = originator; }
static struct call_followme* find_realtime | ( | const char * | name | ) | [static, read] |
Definition at line 923 of file app_followme.c.
References alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_false(), ast_free, AST_LIST_INSERT_TAIL, ast_load_realtime(), ast_load_realtime_multientry(), ast_mutex_destroy(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_variable_retrieve(), ast_variables_destroy(), create_followme_number(), ast_variable::next, profile_set_param(), SENTINEL, str, number::timeout, and var.
Referenced by app_exec().
{ struct ast_variable *var = ast_load_realtime("followme", "name", name, SENTINEL), *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, SENTINEL))) { 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, "%30d", &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_set(&str, 0, "%s", numstr); if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) { AST_LIST_INSERT_TAIL(&new->numbers, cur, entry); } } ast_config_destroy(cfg); return new; }
static void findmeexec | ( | struct fm_args * | tpargs | ) | [static] |
Definition at line 777 of file app_followme.c.
References ast_channel::accountcode, accountcode, ast_best_codec(), ast_call(), ast_calloc, ast_cause2str(), ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_free, ast_hangup(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_request(), ast_set_callerid(), ast_strdupa, ast_string_field_set, ast_verb, ast_channel::cdr, fm_args::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, clear_caller(), findme_user::cleared, fm_args::cnumbers, fm_args::context, findme_user::dialarg, free, ast_channel::hangupcause, ast_channel::language, language, LOG_ERROR, LOG_WARNING, ast_channel::musicclass, musicclass, fm_args::namerecloc, ast_channel::nativeformats, fm_args::nextindp, number::number, findme_user::ochan, number::order, fm_args::outbound, findme_user::state, fm_args::status, status, fm_args::takecall, number::timeout, and wait_for_winner().
Referenced by app_exec().
{ struct number *nm; struct ast_channel *outbound; struct ast_channel *caller; struct ast_channel *winner = NULL; char dialarg[512]; int dg, idx; char *rest, *number; struct findme_user *tmpuser; struct findme_user *fmuser; struct findme_user *headuser; struct findme_user_listptr *findme_user_list; int status; findme_user_list = ast_calloc(1, sizeof(*findme_user_list)); AST_LIST_HEAD_INIT_NOLOCK(findme_user_list); /* We're going to figure out what the longest possible string of digits to collect is */ ynlongest = 0; if (strlen(tpargs->takecall) > ynlongest) ynlongest = strlen(tpargs->takecall); if (strlen(tpargs->nextindp) > ynlongest) ynlongest = strlen(tpargs->nextindp); idx = 1; caller = tpargs->chan; AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) if (nm->order == idx) break; while (nm) { ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout); number = ast_strdupa(nm->number); ast_debug(3, "examining %s\n", number); do { rest = strchr(number, '&'); if (rest) { *rest = 0; rest++; } /* We check if that context exists, before creating the ast_channel struct needed */ if (!ast_exists_extension(caller, tpargs->context, number, 1, caller->cid.cid_num)) { /* XXX Should probably restructure to simply skip this item, instead of returning. XXX */ ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context); free(findme_user_list); return; } if (!strcmp(tpargs->context, "")) snprintf(dialarg, sizeof(dialarg), "%s", number); else snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context); tmpuser = ast_calloc(1, sizeof(*tmpuser)); if (!tmpuser) { ast_free(findme_user_list); return; } outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg); if (outbound) { ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num); ast_channel_inherit_variables(tpargs->chan, outbound); ast_channel_datastore_inherit(tpargs->chan, outbound); ast_string_field_set(outbound, language, tpargs->chan->language); ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode); ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass); ast_verb(3, "calling %s\n", dialarg); if (!ast_call(outbound,dialarg,0)) { tmpuser->ochan = outbound; tmpuser->state = 0; tmpuser->cleared = 0; ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg)); AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry); } else { ast_verb(3, "couldn't reach at this number.\n"); if (outbound) { if (!outbound->cdr) outbound->cdr = ast_cdr_alloc(); if (outbound->cdr) { char tmp[256]; ast_cdr_init(outbound->cdr, outbound); snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg); ast_cdr_setapp(outbound->cdr, "FollowMe", tmp); ast_cdr_update(outbound); ast_cdr_start(outbound->cdr); ast_cdr_end(outbound->cdr); /* If the cause wasn't handled properly */ if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause)) ast_cdr_failed(outbound->cdr); } else { ast_log(LOG_ERROR, "Unable to create Call Detail Record\n"); ast_hangup(outbound); outbound = NULL; } } } } else ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg)); number = rest; } while (number); status = 0; if (!AST_LIST_EMPTY(findme_user_list)) winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs); while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) { if (!fmuser->cleared && fmuser->ochan != winner) clear_caller(fmuser); ast_free(fmuser); } fmuser = NULL; tmpuser = NULL; headuser = NULL; if (winner) break; if (!caller || ast_check_hangup(caller)) { tpargs->status = 1; ast_free(findme_user_list); return; } idx++; AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) { if (nm->order == idx) break; } } ast_free(findme_user_list); if (!winner) tpargs->status = 1; else { tpargs->status = 100; tpargs->outbound = winner; } return; }
static void free_numbers | ( | struct call_followme * | f | ) | [static] |
Definition at line 189 of file app_followme.c.
References ast_free, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, call_followme::blnumbers, call_followme::numbers, and call_followme::wlnumbers.
Referenced by app_exec(), reload_followme(), and unload_module().
{ /* Free numbers attached to the profile */ struct number *prev; while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry))) /* Free the number */ ast_free(prev); AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry))) /* Free the blacklisted number */ ast_free(prev); AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry))) /* Free the whitelisted number */ ast_free(prev); AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); }
static void init_profile | ( | struct call_followme * | f | ) | [static] |
Definition at line 237 of file app_followme.c.
References call_followme::active, ast_copy_string(), and call_followme::moh.
Referenced by reload_followme().
{ f->active = 1; ast_copy_string(f->moh, defaultmoh, sizeof(f->moh)); }
static int load_module | ( | void | ) | [static] |
Definition at line 1184 of file app_followme.c.
References app_exec(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, and reload_followme().
{ if(!reload_followme(0)) return AST_MODULE_LOAD_DECLINE; return ast_register_application_xml(app, app_exec); }
static void profile_set_param | ( | struct call_followme * | f, |
const char * | param, | ||
const char * | val, | ||
int | linenum, | ||
int | failunknown | ||
) | [static] |
Set parameter in profile from configuration file.
Definition at line 246 of file app_followme.c.
References ast_copy_string(), ast_log(), call_followme::callfromprompt, call_followme::context, LOG_WARNING, call_followme::moh, call_followme::name, call_followme::nextindp, call_followme::norecordingprompt, call_followme::optionsprompt, call_followme::plsholdprompt, call_followme::sorryprompt, call_followme::statusprompt, and call_followme::takecall.
Referenced by find_realtime(), and reload_followme().
{ if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music")) ast_copy_string(f->moh, val, sizeof(f->moh)); else if (!strcasecmp(param, "context")) ast_copy_string(f->context, val, sizeof(f->context)); else if (!strcasecmp(param, "takecall")) 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") || !strcasecmp(param, "call_from_prompt")) ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt)); 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") || !strcasecmp(param, "options_prompt")) ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt)); else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt")) ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt)); 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") || !strcasecmp(param, "sorry_prompt")) ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt)); else if (failunknown) { if (linenum >= 0) ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum); else ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param); } }
static int reload | ( | void | ) | [static] |
Definition at line 1192 of file app_followme.c.
References reload_followme().
{ reload_followme(1); return 0; }
static int reload_followme | ( | int | reload | ) | [static] |
Reload followme application module.
Definition at line 297 of file app_followme.c.
References call_followme::active, alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, create_followme_number(), f, free_numbers(), init_profile(), ast_variable::lineno, call_followme::lock, LOG_ERROR, LOG_WARNING, ast_variable::name, call_followme::name, ast_variable::next, call_followme::numbers, profile_set_param(), number::timeout, ast_variable::value, and var.
Referenced by load_module(), and reload().
{ struct call_followme *f; struct ast_config *cfg; char *cat = NULL, *tmp; struct ast_variable *var; struct number *cur, *nm; char numberstr[90]; int timeout; char *timeoutstr; int numorder; const char *takecallstr; const char *declinecallstr; const char *tmpstr; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; if (!(cfg = ast_config_load("followme.conf", config_flags))) { ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n"); return 0; } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { return 0; } else if (cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n"); return 0; } AST_RWLIST_WRLOCK(&followmes); /* Reset Global Var Values */ featuredigittimeout = 5000; /* Mark all profiles as inactive for the moment */ AST_RWLIST_TRAVERSE(&followmes, f, entry) { f->active = 0; } featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout"); if (!ast_strlen_zero(featuredigittostr)) { if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout)) featuredigittimeout = 5000; } if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) { ast_copy_string(takecall, takecallstr, sizeof(takecall)); } if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) { ast_copy_string(nextindp, declinecallstr, sizeof(nextindp)); } if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); } if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); } if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); } if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); } if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); } if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) { ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); } /* Chug through config file */ while ((cat = ast_category_browse(cfg, cat))) { int new = 0; if (!strcasecmp(cat, "general")) continue; /* Look for an existing one */ AST_LIST_TRAVERSE(&followmes, f, entry) { if (!strcasecmp(f->name, cat)) break; } ast_debug(1, "New profile %s.\n", cat); if (!f) { /* Make one then */ f = alloc_profile(cat); new = 1; } /* Totally fail if we fail to find/create an entry */ if (!f) continue; if (!new) ast_mutex_lock(&f->lock); /* Re-initialize the profile */ init_profile(f); free_numbers(f); var = ast_variable_browse(cfg, cat); while (var) { if (!strcasecmp(var->name, "number")) { int idx = 0; /* Add a new number */ ast_copy_string(numberstr, var->value, sizeof(numberstr)); if ((tmp = strchr(numberstr, ','))) { *tmp++ = '\0'; timeoutstr = ast_strdupa(tmp); if ((tmp = strchr(timeoutstr, ','))) { *tmp++ = '\0'; numorder = atoi(tmp); if (numorder < 0) numorder = 0; } else numorder = 0; timeout = atoi(timeoutstr); if (timeout < 0) timeout = 25; } else { timeout = 25; numorder = 0; } if (!numorder) { idx = 1; AST_LIST_TRAVERSE(&f->numbers, nm, entry) idx++; numorder = idx; } cur = create_followme_number(numberstr, timeout, numorder); AST_LIST_INSERT_TAIL(&f->numbers, cur, entry); } else { profile_set_param(f, var->name, var->value, var->lineno, 1); ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno); } var = var->next; } /* End while(var) loop */ if (!new) ast_mutex_unlock(&f->lock); else AST_RWLIST_INSERT_HEAD(&followmes, f, entry); } ast_config_destroy(cfg); AST_RWLIST_UNLOCK(&followmes); return 1; }
static int unload_module | ( | void | ) | [static] |
Definition at line 1166 of file app_followme.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), f, and free_numbers().
{ struct call_followme *f; ast_unregister_application(app); /* Free Memory. Yeah! I'm free! */ AST_RWLIST_WRLOCK(&followmes); while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) { free_numbers(f); ast_free(f); } AST_RWLIST_UNLOCK(&followmes); return 0; }
static struct ast_channel* wait_for_winner | ( | struct findme_user_listptr * | findme_user_list, |
struct number * | nm, | ||
struct ast_channel * | caller, | ||
char * | namerecloc, | ||
int * | status, | ||
struct fm_args * | tpargs | ||
) | [static, read] |
Definition at line 509 of file app_followme.c.
References AST_CAUSE_NORMAL_CLEARING, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_hangup(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_log(), ast_read(), ast_sched_runq(), ast_sched_wait(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitfor_n(), fm_args::callfromprompt, clear_calling_tree(), ast_frame::data, findme_user::digts, f, ast_frame::frametype, ast_channel::hangupcause, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, fm_args::nextindp, fm_args::norecordingprompt, findme_user::ochan, fm_args::optionsprompt, ast_channel::sched, findme_user::state, ast_channel::stream, ast_frame::subclass, fm_args::takecall, number::timeout, ast_channel::timingfunc, ast_frame::uint32, findme_user::yn, and findme_user::ynidx.
Referenced by findmeexec().
{ struct ast_channel *watchers[256]; int pos; struct ast_channel *winner; struct ast_frame *f; int ctstatus = 0; int dg; struct findme_user *tmpuser; int to = 0; int livechannels = 0; int tmpto; long totalwait = 0, wtd = 0, towas = 0; char *callfromname; char *pressbuttonname; /* ------------ wait_for_winner_channel start --------------- */ callfromname = ast_strdupa(tpargs->callfromprompt); pressbuttonname = ast_strdupa(tpargs->optionsprompt); if (AST_LIST_EMPTY(findme_user_list)) { ast_verb(3, "couldn't reach at this number.\n"); return NULL; } if (!caller) { ast_verb(3, "Original caller hungup. Cleanup.\n"); clear_calling_tree(findme_user_list); return NULL; } totalwait = nm->timeout * 1000; while (!ctstatus) { to = 1000; pos = 1; livechannels = 0; watchers[0] = caller; dg = 0; winner = NULL; AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { if (tmpuser->state >= 0 && tmpuser->ochan) { if (tmpuser->state == 3) tmpuser->digts += (towas - wtd); if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) { ast_verb(3, "We've been waiting for digits longer than we should have.\n"); if (!ast_strlen_zero(namerecloc)) { tmpuser->state = 1; tmpuser->digts = 0; if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) { ast_sched_runq(tmpuser->ochan->sched); } else { ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); return NULL; } } else { tmpuser->state = 2; tmpuser->digts = 0; if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language)) ast_sched_runq(tmpuser->ochan->sched); else { ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); return NULL; } } } if (tmpuser->ochan->stream) { ast_sched_runq(tmpuser->ochan->sched); tmpto = ast_sched_wait(tmpuser->ochan->sched); if (tmpto > 0 && tmpto < to) to = tmpto; else if (tmpto < 0 && !tmpuser->ochan->timingfunc) { ast_stopstream(tmpuser->ochan); if (tmpuser->state == 1) { ast_verb(3, "Playback of the call-from file appears to be done.\n"); if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) { tmpuser->state = 2; } else { ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc); memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); tmpuser->ynidx = 0; if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) tmpuser->state = 3; else { ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname); return NULL; } } } else if (tmpuser->state == 2) { ast_verb(3, "Playback of name file appears to be done.\n"); memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); tmpuser->ynidx = 0; if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) { tmpuser->state = 3; } else { return NULL; } } else if (tmpuser->state == 3) { ast_verb(3, "Playback of the next step file appears to be done.\n"); tmpuser->digts = 0; } } } watchers[pos++] = tmpuser->ochan; livechannels++; } } tmpto = to; if (to < 0) { to = 1000; tmpto = 1000; } towas = to; winner = ast_waitfor_n(watchers, pos, &to); tmpto -= to; totalwait -= tmpto; wtd = to; if (totalwait <= 0) { ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait); clear_calling_tree(findme_user_list); return NULL; } if (winner) { /* Need to find out which channel this is */ dg = 0; while ((winner != watchers[dg]) && (dg < 256)) dg++; AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) if (tmpuser->ochan == winner) break; f = ast_read(winner); if (f) { if (f->frametype == AST_FRAME_CONTROL) { switch(f->subclass) { case AST_CONTROL_HANGUP: ast_verb(3, "%s received a hangup frame.\n", winner->name); if (f->data.uint32) { winner->hangupcause = f->data.uint32; } if (dg == 0) { ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n"); clear_calling_tree(findme_user_list); ctstatus = -1; } break; case AST_CONTROL_ANSWER: ast_verb(3, "%s answered %s\n", winner->name, caller->name); /* If call has been answered, then the eventual hangup is likely to be normal hangup */ winner->hangupcause = AST_CAUSE_NORMAL_CLEARING; caller->hangupcause = AST_CAUSE_NORMAL_CLEARING; ast_verb(3, "Starting playback of %s\n", callfromname); if (dg > 0) { if (!ast_strlen_zero(namerecloc)) { if (!ast_streamfile(winner, callfromname, winner->language)) { ast_sched_runq(winner->sched); tmpuser->state = 1; } else { ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); ast_frfree(f); return NULL; } } else { tmpuser->state = 2; if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language)) ast_sched_runq(tmpuser->ochan->sched); else { ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); ast_frfree(f); return NULL; } } } break; case AST_CONTROL_BUSY: ast_verb(3, "%s is busy\n", winner->name); break; case AST_CONTROL_CONGESTION: ast_verb(3, "%s is circuit-busy\n", winner->name); break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", winner->name); break; case AST_CONTROL_PROGRESS: ast_verb(3, "%s is making progress passing it to %s\n", winner->name, caller->name); break; case AST_CONTROL_VIDUPDATE: ast_verb(3, "%s requested a video update, passing it to %s\n", winner->name, caller->name); break; case AST_CONTROL_SRCUPDATE: ast_verb(3, "%s requested a source update, passing it to %s\n", winner->name, caller->name); break; case AST_CONTROL_PROCEEDING: ast_verb(3, "%s is proceeding passing it to %s\n", winner->name,caller->name); break; case AST_CONTROL_HOLD: ast_verb(3, "Call on %s placed on hold\n", winner->name); break; case AST_CONTROL_UNHOLD: ast_verb(3, "Call on %s left from hold\n", winner->name); break; case AST_CONTROL_OFFHOOK: case AST_CONTROL_FLASH: /* Ignore going off hook and flash */ break; case -1: ast_verb(3, "%s stopped sounds\n", winner->name); break; default: ast_debug(1, "Dunno what to do with control type %d\n", f->subclass); break; } } if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) { if (winner->stream) ast_stopstream(winner); tmpuser->digts = 0; ast_debug(1, "DTMF received: %c\n",(char) f->subclass); tmpuser->yn[tmpuser->ynidx] = (char) f->subclass; tmpuser->ynidx++; ast_debug(1, "DTMF string: %s\n", tmpuser->yn); if (tmpuser->ynidx >= ynlongest) { ast_debug(1, "reached longest possible match - doing evals\n"); if (!strcmp(tmpuser->yn, tpargs->takecall)) { ast_debug(1, "Match to take the call!\n"); ast_frfree(f); return tmpuser->ochan; } if (!strcmp(tmpuser->yn, tpargs->nextindp)) { ast_debug(1, "Next in dial plan step requested.\n"); *status = 1; ast_frfree(f); return NULL; } } } ast_frfree(f); } else { if (winner) { ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg); if (!dg) { clear_calling_tree(findme_user_list); return NULL; } else { tmpuser->state = -1; ast_hangup(winner); livechannels--; ast_debug(1, "live channels left %d\n", livechannels); if (!livechannels) { ast_verb(3, "no live channels left. exiting.\n"); return NULL; } } } } } else ast_debug(1, "timed out waiting for action\n"); } /* --- WAIT FOR WINNER NUMBER END! -----------*/ return NULL; }
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Find-Me/Follow-Me Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1203 of file app_followme.c.
char* app = "FollowMe" [static] |
Definition at line 96 of file app_followme.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1203 of file app_followme.c.
char callfromprompt[PATH_MAX] = "followme/call-from" [static] |
Definition at line 178 of file app_followme.c.
const char* defaultmoh = "default" [static] |
Default Music-On-Hold Class
Definition at line 175 of file app_followme.c.
int featuredigittimeout = 5000 [static] |
Feature Digit Timeout
Definition at line 174 of file app_followme.c.
const char* featuredigittostr [static] |
Definition at line 173 of file app_followme.c.
struct ast_app_option followme_opts[128] = { [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG },} [static] |
Definition at line 169 of file app_followme.c.
Referenced by app_exec().
char nextindp[20] = "2" |
Definition at line 177 of file app_followme.c.
char norecordingprompt[PATH_MAX] = "followme/no-recording" [static] |
Definition at line 179 of file app_followme.c.
char optionsprompt[PATH_MAX] = "followme/options" [static] |
Definition at line 180 of file app_followme.c.
char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try" [static] |
Definition at line 181 of file app_followme.c.
char sorryprompt[PATH_MAX] = "followme/sorry" [static] |
Definition at line 183 of file app_followme.c.
char statusprompt[PATH_MAX] = "followme/status" [static] |
Definition at line 182 of file app_followme.c.
char takecall[20] = "1" [static] |
Definition at line 177 of file app_followme.c.
int ynlongest = 0 [static] |
Definition at line 171 of file app_followme.c.