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