Thu Mar 25 10:39:19 2010

Asterisk developer's documentation


app_followme.c File Reference

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

#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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, char *language, 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 (void)
 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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .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 142 of file app_followme.c.

00142      {
00143    FOLLOWMEFLAG_STATUSMSG = (1 << 0),
00144    FOLLOWMEFLAG_RECORDNAME = (1 << 1),
00145    FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2)
00146 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1142 of file app_followme.c.

static void __unreg_module ( void   )  [static]

Definition at line 1142 of file app_followme.c.

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

Allocate and initialize followme profile.

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

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

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

Definition at line 947 of file app_followme.c.

References 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_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_REDIRECT, ast_fileexists(), ast_hangup(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_play_and_record(), ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), fm_args::callfromprompt, fm_args::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, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, fm_args::mohclass, ast_channel::name, ast_format::name, fm_args::namerecloc, fm_args::nextindp, fm_args::norecordingprompt, number::number, option_debug, 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.

00948 {
00949    struct fm_args targs = { 0, };
00950    struct ast_bridge_config config;
00951    struct call_followme *f;
00952    struct number *nm, *newnm;
00953    int res = 0;
00954    struct ast_module_user *u;
00955    char *argstr;
00956    char namerecloc[255];
00957    char *fname = NULL;
00958    int duration = 0;
00959    struct ast_channel *caller;
00960    struct ast_channel *outbound;
00961    
00962    AST_DECLARE_APP_ARGS(args,
00963       AST_APP_ARG(followmeid);
00964       AST_APP_ARG(options);
00965    );
00966    
00967    if (ast_strlen_zero(data)) {
00968       ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n",app);
00969       return -1;
00970    }
00971 
00972    if (!(argstr = ast_strdupa((char *)data))) {
00973       ast_log(LOG_ERROR, "Out of memory!\n");
00974       return -1;
00975    }
00976 
00977 
00978    AST_STANDARD_APP_ARGS(args, argstr);
00979    if (ast_strlen_zero(args.followmeid)) {
00980       ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
00981       return -1;
00982    }
00983 
00984    u = ast_module_user_add(chan);
00985 
00986    AST_LIST_LOCK(&followmes);
00987    AST_LIST_TRAVERSE(&followmes, f, entry) {
00988       if (!strcasecmp(f->name, args.followmeid) && (f->active))
00989          break;
00990    }
00991    AST_LIST_UNLOCK(&followmes);
00992 
00993    if (option_debug)
00994       ast_log(LOG_DEBUG, "New profile %s.\n", args.followmeid);
00995    if (!f) { 
00996       ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
00997       res = 0;
00998    } else {
00999       /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
01000 
01001 
01002       if (args.options) 
01003          ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
01004 
01005       /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
01006       ast_mutex_lock(&f->lock);
01007       targs.mohclass = ast_strdupa(f->moh);
01008       ast_copy_string(targs.context, f->context, sizeof(targs.context));
01009       ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
01010       ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
01011       ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
01012       ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt));
01013       ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
01014       ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
01015       ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
01016       ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
01017       /* Copy the numbers we're going to use into another list in case the master list should get modified 
01018                (and locked) while we're trying to do a follow-me */
01019       AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers);
01020       AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
01021          newnm = create_followme_number(nm->number, "", nm->timeout, nm->order);
01022          AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
01023       }
01024       ast_mutex_unlock(&f->lock);
01025 
01026       if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 
01027          ast_stream_and_wait(chan, targs.statusprompt, chan->language, "");
01028 
01029       snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
01030       duration = 5;
01031 
01032       if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 
01033          if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, 128, 0, NULL) < 0)
01034             goto outrun;
01035 
01036       if (!ast_fileexists(namerecloc, NULL, chan->language))
01037          ast_copy_string(namerecloc, "", sizeof(namerecloc));              
01038 
01039       if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
01040          goto outrun;
01041       if (ast_waitstream(chan, "") < 0)
01042          goto outrun;
01043       ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
01044 
01045       targs.status = 0;
01046       targs.chan = chan;
01047       ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
01048 
01049       findmeexec(&targs);     
01050             
01051       AST_LIST_TRAVERSE_SAFE_BEGIN(&targs.cnumbers, nm, entry) {
01052          AST_LIST_REMOVE_CURRENT(&targs.cnumbers, entry);
01053          free(nm);
01054       }
01055       AST_LIST_TRAVERSE_SAFE_END
01056       if (targs.status != 100) {
01057          ast_moh_stop(chan);
01058          if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 
01059             ast_stream_and_wait(chan, targs.sorryprompt, chan->language, "");
01060          res = 0;
01061       } else {
01062          caller = chan;
01063          outbound = targs.outbound;
01064          /* Bridge the two channels. */
01065 
01066          memset(&config,0,sizeof(struct ast_bridge_config));
01067          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01068          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
01069          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
01070 
01071          config.end_bridge_callback = end_bridge_callback;
01072          config.end_bridge_callback_data = chan;
01073          config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
01074 
01075          ast_moh_stop(caller);
01076          /* Be sure no generators are left on it */
01077          ast_deactivate_generator(caller);
01078          /* Make sure channels are compatible */
01079          res = ast_channel_make_compatible(caller, outbound);
01080          if (res < 0) {
01081             ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
01082             ast_hangup(outbound);
01083             goto outrun;
01084          }
01085          res = ast_bridge_call(caller,outbound,&config);
01086          if (outbound)
01087             ast_hangup(outbound);
01088       }
01089    }
01090    outrun:
01091 
01092    if (!ast_strlen_zero(namerecloc)){
01093       fname = alloca(strlen(namerecloc) + 5);
01094       sprintf(fname, "%s.sln", namerecloc);
01095       unlink(fname);
01096    }
01097    
01098    ast_module_user_remove(u);
01099 
01100    return res;
01101 }

static void clear_caller ( struct findme_user tmpuser  )  [static]

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

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

static void clear_calling_tree ( struct findme_user_listptr findme_user_list  )  [static]

Definition at line 462 of file app_followme.c.

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

Referenced by wait_for_winner().

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

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

Add a new number.

Definition at line 262 of file app_followme.c.

References ast_calloc, ast_copy_string(), ast_log(), LOG_DEBUG, option_debug, and number::timeout.

Referenced by app_exec(), and reload_followme().

00263 {
00264    struct number *cur;
00265    char *tmp;
00266    
00267 
00268    if (!(cur = ast_calloc(1, sizeof(*cur))))
00269       return NULL;
00270 
00271    cur->timeout = timeout;
00272    if ((tmp = strchr(number, ','))) 
00273       *tmp = '\0';
00274    ast_copy_string(cur->number, number, sizeof(cur->number));
00275    ast_copy_string(cur->language, language, sizeof(cur->language));
00276    cur->order = numorder;
00277    if (option_debug)
00278       ast_log(LOG_DEBUG, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
00279 
00280    return cur;
00281 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 921 of file app_followme.c.

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

00922 {
00923    char buf[80];
00924    time_t end;
00925    struct ast_channel *chan = data;
00926 
00927    time(&end);
00928 
00929    ast_channel_lock(chan);
00930    if (chan->cdr->answer.tv_sec) {
00931       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec);
00932       pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
00933    }
00934 
00935    if (chan->cdr->start.tv_sec) {
00936       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec);
00937       pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
00938    }
00939    ast_channel_unlock(chan);
00940 }

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

Definition at line 942 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

00943 {
00944    bconfig->end_bridge_callback_data = originator;
00945 }

static void findmeexec ( struct fm_args tpargs  )  [static]

Definition at line 772 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_hangup(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_request(), ast_set_callerid(), ast_strdupa, ast_string_field_set, ast_verbose(), 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, free, ast_channel::language, number::language, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::musicclass, musicclass, fm_args::namerecloc, ast_channel::nativeformats, fm_args::nextindp, number::number, findme_user::ochan, option_debug, option_verbose, number::order, fm_args::outbound, fm_args::status, fm_args::takecall, number::timeout, VERBOSE_PREFIX_3, and wait_for_winner().

Referenced by app_exec().

00773 {
00774    struct number *nm;
00775    struct ast_channel *outbound;
00776    struct ast_channel *caller;
00777    struct ast_channel *winner = NULL;
00778    char dialarg[512];
00779    int dg, idx;
00780    char *rest, *number;
00781    struct findme_user *tmpuser;
00782    struct findme_user *fmuser;
00783    struct findme_user *headuser;
00784    struct findme_user_listptr *findme_user_list;
00785    int status;
00786 
00787    findme_user_list = ast_calloc(1, sizeof(*findme_user_list));      
00788    AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
00789 
00790    /* We're going to figure out what the longest possible string of digits to collect is */
00791    ynlongest = 0;
00792    if (strlen(tpargs->takecall) > ynlongest)
00793       ynlongest = strlen(tpargs->takecall);
00794    if (strlen(tpargs->nextindp) > ynlongest)
00795       ynlongest = strlen(tpargs->nextindp);
00796 
00797    idx = 1;
00798    caller = tpargs->chan;
00799    AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
00800       if (nm->order == idx)
00801          break;
00802 
00803    while (nm) {
00804 
00805       if (option_debug > 1)   
00806          ast_log(LOG_DEBUG, "Number %s timeout %ld\n", nm->number,nm->timeout);
00807 
00808       number = ast_strdupa(nm->number);
00809       if (option_debug > 2)
00810          ast_log(LOG_DEBUG, "examining %s\n", number);
00811       do {
00812          rest = strchr(number, '&');
00813          if (rest) {
00814             *rest = 0;
00815             rest++;
00816          }
00817 
00818          if (!strcmp(tpargs->context, ""))
00819             snprintf(dialarg, sizeof(dialarg), "%s", number);
00820          else
00821             snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context);
00822                
00823          tmpuser = ast_calloc(1, sizeof(*tmpuser));
00824          if (!tmpuser) {
00825             ast_log(LOG_WARNING, "Out of memory!\n");
00826             free(findme_user_list);
00827             return;
00828          }
00829                
00830          outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg);
00831          if (outbound) {
00832             ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num);
00833             ast_channel_inherit_variables(tpargs->chan, outbound);
00834             ast_channel_datastore_inherit(tpargs->chan, outbound);
00835             ast_string_field_set(outbound, language, tpargs->chan->language);
00836             ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode);
00837             ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass);
00838             if (option_verbose > 2)
00839                ast_verbose(VERBOSE_PREFIX_3 "calling %s\n", dialarg);
00840             if (!ast_call(outbound,dialarg,0)) {
00841                tmpuser->ochan = outbound;
00842                tmpuser->state = 0;
00843                tmpuser->cleared = 0;
00844                ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
00845                AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
00846             } else {
00847                if (option_verbose > 2) 
00848                   ast_verbose(VERBOSE_PREFIX_3 "couldn't reach at this number.\n"); 
00849                if (outbound) {
00850                   if (!outbound->cdr) 
00851                      outbound->cdr = ast_cdr_alloc();
00852                   if (outbound->cdr) {
00853                      char tmp[256];
00854 
00855                      ast_cdr_init(outbound->cdr, outbound);
00856                      snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
00857                      ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00858                      ast_cdr_update(outbound);
00859                      ast_cdr_start(outbound->cdr);
00860                      ast_cdr_end(outbound->cdr);
00861                      /* If the cause wasn't handled properly */
00862                      if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
00863                         ast_cdr_failed(outbound->cdr);
00864                   } else {
00865                      ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
00866                      ast_hangup(outbound);
00867                      outbound = NULL;
00868                   }
00869                }
00870                   
00871             }
00872          } else 
00873             ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
00874                
00875          number = rest;
00876       } while (number);
00877             
00878       status = 0; 
00879       if (!AST_LIST_EMPTY(findme_user_list))
00880          winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
00881 
00882       AST_LIST_TRAVERSE_SAFE_BEGIN(findme_user_list, fmuser, entry) {
00883          if (!fmuser->cleared && fmuser->ochan != winner)
00884             clear_caller(fmuser);
00885          AST_LIST_REMOVE_CURRENT(findme_user_list, entry);
00886          free(fmuser);
00887       }
00888       AST_LIST_TRAVERSE_SAFE_END;
00889 
00890       fmuser = NULL;
00891       tmpuser = NULL;
00892       headuser = NULL;  
00893       if (winner)
00894          break;
00895 
00896       if (!caller || ast_check_hangup(caller)) {
00897          tpargs->status = 1;
00898          free(findme_user_list);
00899          return;  
00900       }
00901 
00902       idx++;
00903       AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
00904          if (nm->order == idx)
00905             break;
00906 
00907    }
00908    free(findme_user_list);
00909    if (!winner) 
00910       tpargs->status = 1;
00911    else {
00912       tpargs->status = 100;
00913       tpargs->outbound = winner;
00914    }
00915 
00916    
00917    return;
00918       
00919 }

static void free_numbers ( struct call_followme f  )  [static]

Definition at line 172 of file app_followme.c.

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

Referenced by reload_followme(), and unload_module().

00173 {
00174    /* Free numbers attached to the profile */
00175    struct number *prev;
00176 
00177    while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
00178       /* Free the number */
00179       free(prev);
00180    AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
00181 
00182    while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
00183       /* Free the blacklisted number */
00184       free(prev);
00185    AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
00186 
00187    while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
00188       /* Free the whitelisted number */
00189       free(prev);
00190    AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
00191    
00192 }

static void init_profile ( struct call_followme f  )  [static]

Definition at line 221 of file app_followme.c.

References ast_copy_string(), and f.

Referenced by reload_followme().

00222 {
00223    f->active = 1;
00224    ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
00225 }

static int load_module ( void   )  [static]

Definition at line 1123 of file app_followme.c.

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

01124 {
01125    if(!reload_followme())
01126       return AST_MODULE_LOAD_DECLINE;
01127 
01128    return ast_register_application(app, app_exec, synopsis, descrip);
01129 }

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

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

Referenced by reload_followme().

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

static int reload ( void   )  [static]

Definition at line 1131 of file app_followme.c.

References reload_followme().

01132 {
01133    reload_followme();
01134 
01135    return 0;   
01136 }

static int reload_followme ( void   )  [static]

Reload followme application module.

Definition at line 284 of file app_followme.c.

References alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load(), ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), create_followme_number(), number::entry, f, free_numbers(), init_profile(), LOG_DEBUG, LOG_WARNING, ast_format::name, option_debug, profile_set_param(), number::timeout, and var.

Referenced by load_module(), and reload().

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

static int unload_module ( void   )  [static]

Definition at line 1103 of file app_followme.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_module_user_hangup_all, ast_unregister_application(), number::entry, f, free, and free_numbers().

01104 {
01105    struct call_followme *f;
01106 
01107    ast_module_user_hangup_all();
01108 
01109    ast_unregister_application(app);
01110 
01111    /* Free Memory. Yeah! I'm free! */
01112    AST_LIST_LOCK(&followmes);
01113    while ((f = AST_LIST_REMOVE_HEAD(&followmes, entry))) {
01114       free_numbers(f);
01115       free(f);
01116    }
01117 
01118    AST_LIST_UNLOCK(&followmes);
01119 
01120    return 0;
01121 }

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 475 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_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_verbose(), ast_waitfor_n(), fm_args::callfromprompt, clear_calling_tree(), findme_user::digts, number::entry, f, ast_channel::hangupcause, ast_channel::language, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::name, fm_args::nextindp, fm_args::norecordingprompt, findme_user::ochan, option_debug, option_verbose, fm_args::optionsprompt, ast_channel::sched, findme_user::state, ast_channel::stream, fm_args::takecall, number::timeout, ast_channel::timingfunc, VERBOSE_PREFIX_3, findme_user::yn, and findme_user::ynidx.

Referenced by findmeexec().

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


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1142 of file app_followme.c.

char* app = "FollowMe" [static]

Definition at line 65 of file app_followme.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1142 of file app_followme.c.

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

Definition at line 161 of file app_followme.c.

const char* defaultmoh = "default" [static]

Default Music-On-Hold Class

Definition at line 158 of file app_followme.c.

char* descrip [static]

Definition at line 67 of file app_followme.c.

int featuredigittimeout = 5000 [static]

Feature Digit Timeout

Definition at line 157 of file app_followme.c.

Referenced by load_config().

const char* featuredigittostr [static]

Definition at line 156 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 152 of file app_followme.c.

Referenced by app_exec().

char nextindp[20] = "2" [static]

Definition at line 160 of file app_followme.c.

char norecordingprompt[PATH_MAX] = "followme/no-recording" [static]

Definition at line 162 of file app_followme.c.

char optionsprompt[PATH_MAX] = "followme/options" [static]

Definition at line 163 of file app_followme.c.

char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try" [static]

Definition at line 164 of file app_followme.c.

char sorryprompt[PATH_MAX] = "followme/sorry" [static]

Definition at line 166 of file app_followme.c.

char statusprompt[PATH_MAX] = "followme/status" [static]

Definition at line 165 of file app_followme.c.

char* synopsis = "Find-Me/Follow-Me application" [static]

Definition at line 66 of file app_followme.c.

char takecall[20] = "1" [static]

Definition at line 160 of file app_followme.c.

int ynlongest = 0 [static]

Definition at line 154 of file app_followme.c.


Generated on Thu Mar 25 10:39:19 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7