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