Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Enumerations | Functions | Variables
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"
#include "asterisk/stasis_channels.h"
#include "asterisk/max_forwards.h"
Include dependency graph for app_followme.c:

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
 
#define REC_FORMAT   "sln"
 

Enumerations

enum  {
  FOLLOWMEFLAG_STATUSMSG = (1 << 0), FOLLOWMEFLAG_RECORDNAME = (1 << 1), FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2), FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
  FOLLOWMEFLAG_NOANSWER = (1 << 4), FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5), FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6), FOLLOWMEFLAG_PREDIAL_CALLER = (1 << 7),
  FOLLOWMEFLAG_PREDIAL_CALLEE = (1 << 8)
}
 
enum  { FOLLOWMEFLAG_ARG_PREDIAL_CALLER, FOLLOWMEFLAG_ARG_PREDIAL_CALLEE, FOLLOWMEFLAG_ARG_ARRAY_SIZE }
 

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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void clear_caller (struct findme_user *tmpuser)
 
static void clear_unanswered_calls (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_node (struct findme_user *node)
 
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 struct ast_channelfindmeexec (struct fm_args *tpargs, struct ast_channel *caller)
 
static void free_numbers (struct call_followme *f)
 
static void init_profile (struct call_followme *f, int activate)
 
static int load_module (void)
 Load the module. More...
 
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 void publish_dial_end_event (struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
 
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, 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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, }
 
static char * app = "FollowMe"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static char callfromprompt [PATH_MAX] = "followme/call-from"
 
static char connprompt [PATH_MAX] = ""
 
static const char * defaultmoh = "default"
 
static int enable_callee_prompt = 1
 
static int featuredigittimeout = 5000
 
static const char * featuredigittostr
 
static const struct ast_app_option followme_opts [128] = { [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'B' ] = { .flag = FOLLOWMEFLAG_PREDIAL_CALLER , .arg_index = FOLLOWMEFLAG_ARG_PREDIAL_CALLER + 1 }, [ 'b' ] = { .flag = FOLLOWMEFLAG_PREDIAL_CALLEE , .arg_index = FOLLOWMEFLAG_ARG_PREDIAL_CALLEE + 1 }, [ 'd' ] = { .flag = FOLLOWMEFLAG_DISABLEHOLDPROMPT }, [ 'I' ] = { .flag = FOLLOWMEFLAG_IGNORE_CONNECTEDLINE }, [ 'l' ] = { .flag = FOLLOWMEFLAG_DISABLEOPTIMIZATION }, [ 'N' ] = { .flag = FOLLOWMEFLAG_NOANSWER }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG }, [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, }
 
static struct followmes followmes = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
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

Find-Me Follow-Me application.

Author
BJ Weschke bwesc.nosp@m.hke@.nosp@m.btwte.nosp@m.ch.c.nosp@m.om

Definition in file app_followme.c.

Macro Definition Documentation

◆ MAX_YN_STRING

#define MAX_YN_STRING   20

Maximum accept/decline DTMF string plus terminator.

Definition at line 151 of file app_followme.c.

◆ REC_FORMAT

#define REC_FORMAT   "sln"

Definition at line 67 of file app_followme.c.

Referenced by app_exec().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
FOLLOWMEFLAG_STATUSMSG 
FOLLOWMEFLAG_RECORDNAME 
FOLLOWMEFLAG_UNREACHABLEMSG 
FOLLOWMEFLAG_DISABLEHOLDPROMPT 
FOLLOWMEFLAG_NOANSWER 
FOLLOWMEFLAG_DISABLEOPTIMIZATION 
FOLLOWMEFLAG_IGNORE_CONNECTEDLINE 
FOLLOWMEFLAG_PREDIAL_CALLER 
FOLLOWMEFLAG_PREDIAL_CALLEE 

Definition at line 237 of file app_followme.c.

◆ anonymous enum

anonymous enum
Enumerator
FOLLOWMEFLAG_ARG_PREDIAL_CALLER 
FOLLOWMEFLAG_ARG_PREDIAL_CALLEE 
FOLLOWMEFLAG_ARG_ARRAY_SIZE 

Definition at line 249 of file app_followme.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1655 of file app_followme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1655 of file app_followme.c.

◆ alloc_profile()

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

Allocate and initialize followme profile.

Definition at line 311 of file app_followme.c.

References ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, ast_mutex_init, call_followme::blnumbers, call_followme::lock, call_followme::name, NULL, call_followme::numbers, and call_followme::wlnumbers.

Referenced by find_realtime(), and reload_followme().

312 {
313  struct call_followme *f;
314 
315  if (!(f = ast_calloc(1, sizeof(*f))))
316  return NULL;
317 
318  ast_mutex_init(&f->lock);
319  ast_copy_string(f->name, fmname, sizeof(f->name));
323  return f;
324 }
ast_mutex_t lock
Definition: app_followme.c:163
struct call_followme::numbers numbers
#define NULL
Definition: resample.c:96
struct call_followme::wlnumbers wlnumbers
Data structure for followme scripts.
Definition: app_followme.c:162
struct call_followme::blnumbers blnumbers
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:164
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define ast_mutex_init(pmutex)
Definition: lock.h:184

◆ app_exec()

static int app_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 1339 of file app_followme.c.

References call_followme::active, app, args, ast_answer(), AST_APP_ARG, ast_app_exec_sub(), ast_app_expand_sub_args(), ast_app_parse_options(), ast_autoservice_chan_hangup_peer(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, ast_channel_caller(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_language(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, ast_channel_update_connected_line(), ast_clear_flag, ast_config_AST_SPOOL_DIR, ast_connected_line_copy_from_caller(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, 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_indicate(), ast_indicate_data(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log, ast_max_forwards_get(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock, ast_mutex_unlock, ast_party_connected_line_free(), ast_play_and_record(), ast_replace_subargument_delimiter(), 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::cnumbers, fm_args::connected_in, fm_args::connected_out, call_followme::connprompt, fm_args::connprompt, call_followme::context, fm_args::context, create_followme_number(), call_followme::enable_callee_prompt, fm_args::enable_callee_prompt, 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(), errno, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_realtime(), findmeexec(), followme_opts, FOLLOWMEFLAG_ARG_ARRAY_SIZE, FOLLOWMEFLAG_ARG_PREDIAL_CALLEE, FOLLOWMEFLAG_ARG_PREDIAL_CALLER, FOLLOWMEFLAG_DISABLEHOLDPROMPT, FOLLOWMEFLAG_NOANSWER, FOLLOWMEFLAG_PREDIAL_CALLEE, FOLLOWMEFLAG_PREDIAL_CALLER, FOLLOWMEFLAG_RECORDNAME, FOLLOWMEFLAG_STATUSMSG, FOLLOWMEFLAG_UNREACHABLEMSG, fm_args::followmeflags, free_numbers(), call_followme::lock, LOG_NOTICE, LOG_WARNING, call_followme::moh, fm_args::mohclass, call_followme::name, fm_args::namerecloc, call_followme::nextindp, fm_args::nextindp, call_followme::norecordingprompt, fm_args::norecordingprompt, NULL, number::number, call_followme::numbers, options, call_followme::optionsprompt, fm_args::optionsprompt, number::order, PATH_MAX, fm_args::pending_hold, fm_args::pending_in_connected_update, fm_args::pending_out_connected_update, call_followme::plsholdprompt, fm_args::plsholdprompt, fm_args::predial_callee, call_followme::realtime, REC_FORMAT, call_followme::sorryprompt, fm_args::sorryprompt, call_followme::statusprompt, fm_args::statusprompt, fm_args::suggested_moh, call_followme::takecall, fm_args::takecall, THRESHOLD_SILENCE, and number::timeout.

Referenced by load_module().

1340 {
1341  struct fm_args *targs;
1342  struct ast_bridge_config config;
1343  struct call_followme *f;
1344  struct number *nm, *newnm;
1345  int res = 0;
1346  char *argstr;
1347  struct ast_channel *caller;
1348  struct ast_channel *outbound;
1350  AST_APP_ARG(followmeid);
1352  );
1353  char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
1354  int max_forwards;
1355 
1356  if (ast_strlen_zero(data)) {
1357  ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1358  return -1;
1359  }
1360 
1361  ast_channel_lock(chan);
1362  max_forwards = ast_max_forwards_get(chan);
1363  ast_channel_unlock(chan);
1364 
1365  if (max_forwards <= 0) {
1366  ast_log(LOG_WARNING, "Unable to execute FollowMe on channel %s. Max forwards exceeded\n",
1367  ast_channel_name(chan));
1368  return -1;
1369  }
1370 
1371  argstr = ast_strdupa((char *) data);
1372 
1373  AST_STANDARD_APP_ARGS(args, argstr);
1374 
1375  if (ast_strlen_zero(args.followmeid)) {
1376  ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1377  return -1;
1378  }
1379 
1380  targs = ast_calloc(1, sizeof(*targs));
1381  if (!targs) {
1382  return -1;
1383  }
1384 
1387  if (!strcasecmp(f->name, args.followmeid) && (f->active))
1388  break;
1389  }
1391 
1392  ast_debug(1, "New profile %s.\n", args.followmeid);
1393 
1394  if (!f) {
1395  f = find_realtime(args.followmeid);
1396  }
1397 
1398  if (!f) {
1399  ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1400  ast_free(targs);
1401  return 0;
1402  }
1403 
1404  /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1405  if (args.options) {
1406  ast_app_parse_options(followme_opts, &targs->followmeflags, opt_args, args.options);
1407  }
1408 
1409  /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1410  ast_mutex_lock(&f->lock);
1412  targs->mohclass = ast_strdupa(f->moh);
1413  ast_copy_string(targs->context, f->context, sizeof(targs->context));
1414  ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall));
1415  ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp));
1416  ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt));
1418  ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt));
1419  ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt));
1420  ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt));
1421  ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt));
1422  ast_copy_string(targs->connprompt, f->connprompt, sizeof(targs->connprompt));
1423  /* Copy the numbers we're going to use into another list in case the master list should get modified
1424  (and locked) while we're trying to do a follow-me */
1426  AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1427  newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1428  if (newnm) {
1429  AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry);
1430  }
1431  }
1432  ast_mutex_unlock(&f->lock);
1433 
1434  /* PREDIAL: Preprocess any callee gosub arguments. */
1437  ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE]);
1438  targs->predial_callee =
1439  ast_app_expand_sub_args(chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE]);
1440  }
1441 
1442  /* PREDIAL: Run gosub on the caller's channel */
1445  ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER]);
1446  ast_app_exec_sub(NULL, chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER], 0);
1447  }
1448 
1449  /* Forget the 'N' option if the call is already up. */
1450  if (ast_channel_state(chan) == AST_STATE_UP) {
1452  }
1453 
1456  } else {
1457  /* Answer the call */
1458  if (ast_channel_state(chan) != AST_STATE_UP) {
1459  ast_answer(chan);
1460  }
1461 
1463  ast_stream_and_wait(chan, targs->statusprompt, "");
1464  }
1465 
1467  int duration = 5;
1468 
1469  snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s",
1471  if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration,
1473  goto outrun;
1474  }
1475  if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
1476  targs->namerecloc[0] = '\0';
1477  }
1478  }
1479 
1481  if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) {
1482  goto outrun;
1483  }
1484  if (ast_waitstream(chan, "") < 0)
1485  goto outrun;
1486  }
1487  ast_moh_start(chan, targs->mohclass, NULL);
1488  }
1489 
1490  ast_channel_lock(chan);
1492  ast_channel_unlock(chan);
1493 
1494  outbound = findmeexec(targs, chan);
1495  if (!outbound) {
1497  if (ast_channel_state(chan) != AST_STATE_UP) {
1498  ast_answer(chan);
1499  }
1500  } else {
1501  ast_moh_stop(chan);
1502  }
1503 
1505  ast_stream_and_wait(chan, targs->sorryprompt, "");
1506  }
1507  res = 0;
1508  } else {
1509  caller = chan;
1510 
1511  /* Play "connecting" message to the winner, if configured. */
1512  if (!ast_strlen_zero(targs->connprompt)) {
1513  ast_autoservice_start(caller);
1514  ast_stream_and_wait(outbound, targs->connprompt, "");
1515  ast_autoservice_stop(caller);
1516  }
1517 
1518  /* Bridge the two channels. */
1519 
1520  memset(&config, 0, sizeof(config));
1521  ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1522  ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1523  ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1524  config.end_bridge_callback = end_bridge_callback;
1525  config.end_bridge_callback_data = chan;
1526  config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1527 
1528  /* Update connected line to caller if available. */
1529  if (targs->pending_out_connected_update) {
1530  if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0) &&
1531  ast_channel_connected_line_macro(outbound, caller, &targs->connected_out, 1, 0)) {
1533  }
1534  }
1535 
1537  if (ast_channel_state(caller) != AST_STATE_UP) {
1538  ast_answer(caller);
1539  }
1540  } else {
1541  ast_moh_stop(caller);
1542  }
1543 
1544  /* Be sure no generators are left on it */
1545  ast_deactivate_generator(caller);
1546  /* Make sure channels are compatible */
1547  res = ast_channel_make_compatible(caller, outbound);
1548  if (res < 0) {
1549  ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(caller), ast_channel_name(outbound));
1550  ast_autoservice_chan_hangup_peer(caller, outbound);
1551  goto outrun;
1552  }
1553 
1554  /* Update connected line to winner if changed. */
1555  if (targs->pending_in_connected_update) {
1556  if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0) &&
1557  ast_channel_connected_line_macro(caller, outbound, &targs->connected_in, 0, 0)) {
1559  }
1560  }
1561 
1562  /* Put winner on hold if caller requested. */
1563  if (targs->pending_hold) {
1564  if (ast_strlen_zero(targs->suggested_moh)) {
1565  ast_indicate_data(outbound, AST_CONTROL_HOLD, NULL, 0);
1566  } else {
1568  targs->suggested_moh, strlen(targs->suggested_moh) + 1);
1569  }
1570  }
1571 
1572  res = ast_bridge_call(caller, outbound, &config);
1573  }
1574 
1575 outrun:
1576  while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) {
1577  ast_free(nm);
1578  }
1579  if (!ast_strlen_zero(targs->namerecloc)) {
1580  int ret;
1581  char fn[PATH_MAX + sizeof(REC_FORMAT)];
1582 
1583  snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc,
1584  REC_FORMAT);
1585  ret = unlink(fn);
1586  if (ret != 0) {
1587  ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n",
1588  fn, errno, strerror(errno));
1589  } else {
1590  ast_debug(2, "deleted recorded prompt %s.\n", fn);
1591  }
1592  }
1593  ast_free((char *) targs->predial_callee);
1596  ast_free(targs);
1597 
1598  if (f->realtime) {
1599  /* Not in list */
1600  free_numbers(f);
1601  ast_free(f);
1602  }
1603 
1604  return res;
1605 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:288
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:211
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:10435
struct ast_party_caller caller
Channel Caller ID information.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
unsigned int pending_out_connected_update
Definition: app_followme.c:199
char connprompt[PATH_MAX]
Definition: app_followme.c:179
char * config
Definition: conf2ael.c:66
const char * ast_app_expand_sub_args(struct ast_channel *chan, const char *args)
Add missing context/exten to subroutine argument string.
Definition: main/app.c:351
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:174
#define REC_FORMAT
Definition: app_followme.c:67
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
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:9189
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:384
struct fm_args::cnumbers cnumbers
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static char * app
Definition: app_followme.c:148
char callfromprompt[PATH_MAX]
Definition: app_followme.c:210
struct ast_party_connected_line connected_out
Definition: app_followme.c:195
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
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:716
char connprompt[PATH_MAX]
Definition: app_followme.c:216
ast_mutex_t lock
Definition: app_followme.c:163
#define ast_mutex_lock(a)
Definition: lock.h:187
long timeout
Definition: app_followme.c:156
struct call_followme::numbers numbers
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:166
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
char namerecloc[PATH_MAX]
Definition: app_followme.c:207
const char * args
#define NULL
Definition: resample.c:96
const char * data
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:176
unsigned int enable_callee_prompt
Definition: app_followme.c:170
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:7876
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:172
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
char callfromprompt[PATH_MAX]
Definition: app_followme.c:173
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
void ast_replace_subargument_delimiter(char *s)
Replace &#39;^&#39; in a string with &#39;,&#39;.
Definition: main/utils.c:2095
#define ast_log
Definition: astobj2.c:42
unsigned int pending_hold
Definition: app_followme.c:201
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6817
Data structure for followme scripts.
Definition: app_followme.c:162
unsigned int pending_in_connected_update
Definition: app_followme.c:197
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
bridge configuration
Definition: channel.h:1077
char sorryprompt[PATH_MAX]
Definition: app_followme.c:215
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static void end_bridge_callback(void *data)
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:206
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
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: main/app.c:2906
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:209
char optionsprompt[PATH_MAX]
Definition: app_followme.c:212
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel&#39;s connected line information...
Definition: channel.c:10539
Channel datastore data for max forwards.
Definition: max_forwards.c:29
int errno
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: main/app.c:1997
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:7866
#define LOG_NOTICE
Definition: logger.h:263
#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:164
char * mohclass
Definition: app_followme.c:188
#define ast_channel_unlock(chan)
Definition: channel.h:2946
struct ast_flags followmeflags
Definition: app_followme.c:217
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
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:1814
int order
Definition: app_followme.c:157
char statusprompt[PATH_MAX]
Definition: app_followme.c:177
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
char suggested_moh[MAX_MUSICCLASS]
Definition: app_followme.c:205
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:342
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2902
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
unsigned int active
Definition: app_followme.c:167
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
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:8389
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:213
const char * ast_channel_name(const struct ast_channel *chan)
const char * predial_callee
Definition: app_followme.c:191
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
char number[512]
Definition: app_followme.c:155
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:165
char takecall[MAX_YN_STRING]
Definition: app_followme.c:171
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:370
const char * ast_channel_language(const struct ast_channel *chan)
Definition: search.h:40
#define PATH_MAX
Definition: asterisk.h:40
static struct test_options options
static const struct ast_app_option followme_opts[128]
Definition: app_followme.c:267
char sorryprompt[PATH_MAX]
Definition: app_followme.c:178
char takecall[MAX_YN_STRING]
Definition: app_followme.c:208
static struct ast_channel * findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
char optionsprompt[PATH_MAX]
Definition: app_followme.c:175
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:1996
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
struct ast_party_connected_line connected_in
Definition: app_followme.c:193
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define AST_APP_ARG(name)
Define an application argument.
char statusprompt[PATH_MAX]
Definition: app_followme.c:214
unsigned int enable_callee_prompt
Definition: app_followme.c:203

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1655 of file app_followme.c.

◆ clear_caller()

static void clear_caller ( struct findme_user tmpuser)
static

Definition at line 603 of file app_followme.c.

References ast_hangup(), NULL, and findme_user::ochan.

Referenced by clear_unanswered_calls(), destroy_calling_node(), and wait_for_winner().

604 {
605  struct ast_channel *outbound;
606 
607  if (!tmpuser->ochan) {
608  /* Call already cleared. */
609  return;
610  }
611 
612  outbound = tmpuser->ochan;
613  ast_hangup(outbound);
614  tmpuser->ochan = NULL;
615 }
Main Channel structure associated with a channel.
#define NULL
Definition: resample.c:96
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct ast_channel * ochan
Definition: app_followme.c:221

◆ clear_unanswered_calls()

static void clear_unanswered_calls ( struct findme_user_listptr findme_user_list)
static

Definition at line 617 of file app_followme.c.

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

Referenced by wait_for_winner().

618 {
619  struct findme_user *tmpuser;
620 
621  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
622  if (!tmpuser->answered) {
623  clear_caller(tmpuser);
624  }
625  }
626 }
unsigned int answered
Definition: app_followme.c:231
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:603
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Definition: search.h:40

◆ create_followme_number()

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

Add a new number.

Definition at line 384 of file app_followme.c.

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

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

385 {
386  struct number *cur;
387  char *buf = ast_strdupa(number);
388  char *tmp;
389 
390  if (!(cur = ast_calloc(1, sizeof(*cur))))
391  return NULL;
392 
393  cur->timeout = timeout;
394  if ((tmp = strchr(buf, ',')))
395  *tmp = '\0';
396  ast_copy_string(cur->number, buf, sizeof(cur->number));
397  cur->order = numorder;
398  ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
399 
400  return cur;
401 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
long timeout
Definition: app_followme.c:156
#define NULL
Definition: resample.c:96
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int order
Definition: app_followme.c:157
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char number[512]
Definition: app_followme.c:155

◆ destroy_calling_node()

static void destroy_calling_node ( struct findme_user node)
static

Definition at line 628 of file app_followme.c.

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

Referenced by destroy_calling_tree(), and findmeexec().

629 {
630  clear_caller(node);
632  ast_free(node);
633 }
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:603
struct ast_party_connected_line connected
Definition: app_followme.c:223
#define ast_free(a)
Definition: astmm.h:182

◆ destroy_calling_tree()

static void destroy_calling_tree ( struct findme_user_listptr findme_user_list)
static

Definition at line 635 of file app_followme.c.

References AST_LIST_REMOVE_HEAD, and destroy_calling_node().

Referenced by findmeexec().

636 {
637  struct findme_user *fmuser;
638 
639  while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
640  destroy_calling_node(fmuser);
641  }
642 }
static void destroy_calling_node(struct findme_user *node)
Definition: app_followme.c:628
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
Definition: search.h:40

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 1318 of file app_followme.c.

References ast_channel_get_duration(), ast_channel_get_up_time(), ast_channel_lock, ast_channel_unlock, buf, ast_channel::data, end, and pbx_builtin_setvar_helper().

Referenced by app_exec().

1319 {
1320  char buf[80];
1321  time_t end;
1322  struct ast_channel *chan = data;
1323 
1324  time(&end);
1325 
1326  ast_channel_lock(chan);
1327  snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
1328  pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1329  snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
1330  pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1331  ast_channel_unlock(chan);
1332 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition: channel.c:2854
const char * data
char * end
Definition: eagi_proxy.c:73
#define ast_channel_unlock(chan)
Definition: channel.h:2946
int ast_channel_get_duration(struct ast_channel *chan)
Obtain how long the channel since the channel was created.
Definition: channel.c:2839
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...

◆ end_bridge_callback_data_fixup()

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

Definition at line 1334 of file app_followme.c.

References ast_bridge_config::end_bridge_callback_data.

Referenced by app_exec().

1335 {
1336  bconfig->end_bridge_callback_data = originator;
1337 }
void * end_bridge_callback_data
Definition: channel.h:1092

◆ find_realtime()

static struct call_followme* find_realtime ( const char *  name)
static

Definition at line 1236 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(), init_profile(), call_followme::lock, ast_variable::name, ast_variable::next, NULL, call_followme::numbers, profile_set_param(), call_followme::realtime, SENTINEL, str, number::timeout, ast_variable::value, and var.

Referenced by app_exec().

1237 {
1238  struct ast_variable *var;
1239  struct ast_variable *v;
1240  struct ast_config *cfg;
1241  const char *catg;
1242  struct call_followme *new_follower;
1243  struct ast_str *str;
1244 
1245  str = ast_str_create(16);
1246  if (!str) {
1247  return NULL;
1248  }
1249 
1250  var = ast_load_realtime("followme", "name", name, SENTINEL);
1251  if (!var) {
1252  ast_free(str);
1253  return NULL;
1254  }
1255 
1256  if (!(new_follower = alloc_profile(name))) {
1257  ast_variables_destroy(var);
1258  ast_free(str);
1259  return NULL;
1260  }
1261  init_profile(new_follower, 0);
1262 
1263  for (v = var; v; v = v->next) {
1264  if (!strcasecmp(v->name, "active")) {
1265  if (ast_false(v->value)) {
1266  ast_mutex_destroy(&new_follower->lock);
1267  ast_free(new_follower);
1268  ast_variables_destroy(var);
1269  ast_free(str);
1270  return NULL;
1271  }
1272  } else {
1273  profile_set_param(new_follower, v->name, v->value, 0, 0);
1274  }
1275  }
1276 
1277  ast_variables_destroy(var);
1278  new_follower->realtime = 1;
1279 
1280  /* Load numbers */
1281  cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
1282  name, SENTINEL);
1283  if (!cfg) {
1284  ast_mutex_destroy(&new_follower->lock);
1285  ast_free(new_follower);
1286  ast_free(str);
1287  return NULL;
1288  }
1289 
1290  for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
1291  const char *numstr;
1292  const char *timeoutstr;
1293  const char *ordstr;
1294  int timeout;
1295  struct number *cur;
1296 
1297  if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
1298  continue;
1299  }
1300  if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
1301  || sscanf(timeoutstr, "%30d", &timeout) != 1
1302  || timeout < 1) {
1303  timeout = 25;
1304  }
1305  /* This one has to exist; it was part of the query */
1306  ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
1307  ast_str_set(&str, 0, "%s", numstr);
1308  if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
1309  AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
1310  }
1311  }
1312  ast_config_destroy(cfg);
1313 
1314  ast_free(str);
1315  return new_follower;
1316 }
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
struct ast_variable * next
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:384
static int timeout
Definition: cdr_mysql.c:86
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
ast_mutex_t lock
Definition: app_followme.c:163
struct call_followme::numbers numbers
const char * str
Definition: app_jack.c:147
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
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:348
Number structure.
Definition: app_followme.c:154
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:1065
#define SENTINEL
Definition: compiler.h:87
Data structure for followme scripts.
Definition: app_followme.c:162
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:311
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
Definition: search.h:40
#define ast_mutex_destroy(a)
Definition: lock.h:186
static void init_profile(struct call_followme *f, int activate)
Definition: app_followme.c:326
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ findmeexec()

static struct ast_channel* findmeexec ( struct fm_args tpargs,
struct ast_channel caller 
)
static

Definition at line 1033 of file app_followme.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_call(), ast_calloc, ast_cause2str(), ast_channel_caller(), ast_channel_connected(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_language(), ast_channel_lock_both, ast_channel_musicclass(), ast_channel_nativeformats(), ast_channel_publish_dial(), ast_channel_req_accountcodes(), AST_CHANNEL_REQUESTOR_BRIDGE_PEER, ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_free, AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, ast_max_forwards_decrement(), ast_pre_call(), ast_request(), ast_strlen_zero, ast_test_flag, ast_verb, fm_args::cnumbers, findme_user::connected, fm_args::connected_out, fm_args::context, destroy_calling_node(), destroy_calling_tree(), findme_user::dialarg, FOLLOWMEFLAG_DISABLEOPTIMIZATION, fm_args::followmeflags, LOG_ERROR, LOG_WARNING, NULL, number::number, findme_user::ochan, number::order, findme_user::pending_connected_update, fm_args::pending_out_connected_update, fm_args::predial_callee, S_COR, findme_user::state, number::timeout, and wait_for_winner().

Referenced by app_exec().

1034 {
1035  struct number *nm;
1036  struct ast_channel *winner = NULL;
1037  char num[512];
1038  int dg, idx;
1039  char *rest, *number;
1040  struct findme_user *tmpuser;
1041  struct findme_user *fmuser;
1042  struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1044 
1045  for (idx = 1; !ast_check_hangup(caller); ++idx) {
1046  /* Find next followme numbers to dial. */
1047  AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
1048  if (nm->order == idx) {
1049  break;
1050  }
1051  }
1052  if (!nm) {
1053  ast_verb(3, "No more steps left.\n");
1054  break;
1055  }
1056 
1057  ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout);
1058 
1059  /*
1060  * Put all active outgoing channels into autoservice.
1061  *
1062  * This needs to be done because ast_exists_extension() may put
1063  * the caller into autoservice.
1064  */
1065  AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1066  if (tmpuser->ochan) {
1067  ast_autoservice_start(tmpuser->ochan);
1068  }
1069  }
1070 
1071  /* Create all new outgoing calls */
1072  ast_copy_string(num, nm->number, sizeof(num));
1073  for (number = num; number; number = rest) {
1074  struct ast_channel *outbound;
1075 
1076  rest = strchr(number, '&');
1077  if (rest) {
1078  *rest++ = 0;
1079  }
1080 
1081  /* We check if the extension exists, before creating the ast_channel struct */
1082  if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(ast_channel_caller(caller)->id.number.valid, ast_channel_caller(caller)->id.number.str, NULL))) {
1083  ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
1084  continue;
1085  }
1086 
1087  tmpuser = ast_calloc(1, sizeof(*tmpuser));
1088  if (!tmpuser) {
1089  continue;
1090  }
1091 
1092  if (ast_strlen_zero(tpargs->context)) {
1093  snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s%s",
1094  number,
1096  ? "/n" : "/m");
1097  } else {
1098  snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s@%s%s",
1099  number, tpargs->context,
1101  ? "/n" : "/m");
1102  }
1103 
1104  outbound = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller,
1105  tmpuser->dialarg, &dg);
1106  if (!outbound) {
1107  ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
1108  tmpuser->dialarg, ast_cause2str(dg));
1109  ast_free(tmpuser);
1110  continue;
1111  }
1112 
1113  ast_channel_lock_both(caller, outbound);
1115  ast_channel_inherit_variables(caller, outbound);
1116  ast_channel_datastore_inherit(caller, outbound);
1117  ast_max_forwards_decrement(outbound);
1118  ast_channel_language_set(outbound, ast_channel_language(caller));
1120  ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
1121  ast_channel_unlock(outbound);
1122  ast_channel_unlock(caller);
1123 
1124  tmpuser->ochan = outbound;
1125  tmpuser->state = 0;
1126  AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry);
1127  }
1128 
1129  /*
1130  * PREDIAL: Run gosub on all of the new callee channels
1131  *
1132  * We run the callee predial before ast_call() in case the user
1133  * wishes to do something on the newly created channels before
1134  * the channel does anything important.
1135  */
1136  if (tpargs->predial_callee && !AST_LIST_EMPTY(&new_user_list)) {
1137  /* Put caller into autoservice. */
1138  ast_autoservice_start(caller);
1139 
1140  /* Run predial on all new outgoing calls. */
1141  AST_LIST_TRAVERSE(&new_user_list, tmpuser, entry) {
1142  ast_pre_call(tmpuser->ochan, tpargs->predial_callee);
1143  }
1144 
1145  /* Take caller out of autoservice. */
1146  if (ast_autoservice_stop(caller)) {
1147  /*
1148  * Caller hungup.
1149  *
1150  * Destoy all new outgoing calls.
1151  */
1152  while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
1153  destroy_calling_node(tmpuser);
1154  }
1155 
1156  /* Take all active outgoing channels out of autoservice. */
1157  AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1158  if (tmpuser->ochan) {
1159  ast_autoservice_stop(tmpuser->ochan);
1160  }
1161  }
1162  break;
1163  }
1164  }
1165 
1166  /* Start all new outgoing calls */
1167  AST_LIST_TRAVERSE_SAFE_BEGIN(&new_user_list, tmpuser, entry) {
1168  ast_verb(3, "calling Local/%s\n", tmpuser->dialarg);
1169  if (ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) {
1170  ast_verb(3, "couldn't reach at this number.\n");
1172 
1173  /* Destroy this failed new outgoing call. */
1174  destroy_calling_node(tmpuser);
1175  continue;
1176  }
1177 
1178  ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL);
1179  }
1181 
1182  /* Take all active outgoing channels out of autoservice. */
1183  AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1184  if (tmpuser->ochan && ast_autoservice_stop(tmpuser->ochan)) {
1185  /* Existing outgoing call hungup. */
1187  destroy_calling_node(tmpuser);
1188  }
1189  }
1191 
1192  if (AST_LIST_EMPTY(&new_user_list)) {
1193  /* No new channels remain at this order level. If there were any at all. */
1194  continue;
1195  }
1196 
1197  /* Add new outgoing channels to the findme list. */
1198  AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry);
1199 
1200  winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
1201  if (!winner) {
1202  /* Remove all dead outgoing nodes. */
1203  AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1204  if (!tmpuser->ochan) {
1206  destroy_calling_node(tmpuser);
1207  }
1208  }
1210  continue;
1211  }
1212 
1213  /* Destroy losing calls up to the winner. The rest will be destroyed later. */
1214  while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) {
1215  if (fmuser->ochan == winner) {
1216  /*
1217  * Pass any connected line info up.
1218  *
1219  * NOTE: This code must be in line with destroy_calling_node().
1220  */
1221  tpargs->connected_out = fmuser->connected;
1223  ast_free(fmuser);
1224  break;
1225  } else {
1226  /* Destroy losing call. */
1227  destroy_calling_node(fmuser);
1228  }
1229  }
1230  break;
1231  }
1232  destroy_calling_tree(&findme_user_list);
1233  return winner;
1234 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
Main Channel structure associated with a channel.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
unsigned int pending_out_connected_update
Definition: app_followme.c:199
static void destroy_calling_node(struct findme_user *node)
Definition: app_followme.c:628
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define LOG_WARNING
Definition: logger.h:274
struct fm_args::cnumbers cnumbers
char dialarg[768]
Definition: app_followme.c:227
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6553
struct ast_party_connected_line connected_out
Definition: app_followme.c:195
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
long timeout
Definition: app_followme.c:156
#define NULL
Definition: resample.c:96
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6444
Number structure.
Definition: app_followme.c:154
static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:635
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2373
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_connected_line connected
Definition: app_followme.c:223
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#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:85
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:206
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
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:4179
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition: channel.c:6536
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6526
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
static struct ast_channel * wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs)
Definition: app_followme.c:644
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#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:2946
struct ast_flags followmeflags
Definition: app_followme.c:217
const char * ast_cause2str(int state) attribute_pure
Gives the string form of a given cause code.
Definition: channel.c:612
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:6866
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int order
Definition: app_followme.c:157
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:251
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2952
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
struct ast_channel * ochan
Definition: app_followme.c:221
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
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:8389
const char * predial_callee
Definition: app_followme.c:191
char number[512]
Definition: app_followme.c:155
const char * ast_channel_language(const struct ast_channel *chan)
Definition: search.h:40
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
const char * ast_channel_musicclass(const struct ast_channel *chan)
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:782
unsigned int pending_connected_update
Definition: app_followme.c:233

◆ free_numbers()

static void free_numbers ( struct call_followme f)
static

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

289 {
290  /* Free numbers attached to the profile */
291  struct number *prev;
292 
293  while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
294  /* Free the number */
295  ast_free(prev);
297 
298  while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
299  /* Free the blacklisted number */
300  ast_free(prev);
302 
303  while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
304  /* Free the whitelisted number */
305  ast_free(prev);
307 }
struct call_followme::numbers numbers
Number structure.
Definition: app_followme.c:154
struct call_followme::wlnumbers wlnumbers
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
struct call_followme::blnumbers blnumbers
#define ast_free(a)
Definition: astmm.h:182
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
Definition: search.h:40

◆ init_profile()

static void init_profile ( struct call_followme f,
int  activate 
)
static

Definition at line 326 of file app_followme.c.

References call_followme::active, ast_copy_string(), call_followme::callfromprompt, call_followme::connprompt, call_followme::context, call_followme::enable_callee_prompt, enable_callee_prompt, call_followme::moh, 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().

327 {
329  f->context[0] = '\0';
330  ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
331  ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
332  ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
340  if (activate) {
341  f->active = 1;
342  }
343 }
static char connprompt[PATH_MAX]
Definition: app_followme.c:282
char connprompt[PATH_MAX]
Definition: app_followme.c:179
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:174
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:166
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:176
unsigned int enable_callee_prompt
Definition: app_followme.c:170
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:172
char callfromprompt[PATH_MAX]
Definition: app_followme.c:173
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:276
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:278
static char statusprompt[PATH_MAX]
Definition: app_followme.c:280
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:274
static char norecordingprompt[PATH_MAX]
Definition: app_followme.c:277
char statusprompt[PATH_MAX]
Definition: app_followme.c:177
unsigned int active
Definition: app_followme.c:167
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:165
char takecall[MAX_YN_STRING]
Definition: app_followme.c:171
static const char * defaultmoh
Definition: app_followme.c:271
char sorryprompt[PATH_MAX]
Definition: app_followme.c:178
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:279
char optionsprompt[PATH_MAX]
Definition: app_followme.c:175
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:273
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:281
static int enable_callee_prompt
Definition: app_followme.c:275

◆ load_module()

static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 1635 of file app_followme.c.

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

Referenced by reload().

1636 {
1637  if(!reload_followme(0))
1638  return AST_MODULE_LOAD_DECLINE;
1639 
1641 }
static char * app
Definition: app_followme.c:148
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:404
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
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:626

◆ profile_set_param()

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

References ast_copy_string(), ast_log, ast_true(), call_followme::callfromprompt, call_followme::connprompt, call_followme::context, call_followme::enable_callee_prompt, 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().

349 {
350 
351  if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
352  ast_copy_string(f->moh, val, sizeof(f->moh));
353  else if (!strcasecmp(param, "context"))
354  ast_copy_string(f->context, val, sizeof(f->context));
355  else if (!strcasecmp(param, "enable_callee_prompt"))
357  else if (!strcasecmp(param, "takecall"))
358  ast_copy_string(f->takecall, val, sizeof(f->takecall));
359  else if (!strcasecmp(param, "declinecall"))
360  ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
361  else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
363  else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
365  else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
367  else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
369  else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
370  ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
371  else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
372  ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
373  else if (!strcasecmp(param, "followme-connecting-prompt") || !strcasecmp(param, "connecting_prompt")) {
374  ast_copy_string(f->connprompt, val, sizeof(f->connprompt));
375  } else if (failunknown) {
376  if (linenum >= 0)
377  ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
378  else
379  ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
380  }
381 }
char connprompt[PATH_MAX]
Definition: app_followme.c:179
Definition: ast_expr2.c:325
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:174
#define LOG_WARNING
Definition: logger.h:274
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:166
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:176
unsigned int enable_callee_prompt
Definition: app_followme.c:170
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:172
char callfromprompt[PATH_MAX]
Definition: app_followme.c:173
#define ast_log
Definition: astobj2.c:42
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:164
char statusprompt[PATH_MAX]
Definition: app_followme.c:177
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:165
char takecall[MAX_YN_STRING]
Definition: app_followme.c:171
char sorryprompt[PATH_MAX]
Definition: app_followme.c:178
char optionsprompt[PATH_MAX]
Definition: app_followme.c:175

◆ publish_dial_end_event()

static void publish_dial_end_event ( struct ast_channel in,
struct findme_user_listptr findme_user_list,
struct ast_channel exception,
const char *  status 
)
static

Definition at line 592 of file app_followme.c.

References ast_channel_publish_dial(), AST_LIST_TRAVERSE, NULL, and findme_user::ochan.

Referenced by wait_for_winner().

593 {
594  struct findme_user *tmpuser;
595 
596  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
597  if (tmpuser->ochan && tmpuser->ochan != exception) {
598  ast_channel_publish_dial(in, tmpuser->ochan, NULL, status);
599  }
600  }
601 }
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define NULL
Definition: resample.c:96
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_channel * ochan
Definition: app_followme.c:221
Definition: search.h:40
jack_status_t status
Definition: app_jack.c:146

◆ reload()

static int reload ( void  )
static

Definition at line 1643 of file app_followme.c.

References AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ASTERISK_GPL_KEY, load_module(), reload_followme(), and unload_module().

1644 {
1645  reload_followme(1);
1646 
1647  return 0;
1648 }
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:404

◆ reload_followme()

static int reload_followme ( int  reload)
static

Reload followme application module.

Definition at line 404 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_strlen_zero, ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, copy(), create_followme_number(), free_numbers(), init_profile(), ast_variable::lineno, call_followme::lock, LOG_ERROR, LOG_WARNING, ast_variable::name, call_followme::name, ast_variable::next, NULL, call_followme::numbers, profile_set_param(), number::timeout, tmp(), ast_variable::value, and var.

Referenced by load_module(), and reload().

405 {
406  struct call_followme *f;
407  struct ast_config *cfg;
408  char *cat = NULL, *tmp;
409  struct ast_variable *var;
410  struct number *cur, *nm;
411  int timeout;
412  int numorder;
413  const char* enable_callee_prompt_str;
414  const char *takecallstr;
415  const char *declinecallstr;
416  const char *tmpstr;
417  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
418 
419  if (!(cfg = ast_config_load("followme.conf", config_flags))) {
420  ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
421  return 0;
422  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
423  return 0;
424  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
425  ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
426  return 0;
427  }
428 
430 
431  /* Reset Global Var Values */
432  featuredigittimeout = 5000;
433 
434  /* Mark all profiles as inactive for the moment */
436  f->active = 0;
437  }
438 
439  featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
440 
442  if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
443  featuredigittimeout = 5000;
444  }
445 
446  if ((enable_callee_prompt_str = ast_variable_retrieve(cfg, "general",
447  "enable_callee_prompt")) &&
448  !ast_strlen_zero(enable_callee_prompt_str)) {
449  enable_callee_prompt = ast_true(enable_callee_prompt_str);
450  }
451 
452  if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
453  ast_copy_string(takecall, takecallstr, sizeof(takecall));
454  }
455 
456  if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
457  ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
458  }
459 
460  if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
462  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
464  }
465 
466  if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
468  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
470  }
471 
472 
473  if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
474  ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
475  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
476  ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
477  }
478 
479  if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
480  ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
481  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
482  ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
483  }
484 
485  if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
486  ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
487  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
488  ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
489  }
490 
491  if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
492  ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
493  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
494  ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
495  }
496 
497  if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting-prompt")) && !ast_strlen_zero(tmpstr)) {
498  ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
499  } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting_prompt")) && !ast_strlen_zero(tmpstr)) {
500  ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
501  }
502 
503 
504  /* Chug through config file */
505  while ((cat = ast_category_browse(cfg, cat))) {
506  int new = 0;
507 
508  if (!strcasecmp(cat, "general"))
509  continue;
510 
511  /* Look for an existing one */
513  if (!strcasecmp(f->name, cat))
514  break;
515  }
516 
517  ast_debug(1, "New profile %s.\n", cat);
518 
519  if (!f) {
520  /* Make one then */
521  f = alloc_profile(cat);
522  new = 1;
523  }
524 
525  /* Totally fail if we fail to find/create an entry */
526  if (!f)
527  continue;
528 
529  if (!new)
530  ast_mutex_lock(&f->lock);
531  /* Re-initialize the profile */
532  init_profile(f, 1);
533  free_numbers(f);
534  var = ast_variable_browse(cfg, cat);
535  while (var) {
536  if (!strcasecmp(var->name, "number")) {
537  int idx = 0;
538  char copy[strlen(var->value) + 1];
539  char *numberstr;
540 
541  /* Add a new number */
542  strcpy(copy, var->value); /* safe */
543  numberstr = copy;
544  if ((tmp = strchr(numberstr, ','))) {
545  *tmp++ = '\0';
546  timeout = atoi(tmp);
547  if (timeout < 0) {
548  timeout = 25;
549  }
550  if ((tmp = strchr(tmp, ','))) {
551  *tmp++ = '\0';
552  numorder = atoi(tmp);
553  if (numorder < 0)
554  numorder = 0;
555  } else
556  numorder = 0;
557  } else {
558  timeout = 25;
559  numorder = 0;
560  }
561 
562  if (!numorder) {
563  idx = 1;
565  idx++;
566  numorder = idx;
567  }
568  cur = create_followme_number(numberstr, timeout, numorder);
569  if (cur) {
571  }
572  } else {
573  profile_set_param(f, var->name, var->value, var->lineno, 1);
574  ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
575  }
576  var = var->next;
577  } /* End while(var) loop */
578 
579  if (!new)
580  ast_mutex_unlock(&f->lock);
581  else
583  }
584 
585  ast_config_destroy(cfg);
586 
588 
589  return 1;
590 }
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:288
struct ast_variable * next
static char connprompt[PATH_MAX]
Definition: app_followme.c:282
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define LOG_WARNING
Definition: logger.h:274
#define CONFIG_STATUS_FILEINVALID
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:384
static int timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
#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.
#define var
Definition: ast_expr2f.c:614
ast_mutex_t lock
Definition: app_followme.c:163
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_mutex_lock(a)
Definition: lock.h:187
struct call_followme::numbers numbers
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
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:348
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:276
#define ast_config_load(filename, flags)
Load a config file.
Data structure for followme scripts.
Definition: app_followme.c:162
static int featuredigittimeout
Definition: app_followme.c:270
static int reload(void)
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:278
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
static char statusprompt[PATH_MAX]
Definition: app_followme.c:280
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:274
#define CONFIG_STATUS_FILEUNCHANGED
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static char norecordingprompt[PATH_MAX]
Definition: app_followme.c:277
#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:164
Structure used to handle boolean flags.
Definition: utils.h:199
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:311
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static const char * featuredigittostr
Definition: app_followme.c:269
unsigned int active
Definition: app_followme.c:167
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
Definition: search.h:40
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:279
static void init_profile(struct call_followme *f, int activate)
Definition: app_followme.c:326
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:273
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:281
static int enable_callee_prompt
Definition: app_followme.c:275
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1607 of file app_followme.c.

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

Referenced by reload().

1608 {
1609  struct call_followme *f;
1610 
1612 
1613  /* Free Memory. Yeah! I'm free! */
1615  while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1616  free_numbers(f);
1617  ast_free(f);
1618  }
1619 
1621 
1622  return 0;
1623 }
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:288
#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:148
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
Data structure for followme scripts.
Definition: app_followme.c:162
#define ast_free(a)
Definition: astmm.h:182
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
Definition: search.h:40

◆ wait_for_winner()

static struct ast_channel* wait_for_winner ( struct findme_user_listptr findme_user_list,
struct number nm,
struct ast_channel caller,
struct fm_args tpargs 
)
static

Definition at line 644 of file app_followme.c.

References findme_user::answered, ARRAY_LEN, AST_CAUSE_NORMAL_CLEARING, ast_channel_hangupcause_set(), ast_channel_language(), ast_channel_name(), ast_channel_publish_dial(), ast_channel_sched(), ast_channel_stream(), ast_channel_timingfunc(), 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_PVT_CAUSE_CODE, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_string(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_indicate_data(), 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_caller(), clear_unanswered_calls(), findme_user::connected, fm_args::connected_in, ast_frame::data, ast_frame::datalen, findme_user::digts, fm_args::enable_callee_prompt, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE, fm_args::followmeflags, ast_frame::frametype, ast_frame_subclass::integer, LOG_NOTICE, LOG_WARNING, fm_args::namerecloc, fm_args::nextindp, fm_args::norecordingprompt, NULL, findme_user::ochan, fm_args::optionsprompt, findme_user::pending_connected_update, fm_args::pending_hold, fm_args::pending_in_connected_update, ast_frame::ptr, publish_dial_end_event(), findme_user::state, ast_frame::subclass, fm_args::suggested_moh, fm_args::takecall, number::timeout, ast_frame::uint32, findme_user::yn, and findme_user::ynidx.

Referenced by findmeexec().

645 {
647  struct ast_channel *watchers[256];
648  int pos;
649  struct ast_channel *winner;
650  struct ast_frame *f;
651  struct findme_user *tmpuser;
652  int to = 0;
653  int livechannels;
654  int tmpto;
655  long totalwait = 0, wtd = 0, towas = 0;
656  char *callfromname;
657  char *pressbuttonname;
658 
659  /* ------------ wait_for_winner_channel start --------------- */
660 
661  callfromname = ast_strdupa(tpargs->callfromprompt);
662  pressbuttonname = ast_strdupa(tpargs->optionsprompt);
663 
664  totalwait = nm->timeout * 1000;
665 
666  for (;;) {
667  to = 1000;
668  pos = 1;
669  livechannels = 0;
670  watchers[0] = caller;
671 
672  winner = NULL;
673  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
674  if (!tmpuser->ochan) {
675  continue;
676  }
677  if (tmpuser->state == 3) {
678  tmpuser->digts += (towas - wtd);
679  }
680  if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
681  ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n",
682  ast_channel_name(tmpuser->ochan));
683  if (tpargs->enable_callee_prompt) {
684  if (!ast_strlen_zero(tpargs->namerecloc)) {
685  tmpuser->state = 1;
686  tmpuser->digts = 0;
687  if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
689  } else {
690  ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
691  clear_caller(tmpuser);
692  continue;
693  }
694  } else {
695  tmpuser->state = 2;
696  tmpuser->digts = 0;
697  if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
699  else {
700  ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
701  clear_caller(tmpuser);
702  continue;
703  }
704  }
705  } else {
706  tmpuser->state = 3;
707  }
708  }
709  if (ast_channel_stream(tmpuser->ochan)) {
711  tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan));
712  if (tmpto > 0 && tmpto < to)
713  to = tmpto;
714  else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
715  ast_stopstream(tmpuser->ochan);
716  switch (tmpuser->state) {
717  case 1:
718  ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n",
719  ast_channel_name(tmpuser->ochan));
720  if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) {
721  tmpuser->state = 2;
722  } else {
723  ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n",
724  ast_channel_name(tmpuser->ochan), tpargs->namerecloc);
725  memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
726  tmpuser->ynidx = 0;
727  if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
728  tmpuser->state = 3;
729  else {
730  ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
731  clear_caller(tmpuser);
732  continue;
733  }
734  }
735  break;
736  case 2:
737  ast_verb(3, "<%s> Playback of name file appears to be done.\n",
738  ast_channel_name(tmpuser->ochan));
739  memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
740  tmpuser->ynidx = 0;
741  if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
742  tmpuser->state = 3;
743  } else {
744  clear_caller(tmpuser);
745  continue;
746  }
747  break;
748  case 3:
749  ast_verb(3, "<%s> Playback of the next step file appears to be done.\n",
750  ast_channel_name(tmpuser->ochan));
751  tmpuser->digts = 0;
752  break;
753  default:
754  break;
755  }
756  }
757  }
758  watchers[pos++] = tmpuser->ochan;
759  livechannels++;
760  }
761  if (!livechannels) {
762  ast_verb(3, "No live channels left for this step.\n");
763  return NULL;
764  }
765 
766  tmpto = to;
767  towas = to;
768  winner = ast_waitfor_n(watchers, pos, &to);
769  tmpto -= to;
770  totalwait -= tmpto;
771  wtd = to;
772  if (totalwait <= 0) {
773  ast_verb(3, "We've hit our timeout for this step. Dropping unanswered calls and starting the next step.\n");
774  clear_unanswered_calls(findme_user_list);
775  return NULL;
776  }
777  if (winner) {
778  /* Need to find out which channel this is */
779  if (winner != caller) {
780  /* The winner is an outgoing channel. */
781  AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
782  if (tmpuser->ochan == winner) {
783  break;
784  }
785  }
786  } else {
787  tmpuser = NULL;
788  }
789 
790  f = ast_read(winner);
791  if (f) {
792  if (f->frametype == AST_FRAME_CONTROL) {
793  switch (f->subclass.integer) {
794  case AST_CONTROL_HANGUP:
795  ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner));
796  if (f->data.uint32) {
798  }
799  if (!tmpuser) {
800  ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
801  publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL");
802  ast_frfree(f);
803  return NULL;
804  }
805  clear_caller(tmpuser);
806  break;
807  case AST_CONTROL_ANSWER:
808  if (!tmpuser) {
809  /* The caller answered? We want an outgoing channel to answer. */
810  break;
811  }
812  ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
813  ast_channel_publish_dial(caller, winner, NULL, "ANSWER");
814  publish_dial_end_event(caller, findme_user_list, winner, "CANCEL");
815  tmpuser->answered = 1;
816  /* If call has been answered, then the eventual hangup is likely to be normal hangup */
819  if (tpargs->enable_callee_prompt) {
820  ast_verb(3, "Starting playback of %s\n", callfromname);
821  if (!ast_strlen_zero(tpargs->namerecloc)) {
822  if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) {
824  tmpuser->state = 1;
825  } else {
826  ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
827  clear_caller(tmpuser);
828  }
829  } else {
830  tmpuser->state = 2;
831  if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
833  else {
834  ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
835  clear_caller(tmpuser);
836  }
837  }
838  } else {
839  ast_verb(3, "Skip playback of caller name / norecording\n");
840  tmpuser->state = 2;
841  }
842  break;
843  case AST_CONTROL_BUSY:
844  ast_verb(3, "%s is busy\n", ast_channel_name(winner));
845  if (tmpuser) {
846  /* Outbound call was busy. Drop it. */
847  ast_channel_publish_dial(caller, winner, NULL, "BUSY");
848  clear_caller(tmpuser);
849  }
850  break;
852  ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
853  if (tmpuser) {
854  /* Outbound call was congested. Drop it. */
855  ast_channel_publish_dial(caller, winner, NULL, "CONGESTION");
856  clear_caller(tmpuser);
857  }
858  break;
859  case AST_CONTROL_RINGING:
860  ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
861  ast_channel_publish_dial(caller, winner, NULL, "RINGING");
862  break;
864  ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
865  ast_channel_publish_dial(caller, winner, NULL, "PROGRESS");
866  break;
868  ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
869  break;
871  ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
872  break;
874  ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
875  ast_channel_publish_dial(caller, winner, NULL, "PROCEEDING");
876  break;
877  case AST_CONTROL_HOLD:
878  ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
879  if (!tmpuser) {
880  /* Caller placed outgoing calls on hold. */
881  tpargs->pending_hold = 1;
882  if (f->data.ptr) {
884  sizeof(tpargs->suggested_moh));
885  } else {
886  tpargs->suggested_moh[0] = '\0';
887  }
888  } else {
889  /*
890  * Outgoing call placed caller on hold.
891  *
892  * Ignore because the outgoing call should not be able to place
893  * the caller on hold until after they are bridged.
894  */
895  }
896  break;
897  case AST_CONTROL_UNHOLD:
898  ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
899  if (!tmpuser) {
900  /* Caller removed outgoing calls from hold. */
901  tpargs->pending_hold = 0;
902  } else {
903  /*
904  * Outgoing call removed caller from hold.
905  *
906  * Ignore because the outgoing call should not be able to place
907  * the caller on hold until after they are bridged.
908  */
909  }
910  break;
911  case AST_CONTROL_OFFHOOK:
912  case AST_CONTROL_FLASH:
913  /* Ignore going off hook and flash */
914  break;
917  ast_verb(3, "Connected line update from %s prevented.\n",
918  ast_channel_name(winner));
919  break;
920  }
921  if (!tmpuser) {
922  /*
923  * Hold connected line update from caller until we have a
924  * winner.
925  */
926  ast_verb(3,
927  "%s connected line has changed. Saving it until we have a winner.\n",
928  ast_channel_name(winner));
932  &connected, NULL);
933  tpargs->pending_in_connected_update = 1;
934  }
936  } else {
937  ast_verb(3,
938  "%s connected line has changed. Saving it until answer.\n",
939  ast_channel_name(winner));
943  &connected, NULL);
944  tmpuser->pending_connected_update = 1;
945  }
947  }
948  break;
950  /*
951  * Ignore because we are masking the FollowMe search progress to
952  * the caller.
953  */
954  break;
956  ast_indicate_data(caller, f->subclass.integer, f->data.ptr, f->datalen);
957  break;
958  case -1:
959  ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
960  break;
961  default:
962  ast_debug(1, "Dunno what to do with control type %d from %s\n",
963  f->subclass.integer, ast_channel_name(winner));
964  break;
965  }
966  }
967  if (!tpargs->enable_callee_prompt && tmpuser) {
968  ast_debug(1, "Taking call with no prompt\n");
969  ast_frfree(f);
970  return tmpuser->ochan;
971  }
972  if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
973  int cmp_len;
974 
975  if (ast_channel_stream(winner))
976  ast_stopstream(winner);
977  tmpuser->digts = 0;
978  ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
979  if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
980  tmpuser->yn[tmpuser->ynidx++] = f->subclass.integer;
981  } else {
982  /* Discard oldest digit. */
983  memmove(tmpuser->yn, tmpuser->yn + 1,
984  sizeof(tmpuser->yn) - 2 * sizeof(tmpuser->yn[0]));
985  tmpuser->yn[ARRAY_LEN(tmpuser->yn) - 2] = f->subclass.integer;
986  }
987  ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
988  cmp_len = strlen(tpargs->takecall);
989  if (cmp_len <= tmpuser->ynidx
990  && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->takecall)) {
991  ast_debug(1, "Match to take the call!\n");
992  ast_frfree(f);
993  return tmpuser->ochan;
994  }
995  cmp_len = strlen(tpargs->nextindp);
996  if (cmp_len <= tmpuser->ynidx
997  && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->nextindp)) {
998  ast_debug(1, "Declined to take the call.\n");
999  clear_caller(tmpuser);
1000  }
1001  }
1002 
1003  ast_frfree(f);
1004  } else {
1005  ast_debug(1, "we didn't get a frame. hanging up.\n");
1006  if (!tmpuser) {
1007  /* Caller hung up. */
1008  ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
1009  return NULL;
1010  }
1011  /* Outgoing channel hung up. */
1012  ast_channel_publish_dial(caller, winner, NULL, "NOANSWER");
1013  clear_caller(tmpuser);
1014  }
1015  } else {
1016  ast_debug(1, "timed out waiting for action\n");
1017  }
1018  }
1019 
1020  /* Unreachable. */
1021 }
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:3166
Main Channel structure associated with a channel.
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:211
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
Definition: app_followme.c:592
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:755
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:2045
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define LOG_WARNING
Definition: logger.h:274
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
char callfromprompt[PATH_MAX]
Definition: app_followme.c:210
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
long timeout
Definition: app_followme.c:156
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
unsigned int answered
Definition: app_followme.c:231
char namerecloc[PATH_MAX]
Definition: app_followme.c:207
static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:617
#define NULL
Definition: resample.c:96
#define AST_FRAME_DTMF
#define ast_verb(level,...)
Definition: logger.h:463
struct ast_frame_subclass subclass
#define ast_strlen_zero(foo)
Definition: strings.h:52
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:603
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
unsigned int pending_hold
Definition: app_followme.c:201
static int featuredigittimeout
Definition: app_followme.c:270
unsigned int pending_in_connected_update
Definition: app_followme.c:197
struct ast_party_connected_line connected
Definition: app_followme.c:223
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:105
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char yn[MAX_YN_STRING]
Definition: app_followme.c:229
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:8881
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:209
char optionsprompt[PATH_MAX]
Definition: app_followme.c:212
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:2054
Connected Line/Party information.
Definition: channel.h:457
#define LOG_NOTICE
Definition: logger.h:263
#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:217
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
char suggested_moh[MAX_MUSICCLASS]
Definition: app_followme.c:205
struct ast_channel * ochan
Definition: app_followme.c:221
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_frfree(fr)
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:431
Data structure associated with a single frame of data.
const char * ast_channel_language(const struct ast_channel *chan)
Definition: search.h:40
union ast_frame::@263 data
enum ast_frame_type frametype
char takecall[MAX_YN_STRING]
Definition: app_followme.c:208
char connected
Definition: eagi_proxy.c:82
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
struct ast_party_connected_line connected_in
Definition: app_followme.c:193
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
unsigned int pending_connected_update
Definition: app_followme.c:233
unsigned int enable_callee_prompt
Definition: app_followme.c:203

Variable Documentation

◆ __mod_info

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, }
static

Definition at line 1655 of file app_followme.c.

◆ app

char* app = "FollowMe"
static

Definition at line 148 of file app_followme.c.

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1655 of file app_followme.c.

◆ callfromprompt

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

Definition at line 276 of file app_followme.c.

◆ connprompt

char connprompt[PATH_MAX] = ""
static

Definition at line 282 of file app_followme.c.

◆ defaultmoh

const char* defaultmoh = "default"
static

Default Music-On-Hold Class

Definition at line 271 of file app_followme.c.

◆ enable_callee_prompt

int enable_callee_prompt = 1
static

Definition at line 275 of file app_followme.c.

Referenced by init_profile().

◆ featuredigittimeout

int featuredigittimeout = 5000
static

Feature Digit Timeout

Definition at line 270 of file app_followme.c.

◆ featuredigittostr

const char* featuredigittostr
static

Definition at line 269 of file app_followme.c.

◆ followme_opts

const struct ast_app_option followme_opts[128] = { [ 'a' ] = { .flag = FOLLOWMEFLAG_RECORDNAME }, [ 'B' ] = { .flag = FOLLOWMEFLAG_PREDIAL_CALLER , .arg_index = FOLLOWMEFLAG_ARG_PREDIAL_CALLER + 1 }, [ 'b' ] = { .flag = FOLLOWMEFLAG_PREDIAL_CALLEE , .arg_index = FOLLOWMEFLAG_ARG_PREDIAL_CALLEE + 1 }, [ 'd' ] = { .flag = FOLLOWMEFLAG_DISABLEHOLDPROMPT }, [ 'I' ] = { .flag = FOLLOWMEFLAG_IGNORE_CONNECTEDLINE }, [ 'l' ] = { .flag = FOLLOWMEFLAG_DISABLEOPTIMIZATION }, [ 'N' ] = { .flag = FOLLOWMEFLAG_NOANSWER }, [ 'n' ] = { .flag = FOLLOWMEFLAG_UNREACHABLEMSG }, [ 's' ] = { .flag = FOLLOWMEFLAG_STATUSMSG }, }
static

Definition at line 267 of file app_followme.c.

Referenced by app_exec().

◆ followmes

struct followmes followmes = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

◆ nextindp

char nextindp[MAX_YN_STRING] = "2"
static

Definition at line 274 of file app_followme.c.

◆ norecordingprompt

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

Definition at line 277 of file app_followme.c.

◆ optionsprompt

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

Definition at line 278 of file app_followme.c.

◆ plsholdprompt

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

Definition at line 279 of file app_followme.c.

◆ sorryprompt

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

Definition at line 281 of file app_followme.c.

◆ statusprompt

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

Definition at line 280 of file app_followme.c.

◆ takecall

char takecall[MAX_YN_STRING] = "1"
static

Definition at line 273 of file app_followme.c.