Sat Aug 6 00:39:34 2011

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

static void __unreg_module ( void   )  [static]

Definition at line 1148 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 953 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.

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

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 927 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.

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

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

Definition at line 948 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

00949 {
00950    bconfig->end_bridge_callback_data = originator;
00951 }

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_exists_extension(), 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       if (option_debug > 1)   
00805          ast_log(LOG_DEBUG, "Number %s timeout %ld\n", nm->number,nm->timeout);
00806 
00807       number = ast_strdupa(nm->number);
00808       if (option_debug > 2)
00809          ast_log(LOG_DEBUG, "examining %s\n", number);
00810       do {
00811          rest = strchr(number, '&');
00812          if (rest) {
00813             *rest = 0;
00814             rest++;
00815          }
00816 
00817          /* We check if that context exists, before creating the ast_channel struct needed */
00818          if (!ast_exists_extension(caller, tpargs->context, number, 1, caller->cid.cid_num)) {
00819             /* XXX Should probably restructure to simply skip this item, instead of returning. XXX */
00820             ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
00821             free(findme_user_list);
00822             return;
00823          }
00824 
00825          if (!strcmp(tpargs->context, ""))
00826             snprintf(dialarg, sizeof(dialarg), "%s", number);
00827          else
00828             snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context);
00829 
00830          tmpuser = ast_calloc(1, sizeof(*tmpuser));
00831          if (!tmpuser) {
00832             free(findme_user_list);
00833             return;
00834          }
00835 
00836          outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg);
00837          if (outbound) {
00838             ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num);
00839             ast_channel_inherit_variables(tpargs->chan, outbound);
00840             ast_channel_datastore_inherit(tpargs->chan, outbound);
00841             ast_string_field_set(outbound, language, tpargs->chan->language);
00842             ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode);
00843             ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass);
00844             if (option_verbose > 2)
00845                ast_verbose(VERBOSE_PREFIX_3 "calling %s\n", dialarg);
00846             if (!ast_call(outbound,dialarg,0)) {
00847                tmpuser->ochan = outbound;
00848                tmpuser->state = 0;
00849                tmpuser->cleared = 0;
00850                ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
00851                AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
00852             } else {
00853                if (option_verbose > 2) 
00854                   ast_verbose(VERBOSE_PREFIX_3 "couldn't reach at this number.\n"); 
00855                if (outbound) {
00856                   if (!outbound->cdr) 
00857                      outbound->cdr = ast_cdr_alloc();
00858                   if (outbound->cdr) {
00859                      char tmp[256];
00860 
00861                      ast_cdr_init(outbound->cdr, outbound);
00862                      snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
00863                      ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00864                      ast_cdr_update(outbound);
00865                      ast_cdr_start(outbound->cdr);
00866                      ast_cdr_end(outbound->cdr);
00867                      /* If the cause wasn't handled properly */
00868                      if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
00869                         ast_cdr_failed(outbound->cdr);
00870                   } else {
00871                      ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
00872                      ast_hangup(outbound);
00873                      outbound = NULL;
00874                   }
00875                }
00876                   
00877             }
00878          } else 
00879             ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
00880                
00881          number = rest;
00882       } while (number);
00883             
00884       status = 0; 
00885       if (!AST_LIST_EMPTY(findme_user_list))
00886          winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
00887 
00888       AST_LIST_TRAVERSE_SAFE_BEGIN(findme_user_list, fmuser, entry) {
00889          if (!fmuser->cleared && fmuser->ochan != winner)
00890             clear_caller(fmuser);
00891          AST_LIST_REMOVE_CURRENT(findme_user_list, entry);
00892          free(fmuser);
00893       }
00894       AST_LIST_TRAVERSE_SAFE_END;
00895 
00896       fmuser = NULL;
00897       tmpuser = NULL;
00898       headuser = NULL;  
00899       if (winner)
00900          break;
00901 
00902       if (!caller || ast_check_hangup(caller)) {
00903          tpargs->status = 1;
00904          free(findme_user_list);
00905          return;  
00906       }
00907 
00908       idx++;
00909       AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
00910          if (nm->order == idx)
00911             break;
00912 
00913    }
00914    free(findme_user_list);
00915    if (!winner) 
00916       tpargs->status = 1;
00917    else {
00918       tpargs->status = 100;
00919       tpargs->outbound = winner;
00920    }
00921 
00922    
00923    return;
00924       
00925 }

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

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

01130 {
01131    if(!reload_followme())
01132       return AST_MODULE_LOAD_DECLINE;
01133 
01134    return ast_register_application(app, app_exec, synopsis, descrip);
01135 }

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

References reload_followme().

01138 {
01139    reload_followme();
01140 
01141    return 0;   
01142 }

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 1109 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().

01110 {
01111    struct call_followme *f;
01112 
01113    ast_module_user_hangup_all();
01114 
01115    ast_unregister_application(app);
01116 
01117    /* Free Memory. Yeah! I'm free! */
01118    AST_LIST_LOCK(&followmes);
01119    while ((f = AST_LIST_REMOVE_HEAD(&followmes, entry))) {
01120       free_numbers(f);
01121       free(f);
01122    }
01123 
01124    AST_LIST_UNLOCK(&followmes);
01125 
01126    return 0;
01127 }

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 1148 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 1148 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.

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 Sat Aug 6 00:39:34 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7