#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/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 |
Data structure for followme scripts. More... | |
struct | call_followme::blnumbers |
struct | call_followme::numbers |
struct | call_followme::wlnumbers |
struct | findme_user |
struct | findme_user_listptr |
struct | fm_args |
struct | fm_args::cnumbers |
struct | followmes |
struct | number |
Number structure. More... | |
Enumerations | |
enum | { FOLLOWMEFLAG_STATUSMSG = (1 << 0), FOLLOWMEFLAG_RECORDNAME = (1 << 1), FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2), FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3) } |
Functions | |
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, const char *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 (const 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 | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Find-Me/Follow-Me Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 }, [ 'd' ] = { .flag = FOLLOWMEFLAG_DISABLEHOLDPROMPT },} |
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 |
Definition in file app_followme.c.
anonymous enum |
FOLLOWMEFLAG_STATUSMSG | |
FOLLOWMEFLAG_RECORDNAME | |
FOLLOWMEFLAG_UNREACHABLEMSG | |
FOLLOWMEFLAG_DISABLEHOLDPROMPT |
Definition at line 161 of file app_followme.c.
00161 { 00162 FOLLOWMEFLAG_STATUSMSG = (1 << 0), 00163 FOLLOWMEFLAG_RECORDNAME = (1 << 1), 00164 FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2), 00165 FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3) 00166 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1212 of file app_followme.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1212 of file app_followme.c.
static struct call_followme* alloc_profile | ( | const char * | fmname | ) | [static] |
Allocate and initialize followme profile.
Definition at line 216 of file app_followme.c.
References ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, ast_mutex_init, and f.
Referenced by find_realtime(), and reload_followme().
00217 { 00218 struct call_followme *f; 00219 00220 if (!(f = ast_calloc(1, sizeof(*f)))) 00221 return NULL; 00222 00223 ast_mutex_init(&f->lock); 00224 ast_copy_string(f->name, fmname, sizeof(f->name)); 00225 f->moh[0] = '\0'; 00226 f->context[0] = '\0'; 00227 ast_copy_string(f->takecall, takecall, sizeof(f->takecall)); 00228 ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp)); 00229 ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt)); 00230 ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt)); 00231 ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt)); 00232 ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt)); 00233 ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt)); 00234 ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt)); 00235 AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); 00236 AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); 00237 AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); 00238 return f; 00239 }
static int app_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1017 of file app_followme.c.
References ast_channel::_state, args, 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(), ast_channel::caller, fm_args::callfromprompt, fm_args::chan, fm_args::cnumbers, config, fm_args::context, create_followme_number(), end_bridge_callback(), end_bridge_callback_data_fixup(), f, find_realtime(), findmeexec(), followme_opts, FOLLOWMEFLAG_DISABLEHOLDPROMPT, FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, fm_args::followmeflags, free_numbers(), LOG_ERROR, LOG_WARNING, fm_args::mohclass, ast_channel::name, ast_format::name, fm_args::namerecloc, fm_args::nextindp, fm_args::norecordingprompt, number::number, fm_args::optionsprompt, number::order, fm_args::outbound, fm_args::plsholdprompt, S_OR, fm_args::sorryprompt, fm_args::status, fm_args::statusprompt, fm_args::takecall, THRESHOLD_SILENCE, and number::timeout.
01018 { 01019 struct fm_args targs = { 0, }; 01020 struct ast_bridge_config config; 01021 struct call_followme *f; 01022 struct number *nm, *newnm; 01023 int res = 0; 01024 char *argstr; 01025 char namerecloc[255]; 01026 int duration = 0; 01027 struct ast_channel *caller; 01028 struct ast_channel *outbound; 01029 AST_DECLARE_APP_ARGS(args, 01030 AST_APP_ARG(followmeid); 01031 AST_APP_ARG(options); 01032 ); 01033 01034 if (ast_strlen_zero(data)) { 01035 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); 01036 return -1; 01037 } 01038 01039 if (!(argstr = ast_strdupa((char *)data))) { 01040 ast_log(LOG_ERROR, "Out of memory!\n"); 01041 return -1; 01042 } 01043 01044 AST_STANDARD_APP_ARGS(args, argstr); 01045 01046 if (ast_strlen_zero(args.followmeid)) { 01047 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); 01048 return -1; 01049 } 01050 01051 AST_RWLIST_RDLOCK(&followmes); 01052 AST_RWLIST_TRAVERSE(&followmes, f, entry) { 01053 if (!strcasecmp(f->name, args.followmeid) && (f->active)) 01054 break; 01055 } 01056 AST_RWLIST_UNLOCK(&followmes); 01057 01058 ast_debug(1, "New profile %s.\n", args.followmeid); 01059 01060 if (!f) { 01061 f = find_realtime(args.followmeid); 01062 } 01063 01064 if (!f) { 01065 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid); 01066 return 0; 01067 } 01068 01069 /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */ 01070 if (args.options) 01071 ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options); 01072 01073 /* Lock the profile lock and copy out everything we need to run with before unlocking it again */ 01074 ast_mutex_lock(&f->lock); 01075 targs.mohclass = ast_strdupa(f->moh); 01076 ast_copy_string(targs.context, f->context, sizeof(targs.context)); 01077 ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall)); 01078 ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp)); 01079 ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt)); 01080 ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt)); 01081 ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt)); 01082 ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt)); 01083 ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt)); 01084 ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt)); 01085 /* Copy the numbers we're going to use into another list in case the master list should get modified 01086 (and locked) while we're trying to do a follow-me */ 01087 AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers); 01088 AST_LIST_TRAVERSE(&f->numbers, nm, entry) { 01089 newnm = create_followme_number(nm->number, nm->timeout, nm->order); 01090 AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry); 01091 } 01092 ast_mutex_unlock(&f->lock); 01093 01094 /* Answer the call */ 01095 if (chan->_state != AST_STATE_UP) { 01096 ast_answer(chan); 01097 } 01098 01099 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 01100 ast_stream_and_wait(chan, targs.statusprompt, ""); 01101 01102 snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid); 01103 duration = 5; 01104 01105 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 01106 if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) 01107 goto outrun; 01108 01109 if (!ast_fileexists(namerecloc, NULL, chan->language)) 01110 ast_copy_string(namerecloc, "", sizeof(namerecloc)); 01111 if (!ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) { 01112 if (ast_streamfile(chan, targs.plsholdprompt, chan->language)) 01113 goto outrun; 01114 if (ast_waitstream(chan, "") < 0) 01115 goto outrun; 01116 } 01117 ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL); 01118 01119 targs.status = 0; 01120 targs.chan = chan; 01121 ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc)); 01122 01123 findmeexec(&targs); 01124 01125 while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) 01126 ast_free(nm); 01127 01128 if (!ast_strlen_zero(namerecloc)) 01129 unlink(namerecloc); 01130 01131 if (targs.status != 100) { 01132 ast_moh_stop(chan); 01133 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 01134 ast_stream_and_wait(chan, targs.sorryprompt, ""); 01135 res = 0; 01136 } else { 01137 caller = chan; 01138 outbound = targs.outbound; 01139 /* Bridge the two channels. */ 01140 01141 memset(&config, 0, sizeof(config)); 01142 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01143 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 01144 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 01145 config.end_bridge_callback = end_bridge_callback; 01146 config.end_bridge_callback_data = chan; 01147 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 01148 01149 ast_moh_stop(caller); 01150 /* Be sure no generators are left on it */ 01151 ast_deactivate_generator(caller); 01152 /* Make sure channels are compatible */ 01153 res = ast_channel_make_compatible(caller, outbound); 01154 if (res < 0) { 01155 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name); 01156 ast_hangup(outbound); 01157 goto outrun; 01158 } 01159 res = ast_bridge_call(caller, outbound, &config); 01160 if (outbound) 01161 ast_hangup(outbound); 01162 } 01163 01164 outrun: 01165 01166 if (f->realtime) { 01167 /* Not in list */ 01168 free_numbers(f); 01169 ast_free(f); 01170 } 01171 01172 return res; 01173 }
static void clear_caller | ( | struct findme_user * | tmpuser | ) | [static] |
Definition at line 473 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().
00474 { 00475 struct ast_channel *outbound; 00476 00477 if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) { 00478 outbound = tmpuser->ochan; 00479 if (!outbound->cdr) { 00480 outbound->cdr = ast_cdr_alloc(); 00481 if (outbound->cdr) 00482 ast_cdr_init(outbound->cdr, outbound); 00483 } 00484 if (outbound->cdr) { 00485 char tmp[256]; 00486 00487 snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg); 00488 ast_cdr_setapp(outbound->cdr, "FollowMe", tmp); 00489 ast_cdr_update(outbound); 00490 ast_cdr_start(outbound->cdr); 00491 ast_cdr_end(outbound->cdr); 00492 /* If the cause wasn't handled properly */ 00493 if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) 00494 ast_cdr_failed(outbound->cdr); 00495 } else 00496 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 00497 ast_hangup(tmpuser->ochan); 00498 } 00499 00500 }
static void clear_calling_tree | ( | struct findme_user_listptr * | findme_user_list | ) | [static] |
Definition at line 502 of file app_followme.c.
References AST_LIST_TRAVERSE, clear_caller(), and findme_user::cleared.
Referenced by wait_for_winner().
00503 { 00504 struct findme_user *tmpuser; 00505 00506 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { 00507 clear_caller(tmpuser); 00508 tmpuser->cleared = 1; 00509 } 00510 }
static struct number* create_followme_number | ( | const char * | number, | |
int | timeout, | |||
int | numorder | |||
) | [static] |
Add a new number.
Definition at line 282 of file app_followme.c.
References ast_calloc, ast_copy_string(), ast_debug, and ast_strdupa.
Referenced by app_exec(), and reload_followme().
00283 { 00284 struct number *cur; 00285 char *buf = ast_strdupa(number); 00286 char *tmp; 00287 00288 if (!(cur = ast_calloc(1, sizeof(*cur)))) 00289 return NULL; 00290 00291 cur->timeout = timeout; 00292 if ((tmp = strchr(buf, ','))) 00293 *tmp = '\0'; 00294 ast_copy_string(cur->number, buf, sizeof(cur->number)); 00295 cur->order = numorder; 00296 ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout); 00297 00298 return cur; 00299 }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 991 of file app_followme.c.
References ast_cdr::answer, ast_channel_lock, ast_channel_unlock, ast_channel::cdr, pbx_builtin_setvar_helper(), and ast_cdr::start.
00992 { 00993 char buf[80]; 00994 time_t end; 00995 struct ast_channel *chan = data; 00996 00997 time(&end); 00998 00999 ast_channel_lock(chan); 01000 if (chan->cdr->answer.tv_sec) { 01001 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec); 01002 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 01003 } 01004 01005 if (chan->cdr->start.tv_sec) { 01006 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec); 01007 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 01008 } 01009 ast_channel_unlock(chan); 01010 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 1012 of file app_followme.c.
References ast_bridge_config::end_bridge_callback_data.
01013 { 01014 bconfig->end_bridge_callback_data = originator; 01015 }
static struct call_followme* find_realtime | ( | const char * | name | ) | [static] |
Definition at line 931 of file app_followme.c.
References alloc_profile(), ast_false(), ast_free, ast_load_realtime(), ast_mutex_destroy, ast_str_create(), SENTINEL, str, and var.
Referenced by app_exec().
00932 { 00933 struct ast_variable *var = ast_load_realtime("followme", "name", name, SENTINEL), *v; 00934 struct ast_config *cfg; 00935 const char *catg; 00936 struct call_followme *new; 00937 struct ast_str *str = ast_str_create(16); 00938 00939 if (!var) { 00940 return NULL; 00941 } 00942 00943 if (!(new = alloc_profile(name))) { 00944 return NULL; 00945 } 00946 00947 for (v = var; v; v = v->next) { 00948 if (!strcasecmp(v->name, "active")) { 00949 if (ast_false(v->value)) { 00950 ast_mutex_destroy(&new->lock); 00951 ast_free(new); 00952 return NULL; 00953 } 00954 } else { 00955 profile_set_param(new, v->name, v->value, 0, 0); 00956 } 00957 } 00958 00959 ast_variables_destroy(var); 00960 new->realtime = 1; 00961 00962 /* Load numbers */ 00963 if (!(cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name", name, SENTINEL))) { 00964 ast_mutex_destroy(&new->lock); 00965 ast_free(new); 00966 return NULL; 00967 } 00968 00969 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) { 00970 const char *numstr, *timeoutstr, *ordstr; 00971 int timeout; 00972 struct number *cur; 00973 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) { 00974 continue; 00975 } 00976 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout")) || sscanf(timeoutstr, "%30d", &timeout) != 1 || timeout < 1) { 00977 timeout = 25; 00978 } 00979 /* This one has to exist; it was part of the query */ 00980 ordstr = ast_variable_retrieve(cfg, catg, "ordinal"); 00981 ast_str_set(&str, 0, "%s", numstr); 00982 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) { 00983 AST_LIST_INSERT_TAIL(&new->numbers, cur, entry); 00984 } 00985 } 00986 ast_config_destroy(cfg); 00987 00988 return new; 00989 }
static void findmeexec | ( | struct fm_args * | tpargs | ) | [static] |
Definition at line 782 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::caller, fm_args::chan, clear_caller(), findme_user::cleared, fm_args::cnumbers, fm_args::context, free, ast_party_caller::id, ast_channel::language, language, LOG_ERROR, LOG_WARNING, ast_channel::musicclass, musicclass, ast_party_id::name, fm_args::namerecloc, ast_channel::nativeformats, fm_args::nextindp, ast_party_id::number, number::number, findme_user::ochan, number::order, fm_args::outbound, S_COR, fm_args::status, ast_party_name::str, ast_party_number::str, fm_args::takecall, number::timeout, ast_party_name::valid, ast_party_number::valid, and wait_for_winner().
Referenced by app_exec().
00783 { 00784 struct number *nm; 00785 struct ast_channel *outbound; 00786 struct ast_channel *caller; 00787 struct ast_channel *winner = NULL; 00788 char dialarg[512]; 00789 int dg, idx; 00790 char *rest, *number; 00791 struct findme_user *tmpuser; 00792 struct findme_user *fmuser; 00793 struct findme_user *headuser; 00794 struct findme_user_listptr *findme_user_list; 00795 int status; 00796 00797 findme_user_list = ast_calloc(1, sizeof(*findme_user_list)); 00798 AST_LIST_HEAD_INIT_NOLOCK(findme_user_list); 00799 00800 /* We're going to figure out what the longest possible string of digits to collect is */ 00801 ynlongest = 0; 00802 if (strlen(tpargs->takecall) > ynlongest) 00803 ynlongest = strlen(tpargs->takecall); 00804 if (strlen(tpargs->nextindp) > ynlongest) 00805 ynlongest = strlen(tpargs->nextindp); 00806 00807 idx = 1; 00808 caller = tpargs->chan; 00809 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) 00810 if (nm->order == idx) 00811 break; 00812 00813 while (nm) { 00814 ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout); 00815 00816 number = ast_strdupa(nm->number); 00817 ast_debug(3, "examining %s\n", number); 00818 do { 00819 rest = strchr(number, '&'); 00820 if (rest) { 00821 *rest = 0; 00822 rest++; 00823 } 00824 00825 /* We check if that context exists, before creating the ast_channel struct needed */ 00826 if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL))) { 00827 /* XXX Should probably restructure to simply skip this item, instead of returning. XXX */ 00828 ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context); 00829 free(findme_user_list); 00830 return; 00831 } 00832 00833 if (!strcmp(tpargs->context, "")) 00834 snprintf(dialarg, sizeof(dialarg), "%s", number); 00835 else 00836 snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context); 00837 00838 tmpuser = ast_calloc(1, sizeof(*tmpuser)); 00839 if (!tmpuser) { 00840 ast_free(findme_user_list); 00841 return; 00842 } 00843 00844 outbound = ast_request("Local", ast_best_codec(caller->nativeformats), caller, dialarg, &dg); 00845 if (outbound) { 00846 ast_set_callerid(outbound, 00847 S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL), 00848 S_COR(caller->caller.id.name.valid, caller->caller.id.name.str, NULL), 00849 S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL)); 00850 ast_channel_inherit_variables(tpargs->chan, outbound); 00851 ast_channel_datastore_inherit(tpargs->chan, outbound); 00852 ast_string_field_set(outbound, language, tpargs->chan->language); 00853 ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode); 00854 ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass); 00855 ast_verb(3, "calling %s\n", dialarg); 00856 if (!ast_call(outbound,dialarg,0)) { 00857 tmpuser->ochan = outbound; 00858 tmpuser->state = 0; 00859 tmpuser->cleared = 0; 00860 ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg)); 00861 AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry); 00862 } else { 00863 ast_verb(3, "couldn't reach at this number.\n"); 00864 if (outbound) { 00865 if (!outbound->cdr) 00866 outbound->cdr = ast_cdr_alloc(); 00867 if (outbound->cdr) { 00868 char tmp[256]; 00869 00870 ast_cdr_init(outbound->cdr, outbound); 00871 snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg); 00872 ast_cdr_setapp(outbound->cdr, "FollowMe", tmp); 00873 ast_cdr_update(outbound); 00874 ast_cdr_start(outbound->cdr); 00875 ast_cdr_end(outbound->cdr); 00876 /* If the cause wasn't handled properly */ 00877 if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause)) 00878 ast_cdr_failed(outbound->cdr); 00879 } else { 00880 ast_log(LOG_ERROR, "Unable to create Call Detail Record\n"); 00881 ast_hangup(outbound); 00882 outbound = NULL; 00883 } 00884 } 00885 } 00886 } else 00887 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg)); 00888 00889 number = rest; 00890 } while (number); 00891 00892 status = 0; 00893 if (!AST_LIST_EMPTY(findme_user_list)) 00894 winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs); 00895 00896 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) { 00897 if (!fmuser->cleared && fmuser->ochan != winner) 00898 clear_caller(fmuser); 00899 ast_free(fmuser); 00900 } 00901 00902 fmuser = NULL; 00903 tmpuser = NULL; 00904 headuser = NULL; 00905 if (winner) 00906 break; 00907 00908 if (!caller || ast_check_hangup(caller)) { 00909 tpargs->status = 1; 00910 ast_free(findme_user_list); 00911 return; 00912 } 00913 00914 idx++; 00915 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) { 00916 if (nm->order == idx) 00917 break; 00918 } 00919 } 00920 ast_free(findme_user_list); 00921 if (!winner) 00922 tpargs->status = 1; 00923 else { 00924 tpargs->status = 100; 00925 tpargs->outbound = winner; 00926 } 00927 00928 return; 00929 }
static void free_numbers | ( | struct call_followme * | f | ) | [static] |
Definition at line 193 of file app_followme.c.
References ast_free, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, and f.
Referenced by app_exec(), reload_followme(), and unload_module().
00194 { 00195 /* Free numbers attached to the profile */ 00196 struct number *prev; 00197 00198 while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry))) 00199 /* Free the number */ 00200 ast_free(prev); 00201 AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); 00202 00203 while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry))) 00204 /* Free the blacklisted number */ 00205 ast_free(prev); 00206 AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); 00207 00208 while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry))) 00209 /* Free the whitelisted number */ 00210 ast_free(prev); 00211 AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); 00212 }
static void init_profile | ( | struct call_followme * | f | ) | [static] |
Definition at line 241 of file app_followme.c.
References ast_copy_string(), and f.
Referenced by reload_followme().
00242 { 00243 f->active = 1; 00244 ast_copy_string(f->moh, defaultmoh, sizeof(f->moh)); 00245 }
static int load_module | ( | void | ) | [static] |
Definition at line 1193 of file app_followme.c.
References app_exec, AST_MODULE_LOAD_DECLINE, ast_register_application_xml, and reload_followme().
01194 { 01195 if(!reload_followme(0)) 01196 return AST_MODULE_LOAD_DECLINE; 01197 01198 return ast_register_application_xml(app, app_exec); 01199 }
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 250 of file app_followme.c.
References ast_copy_string(), ast_log(), f, LOG_WARNING, and ast_format::name.
Referenced by reload_followme().
00251 { 00252 00253 if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music")) 00254 ast_copy_string(f->moh, val, sizeof(f->moh)); 00255 else if (!strcasecmp(param, "context")) 00256 ast_copy_string(f->context, val, sizeof(f->context)); 00257 else if (!strcasecmp(param, "takecall")) 00258 ast_copy_string(f->takecall, val, sizeof(f->takecall)); 00259 else if (!strcasecmp(param, "declinecall")) 00260 ast_copy_string(f->nextindp, val, sizeof(f->nextindp)); 00261 else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt")) 00262 ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt)); 00263 else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt")) 00264 ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt)); 00265 else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt")) 00266 ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt)); 00267 else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt")) 00268 ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt)); 00269 else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt")) 00270 ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt)); 00271 else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt")) 00272 ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt)); 00273 else if (failunknown) { 00274 if (linenum >= 0) 00275 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum); 00276 else 00277 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param); 00278 } 00279 }
static int reload | ( | void | ) | [static] |
Definition at line 1201 of file app_followme.c.
References reload_followme().
01202 { 01203 reload_followme(1); 01204 01205 return 0; 01206 }
static int reload_followme | ( | int | reload | ) | [static] |
Reload followme application module.
Definition at line 302 of file app_followme.c.
References 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_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, create_followme_number(), f, free_numbers(), init_profile(), LOG_ERROR, LOG_WARNING, ast_format::name, profile_set_param(), number::timeout, and var.
Referenced by load_module(), and reload().
00303 { 00304 struct call_followme *f; 00305 struct ast_config *cfg; 00306 char *cat = NULL, *tmp; 00307 struct ast_variable *var; 00308 struct number *cur, *nm; 00309 char numberstr[90]; 00310 int timeout; 00311 char *timeoutstr; 00312 int numorder; 00313 const char *takecallstr; 00314 const char *declinecallstr; 00315 const char *tmpstr; 00316 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00317 00318 if (!(cfg = ast_config_load("followme.conf", config_flags))) { 00319 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n"); 00320 return 0; 00321 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 00322 return 0; 00323 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 00324 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n"); 00325 return 0; 00326 } 00327 00328 AST_RWLIST_WRLOCK(&followmes); 00329 00330 /* Reset Global Var Values */ 00331 featuredigittimeout = 5000; 00332 00333 /* Mark all profiles as inactive for the moment */ 00334 AST_RWLIST_TRAVERSE(&followmes, f, entry) { 00335 f->active = 0; 00336 } 00337 00338 featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout"); 00339 00340 if (!ast_strlen_zero(featuredigittostr)) { 00341 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout)) 00342 featuredigittimeout = 5000; 00343 } 00344 00345 if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) { 00346 ast_copy_string(takecall, takecallstr, sizeof(takecall)); 00347 } 00348 00349 if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) { 00350 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp)); 00351 } 00352 00353 if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) { 00354 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); 00355 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) { 00356 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); 00357 } 00358 00359 if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) { 00360 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); 00361 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) { 00362 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); 00363 } 00364 00365 00366 if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) { 00367 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); 00368 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) { 00369 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); 00370 } 00371 00372 if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) { 00373 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); 00374 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) { 00375 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); 00376 } 00377 00378 if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) { 00379 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); 00380 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) { 00381 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); 00382 } 00383 00384 if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) { 00385 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); 00386 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) { 00387 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); 00388 } 00389 00390 /* Chug through config file */ 00391 while ((cat = ast_category_browse(cfg, cat))) { 00392 int new = 0; 00393 00394 if (!strcasecmp(cat, "general")) 00395 continue; 00396 00397 /* Look for an existing one */ 00398 AST_LIST_TRAVERSE(&followmes, f, entry) { 00399 if (!strcasecmp(f->name, cat)) 00400 break; 00401 } 00402 00403 ast_debug(1, "New profile %s.\n", cat); 00404 00405 if (!f) { 00406 /* Make one then */ 00407 f = alloc_profile(cat); 00408 new = 1; 00409 } 00410 00411 /* Totally fail if we fail to find/create an entry */ 00412 if (!f) 00413 continue; 00414 00415 if (!new) 00416 ast_mutex_lock(&f->lock); 00417 /* Re-initialize the profile */ 00418 init_profile(f); 00419 free_numbers(f); 00420 var = ast_variable_browse(cfg, cat); 00421 while (var) { 00422 if (!strcasecmp(var->name, "number")) { 00423 int idx = 0; 00424 00425 /* Add a new number */ 00426 ast_copy_string(numberstr, var->value, sizeof(numberstr)); 00427 if ((tmp = strchr(numberstr, ','))) { 00428 *tmp++ = '\0'; 00429 timeoutstr = ast_strdupa(tmp); 00430 if ((tmp = strchr(timeoutstr, ','))) { 00431 *tmp++ = '\0'; 00432 numorder = atoi(tmp); 00433 if (numorder < 0) 00434 numorder = 0; 00435 } else 00436 numorder = 0; 00437 timeout = atoi(timeoutstr); 00438 if (timeout < 0) 00439 timeout = 25; 00440 } else { 00441 timeout = 25; 00442 numorder = 0; 00443 } 00444 00445 if (!numorder) { 00446 idx = 1; 00447 AST_LIST_TRAVERSE(&f->numbers, nm, entry) 00448 idx++; 00449 numorder = idx; 00450 } 00451 cur = create_followme_number(numberstr, timeout, numorder); 00452 AST_LIST_INSERT_TAIL(&f->numbers, cur, entry); 00453 } else { 00454 profile_set_param(f, var->name, var->value, var->lineno, 1); 00455 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno); 00456 } 00457 var = var->next; 00458 } /* End while(var) loop */ 00459 00460 if (!new) 00461 ast_mutex_unlock(&f->lock); 00462 else 00463 AST_RWLIST_INSERT_HEAD(&followmes, f, entry); 00464 } 00465 00466 ast_config_destroy(cfg); 00467 00468 AST_RWLIST_UNLOCK(&followmes); 00469 00470 return 1; 00471 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1175 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().
01176 { 01177 struct call_followme *f; 01178 01179 ast_unregister_application(app); 01180 01181 /* Free Memory. Yeah! I'm free! */ 01182 AST_RWLIST_WRLOCK(&followmes); 01183 while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) { 01184 free_numbers(f); 01185 ast_free(f); 01186 } 01187 01188 AST_RWLIST_UNLOCK(&followmes); 01189 01190 return 0; 01191 }
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] |
Definition at line 514 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(), findme_user::digts, f, 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, fm_args::takecall, number::timeout, ast_channel::timingfunc, findme_user::yn, and findme_user::ynidx.
Referenced by findmeexec().
00515 { 00516 struct ast_channel *watchers[256]; 00517 int pos; 00518 struct ast_channel *winner; 00519 struct ast_frame *f; 00520 int ctstatus = 0; 00521 int dg; 00522 struct findme_user *tmpuser; 00523 int to = 0; 00524 int livechannels = 0; 00525 int tmpto; 00526 long totalwait = 0, wtd = 0, towas = 0; 00527 char *callfromname; 00528 char *pressbuttonname; 00529 00530 /* ------------ wait_for_winner_channel start --------------- */ 00531 00532 callfromname = ast_strdupa(tpargs->callfromprompt); 00533 pressbuttonname = ast_strdupa(tpargs->optionsprompt); 00534 00535 if (AST_LIST_EMPTY(findme_user_list)) { 00536 ast_verb(3, "couldn't reach at this number.\n"); 00537 return NULL; 00538 } 00539 00540 if (!caller) { 00541 ast_verb(3, "Original caller hungup. Cleanup.\n"); 00542 clear_calling_tree(findme_user_list); 00543 return NULL; 00544 } 00545 00546 totalwait = nm->timeout * 1000; 00547 00548 while (!ctstatus) { 00549 to = 1000; 00550 pos = 1; 00551 livechannels = 0; 00552 watchers[0] = caller; 00553 00554 dg = 0; 00555 winner = NULL; 00556 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { 00557 if (tmpuser->state >= 0 && tmpuser->ochan) { 00558 if (tmpuser->state == 3) 00559 tmpuser->digts += (towas - wtd); 00560 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) { 00561 ast_verb(3, "We've been waiting for digits longer than we should have.\n"); 00562 if (!ast_strlen_zero(namerecloc)) { 00563 tmpuser->state = 1; 00564 tmpuser->digts = 0; 00565 if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) { 00566 ast_sched_runq(tmpuser->ochan->sched); 00567 } else { 00568 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); 00569 return NULL; 00570 } 00571 } else { 00572 tmpuser->state = 2; 00573 tmpuser->digts = 0; 00574 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language)) 00575 ast_sched_runq(tmpuser->ochan->sched); 00576 else { 00577 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); 00578 return NULL; 00579 } 00580 } 00581 } 00582 if (tmpuser->ochan->stream) { 00583 ast_sched_runq(tmpuser->ochan->sched); 00584 tmpto = ast_sched_wait(tmpuser->ochan->sched); 00585 if (tmpto > 0 && tmpto < to) 00586 to = tmpto; 00587 else if (tmpto < 0 && !tmpuser->ochan->timingfunc) { 00588 ast_stopstream(tmpuser->ochan); 00589 if (tmpuser->state == 1) { 00590 ast_verb(3, "Playback of the call-from file appears to be done.\n"); 00591 if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) { 00592 tmpuser->state = 2; 00593 } else { 00594 ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc); 00595 memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); 00596 tmpuser->ynidx = 0; 00597 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) 00598 tmpuser->state = 3; 00599 else { 00600 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname); 00601 return NULL; 00602 } 00603 } 00604 } else if (tmpuser->state == 2) { 00605 ast_verb(3, "Playback of name file appears to be done.\n"); 00606 memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); 00607 tmpuser->ynidx = 0; 00608 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) { 00609 tmpuser->state = 3; 00610 } else { 00611 return NULL; 00612 } 00613 } else if (tmpuser->state == 3) { 00614 ast_verb(3, "Playback of the next step file appears to be done.\n"); 00615 tmpuser->digts = 0; 00616 } 00617 } 00618 } 00619 watchers[pos++] = tmpuser->ochan; 00620 livechannels++; 00621 } 00622 } 00623 00624 tmpto = to; 00625 if (to < 0) { 00626 to = 1000; 00627 tmpto = 1000; 00628 } 00629 towas = to; 00630 winner = ast_waitfor_n(watchers, pos, &to); 00631 tmpto -= to; 00632 totalwait -= tmpto; 00633 wtd = to; 00634 if (totalwait <= 0) { 00635 ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait); 00636 clear_calling_tree(findme_user_list); 00637 return NULL; 00638 } 00639 if (winner) { 00640 /* Need to find out which channel this is */ 00641 dg = 0; 00642 while ((winner != watchers[dg]) && (dg < 256)) 00643 dg++; 00644 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) 00645 if (tmpuser->ochan == winner) 00646 break; 00647 f = ast_read(winner); 00648 if (f) { 00649 if (f->frametype == AST_FRAME_CONTROL) { 00650 switch (f->subclass.integer) { 00651 case AST_CONTROL_HANGUP: 00652 ast_verb(3, "%s received a hangup frame.\n", winner->name); 00653 if (f->data.uint32) { 00654 winner->hangupcause = f->data.uint32; 00655 } 00656 if (dg == 0) { 00657 ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n"); 00658 clear_calling_tree(findme_user_list); 00659 ctstatus = -1; 00660 } 00661 break; 00662 case AST_CONTROL_ANSWER: 00663 ast_verb(3, "%s answered %s\n", winner->name, caller->name); 00664 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 00665 winner->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00666 caller->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00667 ast_verb(3, "Starting playback of %s\n", callfromname); 00668 if (dg > 0) { 00669 if (!ast_strlen_zero(namerecloc)) { 00670 if (!ast_streamfile(winner, callfromname, winner->language)) { 00671 ast_sched_runq(winner->sched); 00672 tmpuser->state = 1; 00673 } else { 00674 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); 00675 ast_frfree(f); 00676 return NULL; 00677 } 00678 } else { 00679 tmpuser->state = 2; 00680 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language)) 00681 ast_sched_runq(tmpuser->ochan->sched); 00682 else { 00683 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); 00684 ast_frfree(f); 00685 return NULL; 00686 } 00687 } 00688 } 00689 break; 00690 case AST_CONTROL_BUSY: 00691 ast_verb(3, "%s is busy\n", winner->name); 00692 break; 00693 case AST_CONTROL_CONGESTION: 00694 ast_verb(3, "%s is circuit-busy\n", winner->name); 00695 break; 00696 case AST_CONTROL_RINGING: 00697 ast_verb(3, "%s is ringing\n", winner->name); 00698 break; 00699 case AST_CONTROL_PROGRESS: 00700 ast_verb(3, "%s is making progress passing it to %s\n", winner->name, caller->name); 00701 break; 00702 case AST_CONTROL_VIDUPDATE: 00703 ast_verb(3, "%s requested a video update, passing it to %s\n", winner->name, caller->name); 00704 break; 00705 case AST_CONTROL_SRCUPDATE: 00706 ast_verb(3, "%s requested a source update, passing it to %s\n", winner->name, caller->name); 00707 break; 00708 case AST_CONTROL_PROCEEDING: 00709 ast_verb(3, "%s is proceeding passing it to %s\n", winner->name,caller->name); 00710 break; 00711 case AST_CONTROL_HOLD: 00712 ast_verb(3, "Call on %s placed on hold\n", winner->name); 00713 break; 00714 case AST_CONTROL_UNHOLD: 00715 ast_verb(3, "Call on %s left from hold\n", winner->name); 00716 break; 00717 case AST_CONTROL_OFFHOOK: 00718 case AST_CONTROL_FLASH: 00719 /* Ignore going off hook and flash */ 00720 break; 00721 case -1: 00722 ast_verb(3, "%s stopped sounds\n", winner->name); 00723 break; 00724 default: 00725 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer); 00726 break; 00727 } 00728 } 00729 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) { 00730 if (winner->stream) 00731 ast_stopstream(winner); 00732 tmpuser->digts = 0; 00733 ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer); 00734 tmpuser->yn[tmpuser->ynidx] = (char) f->subclass.integer; 00735 tmpuser->ynidx++; 00736 ast_debug(1, "DTMF string: %s\n", tmpuser->yn); 00737 if (tmpuser->ynidx >= ynlongest) { 00738 ast_debug(1, "reached longest possible match - doing evals\n"); 00739 if (!strcmp(tmpuser->yn, tpargs->takecall)) { 00740 ast_debug(1, "Match to take the call!\n"); 00741 ast_frfree(f); 00742 return tmpuser->ochan; 00743 } 00744 if (!strcmp(tmpuser->yn, tpargs->nextindp)) { 00745 ast_debug(1, "Next in dial plan step requested.\n"); 00746 *status = 1; 00747 ast_frfree(f); 00748 return NULL; 00749 } 00750 00751 } 00752 } 00753 00754 ast_frfree(f); 00755 } else { 00756 if (winner) { 00757 ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg); 00758 if (!dg) { 00759 clear_calling_tree(findme_user_list); 00760 return NULL; 00761 } else { 00762 tmpuser->state = -1; 00763 ast_hangup(winner); 00764 livechannels--; 00765 ast_debug(1, "live channels left %d\n", livechannels); 00766 if (!livechannels) { 00767 ast_verb(3, "no live channels left. exiting.\n"); 00768 return NULL; 00769 } 00770 } 00771 } 00772 } 00773 00774 } else 00775 ast_debug(1, "timed out waiting for action\n"); 00776 } 00777 00778 /* --- WAIT FOR WINNER NUMBER END! -----------*/ 00779 return NULL; 00780 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Find-Me/Follow-Me Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1212 of file app_followme.c.
char* app = "FollowMe" [static] |
Definition at line 98 of file app_followme.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1212 of file app_followme.c.
char callfromprompt[PATH_MAX] = "followme/call-from" [static] |
Definition at line 182 of file app_followme.c.
const char* defaultmoh = "default" [static] |
Default Music-On-Hold Class
Definition at line 179 of file app_followme.c.
int featuredigittimeout = 5000 [static] |
Feature Digit Timeout
Definition at line 178 of file app_followme.c.
Referenced by ast_bridge_call(), and load_config().
const char* featuredigittostr [static] |
Definition at line 177 of file app_followme.c.
struct ast_app_option followme_opts[128] = { [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG }, [ 'd' ] = { .flag = FOLLOWMEFLAG_DISABLEHOLDPROMPT },} [static] |
char nextindp[20] = "2" [static] |
Definition at line 181 of file app_followme.c.
char norecordingprompt[PATH_MAX] = "followme/no-recording" [static] |
Definition at line 183 of file app_followme.c.
char optionsprompt[PATH_MAX] = "followme/options" [static] |
Definition at line 184 of file app_followme.c.
char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try" [static] |
Definition at line 185 of file app_followme.c.
char sorryprompt[PATH_MAX] = "followme/sorry" [static] |
Definition at line 187 of file app_followme.c.
char statusprompt[PATH_MAX] = "followme/status" [static] |
Definition at line 186 of file app_followme.c.
char takecall[20] = "1" [static] |
Definition at line 181 of file app_followme.c.
int ynlongest = 0 [static] |
Definition at line 175 of file app_followme.c.