Wed Oct 28 11:45:45 2009

Asterisk developer's documentation


app_followme.c File Reference

Find-Me Follow-Me application. More...

#include "asterisk.h"
#include <signal.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/app.h"

Include dependency graph for app_followme.c:

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 __fini_followmes (void)
static void __init_followmes (void)
static void __reg_module (void)
static void __unreg_module (void)
static struct call_followmealloc_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 numbercreate_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_channelwait_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 = AST_BUILDOPT_SUM, .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


Detailed Description

Find-Me Follow-Me application.

Author:
BJ Weschke <bweschke@btwtech.com>

Definition in file app_followme.c.


Enumeration Type Documentation

anonymous enum

Enumerator:
FOLLOWMEFLAG_STATUSMSG 
FOLLOWMEFLAG_RECORDNAME 
FOLLOWMEFLAG_UNREACHABLEMSG 

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 };


Function Documentation

static void __fini_followmes ( void   )  [static]

Definition at line 163 of file app_followme.c.

00167 {

static void __init_followmes ( void   )  [static]

Definition at line 163 of file app_followme.c.

00167 {

static void __reg_module ( void   )  [static]

Definition at line 1093 of file app_followme.c.

static void __unreg_module ( void   )  [static]

Definition at line 1093 of file app_followme.c.

static struct call_followme* alloc_profile ( const char *  fmname  )  [static, read]

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(), call_followme::blnumbers, call_followme::callfromprompt, call_followme::context, f, call_followme::lock, call_followme::moh, call_followme::name, call_followme::nextindp, call_followme::norecordingprompt, call_followme::numbers, call_followme::optionsprompt, call_followme::plsholdprompt, call_followme::sorryprompt, call_followme::statusprompt, call_followme::takecall, and call_followme::wlnumbers.

Referenced by 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 908 of file app_followme.c.

References ast_channel::_state, call_followme::active, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_make_compatible(), ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, AST_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(), call_followme::callfromprompt, fm_args::callfromprompt, fm_args::chan, fm_args::cnumbers, call_followme::context, fm_args::context, create_followme_number(), end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, f, ast_bridge_config::features_callee, ast_bridge_config::features_caller, findmeexec(), followme_opts, FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, fm_args::followmeflags, ast_channel::language, call_followme::lock, LOG_ERROR, LOG_WARNING, call_followme::moh, fm_args::mohclass, ast_channel::name, call_followme::name, fm_args::namerecloc, call_followme::nextindp, fm_args::nextindp, call_followme::norecordingprompt, fm_args::norecordingprompt, number::number, call_followme::numbers, call_followme::optionsprompt, fm_args::optionsprompt, number::order, fm_args::outbound, call_followme::plsholdprompt, fm_args::plsholdprompt, S_OR, call_followme::sorryprompt, fm_args::sorryprompt, fm_args::status, call_followme::statusprompt, fm_args::statusprompt, call_followme::takecall, fm_args::takecall, number::timeout, and ast_channel::uniqueid.

00909 {
00910    struct fm_args targs = { 0, };
00911    struct ast_bridge_config config;
00912    struct call_followme *f;
00913    struct number *nm, *newnm;
00914    int res = 0;
00915    char *argstr;
00916    char namerecloc[255];
00917    int duration = 0;
00918    struct ast_channel *caller;
00919    struct ast_channel *outbound;
00920    
00921    AST_DECLARE_APP_ARGS(args,
00922       AST_APP_ARG(followmeid);
00923       AST_APP_ARG(options);
00924    );
00925 
00926    if (ast_strlen_zero(data)) {
00927       ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
00928       return -1;
00929    }
00930    
00931    if (!(argstr = ast_strdupa((char *)data))) {
00932       ast_log(LOG_ERROR, "Out of memory!\n");
00933       return -1;
00934    }
00935 
00936    AST_STANDARD_APP_ARGS(args, argstr);
00937 
00938    if (ast_strlen_zero(args.followmeid)) {
00939       ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
00940       return -1;
00941    }
00942 
00943    AST_RWLIST_RDLOCK(&followmes);
00944    AST_RWLIST_TRAVERSE(&followmes, f, entry) {
00945       if (!strcasecmp(f->name, args.followmeid) && (f->active))
00946          break;
00947    }
00948    AST_RWLIST_UNLOCK(&followmes);
00949    
00950    ast_debug(1, "New profile %s.\n", args.followmeid);
00951 
00952    if (!f) {
00953       ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
00954       return 0;
00955    }
00956 
00957    /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
00958    if (args.options) 
00959       ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
00960    
00961    /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
00962    ast_mutex_lock(&f->lock);
00963    targs.mohclass = ast_strdupa(f->moh);
00964    ast_copy_string(targs.context, f->context, sizeof(targs.context));
00965    ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
00966    ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
00967    ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
00968    ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt));
00969    ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
00970    ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
00971    ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
00972    ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
00973    /* Copy the numbers we're going to use into another list in case the master list should get modified 
00974       (and locked) while we're trying to do a follow-me */
00975    AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers);
00976    AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
00977       newnm = create_followme_number(nm->number, nm->timeout, nm->order);
00978       AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
00979    }
00980    ast_mutex_unlock(&f->lock);
00981    
00982    /* Answer the call */
00983    if (chan->_state != AST_STATE_UP) {
00984       ast_answer(chan);
00985    }
00986 
00987    if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 
00988       ast_stream_and_wait(chan, targs.statusprompt, "");
00989    
00990    snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
00991    duration = 5;
00992    
00993    if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 
00994       if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, 128, 0, NULL) < 0)
00995          goto outrun;
00996    
00997    if (!ast_fileexists(namerecloc, NULL, chan->language))
00998       ast_copy_string(namerecloc, "", sizeof(namerecloc));              
00999    
01000    if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
01001       goto outrun;
01002    if (ast_waitstream(chan, "") < 0)
01003       goto outrun;
01004    ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
01005    
01006    targs.status = 0;
01007    targs.chan = chan;
01008    ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
01009    
01010    findmeexec(&targs);     
01011    
01012    while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry)))
01013       ast_free(nm);
01014       
01015    if (!ast_strlen_zero(namerecloc))
01016       unlink(namerecloc);  
01017    
01018    if (targs.status != 100) {
01019       ast_moh_stop(chan);
01020       if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 
01021          ast_stream_and_wait(chan, targs.sorryprompt, "");
01022       res = 0;
01023    } else {
01024       caller = chan;
01025       outbound = targs.outbound;
01026       /* Bridge the two channels. */
01027       
01028       memset(&config,0,sizeof(struct ast_bridge_config));
01029       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01030       ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
01031       ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
01032       config.end_bridge_callback = end_bridge_callback;
01033       config.end_bridge_callback_data = chan;
01034       config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
01035 
01036       ast_moh_stop(caller);
01037       /* Be sure no generators are left on it */
01038       ast_deactivate_generator(caller);
01039       /* Make sure channels are compatible */
01040       res = ast_channel_make_compatible(caller, outbound);
01041       if (res < 0) {
01042          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
01043          ast_hangup(outbound);
01044          goto outrun;
01045       }
01046       res = ast_bridge_call(caller,outbound,&config);
01047       if (outbound)
01048          ast_hangup(outbound);
01049    }
01050 
01051    outrun:
01052    
01053    return res;
01054 }

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(), and findme_user::cleared.

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, read]

Add a new number.

Definition at line 256 of file app_followme.c.

References ast_calloc, ast_copy_string(), ast_debug, number::number, number::order, 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 882 of file app_followme.c.

References ast_cdr::answer, ast_channel_lock, ast_channel_unlock, buf, ast_channel::cdr, pbx_builtin_setvar_helper(), and ast_cdr::start.

00883 {
00884    char buf[80];
00885    time_t end;
00886    struct ast_channel *chan = data;
00887 
00888    time(&end);
00889 
00890    ast_channel_lock(chan);
00891    if (chan->cdr->answer.tv_sec) {
00892       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec);
00893       pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
00894    }
00895 
00896    if (chan->cdr->start.tv_sec) {
00897       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec);
00898       pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
00899    }
00900    ast_channel_unlock(chan);
00901 }

static void end_bridge_callback_data_fixup ( struct ast_bridge_config bconfig,
struct ast_channel originator,
struct ast_channel terminator 
) [static]

Definition at line 903 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

00904 {
00905    bconfig->end_bridge_callback_data = originator;
00906 }

static void findmeexec ( struct fm_args tpargs  )  [static]

Definition at line 738 of file app_followme.c.

References ast_channel::accountcode, accountcode, ast_best_codec(), ast_call(), ast_calloc, ast_cause2str(), ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_free, ast_hangup(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_request(), ast_set_callerid(), ast_strdupa, ast_string_field_set, ast_verb, ast_channel::cdr, fm_args::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, clear_caller(), findme_user::cleared, fm_args::cnumbers, fm_args::context, findme_user::dialarg, ast_channel::hangupcause, ast_channel::language, language, LOG_ERROR, LOG_WARNING, ast_channel::musicclass, musicclass, fm_args::namerecloc, ast_channel::nativeformats, fm_args::nextindp, number::number, findme_user::ochan, number::order, fm_args::outbound, findme_user::state, fm_args::status, fm_args::takecall, number::timeout, and wait_for_winner().

Referenced by app_exec().

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_channel_datastore_inherit(tpargs->chan, outbound);
00799             ast_string_field_set(outbound, language, tpargs->chan->language);
00800             ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode);
00801             ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass);
00802             ast_verb(3, "calling %s\n", dialarg);
00803             if (!ast_call(outbound,dialarg,0)) {
00804                tmpuser->ochan = outbound;
00805                tmpuser->state = 0;
00806                tmpuser->cleared = 0;
00807                ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
00808                AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
00809             } else {
00810                ast_verb(3, "couldn't reach at this number.\n"); 
00811                if (outbound) {
00812                   if (!outbound->cdr) 
00813                      outbound->cdr = ast_cdr_alloc();
00814                   if (outbound->cdr) {
00815                      char tmp[256];
00816 
00817                      ast_cdr_init(outbound->cdr, outbound);
00818                      snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
00819                      ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00820                      ast_cdr_update(outbound);
00821                      ast_cdr_start(outbound->cdr);
00822                      ast_cdr_end(outbound->cdr);
00823                      /* If the cause wasn't handled properly */
00824                      if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
00825                         ast_cdr_failed(outbound->cdr);
00826                   } else {
00827                      ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
00828                      ast_hangup(outbound);
00829                      outbound = NULL;
00830                   }
00831                }
00832                   
00833             }
00834          } else 
00835             ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
00836                
00837          number = rest;
00838       } while (number);
00839             
00840       status = 0; 
00841       if (!AST_LIST_EMPTY(findme_user_list))
00842          winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
00843       
00844                
00845       while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
00846          if (!fmuser->cleared && fmuser->ochan != winner)
00847             clear_caller(fmuser);
00848          ast_free(fmuser);
00849       }
00850 
00851       fmuser = NULL;
00852       tmpuser = NULL;
00853       headuser = NULL;  
00854       if (winner)
00855          break;
00856 
00857       if (!caller || ast_check_hangup(caller)) {
00858          tpargs->status = 1;
00859          ast_free(findme_user_list);
00860          return;  
00861       }
00862 
00863       idx++;
00864       AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
00865          if (nm->order == idx)
00866             break;
00867 
00868    }
00869    ast_free(findme_user_list);
00870    if (!winner) 
00871       tpargs->status = 1;
00872    else {
00873       tpargs->status = 100;
00874       tpargs->outbound = winner;
00875    }
00876 
00877    
00878    return;
00879       
00880 }

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, call_followme::blnumbers, call_followme::numbers, and call_followme::wlnumbers.

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 call_followme::active, ast_copy_string(), and call_followme::moh.

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 1074 of file app_followme.c.

References app_exec, AST_MODULE_LOAD_DECLINE, ast_register_application, and reload_followme().

01075 {
01076    if(!reload_followme(0))
01077       return AST_MODULE_LOAD_DECLINE;
01078 
01079    return ast_register_application(app, app_exec, synopsis, descrip);
01080 }

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(), call_followme::callfromprompt, call_followme::context, LOG_WARNING, call_followme::moh, call_followme::name, call_followme::nextindp, call_followme::norecordingprompt, call_followme::optionsprompt, call_followme::plsholdprompt, call_followme::sorryprompt, call_followme::statusprompt, and call_followme::takecall.

Referenced by 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 1082 of file app_followme.c.

References reload_followme().

01083 {
01084    reload_followme(1);
01085 
01086    return 0;   
01087 }

static int reload_followme ( int  reload  )  [static]

Reload followme application module.

Definition at line 276 of file app_followme.c.

References call_followme::active, alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, create_followme_number(), f, free_numbers(), init_profile(), ast_variable::lineno, call_followme::lock, LOG_WARNING, ast_variable::name, call_followme::name, ast_variable::next, call_followme::numbers, profile_set_param(), number::timeout, ast_variable::value, and var.

Referenced by load_module(), and reload().

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, "%30d", &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 1056 of file app_followme.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), f, and free_numbers().

01057 {
01058    struct call_followme *f;
01059 
01060    ast_unregister_application(app);
01061 
01062    /* Free Memory. Yeah! I'm free! */
01063    AST_RWLIST_WRLOCK(&followmes);
01064    while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
01065       free_numbers(f);
01066       ast_free(f);
01067    }
01068 
01069    AST_RWLIST_UNLOCK(&followmes);
01070 
01071    return 0;
01072 }

static struct ast_channel* wait_for_winner ( struct findme_user_listptr findme_user_list,
struct number nm,
struct ast_channel caller,
char *  namerecloc,
int *  status,
struct fm_args tpargs 
) [static, read]

Definition at line 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, f, ast_frame::frametype, ast_channel::hangupcause, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, fm_args::nextindp, fm_args::norecordingprompt, findme_user::ochan, fm_args::optionsprompt, ast_channel::sched, findme_user::state, ast_channel::stream, ast_frame::subclass, fm_args::takecall, number::timeout, ast_channel::timingfunc, 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 }


Variable Documentation

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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1093 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 1093 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]

Definition at line 146 of file app_followme.c.

Referenced by app_exec().

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.


Generated on Wed Oct 28 11:45:45 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6