#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 1148 of file app_followme.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1148 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 953 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.
00954 { 00955 struct fm_args targs = { 0, }; 00956 struct ast_bridge_config config; 00957 struct call_followme *f; 00958 struct number *nm, *newnm; 00959 int res = 0; 00960 struct ast_module_user *u; 00961 char *argstr; 00962 char namerecloc[255]; 00963 char *fname = NULL; 00964 int duration = 0; 00965 struct ast_channel *caller; 00966 struct ast_channel *outbound; 00967 00968 AST_DECLARE_APP_ARGS(args, 00969 AST_APP_ARG(followmeid); 00970 AST_APP_ARG(options); 00971 ); 00972 00973 if (ast_strlen_zero(data)) { 00974 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n",app); 00975 return -1; 00976 } 00977 00978 if (!(argstr = ast_strdupa((char *)data))) { 00979 ast_log(LOG_ERROR, "Out of memory!\n"); 00980 return -1; 00981 } 00982 00983 00984 AST_STANDARD_APP_ARGS(args, argstr); 00985 if (ast_strlen_zero(args.followmeid)) { 00986 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); 00987 return -1; 00988 } 00989 00990 u = ast_module_user_add(chan); 00991 00992 AST_LIST_LOCK(&followmes); 00993 AST_LIST_TRAVERSE(&followmes, f, entry) { 00994 if (!strcasecmp(f->name, args.followmeid) && (f->active)) 00995 break; 00996 } 00997 AST_LIST_UNLOCK(&followmes); 00998 00999 if (option_debug) 01000 ast_log(LOG_DEBUG, "New profile %s.\n", args.followmeid); 01001 if (!f) { 01002 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid); 01003 res = 0; 01004 } else { 01005 /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */ 01006 01007 01008 if (args.options) 01009 ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options); 01010 01011 /* Lock the profile lock and copy out everything we need to run with before unlocking it again */ 01012 ast_mutex_lock(&f->lock); 01013 targs.mohclass = ast_strdupa(f->moh); 01014 ast_copy_string(targs.context, f->context, sizeof(targs.context)); 01015 ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall)); 01016 ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp)); 01017 ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt)); 01018 ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt)); 01019 ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt)); 01020 ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt)); 01021 ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt)); 01022 ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt)); 01023 /* Copy the numbers we're going to use into another list in case the master list should get modified 01024 (and locked) while we're trying to do a follow-me */ 01025 AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers); 01026 AST_LIST_TRAVERSE(&f->numbers, nm, entry) { 01027 newnm = create_followme_number(nm->number, "", nm->timeout, nm->order); 01028 AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry); 01029 } 01030 ast_mutex_unlock(&f->lock); 01031 01032 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 01033 ast_stream_and_wait(chan, targs.statusprompt, chan->language, ""); 01034 01035 snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid); 01036 duration = 5; 01037 01038 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 01039 if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, 128, 0, NULL) < 0) 01040 goto outrun; 01041 01042 if (!ast_fileexists(namerecloc, NULL, chan->language)) 01043 ast_copy_string(namerecloc, "", sizeof(namerecloc)); 01044 01045 if (ast_streamfile(chan, targs.plsholdprompt, chan->language)) 01046 goto outrun; 01047 if (ast_waitstream(chan, "") < 0) 01048 goto outrun; 01049 ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL); 01050 01051 targs.status = 0; 01052 targs.chan = chan; 01053 ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc)); 01054 01055 findmeexec(&targs); 01056 01057 AST_LIST_TRAVERSE_SAFE_BEGIN(&targs.cnumbers, nm, entry) { 01058 AST_LIST_REMOVE_CURRENT(&targs.cnumbers, entry); 01059 free(nm); 01060 } 01061 AST_LIST_TRAVERSE_SAFE_END 01062 if (targs.status != 100) { 01063 ast_moh_stop(chan); 01064 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 01065 ast_stream_and_wait(chan, targs.sorryprompt, chan->language, ""); 01066 res = 0; 01067 } else { 01068 caller = chan; 01069 outbound = targs.outbound; 01070 /* Bridge the two channels. */ 01071 01072 memset(&config,0,sizeof(struct ast_bridge_config)); 01073 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01074 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 01075 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 01076 01077 config.end_bridge_callback = end_bridge_callback; 01078 config.end_bridge_callback_data = chan; 01079 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 01080 01081 ast_moh_stop(caller); 01082 /* Be sure no generators are left on it */ 01083 ast_deactivate_generator(caller); 01084 /* Make sure channels are compatible */ 01085 res = ast_channel_make_compatible(caller, outbound); 01086 if (res < 0) { 01087 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name); 01088 ast_hangup(outbound); 01089 goto outrun; 01090 } 01091 res = ast_bridge_call(caller,outbound,&config); 01092 if (outbound) 01093 ast_hangup(outbound); 01094 } 01095 } 01096 outrun: 01097 01098 if (!ast_strlen_zero(namerecloc)){ 01099 fname = alloca(strlen(namerecloc) + 5); 01100 sprintf(fname, "%s.sln", namerecloc); 01101 unlink(fname); 01102 } 01103 01104 ast_module_user_remove(u); 01105 01106 return res; 01107 }
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 927 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.
00928 { 00929 char buf[80]; 00930 time_t end; 00931 struct ast_channel *chan = data; 00932 00933 time(&end); 00934 00935 ast_channel_lock(chan); 00936 if (chan->cdr->answer.tv_sec) { 00937 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec); 00938 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 00939 } 00940 00941 if (chan->cdr->start.tv_sec) { 00942 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec); 00943 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 00944 } 00945 ast_channel_unlock(chan); 00946 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 948 of file app_followme.c.
References ast_bridge_config::end_bridge_callback_data.
00949 { 00950 bconfig->end_bridge_callback_data = originator; 00951 }
static void findmeexec | ( | struct fm_args * | tpargs | ) | [static] |
Definition at line 772 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_exists_extension(), 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_string_field_set, 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, ast_channel::language, number::language, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::musicclass, musicclass, 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 if (option_debug > 1) 00805 ast_log(LOG_DEBUG, "Number %s timeout %ld\n", nm->number,nm->timeout); 00806 00807 number = ast_strdupa(nm->number); 00808 if (option_debug > 2) 00809 ast_log(LOG_DEBUG, "examining %s\n", number); 00810 do { 00811 rest = strchr(number, '&'); 00812 if (rest) { 00813 *rest = 0; 00814 rest++; 00815 } 00816 00817 /* We check if that context exists, before creating the ast_channel struct needed */ 00818 if (!ast_exists_extension(caller, tpargs->context, number, 1, caller->cid.cid_num)) { 00819 /* XXX Should probably restructure to simply skip this item, instead of returning. XXX */ 00820 ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context); 00821 free(findme_user_list); 00822 return; 00823 } 00824 00825 if (!strcmp(tpargs->context, "")) 00826 snprintf(dialarg, sizeof(dialarg), "%s", number); 00827 else 00828 snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context); 00829 00830 tmpuser = ast_calloc(1, sizeof(*tmpuser)); 00831 if (!tmpuser) { 00832 free(findme_user_list); 00833 return; 00834 } 00835 00836 outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg); 00837 if (outbound) { 00838 ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num); 00839 ast_channel_inherit_variables(tpargs->chan, outbound); 00840 ast_channel_datastore_inherit(tpargs->chan, outbound); 00841 ast_string_field_set(outbound, language, tpargs->chan->language); 00842 ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode); 00843 ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass); 00844 if (option_verbose > 2) 00845 ast_verbose(VERBOSE_PREFIX_3 "calling %s\n", dialarg); 00846 if (!ast_call(outbound,dialarg,0)) { 00847 tmpuser->ochan = outbound; 00848 tmpuser->state = 0; 00849 tmpuser->cleared = 0; 00850 ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg)); 00851 AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry); 00852 } else { 00853 if (option_verbose > 2) 00854 ast_verbose(VERBOSE_PREFIX_3 "couldn't reach at this number.\n"); 00855 if (outbound) { 00856 if (!outbound->cdr) 00857 outbound->cdr = ast_cdr_alloc(); 00858 if (outbound->cdr) { 00859 char tmp[256]; 00860 00861 ast_cdr_init(outbound->cdr, outbound); 00862 snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg); 00863 ast_cdr_setapp(outbound->cdr, "FollowMe", tmp); 00864 ast_cdr_update(outbound); 00865 ast_cdr_start(outbound->cdr); 00866 ast_cdr_end(outbound->cdr); 00867 /* If the cause wasn't handled properly */ 00868 if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause)) 00869 ast_cdr_failed(outbound->cdr); 00870 } else { 00871 ast_log(LOG_ERROR, "Unable to create Call Detail Record\n"); 00872 ast_hangup(outbound); 00873 outbound = NULL; 00874 } 00875 } 00876 00877 } 00878 } else 00879 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg)); 00880 00881 number = rest; 00882 } while (number); 00883 00884 status = 0; 00885 if (!AST_LIST_EMPTY(findme_user_list)) 00886 winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs); 00887 00888 AST_LIST_TRAVERSE_SAFE_BEGIN(findme_user_list, fmuser, entry) { 00889 if (!fmuser->cleared && fmuser->ochan != winner) 00890 clear_caller(fmuser); 00891 AST_LIST_REMOVE_CURRENT(findme_user_list, entry); 00892 free(fmuser); 00893 } 00894 AST_LIST_TRAVERSE_SAFE_END; 00895 00896 fmuser = NULL; 00897 tmpuser = NULL; 00898 headuser = NULL; 00899 if (winner) 00900 break; 00901 00902 if (!caller || ast_check_hangup(caller)) { 00903 tpargs->status = 1; 00904 free(findme_user_list); 00905 return; 00906 } 00907 00908 idx++; 00909 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) 00910 if (nm->order == idx) 00911 break; 00912 00913 } 00914 free(findme_user_list); 00915 if (!winner) 00916 tpargs->status = 1; 00917 else { 00918 tpargs->status = 100; 00919 tpargs->outbound = winner; 00920 } 00921 00922 00923 return; 00924 00925 }
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 1129 of file app_followme.c.
References app_exec, AST_MODULE_LOAD_DECLINE, ast_register_application(), and reload_followme().
01130 { 01131 if(!reload_followme()) 01132 return AST_MODULE_LOAD_DECLINE; 01133 01134 return ast_register_application(app, app_exec, synopsis, descrip); 01135 }
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 1137 of file app_followme.c.
References reload_followme().
01138 { 01139 reload_followme(); 01140 01141 return 0; 01142 }
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 1109 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().
01110 { 01111 struct call_followme *f; 01112 01113 ast_module_user_hangup_all(); 01114 01115 ast_unregister_application(app); 01116 01117 /* Free Memory. Yeah! I'm free! */ 01118 AST_LIST_LOCK(&followmes); 01119 while ((f = AST_LIST_REMOVE_HEAD(&followmes, entry))) { 01120 free_numbers(f); 01121 free(f); 01122 } 01123 01124 AST_LIST_UNLOCK(&followmes); 01125 01126 return 0; 01127 }
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 1148 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 1148 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] |
Feature Digit Timeout
Definition at line 157 of file app_followme.c.
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.