Wed Oct 28 11:51:21 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/dsp.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 struct ast_module_infoast_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 137 of file app_followme.c.

00137      {
00138    FOLLOWMEFLAG_STATUSMSG = (1 << 0),
00139    FOLLOWMEFLAG_RECORDNAME = (1 << 1),
00140    FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2)
00141 };


Function Documentation

static void __fini_followmes ( void   )  [static]

Definition at line 164 of file app_followme.c.

00168 {

static void __init_followmes ( void   )  [static]

Definition at line 164 of file app_followme.c.

00168 {

static void __reg_module ( void   )  [static]

Definition at line 1088 of file app_followme.c.

static void __unreg_module ( void   )  [static]

Definition at line 1088 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 904 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_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(), 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, THRESHOLD_SILENCE, number::timeout, and ast_channel::uniqueid.

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

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

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, 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    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 878 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.

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

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

Definition at line 899 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

00900 {
00901    bconfig->end_bridge_callback_data = originator;
00902 }

static void findmeexec ( struct fm_args tpargs  )  [static]

Definition at line 738 of file app_followme.c.

References ast_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          } else 
00834             ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
00835 
00836          number = rest;
00837       } while (number);
00838 
00839       status = 0;
00840       if (!AST_LIST_EMPTY(findme_user_list))
00841          winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
00842 
00843       while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
00844          if (!fmuser->cleared && fmuser->ochan != winner)
00845             clear_caller(fmuser);
00846          ast_free(fmuser);
00847       }
00848 
00849       fmuser = NULL;
00850       tmpuser = NULL;
00851       headuser = NULL;
00852       if (winner)
00853          break;
00854 
00855       if (!caller || ast_check_hangup(caller)) {
00856          tpargs->status = 1;
00857          ast_free(findme_user_list);
00858          return;
00859       }
00860 
00861       idx++;
00862       AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
00863          if (nm->order == idx)
00864             break;
00865       }
00866    }
00867    ast_free(findme_user_list);
00868    if (!winner) 
00869       tpargs->status = 1;
00870    else {
00871       tpargs->status = 100;
00872       tpargs->outbound = winner;
00873    }
00874 
00875    return;
00876 }

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

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

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

01070 {
01071    if(!reload_followme(0))
01072       return AST_MODULE_LOAD_DECLINE;
01073 
01074    return ast_register_application(app, app_exec, synopsis, descrip);
01075 }

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

References reload_followme().

01078 {
01079    reload_followme(1);
01080 
01081    return 0;
01082 }

static int reload_followme ( int  reload  )  [static]

Reload followme application module.

Definition at line 275 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().

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, "%30d", &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 1051 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().

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

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 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(), ast_frame::data, 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, ast_frame::uint32, 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 }


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

char* app = "FollowMe" [static]

Definition at line 61 of file app_followme.c.

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

Definition at line 147 of file app_followme.c.

Referenced by app_exec().

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.


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