Wed Jan 8 2020 09:49:53

Asterisk developer's documentation


app_followme.c File Reference

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

#include "asterisk.h"
#include <signal.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"

Go to the source code of this file.

Data Structures

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

Macros

#define MAX_YN_STRING   20
 

Enumerations

enum  {
  FOLLOWMEFLAG_STATUSMSG = (1 << 0), FOLLOWMEFLAG_RECORDNAME = (1 << 1), FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2), FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
  FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 4)
}
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static struct call_followmealloc_profile (const char *fmname)
 Allocate and initialize followme profile. More...
 
static int app_exec (struct ast_channel *chan, const char *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 (const char *number, int timeout, int numorder)
 Add a new number. More...
 
static void destroy_calling_tree (struct findme_user_listptr *findme_user_list)
 
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 struct call_followmefind_realtime (const char *name)
 
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. More...
 
static int reload (void)
 
static int reload_followme (int reload)
 Reload followme application module. More...
 
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, struct fm_args *tpargs)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Find-Me/Follow-Me Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, }
 
static char * app = "FollowMe"
 
static struct ast_module_infoast_module_info = &__mod_info
 
static char callfromprompt [PATH_MAX] = "followme/call-from"
 
static const char * defaultmoh = "default"
 
static int featuredigittimeout = 5000
 
static const char * featuredigittostr
 
static struct ast_app_option followme_opts [128] = { [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'd' ] = { .flag = FOLLOWMEFLAG_DISABLEHOLDPROMPT }, [ 'I' ] = { .flag = FOLLOWMEFLAG_IGNORE_CONNECTEDLINE }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG }, [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, }
 
static struct followmes followmes = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } , }
 
static char nextindp [MAX_YN_STRING] = "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 takecall [MAX_YN_STRING] = "1"
 

Detailed Description

Macro Definition Documentation

#define MAX_YN_STRING   20

Maximum accept/decline DTMF string plus terminator.

Definition at line 106 of file app_followme.c.

Enumeration Type Documentation

anonymous enum
Enumerator
FOLLOWMEFLAG_STATUSMSG 
FOLLOWMEFLAG_RECORDNAME 
FOLLOWMEFLAG_UNREACHABLEMSG 
FOLLOWMEFLAG_DISABLEHOLDPROMPT 
FOLLOWMEFLAG_IGNORE_CONNECTEDLINE 

Definition at line 185 of file app_followme.c.

Function Documentation

static void __reg_module ( void  )
static

Definition at line 1342 of file app_followme.c.

static void __unreg_module ( void  )
static

Definition at line 1342 of file app_followme.c.

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

Allocate and initialize followme profile.

Definition at line 241 of file app_followme.c.

References ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, ast_mutex_init, call_followme::blnumbers, call_followme::callfromprompt, call_followme::context, f, call_followme::lock, call_followme::moh, call_followme::name, call_followme::nextindp, call_followme::norecordingprompt, call_followme::numbers, call_followme::optionsprompt, call_followme::plsholdprompt, call_followme::sorryprompt, call_followme::statusprompt, call_followme::takecall, and call_followme::wlnumbers.

Referenced by find_realtime(), and reload_followme().

242 {
243  struct call_followme *f;
244 
245  if (!(f = ast_calloc(1, sizeof(*f))))
246  return NULL;
247 
248  ast_mutex_init(&f->lock);
249  ast_copy_string(f->name, fmname, sizeof(f->name));
250  f->moh[0] = '\0';
251  f->context[0] = '\0';
252  ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
253  ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
263  return f;
264 }
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:127
ast_mutex_t lock
Definition: app_followme.c:118
struct call_followme::numbers numbers
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:121
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:129
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:125
char callfromprompt[PATH_MAX]
Definition: app_followme.c:126
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:207
struct call_followme::wlnumbers wlnumbers
Data structure for followme scripts.
Definition: app_followme.c:117
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:209
static char statusprompt[PATH_MAX]
Definition: app_followme.c:211
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:206
struct call_followme::blnumbers blnumbers
static char norecordingprompt[PATH_MAX]
Definition: app_followme.c:208
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:119
static struct ast_format f[]
Definition: format_g726.c:181
char statusprompt[PATH_MAX]
Definition: app_followme.c:130
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:120
char takecall[MAX_YN_STRING]
Definition: app_followme.c:124
#define ast_mutex_init(pmutex)
Definition: lock.h:152
char sorryprompt[PATH_MAX]
Definition: app_followme.c:131
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:210
char optionsprompt[PATH_MAX]
Definition: app_followme.c:128
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:205
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:212
static int app_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 1126 of file app_followme.c.

References ast_channel::_state, call_followme::active, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_connected_line_macro(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_channel_update_connected_line(), ast_config_AST_SPOOL_DIR, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_get_threshold_from_settings(), AST_FEATURE_AUTOMON, AST_FEATURE_REDIRECT, ast_fileexists(), ast_free, ast_hangup(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock, ast_mutex_unlock, ast_party_connected_line_free(), ast_play_and_record(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), ast_channel::caller, call_followme::callfromprompt, fm_args::callfromprompt, fm_args::chan, fm_args::cnumbers, fm_args::connected_in, fm_args::connected_out, call_followme::context, fm_args::context, create_followme_number(), ast_bridge_config::end_bridge_callback, end_bridge_callback(), ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_bridge_callback_data_fixup, end_bridge_callback_data_fixup(), f, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_realtime(), findmeexec(), followme_opts, FOLLOWMEFLAG_DISABLEHOLDPROMPT, FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, fm_args::followmeflags, free_numbers(), ast_channel::language, call_followme::lock, LOG_WARNING, call_followme::moh, fm_args::mohclass, call_followme::name, ast_channel::name, fm_args::namerecloc, call_followme::nextindp, fm_args::nextindp, call_followme::norecordingprompt, fm_args::norecordingprompt, number::number, call_followme::numbers, call_followme::optionsprompt, fm_args::optionsprompt, number::order, fm_args::outbound, fm_args::pending_in_connected_update, fm_args::pending_out_connected_update, call_followme::plsholdprompt, fm_args::plsholdprompt, call_followme::realtime, S_OR, call_followme::sorryprompt, fm_args::sorryprompt, fm_args::status, call_followme::statusprompt, fm_args::statusprompt, call_followme::takecall, fm_args::takecall, THRESHOLD_SILENCE, number::timeout, and ast_channel::uniqueid.

Referenced by load_module().

1127 {
1128  struct fm_args targs = { 0, };
1129  struct ast_bridge_config config;
1130  struct call_followme *f;
1131  struct number *nm, *newnm;
1132  int res = 0;
1133  char *argstr;
1134  struct ast_channel *caller;
1135  struct ast_channel *outbound;
1137  AST_APP_ARG(followmeid);
1138  AST_APP_ARG(options);
1139  );
1140 
1141  if (ast_strlen_zero(data)) {
1142  ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1143  return -1;
1144  }
1145 
1146  argstr = ast_strdupa((char *) data);
1147 
1148  AST_STANDARD_APP_ARGS(args, argstr);
1149 
1150  if (ast_strlen_zero(args.followmeid)) {
1151  ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1152  return -1;
1153  }
1154 
1156  AST_RWLIST_TRAVERSE(&followmes, f, entry) {
1157  if (!strcasecmp(f->name, args.followmeid) && (f->active))
1158  break;
1159  }
1161 
1162  ast_debug(1, "New profile %s.\n", args.followmeid);
1163 
1164  if (!f) {
1165  f = find_realtime(args.followmeid);
1166  }
1167 
1168  if (!f) {
1169  ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1170  return 0;
1171  }
1172 
1173  /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1174  if (args.options)
1175  ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
1176 
1177  /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1178  ast_mutex_lock(&f->lock);
1179  targs.mohclass = ast_strdupa(f->moh);
1180  ast_copy_string(targs.context, f->context, sizeof(targs.context));
1181  ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
1182  ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
1183  ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
1185  ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
1186  ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
1187  ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
1188  ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
1189  /* Copy the numbers we're going to use into another list in case the master list should get modified
1190  (and locked) while we're trying to do a follow-me */
1192  AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1193  newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1194  if (newnm) {
1195  AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
1196  }
1197  }
1198  ast_mutex_unlock(&f->lock);
1199 
1200  /* Answer the call */
1201  if (chan->_state != AST_STATE_UP) {
1202  ast_answer(chan);
1203  }
1204 
1206  ast_stream_and_wait(chan, targs.statusprompt, "");
1207 
1209  int duration = 5;
1210 
1211  snprintf(targs.namerecloc, sizeof(targs.namerecloc), "%s/followme.%s",
1213 
1214  if (ast_play_and_record(chan, "vm-rec-name", targs.namerecloc, 5, "sln", &duration,
1216  goto outrun;
1217  }
1218 
1219  if (!ast_fileexists(targs.namerecloc, NULL, chan->language)) {
1220  targs.namerecloc[0] = '\0';
1221  }
1222  }
1223 
1225  if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
1226  goto outrun;
1227  if (ast_waitstream(chan, "") < 0)
1228  goto outrun;
1229  }
1230  ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
1231 
1232  targs.status = 0;
1233  targs.chan = chan;
1234  ast_channel_lock(chan);
1236  ast_channel_unlock(chan);
1237 
1238  findmeexec(&targs);
1239  if (targs.status != 100) {
1240  ast_moh_stop(chan);
1242  ast_stream_and_wait(chan, targs.sorryprompt, "");
1243  res = 0;
1244  } else {
1245  caller = chan;
1246  outbound = targs.outbound;
1247  /* Bridge the two channels. */
1248 
1249  memset(&config, 0, sizeof(config));
1250  ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1251  ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1252  ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1253  config.end_bridge_callback = end_bridge_callback;
1254  config.end_bridge_callback_data = chan;
1255  config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1256 
1257  ast_moh_stop(caller);
1258  /* Be sure no generators are left on it */
1259  ast_deactivate_generator(caller);
1260  /* Make sure channels are compatible */
1261  res = ast_channel_make_compatible(caller, outbound);
1262  if (res < 0) {
1263  ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
1264  ast_hangup(outbound);
1265  goto outrun;
1266  }
1267 
1268  /* Update connected line to caller if available. */
1269  if (targs.pending_out_connected_update) {
1270  if (ast_channel_connected_line_macro(outbound, caller, &targs.connected_out, 1, 0)) {
1271  ast_channel_update_connected_line(caller, &targs.connected_out, NULL);
1272  }
1273  }
1274 
1275  /* Update connected line to winner if changed. */
1276  if (targs.pending_in_connected_update) {
1277  if (ast_channel_connected_line_macro(caller, outbound, &targs.connected_in, 0, 0)) {
1278  ast_channel_update_connected_line(outbound, &targs.connected_in, NULL);
1279  }
1280  }
1281 
1282  res = ast_bridge_call(caller, outbound, &config);
1283  ast_hangup(outbound);
1284  }
1285 
1286 outrun:
1287  while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) {
1288  ast_free(nm);
1289  }
1290  if (!ast_strlen_zero(targs.namerecloc)) {
1291  unlink(targs.namerecloc);
1292  }
1295 
1296  if (f->realtime) {
1297  /* Not in list */
1298  free_numbers(f);
1299  ast_free(f);
1300  }
1301 
1302  return res;
1303 }
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:218
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path)
Record a file based on input from a channel. Use default accept and cancel DTMF. This function will p...
Definition: app.c:1183
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:160
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
static const char config[]
Definition: cdr_csv.c:57
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
unsigned int pending_out_connected_update
Definition: app_followme.c:153
const ast_string_field uniqueid
Definition: channel.h:787
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_channel * outbound
Definition: app_followme.c:145
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:127
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9085
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:307
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: app.c:2101
struct fm_args::cnumbers cnumbers
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
static char * app
Definition: app_followme.c:103
char callfromprompt[PATH_MAX]
Definition: app_followme.c:159
struct ast_party_connected_line connected_out
Definition: app_followme.c:149
int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
Bridge a call, optionally allowing redirection.
Definition: features.c:3960
ast_mutex_t lock
Definition: app_followme.c:118
#define ast_mutex_lock(a)
Definition: lock.h:155
long timeout
Definition: app_followme.c:111
struct call_followme::numbers numbers
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:121
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2353
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:9618
char namerecloc[PATH_MAX]
Definition: app_followme.c:156
const char * data
Definition: channel.h:755
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:129
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:125
Number structure.
Definition: app_followme.c:109
char callfromprompt[PATH_MAX]
Definition: app_followme.c:126
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
Data structure for followme scripts.
Definition: app_followme.c:117
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
unsigned int pending_in_connected_update
Definition: app_followme.c:151
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
bridge configuration
Definition: channel.h:974
char sorryprompt[PATH_MAX]
Definition: app_followme.c:164
static struct ast_app_option followme_opts[128]
Definition: app_followme.c:199
static void end_bridge_callback(void *data)
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:155
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:158
char optionsprompt[PATH_MAX]
Definition: app_followme.c:161
static struct @350 args
enum ast_channel_state _state
Definition: channel.h:839
const ast_string_field name
Definition: channel.h:787
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:119
char * mohclass
Definition: app_followme.c:142
#define ast_channel_unlock(chan)
Definition: channel.h:2467
struct ast_flags followmeflags
Definition: app_followme.c:165
#define ast_free(a)
Definition: astmm.h:97
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
int order
Definition: app_followme.c:112
static struct ast_format f[]
Definition: format_g726.c:181
char statusprompt[PATH_MAX]
Definition: app_followme.c:130
const char * ast_config_AST_SPOOL_DIR
Definition: asterisk.c:259
static void findmeexec(struct fm_args *tpargs)
Definition: app_followme.c:873
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:3107
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1)
Makes two channel formats compatible.
Definition: channel.c:5970
unsigned int active
Definition: app_followme.c:122
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8443
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:162
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
int status
Definition: app_followme.c:154
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
char number[512]
Definition: app_followme.c:110
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:120
char takecall[MAX_YN_STRING]
Definition: app_followme.c:124
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
struct ast_channel * chan
Definition: app_followme.c:141
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
char sorryprompt[PATH_MAX]
Definition: app_followme.c:131
char takecall[MAX_YN_STRING]
Definition: app_followme.c:157
char optionsprompt[PATH_MAX]
Definition: app_followme.c:128
static struct call_followme * find_realtime(const char *name)
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1880
struct ast_party_connected_line connected_in
Definition: app_followme.c:147
const ast_string_field language
Definition: channel.h:787
#define ast_mutex_unlock(a)
Definition: lock.h:156
char statusprompt[PATH_MAX]
Definition: app_followme.c:163
static void clear_caller ( struct findme_user tmpuser)
static

Definition at line 499 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_channel_lock, ast_channel_unlock, 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(), destroy_calling_tree(), and findmeexec().

500 {
501  struct ast_channel *outbound;
502 
503  if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) {
504  outbound = tmpuser->ochan;
505  ast_channel_lock(outbound);
506  if (!outbound->cdr) {
507  outbound->cdr = ast_cdr_alloc();
508  if (outbound->cdr) {
509  ast_cdr_init(outbound->cdr, outbound);
510  }
511  }
512  if (outbound->cdr) {
513  char tmp[256];
514 
515  snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg);
516  ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
517  ast_cdr_update(outbound);
518  ast_cdr_start(outbound->cdr);
519  ast_cdr_end(outbound->cdr);
520  /* If the cause wasn't handled properly */
521  if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) {
522  ast_cdr_failed(outbound->cdr);
523  }
524  } else {
525  ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
526  }
527  ast_channel_unlock(outbound);
528  ast_hangup(outbound);
529  tmpuser->ochan = NULL;
530  }
531 }
int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
Save the result of the call based on the AST_CAUSE_*.
Definition: cdr.c:790
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
void ast_cdr_failed(struct ast_cdr *cdr)
Fail a call.
Definition: cdr.c:764
void ast_cdr_end(struct ast_cdr *cdr)
End a call.
Definition: cdr.c:933
#define LOG_WARNING
Definition: logger.h:144
struct ast_cdr * cdr
Definition: channel.h:766
int ast_cdr_update(struct ast_channel *chan)
Update CDR on a channel.
Definition: cdr.c:1083
void ast_cdr_start(struct ast_cdr *cdr)
Start a call.
Definition: cdr.c:727
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
Set the last executed application.
Definition: cdr.c:822
struct ast_channel * ochan
Definition: app_followme.c:169
int hangupcause
Definition: channel.h:849
char dialarg[256]
Definition: app_followme.c:175
int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *chan)
Initialize based on a channel.
Definition: cdr.c:897
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition: cdr.c:499
static void clear_calling_tree ( struct findme_user_listptr findme_user_list)
static

Definition at line 533 of file app_followme.c.

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

Referenced by wait_for_winner().

534 {
535  struct findme_user *tmpuser;
536 
537  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
538  clear_caller(tmpuser);
539  tmpuser->cleared = 1;
540  }
541 }
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:499
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
unsigned int cleared
Definition: app_followme.c:179
struct findme_user::@19 entry
static struct number* create_followme_number ( const char *  number,
int  timeout,
int  numorder 
)
static

Add a new number.

Definition at line 307 of file app_followme.c.

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

Referenced by app_exec(), find_realtime(), and reload_followme().

308 {
309  struct number *cur;
310  char *buf = ast_strdupa(number);
311  char *tmp;
312 
313  if (!(cur = ast_calloc(1, sizeof(*cur))))
314  return NULL;
315 
316  cur->timeout = timeout;
317  if ((tmp = strchr(buf, ',')))
318  *tmp = '\0';
319  ast_copy_string(cur->number, buf, sizeof(cur->number));
320  cur->order = numorder;
321  ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
322 
323  return cur;
324 }
long timeout
Definition: app_followme.c:111
Number structure.
Definition: app_followme.c:109
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
int order
Definition: app_followme.c:112
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char number[512]
Definition: app_followme.c:110
static void destroy_calling_tree ( struct findme_user_listptr findme_user_list)
static

Definition at line 543 of file app_followme.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_party_connected_line_free(), clear_caller(), findme_user::cleared, and findme_user::connected.

Referenced by findmeexec().

544 {
545  struct findme_user *fmuser;
546 
547  while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
548  if (!fmuser->cleared) {
549  clear_caller(fmuser);
550  }
552  ast_free(fmuser);
553  }
554  ast_free(findme_user_list);
555 }
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2353
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:499
struct ast_party_connected_line connected
Definition: app_followme.c:171
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
#define ast_free(a)
Definition: astmm.h:97
unsigned int cleared
Definition: app_followme.c:179
struct findme_user::@19 entry
static void end_bridge_callback ( void *  data)
static

Definition at line 1100 of file app_followme.c.

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

Referenced by app_exec().

1101 {
1102  char buf[80];
1103  time_t end;
1104  struct ast_channel *chan = data;
1105 
1106  time(&end);
1107 
1108  ast_channel_lock(chan);
1109  if (chan->cdr->answer.tv_sec) {
1110  snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec);
1111  pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1112  }
1113 
1114  if (chan->cdr->start.tv_sec) {
1115  snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec);
1116  pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1117  }
1118  ast_channel_unlock(chan);
1119 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
struct ast_cdr * cdr
Definition: channel.h:766
const char * data
Definition: channel.h:755
struct timeval answer
Definition: cdr.h:102
#define ast_channel_unlock(chan)
Definition: channel.h:2467
struct timeval start
Definition: cdr.h:100
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
static void end_bridge_callback_data_fixup ( struct ast_bridge_config bconfig,
struct ast_channel originator,
struct ast_channel terminator 
)
static

Definition at line 1121 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

Referenced by app_exec().

1122 {
1123  bconfig->end_bridge_callback_data = originator;
1124 }
void * end_bridge_callback_data
Definition: channel.h:989
static struct call_followme* find_realtime ( const char *  name)
static

Definition at line 1019 of file app_followme.c.

References alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_false(), ast_free, AST_LIST_INSERT_TAIL, ast_load_realtime(), ast_load_realtime_multientry(), ast_mutex_destroy, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_variable_retrieve(), ast_variables_destroy(), create_followme_number(), call_followme::lock, ast_variable::name, ast_variable::next, call_followme::numbers, profile_set_param(), call_followme::realtime, SENTINEL, str, number::timeout, ast_variable::value, and var.

Referenced by app_exec().

1020 {
1021  struct ast_variable *var;
1022  struct ast_variable *v;
1023  struct ast_config *cfg;
1024  const char *catg;
1025  struct call_followme *new_follower;
1026  struct ast_str *str;
1027 
1028  str = ast_str_create(16);
1029  if (!str) {
1030  return NULL;
1031  }
1032 
1033  var = ast_load_realtime("followme", "name", name, SENTINEL);
1034  if (!var) {
1035  ast_free(str);
1036  return NULL;
1037  }
1038 
1039  if (!(new_follower = alloc_profile(name))) {
1040  ast_variables_destroy(var);
1041  ast_free(str);
1042  return NULL;
1043  }
1044 
1045  for (v = var; v; v = v->next) {
1046  if (!strcasecmp(v->name, "active")) {
1047  if (ast_false(v->value)) {
1048  ast_mutex_destroy(&new_follower->lock);
1049  ast_free(new_follower);
1050  ast_variables_destroy(var);
1051  ast_free(str);
1052  return NULL;
1053  }
1054  } else {
1055  profile_set_param(new_follower, v->name, v->value, 0, 0);
1056  }
1057  }
1058 
1059  ast_variables_destroy(var);
1060  new_follower->realtime = 1;
1061 
1062  /* Load numbers */
1063  cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
1064  name, SENTINEL);
1065  if (!cfg) {
1066  ast_mutex_destroy(&new_follower->lock);
1067  ast_free(new_follower);
1068  ast_free(str);
1069  return NULL;
1070  }
1071 
1072  for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
1073  const char *numstr;
1074  const char *timeoutstr;
1075  const char *ordstr;
1076  int timeout;
1077  struct number *cur;
1078 
1079  if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
1080  continue;
1081  }
1082  if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
1083  || sscanf(timeoutstr, "%30d", &timeout) != 1
1084  || timeout < 1) {
1085  timeout = 25;
1086  }
1087  /* This one has to exist; it was part of the query */
1088  ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
1089  ast_str_set(&str, 0, "%s", numstr);
1090  if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
1091  AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
1092  }
1093  }
1094  ast_config_destroy(cfg);
1095 
1096  ast_free(str);
1097  return new_follower;
1098 }
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:307
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2548
ast_mutex_t lock
Definition: app_followme.c:118
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
struct call_followme::numbers numbers
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
const char * str
Definition: app_jack.c:144
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
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.
Definition: app_followme.c:275
Number structure.
Definition: app_followme.c:109
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
#define SENTINEL
Definition: compiler.h:75
const char * value
Definition: config.h:79
Data structure for followme scripts.
Definition: app_followme.c:117
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
const char * name
Definition: config.h:77
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
struct number::@17 entry
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:241
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
struct ast_variable * next
Definition: config.h:82
#define ast_mutex_destroy(a)
Definition: lock.h:154
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2650
static void findmeexec ( struct fm_args tpargs)
static

Definition at line 873 of file app_followme.c.

References accountcode, ast_channel::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_channel_lock, ast_channel_lock_both, ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_free, ast_hangup(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_party_connected_line_free(), ast_request(), ast_string_field_set, ast_verb, ast_channel::caller, ast_channel::cdr, fm_args::chan, clear_caller(), findme_user::cleared, fm_args::cnumbers, findme_user::connected, ast_channel::connected, fm_args::connected_out, fm_args::context, destroy_calling_tree(), findme_user::dialarg, ast_channel::hangupcause, ast_party_caller::id, language, ast_channel::language, LOG_ERROR, LOG_WARNING, musicclass, ast_channel::musicclass, fm_args::namerecloc, ast_channel::nativeformats, number::number, ast_party_id::number, findme_user::ochan, number::order, fm_args::outbound, findme_user::pending_connected_update, fm_args::pending_out_connected_update, S_COR, findme_user::state, fm_args::status, ast_party_number::str, number::timeout, ast_party_number::valid, and wait_for_winner().

Referenced by app_exec().

874 {
875  struct number *nm;
876  struct ast_channel *outbound;
877  struct ast_channel *caller;
878  struct ast_channel *winner = NULL;
879  char dialarg[512];
880  char num[512];
881  int dg, idx;
882  char *rest, *number;
883  struct findme_user *tmpuser;
884  struct findme_user *fmuser;
885  struct findme_user_listptr *findme_user_list;
886 
887  findme_user_list = ast_calloc(1, sizeof(*findme_user_list));
888  if (!findme_user_list) {
889  ast_log(LOG_WARNING, "Failed to allocate memory for findme_user_list\n");
890  return;
891  }
892  AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
893 
894  caller = tpargs->chan;
895  for (idx = 1; !ast_check_hangup(caller); ++idx) {
896  /* Find next followme numbers to dial. */
897  AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
898  if (nm->order == idx) {
899  break;
900  }
901  }
902  if (!nm) {
903  break;
904  }
905 
906  ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout);
907 
908  ast_copy_string(num, nm->number, sizeof(num));
909  for (number = num; number; number = rest) {
910  rest = strchr(number, '&');
911  if (rest) {
912  *rest++ = 0;
913  }
914 
915  /* We check if the extension exists, before creating the ast_channel struct */
916  if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL))) {
917  ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
918  continue;
919  }
920 
921  if (!strcmp(tpargs->context, "")) {
922  snprintf(dialarg, sizeof(dialarg), "%s", number);
923  } else {
924  snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context);
925  }
926 
927  tmpuser = ast_calloc(1, sizeof(*tmpuser));
928  if (!tmpuser) {
929  continue;
930  }
931 
932  outbound = ast_request("Local", ast_best_codec(caller->nativeformats), caller, dialarg, &dg);
933  if (outbound) {
934  ast_channel_lock_both(caller, outbound);
936  ast_channel_inherit_variables(caller, outbound);
937  ast_channel_datastore_inherit(caller, outbound);
938  ast_string_field_set(outbound, language, caller->language);
939  ast_string_field_set(outbound, accountcode, caller->accountcode);
940  ast_string_field_set(outbound, musicclass, caller->musicclass);
941  ast_channel_unlock(outbound);
942  ast_channel_unlock(caller);
943  ast_verb(3, "calling Local/%s\n", dialarg);
944  if (!ast_call(outbound, dialarg, 0)) {
945  tmpuser->ochan = outbound;
946  tmpuser->state = 0;
947  tmpuser->cleared = 0;
948  ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
949  AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
950  } else {
951  ast_verb(3, "couldn't reach at this number.\n");
952  ast_channel_lock(outbound);
953  if (!outbound->cdr) {
954  outbound->cdr = ast_cdr_alloc();
955  }
956  if (outbound->cdr) {
957  char tmp[256];
958 
959  ast_cdr_init(outbound->cdr, outbound);
960  snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
961  ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
962  ast_cdr_update(outbound);
963  ast_cdr_start(outbound->cdr);
964  ast_cdr_end(outbound->cdr);
965  /* If the cause wasn't handled properly */
966  if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) {
967  ast_cdr_failed(outbound->cdr);
968  }
969  } else {
970  ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
971  }
972  ast_channel_unlock(outbound);
973  ast_hangup(outbound);
974  ast_free(tmpuser);
975  }
976  } else {
977  ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
978  ast_free(tmpuser);
979  }
980  }
981 
982  if (AST_LIST_EMPTY(findme_user_list)) {
983  continue;
984  }
985 
986  winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, tpargs);
987  if (!winner) {
988  continue;
989  }
990 
991  /* Destroy losing calls up to the winner. The rest will be destroyed later. */
992  while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
993  if (fmuser->ochan == winner) {
994  /* Pass any connected line info up. */
995  tpargs->connected_out = fmuser->connected;
997  ast_free(fmuser);
998  break;
999  } else {
1000  /* Destroy losing call. */
1001  if (!fmuser->cleared) {
1002  clear_caller(fmuser);
1003  }
1005  ast_free(fmuser);
1006  }
1007  }
1008  break;
1009  }
1010  destroy_calling_tree(findme_user_list);
1011  if (!winner) {
1012  tpargs->status = 1;
1013  } else {
1014  tpargs->status = 100;
1015  tpargs->outbound = winner;
1016  }
1017 }
int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
Save the result of the call based on the AST_CAUSE_*.
Definition: cdr.c:790
static char musicclass[MAX_MUSICCLASS]
Definition: chan_mgcp.c:155
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:383
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
void ast_cdr_failed(struct ast_cdr *cdr)
Fail a call.
Definition: cdr.c:764
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
struct ast_party_connected_line connected
Channel Connected Line ID information.
Definition: channel.h:811
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
unsigned int pending_out_connected_update
Definition: app_followme.c:153
struct ast_channel * outbound
Definition: app_followme.c:145
void ast_cdr_end(struct ast_cdr *cdr)
End a call.
Definition: cdr.c:933
#define LOG_WARNING
Definition: logger.h:144
struct fm_args::cnumbers cnumbers
struct ast_party_connected_line connected_out
Definition: app_followme.c:149
format_t ast_best_codec(format_t fmts)
Pick the best audio codec.
Definition: channel.c:1062
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
struct ast_cdr * cdr
Definition: channel.h:766
long timeout
Definition: app_followme.c:111
format_t nativeformats
Definition: channel.h:852
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2353
char namerecloc[PATH_MAX]
Definition: app_followme.c:156
#define ast_verb(level,...)
Definition: logger.h:243
Number structure.
Definition: app_followme.c:109
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:543
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:499
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2573
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_party_connected_line connected
Definition: app_followme.c:171
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:83
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:108
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:155
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:5400
int ast_cdr_update(struct ast_channel *chan)
Update CDR on a channel.
Definition: cdr.c:1083
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
void ast_cdr_start(struct ast_cdr *cdr)
Start a call.
Definition: cdr.c:727
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2467
const char * ast_cause2str(int state) attribute_pure
Gives the string form of a given cause code.
Definition: channel.c:980
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6241
#define ast_free(a)
Definition: astmm.h:97
int order
Definition: app_followme.c:112
void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
Set the last executed application.
Definition: cdr.c:822
int ast_call(struct ast_channel *chan, char *addr, int timeout)
Make a call.
Definition: channel.c:5761
unsigned int cleared
Definition: app_followme.c:179
static struct ast_channel * wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, char *namerecloc, struct fm_args *tpargs)
Definition: app_followme.c:557
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2473
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
struct ast_channel * ochan
Definition: app_followme.c:169
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8443
int status
Definition: app_followme.c:154
const ast_string_field musicclass
Definition: channel.h:787
char number[512]
Definition: app_followme.c:110
const ast_string_field accountcode
Definition: channel.h:787
int hangupcause
Definition: channel.h:849
struct ast_channel * chan
Definition: app_followme.c:141
struct ast_channel * ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *status)
Requests a channel.
Definition: channel.c:5695
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
char dialarg[256]
Definition: app_followme.c:175
int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *chan)
Initialize based on a channel.
Definition: cdr.c:897
const ast_string_field language
Definition: channel.h:787
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition: cdr.c:499
unsigned int pending_connected_update
Definition: app_followme.c:181
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292
static void free_numbers ( struct call_followme f)
static

Definition at line 218 of file app_followme.c.

References ast_free, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, call_followme::blnumbers, call_followme::numbers, and call_followme::wlnumbers.

Referenced by app_exec(), reload_followme(), and unload_module().

219 {
220  /* Free numbers attached to the profile */
221  struct number *prev;
222 
223  while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
224  /* Free the number */
225  ast_free(prev);
227 
228  while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
229  /* Free the blacklisted number */
230  ast_free(prev);
232 
233  while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
234  /* Free the whitelisted number */
235  ast_free(prev);
237 }
struct call_followme::numbers numbers
Number structure.
Definition: app_followme.c:109
struct call_followme::wlnumbers wlnumbers
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
struct call_followme::blnumbers blnumbers
#define ast_free(a)
Definition: astmm.h:97
struct number::@17 entry
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
static void init_profile ( struct call_followme f)
static

Definition at line 266 of file app_followme.c.

References call_followme::active, ast_copy_string(), and call_followme::moh.

Referenced by reload_followme().

267 {
268  f->active = 1;
269  ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
270 }
unsigned int active
Definition: app_followme.c:122
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:120
static const char * defaultmoh
Definition: app_followme.c:203
static int load_module ( void  )
static

Definition at line 1323 of file app_followme.c.

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

1324 {
1325  if(!reload_followme(0))
1326  return AST_MODULE_LOAD_DECLINE;
1327 
1329 }
static char * app
Definition: app_followme.c:103
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:327
static int app_exec(struct ast_channel *chan, const char *data)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
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 275 of file app_followme.c.

References ast_copy_string(), ast_log(), call_followme::callfromprompt, call_followme::context, LOG_WARNING, call_followme::moh, call_followme::name, call_followme::nextindp, call_followme::norecordingprompt, call_followme::optionsprompt, call_followme::plsholdprompt, call_followme::sorryprompt, call_followme::statusprompt, and call_followme::takecall.

Referenced by find_realtime(), and reload_followme().

276 {
277 
278  if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
279  ast_copy_string(f->moh, val, sizeof(f->moh));
280  else if (!strcasecmp(param, "context"))
281  ast_copy_string(f->context, val, sizeof(f->context));
282  else if (!strcasecmp(param, "takecall"))
283  ast_copy_string(f->takecall, val, sizeof(f->takecall));
284  else if (!strcasecmp(param, "declinecall"))
285  ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
286  else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
288  else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
290  else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
292  else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
294  else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
295  ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
296  else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
297  ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
298  else if (failunknown) {
299  if (linenum >= 0)
300  ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
301  else
302  ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
303  }
304 }
Definition: ast_expr2.c:325
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:127
#define LOG_WARNING
Definition: logger.h:144
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:121
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:129
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:125
char callfromprompt[PATH_MAX]
Definition: app_followme.c:126
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:119
char statusprompt[PATH_MAX]
Definition: app_followme.c:130
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:120
char takecall[MAX_YN_STRING]
Definition: app_followme.c:124
char sorryprompt[PATH_MAX]
Definition: app_followme.c:131
char optionsprompt[PATH_MAX]
Definition: app_followme.c:128
static int reload ( void  )
static

Definition at line 1331 of file app_followme.c.

References reload_followme().

1332 {
1333  reload_followme(1);
1334 
1335  return 0;
1336 }
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:327
static int reload_followme ( int  reload)
static

Reload followme application module.

Definition at line 327 of file app_followme.c.

References call_followme::active, alloc_profile(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, create_followme_number(), f, free_numbers(), init_profile(), ast_variable::lineno, call_followme::lock, LOG_ERROR, LOG_WARNING, ast_variable::name, call_followme::name, ast_variable::next, call_followme::numbers, profile_set_param(), number::timeout, ast_variable::value, and var.

Referenced by load_module(), and reload().

328 {
329  struct call_followme *f;
330  struct ast_config *cfg;
331  char *cat = NULL, *tmp;
332  struct ast_variable *var;
333  struct number *cur, *nm;
334  char *numberstr;
335  int timeout;
336  int numorder;
337  const char *takecallstr;
338  const char *declinecallstr;
339  const char *tmpstr;
340  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
341 
342  if (!(cfg = ast_config_load("followme.conf", config_flags))) {
343  ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
344  return 0;
345  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
346  return 0;
347  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
348  ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
349  return 0;
350  }
351 
353 
354  /* Reset Global Var Values */
355  featuredigittimeout = 5000;
356 
357  /* Mark all profiles as inactive for the moment */
358  AST_RWLIST_TRAVERSE(&followmes, f, entry) {
359  f->active = 0;
360  }
361 
362  featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
363 
365  if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
366  featuredigittimeout = 5000;
367  }
368 
369  if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
370  ast_copy_string(takecall, takecallstr, sizeof(takecall));
371  }
372 
373  if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
374  ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
375  }
376 
377  if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
379  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
381  }
382 
383  if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
385  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
387  }
388 
389 
390  if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
391  ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
392  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
393  ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
394  }
395 
396  if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
397  ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
398  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
399  ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
400  }
401 
402  if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
403  ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
404  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
405  ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
406  }
407 
408  if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
409  ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
410  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
411  ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
412  }
413 
414  /* Chug through config file */
415  while ((cat = ast_category_browse(cfg, cat))) {
416  int new = 0;
417 
418  if (!strcasecmp(cat, "general"))
419  continue;
420 
421  /* Look for an existing one */
422  AST_LIST_TRAVERSE(&followmes, f, entry) {
423  if (!strcasecmp(f->name, cat))
424  break;
425  }
426 
427  ast_debug(1, "New profile %s.\n", cat);
428 
429  if (!f) {
430  /* Make one then */
431  f = alloc_profile(cat);
432  new = 1;
433  }
434 
435  /* Totally fail if we fail to find/create an entry */
436  if (!f)
437  continue;
438 
439  if (!new)
440  ast_mutex_lock(&f->lock);
441  /* Re-initialize the profile */
442  init_profile(f);
443  free_numbers(f);
444  var = ast_variable_browse(cfg, cat);
445  while (var) {
446  if (!strcasecmp(var->name, "number")) {
447  int idx = 0;
448 
449  /* Add a new number */
450  numberstr = ast_strdupa(var->value);
451  if ((tmp = strchr(numberstr, ','))) {
452  *tmp++ = '\0';
453  timeout = atoi(tmp);
454  if (timeout < 0) {
455  timeout = 25;
456  }
457  if ((tmp = strchr(tmp, ','))) {
458  *tmp++ = '\0';
459  numorder = atoi(tmp);
460  if (numorder < 0)
461  numorder = 0;
462  } else
463  numorder = 0;
464  } else {
465  timeout = 25;
466  numorder = 0;
467  }
468 
469  if (!numorder) {
470  idx = 1;
471  AST_LIST_TRAVERSE(&f->numbers, nm, entry)
472  idx++;
473  numorder = idx;
474  }
475  cur = create_followme_number(numberstr, timeout, numorder);
476  if (cur) {
477  AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
478  }
479  } else {
480  profile_set_param(f, var->name, var->value, var->lineno, 1);
481  ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
482  }
483  var = var->next;
484  } /* End while(var) loop */
485 
486  if (!new)
487  ast_mutex_unlock(&f->lock);
488  else
489  AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
490  }
491 
492  ast_config_destroy(cfg);
493 
495 
496  return 1;
497 }
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:218
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
static void init_profile(struct call_followme *f)
Definition: app_followme.c:266
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:307
int lineno
Definition: config.h:87
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
ast_mutex_t lock
Definition: app_followme.c:118
#define ast_mutex_lock(a)
Definition: lock.h:155
long timeout
Definition: app_followme.c:111
struct call_followme::numbers numbers
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
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.
Definition: app_followme.c:275
Number structure.
Definition: app_followme.c:109
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:207
const char * value
Definition: config.h:79
Data structure for followme scripts.
Definition: app_followme.c:117
static int featuredigittimeout
Definition: app_followme.c:202
static int reload(void)
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:209
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
const char * name
Definition: config.h:77
static char statusprompt[PATH_MAX]
Definition: app_followme.c:211
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:206
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static char norecordingprompt[PATH_MAX]
Definition: app_followme.c:208
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:119
static struct ast_format f[]
Definition: format_g726.c:181
if(yyss+yystacksize-1<=yyssp)
Definition: ast_expr2.c:1874
Structure used to handle boolean flags.
Definition: utils.h:200
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:241
static const char * featuredigittostr
Definition: app_followme.c:201
unsigned int active
Definition: app_followme.c:122
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
struct ast_variable * next
Definition: config.h:82
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:210
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:205
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:212
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int unload_module ( void  )
static

Definition at line 1305 of file app_followme.c.

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

1306 {
1307  struct call_followme *f;
1308 
1310 
1311  /* Free Memory. Yeah! I'm free! */
1313  while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1314  free_numbers(f);
1315  ast_free(f);
1316  }
1317 
1319 
1320  return 0;
1321 }
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:218
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static char * app
Definition: app_followme.c:103
struct call_followme::@18 entry
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
Data structure for followme scripts.
Definition: app_followme.c:117
#define ast_free(a)
Definition: astmm.h:97
static struct ast_format f[]
Definition: format_g726.c:181
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
static struct ast_channel* wait_for_winner ( struct findme_user_listptr findme_user_list,
struct number nm,
struct ast_channel caller,
char *  namerecloc,
struct fm_args tpargs 
)
static

Definition at line 557 of file app_followme.c.

References ARRAY_LEN, AST_CAUSE_NORMAL_CLEARING, ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_hangup(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set(), ast_party_connected_line_set_init(), ast_read(), ast_sched_runq(), ast_sched_wait(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfor_n(), fm_args::callfromprompt, clear_calling_tree(), findme_user::connected, fm_args::connected_in, ast_frame::data, ast_frame::datalen, findme_user::digts, f, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE, fm_args::followmeflags, ast_frame::frametype, ast_channel::hangupcause, ast_frame_subclass::integer, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, fm_args::nextindp, fm_args::norecordingprompt, findme_user::ochan, fm_args::optionsprompt, findme_user::pending_connected_update, fm_args::pending_in_connected_update, ast_frame::ptr, ast_channel::sched, findme_user::state, ast_channel::stream, ast_frame::subclass, fm_args::takecall, number::timeout, ast_channel::timingfunc, ast_frame::uint32, findme_user::yn, and findme_user::ynidx.

Referenced by findmeexec().

558 {
560  struct ast_channel *watchers[256];
561  int pos;
562  struct ast_channel *winner;
563  struct ast_frame *f;
564  int ctstatus = 0;
565  int dg;
566  struct findme_user *tmpuser;
567  int to = 0;
568  int livechannels = 0;
569  int tmpto;
570  long totalwait = 0, wtd = 0, towas = 0;
571  char *callfromname;
572  char *pressbuttonname;
573 
574  /* ------------ wait_for_winner_channel start --------------- */
575 
576  callfromname = ast_strdupa(tpargs->callfromprompt);
577  pressbuttonname = ast_strdupa(tpargs->optionsprompt);
578 
579  if (AST_LIST_EMPTY(findme_user_list)) {
580  ast_verb(3, "couldn't reach at this number.\n");
581  return NULL;
582  }
583 
584  if (!caller) {
585  ast_verb(3, "Original caller hungup. Cleanup.\n");
586  clear_calling_tree(findme_user_list);
587  return NULL;
588  }
589 
590  totalwait = nm->timeout * 1000;
591 
592  while (!ctstatus) {
593  to = 1000;
594  pos = 1;
595  livechannels = 0;
596  watchers[0] = caller;
597 
598  dg = 0;
599  winner = NULL;
600  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
601  if (tmpuser->state >= 0 && tmpuser->ochan) {
602  if (tmpuser->state == 3)
603  tmpuser->digts += (towas - wtd);
604  if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
605  ast_verb(3, "We've been waiting for digits longer than we should have.\n");
606  if (!ast_strlen_zero(namerecloc)) {
607  tmpuser->state = 1;
608  tmpuser->digts = 0;
609  if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) {
610  ast_sched_runq(tmpuser->ochan->sched);
611  } else {
612  ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
613  return NULL;
614  }
615  } else {
616  tmpuser->state = 2;
617  tmpuser->digts = 0;
618  if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
619  ast_sched_runq(tmpuser->ochan->sched);
620  else {
621  ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
622  return NULL;
623  }
624  }
625  }
626  if (tmpuser->ochan->stream) {
627  ast_sched_runq(tmpuser->ochan->sched);
628  tmpto = ast_sched_wait(tmpuser->ochan->sched);
629  if (tmpto > 0 && tmpto < to)
630  to = tmpto;
631  else if (tmpto < 0 && !tmpuser->ochan->timingfunc) {
632  ast_stopstream(tmpuser->ochan);
633  if (tmpuser->state == 1) {
634  ast_verb(3, "Playback of the call-from file appears to be done.\n");
635  if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) {
636  tmpuser->state = 2;
637  } else {
638  ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc);
639  memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
640  tmpuser->ynidx = 0;
641  if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language))
642  tmpuser->state = 3;
643  else {
644  ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
645  return NULL;
646  }
647  }
648  } else if (tmpuser->state == 2) {
649  ast_verb(3, "Playback of name file appears to be done.\n");
650  memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
651  tmpuser->ynidx = 0;
652  if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) {
653  tmpuser->state = 3;
654  } else {
655  return NULL;
656  }
657  } else if (tmpuser->state == 3) {
658  ast_verb(3, "Playback of the next step file appears to be done.\n");
659  tmpuser->digts = 0;
660  }
661  }
662  }
663  watchers[pos++] = tmpuser->ochan;
664  livechannels++;
665  }
666  }
667 
668  tmpto = to;
669  if (to < 0) {
670  to = 1000;
671  tmpto = 1000;
672  }
673  towas = to;
674  winner = ast_waitfor_n(watchers, pos, &to);
675  tmpto -= to;
676  totalwait -= tmpto;
677  wtd = to;
678  if (totalwait <= 0) {
679  ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
680  clear_calling_tree(findme_user_list);
681  return NULL;
682  }
683  if (winner) {
684  /* Need to find out which channel this is */
685  for (dg = 0; dg < ARRAY_LEN(watchers); ++dg) {
686  if (winner == watchers[dg]) {
687  break;
688  }
689  }
690  if (dg) {
691  /* The winner is an outgoing channel. */
692  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
693  if (tmpuser->ochan == winner) {
694  break;
695  }
696  }
697  } else {
698  tmpuser = NULL;
699  }
700  f = ast_read(winner);
701  if (f) {
702  if (f->frametype == AST_FRAME_CONTROL) {
703  switch (f->subclass.integer) {
704  case AST_CONTROL_HANGUP:
705  ast_verb(3, "%s received a hangup frame.\n", winner->name);
706  if (f->data.uint32) {
707  winner->hangupcause = f->data.uint32;
708  }
709  if (dg == 0) {
710  ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n");
711  clear_calling_tree(findme_user_list);
712  ctstatus = -1;
713  }
714  break;
715  case AST_CONTROL_ANSWER:
716  ast_verb(3, "%s answered %s\n", winner->name, caller->name);
717  /* If call has been answered, then the eventual hangup is likely to be normal hangup */
720  ast_verb(3, "Starting playback of %s\n", callfromname);
721  if (dg > 0) {
722  if (!ast_strlen_zero(namerecloc)) {
723  if (!ast_streamfile(winner, callfromname, winner->language)) {
724  ast_sched_runq(winner->sched);
725  tmpuser->state = 1;
726  } else {
727  ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
728  ast_frfree(f);
729  return NULL;
730  }
731  } else {
732  tmpuser->state = 2;
733  if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
734  ast_sched_runq(tmpuser->ochan->sched);
735  else {
736  ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
737  ast_frfree(f);
738  return NULL;
739  }
740  }
741  }
742  break;
743  case AST_CONTROL_BUSY:
744  ast_verb(3, "%s is busy\n", winner->name);
745  break;
747  ast_verb(3, "%s is circuit-busy\n", winner->name);
748  break;
749  case AST_CONTROL_RINGING:
750  ast_verb(3, "%s is ringing\n", winner->name);
751  break;
753  ast_verb(3, "%s is making progress\n", winner->name);
754  break;
756  ast_verb(3, "%s requested a video update\n", winner->name);
757  break;
759  ast_verb(3, "%s requested a source update\n", winner->name);
760  break;
762  ast_verb(3, "%s is proceeding\n", winner->name);
763  break;
764  case AST_CONTROL_HOLD:
765  ast_verb(3, "%s placed call on hold\n", winner->name);
766  break;
767  case AST_CONTROL_UNHOLD:
768  ast_verb(3, "%s removed call from hold\n", winner->name);
769  break;
770  case AST_CONTROL_OFFHOOK:
771  case AST_CONTROL_FLASH:
772  /* Ignore going off hook and flash */
773  break;
775  if (!tmpuser) {
776  /*
777  * Hold connected line update from caller until we have a
778  * winner.
779  */
780  ast_verb(3,
781  "%s connected line has changed. Saving it until we have a winner.\n",
782  winner->name);
786  &connected, NULL);
787  tpargs->pending_in_connected_update = 1;
788  }
790  break;
791  }
793  ast_verb(3, "Connected line update from %s prevented.\n",
794  winner->name);
795  } else {
796  ast_verb(3,
797  "%s connected line has changed. Saving it until answer.\n",
798  winner->name);
802  &connected, NULL);
803  tmpuser->pending_connected_update = 1;
804  }
806  }
807  break;
809  /*
810  * Always ignore because the caller is already answered
811  * and is likely listening to MOH.
812  */
813  break;
814  case -1:
815  ast_verb(3, "%s stopped sounds\n", winner->name);
816  break;
817  default:
818  ast_debug(1, "Dunno what to do with control type %d from %s\n",
819  f->subclass.integer, winner->name);
820  break;
821  }
822  }
823  if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
824  if (winner->stream)
825  ast_stopstream(winner);
826  tmpuser->digts = 0;
827  ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
828  if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
829  tmpuser->yn[tmpuser->ynidx++] = (char) f->subclass.integer;
830  }
831  ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
832  if (!strcmp(tmpuser->yn, tpargs->takecall)) {
833  ast_debug(1, "Match to take the call!\n");
834  ast_frfree(f);
835  return tmpuser->ochan;
836  }
837  if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
838  ast_debug(1, "Next in dial plan step requested.\n");
839  ast_frfree(f);
840  return NULL;
841  }
842  }
843 
844  ast_frfree(f);
845  } else {
846  ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n", dg);
847  if (!dg) {
848  /* Caller hung up. */
849  clear_calling_tree(findme_user_list);
850  return NULL;
851  } else {
852  /* Outgoing channel hung up. */
853  tmpuser->state = -1;
854  tmpuser->ochan = NULL;
855  ast_hangup(winner);
856  --livechannels;
857  ast_debug(1, "live channels left %d\n", livechannels);
858  if (!livechannels) {
859  ast_verb(3, "no live channels left. exiting.\n");
860  return NULL;
861  }
862  }
863  }
864  } else {
865  ast_debug(1, "timed out waiting for action\n");
866  }
867  }
868 
869  /* --- WAIT FOR WINNER NUMBER END! -----------*/
870  return NULL;
871 }
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3534
union ast_frame_subclass subclass
Definition: frame.h:146
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
Main Channel structure associated with a channel.
Definition: channel.h:742
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:160
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation...
Definition: channel.c:2329
#define ast_test_flag(p, flag)
Definition: utils.h:63
void * ptr
Definition: frame.h:160
#define LOG_WARNING
Definition: logger.h:144
#define AST_FRAME_DTMF
Definition: frame.h:128
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
char callfromprompt[PATH_MAX]
Definition: app_followme.c:159
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
long timeout
Definition: app_followme.c:111
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2353
#define ast_verb(level,...)
Definition: logger.h:243
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static int featuredigittimeout
Definition: app_followme.c:202
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
unsigned int pending_in_connected_update
Definition: app_followme.c:151
struct ast_party_connected_line connected
Definition: app_followme.c:171
int datalen
Definition: frame.h:148
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:105
struct sched_context * sched
Definition: channel.h:756
int(* timingfunc)(const void *data)
Definition: channel.h:759
char yn[MAX_YN_STRING]
Definition: app_followme.c:177
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
Parse connected line indication frame data.
Definition: channel.c:8886
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:158
char optionsprompt[PATH_MAX]
Definition: app_followme.c:161
static void clear_calling_tree(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:533
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2337
Connected Line/Party information.
Definition: channel.h:401
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_flags followmeflags
Definition: app_followme.c:165
static struct ast_format f[]
Definition: format_g726.c:181
int ast_sched_runq(struct sched_context *con)
Runs the queue.
Definition: sched.c:600
struct ast_channel * ochan
Definition: app_followme.c:169
int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place Determine the number of s...
Definition: sched.c:334
Data structure associated with a single frame of data.
Definition: frame.h:142
int hangupcause
Definition: channel.h:849
static int connected
Definition: cdr_pgsql.c:57
uint32_t uint32
Definition: frame.h:160
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
char takecall[MAX_YN_STRING]
Definition: app_followme.c:157
struct ast_filestream * stream
Definition: channel.h:757
union ast_frame::@172 data
struct findme_user::@19 entry
struct ast_party_connected_line connected_in
Definition: app_followme.c:147
const ast_string_field language
Definition: channel.h:787
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
unsigned int pending_connected_update
Definition: app_followme.c:181

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Find-Me/Follow-Me Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, }
static

Definition at line 1342 of file app_followme.c.

char* app = "FollowMe"
static

Definition at line 103 of file app_followme.c.

Definition at line 1342 of file app_followme.c.

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

Definition at line 207 of file app_followme.c.

const char* defaultmoh = "default"
static

Default Music-On-Hold Class

Definition at line 203 of file app_followme.c.

int featuredigittimeout = 5000
static

Feature Digit Timeout

Definition at line 202 of file app_followme.c.

const char* featuredigittostr
static

Definition at line 201 of file app_followme.c.

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

Definition at line 199 of file app_followme.c.

Referenced by app_exec().

struct followmes followmes = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } , }
static
char nextindp[MAX_YN_STRING] = "2"
static

Definition at line 206 of file app_followme.c.

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

Definition at line 208 of file app_followme.c.

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

Definition at line 209 of file app_followme.c.

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

Definition at line 210 of file app_followme.c.

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

Definition at line 212 of file app_followme.c.

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

Definition at line 211 of file app_followme.c.

char takecall[MAX_YN_STRING] = "1"
static

Definition at line 205 of file app_followme.c.