Wed Aug 20 06:28:51 2008

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"

Include dependency graph for app_followme.c:

Go to the source code of this file.

Data Structures

struct  call_followme
 Data structure for followme scripts. More...
struct  findme_user
struct  fm_args
struct  number
 Number structure. More...

Enumerations

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

Functions

static struct call_followmealloc_profile (const char *fmname)
 Allocate and initialize followme profile.
static int app_exec (struct ast_channel *chan, void *data)
 AST_APP_OPTIONS (followme_opts,{AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG), AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME), AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG),})
 AST_LIST_HEAD_NOLOCK (findme_user_listptr, findme_user)
static AST_LIST_HEAD_STATIC (followmes, call_followme)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Find-Me/Follow-Me Application",.load=load_module,.unload=unload_module,.reload=reload,)
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 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 time_t answer_time
static char * app = "FollowMe"
static char callfromprompt [PATH_MAX] = "followme/call-from"
static const char * defaultmoh = "default"
static char * descrip
static time_t end_time
static int featuredigittimeout = 5000
static const char * featuredigittostr
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 time_t start_time
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 struct call_followme* alloc_profile ( const char *  fmname  )  [static]

Allocate and initialize followme profile.

Definition at line 197 of file app_followme.c.

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

Referenced by reload_followme().

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

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

Definition at line 919 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_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::chan, config, create_followme_number(), f, findmeexec(), FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, fm_args::mohclass, ast_format::name, number::number, option_debug, number::order, pbx_builtin_setvar_helper(), S_OR, and number::timeout.

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

AST_APP_OPTIONS ( followme_opts   ) 

AST_LIST_HEAD_NOLOCK ( findme_user_listptr  ,
findme_user   
)

static AST_LIST_HEAD_STATIC ( followmes  ,
call_followme   
) [static]

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Find-Me/Follow-Me Application"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

static void clear_caller ( struct findme_user tmpuser  )  [static]

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

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

static void clear_calling_tree ( struct findme_user_listptr *  findme_user_list  )  [static]

Definition at line 463 of file app_followme.c.

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

Referenced by wait_for_winner().

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

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

Add a new number.

Definition at line 263 of file app_followme.c.

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

Referenced by app_exec(), and reload_followme().

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

static void findmeexec ( struct fm_args tpargs  )  [static]

Definition at line 773 of file app_followme.c.

References ast_best_codec(), ast_call(), ast_calloc, ast_cause2str(), ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_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_verbose(), fm_args::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, clear_caller(), findme_user::cleared, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::nativeformats, number::number, findme_user::ochan, option_debug, option_verbose, number::order, number::timeout, VERBOSE_PREFIX_3, and wait_for_winner().

Referenced by app_exec().

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

static void free_numbers ( struct call_followme f  )  [static]

Definition at line 173 of file app_followme.c.

References AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, f, and free.

Referenced by reload_followme(), and unload_module().

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

static void init_profile ( struct call_followme f  )  [static]

Definition at line 222 of file app_followme.c.

References f.

Referenced by reload_followme().

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

static int load_module ( void   )  [static]

Definition at line 1094 of file app_followme.c.

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

01095 {
01096    if(!reload_followme())
01097       return AST_MODULE_LOAD_DECLINE;
01098 
01099    return ast_register_application(app, app_exec, synopsis, descrip);
01100 }

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

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

Referenced by reload_followme().

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

static int reload ( void   )  [static]

Definition at line 1102 of file app_followme.c.

References reload_followme().

01103 {
01104    reload_followme();
01105 
01106    return 0;   
01107 }

static int reload_followme ( void   )  [static]

Reload followme application module.

Definition at line 285 of file app_followme.c.

References alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load(), 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(), 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().

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