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