Thu Jul 9 13:40:44 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"

Go to the source code of this file.

Data Structures

struct  call_followme
 Data structure for followme scripts. More...
struct  call_followme::blnumbers
struct  call_followme::numbers
struct  call_followme::wlnumbers
struct  findme_user
struct  findme_user_listptr
struct  fm_args
struct  fm_args::cnumbers
struct  followmes
struct  number
 Number structure. More...

Enumerations

enum  { FOLLOWMEFLAG_STATUSMSG = (1 << 0), FOLLOWMEFLAG_RECORDNAME = (1 << 1), FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2) }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static struct call_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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "FollowMe"
static const 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 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 __reg_module ( void   )  [static]

Definition at line 1089 of file app_followme.c.

static void __unreg_module ( void   )  [static]

Definition at line 1089 of file app_followme.c.

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

Allocate and initialize followme profile.

Definition at line 190 of file app_followme.c.

References ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, ast_mutex_init(), and f.

Referenced by reload_followme().

00191 {
00192    struct call_followme *f;
00193 
00194    if (!(f = ast_calloc(1, sizeof(*f))))
00195       return NULL;
00196 
00197    ast_mutex_init(&f->lock);
00198    ast_copy_string(f->name, fmname, sizeof(f->name));
00199    f->moh[0] = '\0';
00200    f->context[0] = '\0';
00201    ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
00202    ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
00203    ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
00204    ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt));
00205    ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt));
00206    ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
00207    ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
00208    ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
00209    AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
00210    AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
00211    AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
00212    return f;
00213 }

static int app_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 904 of file app_followme.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_make_compatible(), ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_REDIRECT, ast_fileexists(), ast_free, ast_hangup(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_play_and_record(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), fm_args::callfromprompt, fm_args::chan, chan, fm_args::cnumbers, config, fm_args::context, create_followme_number(), end_bridge_callback(), end_bridge_callback_data_fixup(), number::entry, f, findmeexec(), followme_opts, FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, fm_args::followmeflags, LOG_ERROR, LOG_WARNING, fm_args::mohclass, ast_channel::name, ast_format::name, fm_args::namerecloc, fm_args::nextindp, fm_args::norecordingprompt, number::number, fm_args::optionsprompt, number::order, fm_args::outbound, fm_args::plsholdprompt, S_OR, fm_args::sorryprompt, fm_args::status, fm_args::statusprompt, fm_args::takecall, and number::timeout.

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

static void clear_caller ( struct findme_user tmpuser  )  [static]

Definition at line 430 of file app_followme.c.

References ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_hangup(), ast_log(), ast_channel::cdr, findme_user::dialarg, ast_channel::hangupcause, LOG_WARNING, findme_user::ochan, and findme_user::state.

Referenced by clear_calling_tree(), and findmeexec().

00431 {
00432    struct ast_channel *outbound;
00433    
00434    if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) {
00435       outbound = tmpuser->ochan;
00436       if (!outbound->cdr) {
00437          outbound->cdr = ast_cdr_alloc();
00438          if (outbound->cdr)
00439             ast_cdr_init(outbound->cdr, outbound);
00440       }
00441       if (outbound->cdr) {
00442          char tmp[256];
00443 
00444          snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg);
00445          ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00446          ast_cdr_update(outbound);
00447          ast_cdr_start(outbound->cdr);
00448          ast_cdr_end(outbound->cdr);
00449          /* If the cause wasn't handled properly */
00450          if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause))
00451             ast_cdr_failed(outbound->cdr);
00452       } else
00453          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
00454       ast_hangup(tmpuser->ochan);
00455    }
00456 
00457 }

static void clear_calling_tree ( struct findme_user_listptr findme_user_list  )  [static]

Definition at line 459 of file app_followme.c.

References AST_LIST_TRAVERSE, clear_caller(), findme_user::cleared, and number::entry.

Referenced by wait_for_winner().

00460 {
00461    struct findme_user *tmpuser;
00462    
00463    AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
00464       clear_caller(tmpuser);
00465       tmpuser->cleared = 1;
00466    }
00467    
00468 }

static struct number* create_followme_number ( char *  number,
int  timeout,
int  numorder 
) [static]

Add a new number.

Definition at line 256 of file app_followme.c.

References ast_calloc, ast_copy_string(), ast_debug, and number::timeout.

Referenced by app_exec(), and reload_followme().

00257 {
00258    struct number *cur;
00259    char *tmp;
00260    
00261 
00262    if (!(cur = ast_calloc(1, sizeof(*cur))))
00263       return NULL;
00264 
00265    cur->timeout = timeout;
00266    if ((tmp = strchr(number, ','))) 
00267       *tmp = '\0';
00268    ast_copy_string(cur->number, number, sizeof(cur->number));
00269    cur->order = numorder;
00270    ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
00271 
00272    return cur;
00273 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 878 of file app_followme.c.

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

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

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

Definition at line 899 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

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

static void findmeexec ( struct fm_args tpargs  )  [static]

Definition at line 738 of file app_followme.c.

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

Referenced by app_exec().

00739 {
00740    struct number *nm;
00741    struct ast_channel *outbound;
00742    struct ast_channel *caller;
00743    struct ast_channel *winner = NULL;
00744    char dialarg[512];
00745    int dg, idx;
00746    char *rest, *number;
00747    struct findme_user *tmpuser;
00748    struct findme_user *fmuser;
00749    struct findme_user *headuser;
00750    struct findme_user_listptr *findme_user_list;
00751    int status;
00752 
00753    findme_user_list = ast_calloc(1, sizeof(*findme_user_list));      
00754    AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
00755 
00756    /* We're going to figure out what the longest possible string of digits to collect is */
00757    ynlongest = 0;
00758    if (strlen(tpargs->takecall) > ynlongest)
00759       ynlongest = strlen(tpargs->takecall);
00760    if (strlen(tpargs->nextindp) > ynlongest)
00761       ynlongest = strlen(tpargs->nextindp);
00762 
00763    idx = 1;
00764    caller = tpargs->chan;
00765    AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
00766       if (nm->order == idx)
00767          break;
00768 
00769    while (nm) {
00770 
00771       ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout);
00772 
00773       number = ast_strdupa(nm->number);
00774       ast_debug(3, "examining %s\n", number);
00775       do {
00776          rest = strchr(number, '&');
00777          if (rest) {
00778             *rest = 0;
00779             rest++;
00780          }
00781 
00782          if (!strcmp(tpargs->context, ""))
00783             snprintf(dialarg, sizeof(dialarg), "%s", number);
00784          else
00785             snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context);
00786                
00787          tmpuser = ast_calloc(1, sizeof(*tmpuser));
00788          if (!tmpuser) {
00789             ast_log(LOG_WARNING, "Out of memory!\n");
00790             ast_free(findme_user_list);
00791             return;
00792          }
00793                
00794          outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg);
00795          if (outbound) {
00796             ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num);
00797             ast_channel_inherit_variables(tpargs->chan, outbound);
00798             ast_verb(3, "calling %s\n", dialarg);
00799             if (!ast_call(outbound,dialarg,0)) {
00800                tmpuser->ochan = outbound;
00801                tmpuser->state = 0;
00802                tmpuser->cleared = 0;
00803                ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
00804                AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
00805             } else {
00806                ast_verb(3, "couldn't reach at this number.\n"); 
00807                if (outbound) {
00808                   if (!outbound->cdr) 
00809                      outbound->cdr = ast_cdr_alloc();
00810                   if (outbound->cdr) {
00811                      char tmp[256];
00812 
00813                      ast_cdr_init(outbound->cdr, outbound);
00814                      snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
00815                      ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00816                      ast_cdr_update(outbound);
00817                      ast_cdr_start(outbound->cdr);
00818                      ast_cdr_end(outbound->cdr);
00819                      /* If the cause wasn't handled properly */
00820                      if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
00821                         ast_cdr_failed(outbound->cdr);
00822                   } else {
00823                      ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
00824                      ast_hangup(outbound);
00825                      outbound = NULL;
00826                   }
00827                }
00828                   
00829             }
00830          } else 
00831             ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
00832                
00833          number = rest;
00834       } while (number);
00835             
00836       status = 0; 
00837       if (!AST_LIST_EMPTY(findme_user_list))
00838          winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
00839       
00840                
00841       while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
00842          if (!fmuser->cleared && fmuser->ochan != winner)
00843             clear_caller(fmuser);
00844          ast_free(fmuser);
00845       }
00846 
00847       fmuser = NULL;
00848       tmpuser = NULL;
00849       headuser = NULL;  
00850       if (winner)
00851          break;
00852 
00853       if (!caller || ast_check_hangup(caller)) {
00854          tpargs->status = 1;
00855          ast_free(findme_user_list);
00856          return;  
00857       }
00858 
00859       idx++;
00860       AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
00861          if (nm->order == idx)
00862             break;
00863 
00864    }
00865    ast_free(findme_user_list);
00866    if (!winner) 
00867       tpargs->status = 1;
00868    else {
00869       tpargs->status = 100;
00870       tpargs->outbound = winner;
00871    }
00872 
00873    
00874    return;
00875       
00876 }

static void free_numbers ( struct call_followme f  )  [static]

Definition at line 166 of file app_followme.c.

References ast_free, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, number::entry, and f.

Referenced by reload_followme(), and unload_module().

00167 {
00168    /* Free numbers attached to the profile */
00169    struct number *prev;
00170 
00171    while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
00172       /* Free the number */
00173       ast_free(prev);
00174    AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
00175 
00176    while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
00177       /* Free the blacklisted number */
00178       ast_free(prev);
00179    AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
00180 
00181    while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
00182       /* Free the whitelisted number */
00183       ast_free(prev);
00184    AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
00185    
00186 }

static void init_profile ( struct call_followme f  )  [static]

Definition at line 215 of file app_followme.c.

References ast_copy_string(), and f.

Referenced by reload_followme().

00216 {
00217    f->active = 1;
00218    ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
00219 }

static int load_module ( void   )  [static]

Definition at line 1070 of file app_followme.c.

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

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

static void profile_set_param ( struct call_followme f,
const char *  param,
const char *  val,
int  linenum,
int  failunknown 
) [static]

Set parameter in profile from configuration file.

Definition at line 224 of file app_followme.c.

References ast_copy_string(), ast_log(), f, LOG_WARNING, and ast_format::name.

Referenced by reload_followme().

00225 {
00226 
00227    if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music")) 
00228       ast_copy_string(f->moh, val, sizeof(f->moh));
00229    else if (!strcasecmp(param, "context")) 
00230       ast_copy_string(f->context, val, sizeof(f->context));
00231    else if (!strcasecmp(param, "takecall"))
00232       ast_copy_string(f->takecall, val, sizeof(f->takecall));
00233    else if (!strcasecmp(param, "declinecall"))
00234       ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
00235    else if (!strcasecmp(param, "call-from-prompt"))
00236       ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt));
00237    else if (!strcasecmp(param, "followme-norecording-prompt")) 
00238       ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt));
00239    else if (!strcasecmp(param, "followme-options-prompt")) 
00240       ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt));
00241    else if (!strcasecmp(param, "followme-pls-hold-prompt"))
00242       ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt));
00243    else if (!strcasecmp(param, "followme-status-prompt")) 
00244       ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
00245    else if (!strcasecmp(param, "followme-sorry-prompt")) 
00246       ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
00247    else if (failunknown) {
00248       if (linenum >= 0)
00249          ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
00250       else
00251          ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
00252    }
00253 }

static int reload ( void   )  [static]

Definition at line 1078 of file app_followme.c.

References reload_followme().

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

static int reload_followme ( int  reload  )  [static]

Reload followme application module.

Definition at line 276 of file app_followme.c.

References alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, create_followme_number(), number::entry, f, free_numbers(), init_profile(), LOG_WARNING, ast_format::name, profile_set_param(), number::timeout, and var.

Referenced by load_module(), and reload().

00277 {
00278    struct call_followme *f;
00279    struct ast_config *cfg;
00280    char *cat = NULL, *tmp;
00281    struct ast_variable *var;
00282    struct number *cur, *nm;
00283    char numberstr[90];
00284    int timeout;
00285    char *timeoutstr;
00286    int numorder;  
00287    const char *takecallstr;
00288    const char *declinecallstr;
00289    const char *tmpstr;
00290    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00291 
00292    if (!(cfg = ast_config_load("followme.conf", config_flags))) {
00293       ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
00294       return 0;
00295    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00296       return 0;
00297 
00298    AST_RWLIST_WRLOCK(&followmes);
00299 
00300    /* Reset Global Var Values */
00301    featuredigittimeout = 5000;
00302 
00303    /* Mark all profiles as inactive for the moment */
00304    AST_RWLIST_TRAVERSE(&followmes, f, entry) {
00305       f->active = 0;
00306    }
00307 
00308    featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
00309    
00310    if (!ast_strlen_zero(featuredigittostr)) {
00311       if (!sscanf(featuredigittostr, "%d", &featuredigittimeout))
00312          featuredigittimeout = 5000;
00313    }
00314 
00315    takecallstr = ast_variable_retrieve(cfg, "general", "takecall");
00316    if (!ast_strlen_zero(takecallstr))
00317       ast_copy_string(takecall, takecallstr, sizeof(takecall));
00318    
00319    declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall");
00320    if (!ast_strlen_zero(declinecallstr))
00321       ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
00322 
00323    tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt");
00324    if (!ast_strlen_zero(tmpstr))
00325       ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
00326 
00327    tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt");
00328    if (!ast_strlen_zero(tmpstr))
00329       ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
00330 
00331    tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt");
00332    if (!ast_strlen_zero(tmpstr))
00333       ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
00334 
00335    tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt");
00336    if (!ast_strlen_zero(tmpstr))
00337       ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
00338 
00339    tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt");
00340    if (!ast_strlen_zero(tmpstr))
00341       ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
00342 
00343    tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt");
00344    if (!ast_strlen_zero(tmpstr))
00345       ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
00346 
00347    /* Chug through config file */
00348    while ((cat = ast_category_browse(cfg, cat))) {
00349       int new = 0;
00350 
00351       if (!strcasecmp(cat, "general"))
00352          continue;
00353 
00354       /* Look for an existing one */
00355       AST_LIST_TRAVERSE(&followmes, f, entry) {
00356          if (!strcasecmp(f->name, cat))
00357             break;
00358       }
00359 
00360       ast_debug(1, "New profile %s.\n", cat);
00361 
00362       if (!f) {
00363          /* Make one then */
00364          f = alloc_profile(cat);
00365          new = 1;
00366       }
00367 
00368       /* Totally fail if we fail to find/create an entry */
00369       if (!f)
00370          continue;
00371       
00372       if (!new)
00373          ast_mutex_lock(&f->lock);
00374       /* Re-initialize the profile */
00375       init_profile(f);
00376       free_numbers(f);
00377       var = ast_variable_browse(cfg, cat);
00378       while(var) {
00379          if (!strcasecmp(var->name, "number")) {
00380             int idx = 0;
00381 
00382             /* Add a new number */
00383             ast_copy_string(numberstr, var->value, sizeof(numberstr));
00384             if ((tmp = strchr(numberstr, ','))) {
00385                *tmp++ = '\0';
00386                timeoutstr = ast_strdupa(tmp);
00387                if ((tmp = strchr(timeoutstr, ','))) {
00388                   *tmp++ = '\0';
00389                   numorder = atoi(tmp);
00390                   if (numorder < 0)
00391                      numorder = 0;
00392                } else 
00393                   numorder = 0;
00394                timeout = atoi(timeoutstr);
00395                if (timeout < 0) 
00396                   timeout = 25;
00397             } else {
00398                timeout = 25;
00399                numorder = 0;
00400             }
00401             
00402             if (!numorder) {  
00403                idx = 1;
00404                AST_LIST_TRAVERSE(&f->numbers, nm, entry) 
00405                   idx++;
00406                numorder = idx;
00407             }
00408             cur = create_followme_number(numberstr, timeout, numorder);
00409             AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
00410          } else {
00411             profile_set_param(f, var->name, var->value, var->lineno, 1);
00412             ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
00413          }
00414          var = var->next;
00415       } /* End while(var) loop */
00416       
00417       if (!new) 
00418          ast_mutex_unlock(&f->lock);
00419       else
00420          AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
00421    }
00422 
00423    ast_config_destroy(cfg);
00424 
00425    AST_RWLIST_UNLOCK(&followmes);
00426 
00427    return 1;
00428 }

static int unload_module ( void   )  [static]

Definition at line 1052 of file app_followme.c.

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

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

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

Definition at line 472 of file app_followme.c.

References AST_CAUSE_NORMAL_CLEARING, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_hangup(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_log(), ast_read(), ast_sched_runq(), ast_sched_wait(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitfor_n(), fm_args::callfromprompt, clear_calling_tree(), findme_user::digts, number::entry, f, ast_channel::hangupcause, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, fm_args::nextindp, fm_args::norecordingprompt, findme_user::ochan, fm_args::optionsprompt, ast_channel::sched, findme_user::state, ast_channel::stream, fm_args::takecall, number::timeout, ast_channel::timingfunc, findme_user::yn, and findme_user::ynidx.

Referenced by findmeexec().

00473 {
00474    struct ast_channel *watchers[256];
00475    int pos;
00476    struct ast_channel *winner;
00477    struct ast_frame *f;
00478    int ctstatus = 0;
00479    int dg;
00480    struct findme_user *tmpuser;
00481    int to = 0;
00482    int livechannels = 0;
00483    int tmpto;
00484    long totalwait = 0, wtd = 0, towas = 0;
00485    char *callfromname;
00486    char *pressbuttonname;
00487 
00488    /* ------------ wait_for_winner_channel start --------------- */ 
00489 
00490    callfromname = ast_strdupa(tpargs->callfromprompt);
00491    pressbuttonname = ast_strdupa(tpargs->optionsprompt); 
00492 
00493    if (AST_LIST_EMPTY(findme_user_list)) {
00494       ast_verb(3, "couldn't reach at this number.\n");
00495       return NULL;
00496    }
00497    
00498    if (!caller) {
00499       ast_verb(3, "Original caller hungup. Cleanup.\n");
00500       clear_calling_tree(findme_user_list);
00501       return NULL;
00502    }
00503    
00504    totalwait = nm->timeout * 1000;
00505    
00506    while (!ctstatus) {
00507       to = 1000;
00508       pos = 1; 
00509       livechannels = 0;
00510       watchers[0] = caller;
00511       
00512       dg = 0;  
00513       winner = NULL; 
00514       AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
00515          if (tmpuser->state >= 0 && tmpuser->ochan) {
00516             if (tmpuser->state == 3) 
00517                tmpuser->digts += (towas - wtd);
00518             if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
00519                ast_verb(3, "We've been waiting for digits longer than we should have.\n");
00520                if (!ast_strlen_zero(namerecloc)) {
00521                   tmpuser->state = 1;
00522                   tmpuser->digts = 0;
00523                   if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) {
00524                      ast_sched_runq(tmpuser->ochan->sched);
00525                   } else {
00526                      ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
00527                      return NULL;
00528                   }                    
00529                } else {
00530                   tmpuser->state = 2;
00531                   tmpuser->digts = 0;
00532                   if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
00533                      ast_sched_runq(tmpuser->ochan->sched);
00534                   else {
00535                      ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
00536                      return NULL;
00537                   }
00538                }
00539             }
00540             if (tmpuser->ochan->stream) {
00541                ast_sched_runq(tmpuser->ochan->sched);
00542                tmpto = ast_sched_wait(tmpuser->ochan->sched);
00543                if (tmpto > 0 && tmpto < to)
00544                   to = tmpto;
00545                else if (tmpto < 0 && !tmpuser->ochan->timingfunc) {
00546                   ast_stopstream(tmpuser->ochan);
00547                   if (tmpuser->state == 1) {
00548                      ast_verb(3, "Playback of the call-from file appears to be done.\n");
00549                      if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) {
00550                         tmpuser->state = 2;
00551                      } else {
00552                         ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc);
00553                         memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
00554                         tmpuser->ynidx = 0;
00555                         if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language))
00556                            tmpuser->state = 3;
00557                         else {
00558                            ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
00559                            return NULL;
00560                         } 
00561                      }
00562                   } else if (tmpuser->state == 2) {
00563                      ast_verb(3, "Playback of name file appears to be done.\n");
00564                      memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
00565                      tmpuser->ynidx = 0;
00566                      if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) {
00567                         tmpuser->state = 3;
00568                         
00569                      } else {
00570                         return NULL;
00571                      } 
00572                   } else if (tmpuser->state == 3) {
00573                      ast_verb(3, "Playback of the next step file appears to be done.\n");
00574                      tmpuser->digts = 0;
00575                   }
00576                }
00577             }
00578             watchers[pos++] = tmpuser->ochan;
00579             livechannels++;
00580          }
00581       }
00582       
00583       tmpto = to;
00584       if (to < 0) {
00585          to = 1000;
00586          tmpto = 1000;
00587       }
00588       towas = to;
00589       winner = ast_waitfor_n(watchers, pos, &to);
00590       tmpto -= to;
00591       totalwait -= tmpto;
00592       wtd = to;   
00593       if (totalwait <= 0) {
00594          ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
00595          clear_calling_tree(findme_user_list);
00596          return NULL;
00597       }
00598       if (winner) {
00599          /* Need to find out which channel this is */
00600          dg = 0;
00601          while ((winner != watchers[dg]) && (dg < 256))
00602             dg++;
00603          AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry)
00604             if (tmpuser->ochan == winner)
00605                break;
00606          f = ast_read(winner);
00607          if (f) {
00608             if (f->frametype == AST_FRAME_CONTROL) {
00609                switch(f->subclass) {
00610                case AST_CONTROL_HANGUP:
00611                   ast_verb(3, "%s received a hangup frame.\n", winner->name);
00612                   if (dg == 0) {
00613                      ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n");
00614                      clear_calling_tree(findme_user_list);
00615                      ctstatus = -1;
00616                   }
00617                   break;
00618                case AST_CONTROL_ANSWER:
00619                   ast_verb(3, "%s answered %s\n", winner->name, caller->name);
00620                   /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 
00621                   winner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00622                   caller->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00623                   ast_verb(3, "Starting playback of %s\n", callfromname);
00624                   if (dg > 0) {
00625                      if (!ast_strlen_zero(namerecloc)) {
00626                         if (!ast_streamfile(winner, callfromname, winner->language)) {
00627                            ast_sched_runq(winner->sched);
00628                            tmpuser->state = 1;
00629                         } else {
00630                            ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
00631                            ast_frfree(f);
00632                            return NULL;
00633                         }           
00634                      } else {       
00635                         tmpuser->state = 2;
00636                         if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
00637                            ast_sched_runq(tmpuser->ochan->sched);
00638                         else {
00639                            ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
00640                            ast_frfree(f);
00641                            return NULL;
00642                         }
00643                      }
00644                   }
00645                   break;
00646                case AST_CONTROL_BUSY:
00647                   ast_verb(3, "%s is busy\n", winner->name);
00648                   break;
00649                case AST_CONTROL_CONGESTION:
00650                   ast_verb(3, "%s is circuit-busy\n", winner->name);
00651                   break;
00652                case AST_CONTROL_RINGING:
00653                   ast_verb(3, "%s is ringing\n", winner->name);
00654                   break;
00655                case AST_CONTROL_PROGRESS:
00656                   ast_verb(3, "%s is making progress passing it to %s\n", winner->name, caller->name);
00657                   break;
00658                case AST_CONTROL_VIDUPDATE:
00659                   ast_verb(3, "%s requested a video update, passing it to %s\n", winner->name, caller->name);
00660                   break;
00661                case AST_CONTROL_SRCUPDATE:
00662                   ast_verb(3, "%s requested a source update, passing it to %s\n", winner->name, caller->name);
00663                   break;
00664                case AST_CONTROL_PROCEEDING:
00665                   ast_verb(3, "%s is proceeding passing it to %s\n", winner->name,caller->name);
00666                   break;
00667                case AST_CONTROL_HOLD:
00668                   ast_verb(3, "Call on %s placed on hold\n", winner->name);
00669                   break;
00670                case AST_CONTROL_UNHOLD:
00671                   ast_verb(3, "Call on %s left from hold\n", winner->name);
00672                   break;
00673                case AST_CONTROL_OFFHOOK:
00674                case AST_CONTROL_FLASH:
00675                   /* Ignore going off hook and flash */
00676                   break;
00677                case -1:
00678                   ast_verb(3, "%s stopped sounds\n", winner->name);
00679                   break;
00680                default:
00681                   ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
00682                   break;
00683                }
00684             } 
00685             if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
00686                if (winner->stream)
00687                   ast_stopstream(winner);
00688                tmpuser->digts = 0;
00689                ast_debug(1, "DTMF received: %c\n",(char) f->subclass);
00690                tmpuser->yn[tmpuser->ynidx] = (char) f->subclass;
00691                tmpuser->ynidx++;
00692                ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
00693                if (tmpuser->ynidx >= ynlongest) {
00694                   ast_debug(1, "reached longest possible match - doing evals\n");
00695                   if (!strcmp(tmpuser->yn, tpargs->takecall)) {
00696                      ast_debug(1, "Match to take the call!\n");
00697                      ast_frfree(f);
00698                      return tmpuser->ochan;  
00699                   }
00700                   if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
00701                      ast_debug(1, "Next in dial plan step requested.\n");
00702                      *status = 1;
00703                      ast_frfree(f);
00704                      return NULL;
00705                   }  
00706                   
00707                }
00708             }
00709             
00710             ast_frfree(f);
00711          } else {
00712             if (winner) {
00713                ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg);                   
00714                if (!dg) {
00715                   clear_calling_tree(findme_user_list);
00716                   return NULL;
00717                } else {
00718                   tmpuser->state = -1;
00719                   ast_hangup(winner);  
00720                   livechannels--;
00721                   ast_debug(1, "live channels left %d\n", livechannels);
00722                   if (!livechannels) {
00723                      ast_verb(3, "no live channels left. exiting.\n");
00724                      return NULL;
00725                   }
00726                }
00727             }
00728          }              
00729          
00730       } else
00731          ast_debug(1, "timed out waiting for action\n");
00732    }
00733    
00734    /* --- WAIT FOR WINNER NUMBER END! -----------*/
00735    return NULL;
00736 }


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

Definition at line 1089 of file app_followme.c.

char* app = "FollowMe" [static]

Definition at line 60 of file app_followme.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1089 of file app_followme.c.

char callfromprompt[PATH_MAX] = "followme/call-from" [static]

Definition at line 155 of file app_followme.c.

const char* defaultmoh = "default" [static]

Default Music-On-Hold Class

Definition at line 152 of file app_followme.c.

char* descrip [static]

Definition at line 62 of file app_followme.c.

int featuredigittimeout = 5000 [static]

Feature Digit Timeout

Definition at line 151 of file app_followme.c.

const char* featuredigittostr [static]

Definition at line 150 of file app_followme.c.

struct ast_app_option followme_opts[128] = { [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG },} [static]

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 Thu Jul 9 13:40:45 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7