#include "asterisk.h"
#include <signal.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
Go to the source code of this file.
Data Structures | |
struct | 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
static char * | app = "FollowMe" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char | callfromprompt [PATH_MAX] = "followme/call-from" |
static const char * | defaultmoh = "default" |
static 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 137 of file app_followme.c.
00137 { 00138 FOLLOWMEFLAG_STATUSMSG = (1 << 0), 00139 FOLLOWMEFLAG_RECORDNAME = (1 << 1), 00140 FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2) 00141 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1084 of file app_followme.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1084 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 900 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_dsp_get_threshold_from_settings(), AST_FEATURE_AUTOMON, AST_FEATURE_REDIRECT, ast_fileexists(), ast_free, ast_hangup(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_play_and_record(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), 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, THRESHOLD_SILENCE, and number::timeout.
00901 { 00902 struct fm_args targs = { 0, }; 00903 struct ast_bridge_config config; 00904 struct call_followme *f; 00905 struct number *nm, *newnm; 00906 int res = 0; 00907 char *argstr; 00908 char namerecloc[255]; 00909 int duration = 0; 00910 struct ast_channel *caller; 00911 struct ast_channel *outbound; 00912 AST_DECLARE_APP_ARGS(args, 00913 AST_APP_ARG(followmeid); 00914 AST_APP_ARG(options); 00915 ); 00916 00917 if (ast_strlen_zero(data)) { 00918 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); 00919 return -1; 00920 } 00921 00922 if (!(argstr = ast_strdupa((char *)data))) { 00923 ast_log(LOG_ERROR, "Out of memory!\n"); 00924 return -1; 00925 } 00926 00927 AST_STANDARD_APP_ARGS(args, argstr); 00928 00929 if (ast_strlen_zero(args.followmeid)) { 00930 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); 00931 return -1; 00932 } 00933 00934 AST_RWLIST_RDLOCK(&followmes); 00935 AST_RWLIST_TRAVERSE(&followmes, f, entry) { 00936 if (!strcasecmp(f->name, args.followmeid) && (f->active)) 00937 break; 00938 } 00939 AST_RWLIST_UNLOCK(&followmes); 00940 00941 ast_debug(1, "New profile %s.\n", args.followmeid); 00942 00943 if (!f) { 00944 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid); 00945 return 0; 00946 } 00947 00948 /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */ 00949 if (args.options) 00950 ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options); 00951 00952 /* Lock the profile lock and copy out everything we need to run with before unlocking it again */ 00953 ast_mutex_lock(&f->lock); 00954 targs.mohclass = ast_strdupa(f->moh); 00955 ast_copy_string(targs.context, f->context, sizeof(targs.context)); 00956 ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall)); 00957 ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp)); 00958 ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt)); 00959 ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt)); 00960 ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt)); 00961 ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt)); 00962 ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt)); 00963 ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt)); 00964 /* Copy the numbers we're going to use into another list in case the master list should get modified 00965 (and locked) while we're trying to do a follow-me */ 00966 AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers); 00967 AST_LIST_TRAVERSE(&f->numbers, nm, entry) { 00968 newnm = create_followme_number(nm->number, nm->timeout, nm->order); 00969 AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry); 00970 } 00971 ast_mutex_unlock(&f->lock); 00972 00973 /* Answer the call */ 00974 if (chan->_state != AST_STATE_UP) { 00975 ast_answer(chan); 00976 } 00977 00978 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 00979 ast_stream_and_wait(chan, targs.statusprompt, ""); 00980 00981 snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid); 00982 duration = 5; 00983 00984 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 00985 if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) 00986 goto outrun; 00987 00988 if (!ast_fileexists(namerecloc, NULL, chan->language)) 00989 ast_copy_string(namerecloc, "", sizeof(namerecloc)); 00990 00991 if (ast_streamfile(chan, targs.plsholdprompt, chan->language)) 00992 goto outrun; 00993 if (ast_waitstream(chan, "") < 0) 00994 goto outrun; 00995 ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL); 00996 00997 targs.status = 0; 00998 targs.chan = chan; 00999 ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc)); 01000 01001 findmeexec(&targs); 01002 01003 while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) 01004 ast_free(nm); 01005 01006 if (!ast_strlen_zero(namerecloc)) 01007 unlink(namerecloc); 01008 01009 if (targs.status != 100) { 01010 ast_moh_stop(chan); 01011 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 01012 ast_stream_and_wait(chan, targs.sorryprompt, ""); 01013 res = 0; 01014 } else { 01015 caller = chan; 01016 outbound = targs.outbound; 01017 /* Bridge the two channels. */ 01018 01019 memset(&config, 0, sizeof(config)); 01020 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01021 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 01022 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 01023 config.end_bridge_callback = end_bridge_callback; 01024 config.end_bridge_callback_data = chan; 01025 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 01026 01027 ast_moh_stop(caller); 01028 /* Be sure no generators are left on it */ 01029 ast_deactivate_generator(caller); 01030 /* Make sure channels are compatible */ 01031 res = ast_channel_make_compatible(caller, outbound); 01032 if (res < 0) { 01033 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name); 01034 ast_hangup(outbound); 01035 goto outrun; 01036 } 01037 res = ast_bridge_call(caller, outbound, &config); 01038 if (outbound) 01039 ast_hangup(outbound); 01040 } 01041 01042 outrun: 01043 01044 return res; 01045 }
static void clear_caller | ( | struct findme_user * | tmpuser | ) | [static] |
Definition at line 429 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().
00430 { 00431 struct ast_channel *outbound; 00432 00433 if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) { 00434 outbound = tmpuser->ochan; 00435 if (!outbound->cdr) { 00436 outbound->cdr = ast_cdr_alloc(); 00437 if (outbound->cdr) 00438 ast_cdr_init(outbound->cdr, outbound); 00439 } 00440 if (outbound->cdr) { 00441 char tmp[256]; 00442 00443 snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg); 00444 ast_cdr_setapp(outbound->cdr, "FollowMe", tmp); 00445 ast_cdr_update(outbound); 00446 ast_cdr_start(outbound->cdr); 00447 ast_cdr_end(outbound->cdr); 00448 /* If the cause wasn't handled properly */ 00449 if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) 00450 ast_cdr_failed(outbound->cdr); 00451 } else 00452 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 00453 ast_hangup(tmpuser->ochan); 00454 } 00455 00456 }
static void clear_calling_tree | ( | struct findme_user_listptr * | findme_user_list | ) | [static] |
Definition at line 458 of file app_followme.c.
References AST_LIST_TRAVERSE, clear_caller(), findme_user::cleared, and number::entry.
Referenced by wait_for_winner().
00459 { 00460 struct findme_user *tmpuser; 00461 00462 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { 00463 clear_caller(tmpuser); 00464 tmpuser->cleared = 1; 00465 } 00466 }
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 if (!(cur = ast_calloc(1, sizeof(*cur)))) 00262 return NULL; 00263 00264 cur->timeout = timeout; 00265 if ((tmp = strchr(number, ','))) 00266 *tmp = '\0'; 00267 ast_copy_string(cur->number, number, sizeof(cur->number)); 00268 cur->order = numorder; 00269 ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout); 00270 00271 return cur; 00272 }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 874 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.
00875 { 00876 char buf[80]; 00877 time_t end; 00878 struct ast_channel *chan = data; 00879 00880 time(&end); 00881 00882 ast_channel_lock(chan); 00883 if (chan->cdr->answer.tv_sec) { 00884 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec); 00885 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 00886 } 00887 00888 if (chan->cdr->start.tv_sec) { 00889 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec); 00890 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 00891 } 00892 ast_channel_unlock(chan); 00893 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 895 of file app_followme.c.
References ast_bridge_config::end_bridge_callback_data.
00896 { 00897 bconfig->end_bridge_callback_data = originator; 00898 }
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_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 } else 00830 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg)); 00831 00832 number = rest; 00833 } while (number); 00834 00835 status = 0; 00836 if (!AST_LIST_EMPTY(findme_user_list)) 00837 winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs); 00838 00839 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) { 00840 if (!fmuser->cleared && fmuser->ochan != winner) 00841 clear_caller(fmuser); 00842 ast_free(fmuser); 00843 } 00844 00845 fmuser = NULL; 00846 tmpuser = NULL; 00847 headuser = NULL; 00848 if (winner) 00849 break; 00850 00851 if (!caller) { 00852 tpargs->status = 1; 00853 ast_free(findme_user_list); 00854 return; 00855 } 00856 00857 idx++; 00858 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) { 00859 if (nm->order == idx) 00860 break; 00861 } 00862 } 00863 ast_free(findme_user_list); 00864 if (!winner) 00865 tpargs->status = 1; 00866 else { 00867 tpargs->status = 100; 00868 tpargs->outbound = winner; 00869 } 00870 00871 return; 00872 }
static void free_numbers | ( | struct call_followme * | f | ) | [static] |
Definition at line 167 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().
00168 { 00169 /* Free numbers attached to the profile */ 00170 struct number *prev; 00171 00172 while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry))) 00173 /* Free the number */ 00174 ast_free(prev); 00175 AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); 00176 00177 while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry))) 00178 /* Free the blacklisted number */ 00179 ast_free(prev); 00180 AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); 00181 00182 while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry))) 00183 /* Free the whitelisted number */ 00184 ast_free(prev); 00185 AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); 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 1065 of file app_followme.c.
References app_exec, AST_MODULE_LOAD_DECLINE, ast_register_application, and reload_followme().
01066 { 01067 if(!reload_followme(0)) 01068 return AST_MODULE_LOAD_DECLINE; 01069 01070 return ast_register_application(app, app_exec, synopsis, descrip); 01071 }
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 1073 of file app_followme.c.
References reload_followme().
01074 { 01075 reload_followme(1); 01076 01077 return 0; 01078 }
static int reload_followme | ( | int | reload | ) | [static] |
Reload followme application module.
Definition at line 275 of file app_followme.c.
References alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_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().
00276 { 00277 struct call_followme *f; 00278 struct ast_config *cfg; 00279 char *cat = NULL, *tmp; 00280 struct ast_variable *var; 00281 struct number *cur, *nm; 00282 char numberstr[90]; 00283 int timeout; 00284 char *timeoutstr; 00285 int numorder; 00286 const char *takecallstr; 00287 const char *declinecallstr; 00288 const char *tmpstr; 00289 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00290 00291 if (!(cfg = ast_config_load("followme.conf", config_flags))) { 00292 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n"); 00293 return 0; 00294 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00295 return 0; 00296 00297 AST_RWLIST_WRLOCK(&followmes); 00298 00299 /* Reset Global Var Values */ 00300 featuredigittimeout = 5000; 00301 00302 /* Mark all profiles as inactive for the moment */ 00303 AST_RWLIST_TRAVERSE(&followmes, f, entry) { 00304 f->active = 0; 00305 } 00306 00307 featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout"); 00308 00309 if (!ast_strlen_zero(featuredigittostr)) { 00310 if (!sscanf(featuredigittostr, "%d", &featuredigittimeout)) 00311 featuredigittimeout = 5000; 00312 } 00313 00314 takecallstr = ast_variable_retrieve(cfg, "general", "takecall"); 00315 if (!ast_strlen_zero(takecallstr)) 00316 ast_copy_string(takecall, takecallstr, sizeof(takecall)); 00317 00318 declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall"); 00319 if (!ast_strlen_zero(declinecallstr)) 00320 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp)); 00321 00322 tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt"); 00323 if (!ast_strlen_zero(tmpstr)) 00324 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); 00325 00326 tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt"); 00327 if (!ast_strlen_zero(tmpstr)) 00328 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); 00329 00330 tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt"); 00331 if (!ast_strlen_zero(tmpstr)) 00332 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); 00333 00334 tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt"); 00335 if (!ast_strlen_zero(tmpstr)) 00336 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); 00337 00338 tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt"); 00339 if (!ast_strlen_zero(tmpstr)) 00340 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); 00341 00342 tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt"); 00343 if (!ast_strlen_zero(tmpstr)) 00344 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); 00345 00346 /* Chug through config file */ 00347 while ((cat = ast_category_browse(cfg, cat))) { 00348 int new = 0; 00349 00350 if (!strcasecmp(cat, "general")) 00351 continue; 00352 00353 /* Look for an existing one */ 00354 AST_LIST_TRAVERSE(&followmes, f, entry) { 00355 if (!strcasecmp(f->name, cat)) 00356 break; 00357 } 00358 00359 ast_debug(1, "New profile %s.\n", cat); 00360 00361 if (!f) { 00362 /* Make one then */ 00363 f = alloc_profile(cat); 00364 new = 1; 00365 } 00366 00367 /* Totally fail if we fail to find/create an entry */ 00368 if (!f) 00369 continue; 00370 00371 if (!new) 00372 ast_mutex_lock(&f->lock); 00373 /* Re-initialize the profile */ 00374 init_profile(f); 00375 free_numbers(f); 00376 var = ast_variable_browse(cfg, cat); 00377 while(var) { 00378 if (!strcasecmp(var->name, "number")) { 00379 int idx = 0; 00380 00381 /* Add a new number */ 00382 ast_copy_string(numberstr, var->value, sizeof(numberstr)); 00383 if ((tmp = strchr(numberstr, ','))) { 00384 *tmp++ = '\0'; 00385 timeoutstr = ast_strdupa(tmp); 00386 if ((tmp = strchr(timeoutstr, ','))) { 00387 *tmp++ = '\0'; 00388 numorder = atoi(tmp); 00389 if (numorder < 0) 00390 numorder = 0; 00391 } else 00392 numorder = 0; 00393 timeout = atoi(timeoutstr); 00394 if (timeout < 0) 00395 timeout = 25; 00396 } else { 00397 timeout = 25; 00398 numorder = 0; 00399 } 00400 00401 if (!numorder) { 00402 idx = 1; 00403 AST_LIST_TRAVERSE(&f->numbers, nm, entry) 00404 idx++; 00405 numorder = idx; 00406 } 00407 cur = create_followme_number(numberstr, timeout, numorder); 00408 AST_LIST_INSERT_TAIL(&f->numbers, cur, entry); 00409 } else { 00410 profile_set_param(f, var->name, var->value, var->lineno, 1); 00411 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno); 00412 } 00413 var = var->next; 00414 } /* End while(var) loop */ 00415 00416 if (!new) 00417 ast_mutex_unlock(&f->lock); 00418 else 00419 AST_RWLIST_INSERT_HEAD(&followmes, f, entry); 00420 } 00421 00422 ast_config_destroy(cfg); 00423 00424 AST_RWLIST_UNLOCK(&followmes); 00425 00426 return 1; 00427 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1047 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().
01048 { 01049 struct call_followme *f; 01050 01051 ast_unregister_application(app); 01052 01053 /* Free Memory. Yeah! I'm free! */ 01054 AST_RWLIST_WRLOCK(&followmes); 01055 while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) { 01056 free_numbers(f); 01057 ast_free(f); 01058 } 01059 01060 AST_RWLIST_UNLOCK(&followmes); 01061 01062 return 0; 01063 }
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 470 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().
00471 { 00472 struct ast_channel *watchers[256]; 00473 int pos; 00474 struct ast_channel *winner; 00475 struct ast_frame *f; 00476 int ctstatus = 0; 00477 int dg; 00478 struct findme_user *tmpuser; 00479 int to = 0; 00480 int livechannels = 0; 00481 int tmpto; 00482 long totalwait = 0, wtd = 0, towas = 0; 00483 char *callfromname; 00484 char *pressbuttonname; 00485 00486 /* ------------ wait_for_winner_channel start --------------- */ 00487 00488 callfromname = ast_strdupa(tpargs->callfromprompt); 00489 pressbuttonname = ast_strdupa(tpargs->optionsprompt); 00490 00491 if (AST_LIST_EMPTY(findme_user_list)) { 00492 ast_verb(3, "couldn't reach at this number.\n"); 00493 return NULL; 00494 } 00495 00496 if (!caller) { 00497 ast_verb(3, "Original caller hungup. Cleanup.\n"); 00498 clear_calling_tree(findme_user_list); 00499 return NULL; 00500 } 00501 00502 totalwait = nm->timeout * 1000; 00503 00504 while (!ctstatus) { 00505 to = 1000; 00506 pos = 1; 00507 livechannels = 0; 00508 watchers[0] = caller; 00509 00510 dg = 0; 00511 winner = NULL; 00512 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { 00513 if (tmpuser->state >= 0 && tmpuser->ochan) { 00514 if (tmpuser->state == 3) 00515 tmpuser->digts += (towas - wtd); 00516 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) { 00517 ast_verb(3, "We've been waiting for digits longer than we should have.\n"); 00518 if (!ast_strlen_zero(namerecloc)) { 00519 tmpuser->state = 1; 00520 tmpuser->digts = 0; 00521 if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) { 00522 ast_sched_runq(tmpuser->ochan->sched); 00523 } else { 00524 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); 00525 return NULL; 00526 } 00527 } else { 00528 tmpuser->state = 2; 00529 tmpuser->digts = 0; 00530 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language)) 00531 ast_sched_runq(tmpuser->ochan->sched); 00532 else { 00533 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); 00534 return NULL; 00535 } 00536 } 00537 } 00538 if (tmpuser->ochan->stream) { 00539 ast_sched_runq(tmpuser->ochan->sched); 00540 tmpto = ast_sched_wait(tmpuser->ochan->sched); 00541 if (tmpto > 0 && tmpto < to) 00542 to = tmpto; 00543 else if (tmpto < 0 && !tmpuser->ochan->timingfunc) { 00544 ast_stopstream(tmpuser->ochan); 00545 if (tmpuser->state == 1) { 00546 ast_verb(3, "Playback of the call-from file appears to be done.\n"); 00547 if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) { 00548 tmpuser->state = 2; 00549 } else { 00550 ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc); 00551 memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); 00552 tmpuser->ynidx = 0; 00553 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) 00554 tmpuser->state = 3; 00555 else { 00556 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname); 00557 return NULL; 00558 } 00559 } 00560 } else if (tmpuser->state == 2) { 00561 ast_verb(3, "Playback of name file appears to be done.\n"); 00562 memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); 00563 tmpuser->ynidx = 0; 00564 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) { 00565 tmpuser->state = 3; 00566 } else { 00567 return NULL; 00568 } 00569 } else if (tmpuser->state == 3) { 00570 ast_verb(3, "Playback of the next step file appears to be done.\n"); 00571 tmpuser->digts = 0; 00572 } 00573 } 00574 } 00575 watchers[pos++] = tmpuser->ochan; 00576 livechannels++; 00577 } 00578 } 00579 00580 tmpto = to; 00581 if (to < 0) { 00582 to = 1000; 00583 tmpto = 1000; 00584 } 00585 towas = to; 00586 winner = ast_waitfor_n(watchers, pos, &to); 00587 tmpto -= to; 00588 totalwait -= tmpto; 00589 wtd = to; 00590 if (totalwait <= 0) { 00591 ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait); 00592 clear_calling_tree(findme_user_list); 00593 return NULL; 00594 } 00595 if (winner) { 00596 /* Need to find out which channel this is */ 00597 dg = 0; 00598 while ((winner != watchers[dg]) && (dg < 256)) 00599 dg++; 00600 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) 00601 if (tmpuser->ochan == winner) 00602 break; 00603 f = ast_read(winner); 00604 if (f) { 00605 if (f->frametype == AST_FRAME_CONTROL) { 00606 switch(f->subclass) { 00607 case AST_CONTROL_HANGUP: 00608 ast_verb(3, "%s received a hangup frame.\n", winner->name); 00609 if (f->data.uint32) { 00610 winner->hangupcause = f->data.uint32; 00611 } 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1084 of file app_followme.c.
char* app = "FollowMe" [static] |
Definition at line 61 of file app_followme.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1084 of file app_followme.c.
char callfromprompt[PATH_MAX] = "followme/call-from" [static] |
Definition at line 156 of file app_followme.c.
const char* defaultmoh = "default" [static] |
Default Music-On-Hold Class
Definition at line 153 of file app_followme.c.
char* descrip [static] |
Definition at line 63 of file app_followme.c.
int featuredigittimeout = 5000 [static] |
Feature Digit Timeout
Definition at line 152 of file app_followme.c.
const char* featuredigittostr [static] |
Definition at line 151 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 155 of file app_followme.c.
char norecordingprompt[PATH_MAX] = "followme/no-recording" [static] |
Definition at line 157 of file app_followme.c.
char optionsprompt[PATH_MAX] = "followme/options" [static] |
Definition at line 158 of file app_followme.c.
char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try" [static] |
Definition at line 159 of file app_followme.c.
char sorryprompt[PATH_MAX] = "followme/sorry" [static] |
Definition at line 161 of file app_followme.c.
char statusprompt[PATH_MAX] = "followme/status" [static] |
Definition at line 160 of file app_followme.c.
char* synopsis = "Find-Me/Follow-Me application" [static] |
Definition at line 62 of file app_followme.c.
char takecall[20] = "1" [static] |
Definition at line 155 of file app_followme.c.
int ynlongest = 0 [static] |
Definition at line 149 of file app_followme.c.