Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 = AST_BUILDOPT_SUM, .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 154 of file app_followme.c.

◆ REC_FORMAT

#define REC_FORMAT   "sln"

Definition at line 67 of file app_followme.c.

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

240 {
241 FOLLOWMEFLAG_STATUSMSG = (1 << 0),
242 FOLLOWMEFLAG_RECORDNAME = (1 << 1),
245 FOLLOWMEFLAG_NOANSWER = (1 << 4),
250};
@ FOLLOWMEFLAG_UNREACHABLEMSG
Definition: app_followme.c:243
@ FOLLOWMEFLAG_DISABLEHOLDPROMPT
Definition: app_followme.c:244
@ FOLLOWMEFLAG_NOANSWER
Definition: app_followme.c:245
@ FOLLOWMEFLAG_PREDIAL_CALLER
Definition: app_followme.c:248
@ FOLLOWMEFLAG_IGNORE_CONNECTEDLINE
Definition: app_followme.c:247
@ FOLLOWMEFLAG_RECORDNAME
Definition: app_followme.c:242
@ FOLLOWMEFLAG_DISABLEOPTIMIZATION
Definition: app_followme.c:246
@ FOLLOWMEFLAG_PREDIAL_CALLEE
Definition: app_followme.c:249
@ FOLLOWMEFLAG_STATUSMSG
Definition: app_followme.c:241

◆ anonymous enum

anonymous enum
Enumerator
FOLLOWMEFLAG_ARG_PREDIAL_CALLER 
FOLLOWMEFLAG_ARG_PREDIAL_CALLEE 
FOLLOWMEFLAG_ARG_ARRAY_SIZE 

Definition at line 252 of file app_followme.c.

252 {
255
256 /* note: this entry _MUST_ be the last one in the enum */
258};
@ FOLLOWMEFLAG_ARG_ARRAY_SIZE
Definition: app_followme.c:257
@ FOLLOWMEFLAG_ARG_PREDIAL_CALLER
Definition: app_followme.c:253
@ FOLLOWMEFLAG_ARG_PREDIAL_CALLEE
Definition: app_followme.c:254

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1660 of file app_followme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

315{
316 struct call_followme *f;
317
318 if (!(f = ast_calloc(1, sizeof(*f))))
319 return NULL;
320
321 ast_mutex_init(&f->lock);
322 ast_copy_string(f->name, fmname, sizeof(f->name));
326 return f;
327}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define ast_mutex_init(pmutex)
Definition: lock.h:193
#define NULL
Definition: resample.c:96
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Data structure for followme scripts.
Definition: app_followme.c:165
struct call_followme::wlnumbers wlnumbers
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:167
struct call_followme::blnumbers blnumbers
struct call_followme::numbers numbers
ast_mutex_t lock
Definition: app_followme.c:166

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

◆ app_exec()

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

Definition at line 1346 of file app_followme.c.

1347{
1348 struct fm_args *targs;
1350 struct call_followme *f;
1351 struct number *nm, *newnm;
1352 int res = 0;
1353 char *argstr;
1354 struct ast_channel *caller;
1355 struct ast_channel *outbound;
1357 AST_APP_ARG(followmeid);
1359 );
1360 char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
1361 int max_forwards;
1362
1363 if (ast_strlen_zero(data)) {
1364 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1365 return -1;
1366 }
1367
1368 ast_channel_lock(chan);
1370 ast_channel_unlock(chan);
1371
1372 if (max_forwards <= 0) {
1373 ast_log(LOG_WARNING, "Unable to execute FollowMe on channel %s. Max forwards exceeded\n",
1374 ast_channel_name(chan));
1375 return -1;
1376 }
1377
1378 argstr = ast_strdupa((char *) data);
1379
1380 AST_STANDARD_APP_ARGS(args, argstr);
1381
1382 if (ast_strlen_zero(args.followmeid)) {
1383 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1384 return -1;
1385 }
1386
1387 targs = ast_calloc(1, sizeof(*targs));
1388 if (!targs) {
1389 return -1;
1390 }
1391
1393 AST_RWLIST_TRAVERSE(&followmes, f, entry) {
1394 if (!strcasecmp(f->name, args.followmeid) && (f->active))
1395 break;
1396 }
1398
1399 ast_debug(1, "New profile %s.\n", args.followmeid);
1400
1401 if (!f) {
1402 f = find_realtime(args.followmeid);
1403 }
1404
1405 if (!f) {
1406 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1407 ast_free(targs);
1408 return 0;
1409 }
1410
1411 /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1412 if (args.options) {
1413 ast_app_parse_options(followme_opts, &targs->followmeflags, opt_args, args.options);
1414 }
1415
1416 /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1417 ast_mutex_lock(&f->lock);
1419 targs->mohclass = ast_strdupa(f->moh);
1420 ast_copy_string(targs->context, f->context, sizeof(targs->context));
1421 ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall));
1422 ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp));
1423 ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt));
1425 ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt));
1426 ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt));
1427 ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt));
1428 ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt));
1429 ast_copy_string(targs->connprompt, f->connprompt, sizeof(targs->connprompt));
1430 /* Copy the numbers we're going to use into another list in case the master list should get modified
1431 (and locked) while we're trying to do a follow-me */
1433 AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1434 newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1435 if (newnm) {
1436 AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry);
1437 }
1438 }
1440
1441 /* PREDIAL: Preprocess any callee gosub arguments. */
1445 targs->predial_callee =
1447 }
1448
1449 /* PREDIAL: Run gosub on the caller's channel */
1454 }
1455
1456 /* Forget the 'N' option if the call is already up. */
1457 if (ast_channel_state(chan) == AST_STATE_UP) {
1459 }
1460
1463 } else {
1464 /* Answer the call */
1465 if (ast_channel_state(chan) != AST_STATE_UP) {
1466 ast_answer(chan);
1467 }
1468
1470 ast_stream_and_wait(chan, targs->statusprompt, "");
1471 }
1472
1474 int duration = 5;
1475
1476 snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s",
1478 if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration,
1480 goto outrun;
1481 }
1482 if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
1483 targs->namerecloc[0] = '\0';
1484 }
1485 }
1486
1488 if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) {
1489 goto outrun;
1490 }
1491 if (ast_waitstream(chan, "") < 0)
1492 goto outrun;
1493 }
1494 ast_moh_start(chan, targs->mohclass, NULL);
1495 }
1496
1497 ast_channel_lock(chan);
1499 ast_channel_unlock(chan);
1500
1501 outbound = findmeexec(targs, chan);
1502 if (!outbound) {
1504 if (ast_channel_state(chan) != AST_STATE_UP) {
1505 ast_answer(chan);
1506 }
1507 } else {
1508 ast_moh_stop(chan);
1509 }
1510
1512 ast_stream_and_wait(chan, targs->sorryprompt, "");
1513 }
1514 res = 0;
1515 } else {
1516 caller = chan;
1517
1518 /* Play "connecting" message to the winner, if configured. */
1519 if (!ast_strlen_zero(targs->connprompt)) {
1521 ast_stream_and_wait(outbound, targs->connprompt, "");
1523 }
1524
1525 /* Bridge the two channels. */
1526
1527 memset(&config, 0, sizeof(config));
1528 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1529 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1530 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1531 config.end_bridge_callback = end_bridge_callback;
1532 config.end_bridge_callback_data = chan;
1533 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1534
1535 /* Update connected line to caller if available. */
1536 if (targs->pending_out_connected_update) {
1537 if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0)) {
1539 }
1540 }
1541
1545 }
1546 } else {
1548 }
1549
1550 /* Be sure no generators are left on it */
1552 /* Make sure channels are compatible */
1553 res = ast_channel_make_compatible(caller, outbound);
1554 if (res < 0) {
1555 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));
1557 goto outrun;
1558 }
1559
1560 /* Update connected line to winner if changed. */
1561 if (targs->pending_in_connected_update) {
1562 if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0)) {
1564 }
1565 }
1566
1567 /* Put winner on hold if caller requested. */
1568 if (targs->pending_hold) {
1569 if (ast_strlen_zero(targs->suggested_moh)) {
1571 } else {
1573 targs->suggested_moh, strlen(targs->suggested_moh) + 1);
1574 }
1575 }
1576
1577 res = ast_bridge_call(caller, outbound, &config);
1578 }
1579
1580outrun:
1581 while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) {
1582 ast_free(nm);
1583 }
1584 if (!ast_strlen_zero(targs->namerecloc)) {
1585 int ret;
1586 char fn[PATH_MAX + sizeof(REC_FORMAT)];
1587
1588 snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc,
1589 REC_FORMAT);
1590 ret = unlink(fn);
1591 if (ret != 0) {
1592 ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n",
1593 fn, errno, strerror(errno));
1594 } else {
1595 ast_debug(2, "deleted recorded prompt %s.\n", fn);
1596 }
1597 }
1598 ast_free((char *) targs->predial_callee);
1601 ast_free(targs);
1602
1603 if (f->realtime) {
1604 /* Not in list */
1605 free_numbers(f);
1606 ast_free(f);
1607 }
1608
1609 return res;
1610}
#define REC_FORMAT
Definition: app_followme.c:67
static struct ast_channel * findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
static const struct ast_app_option followme_opts[128]
Definition: app_followme.c:270
static char * app
Definition: app_followme.c:151
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:387
static struct call_followme * find_realtime(const char *name)
static void end_bridge_callback(void *data)
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:291
#define PATH_MAX
Definition: asterisk.h:40
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
static const char config[]
Definition: chan_ooh323.c:111
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
@ AST_FEATURE_REDIRECT
Definition: channel.h:1084
@ AST_FEATURE_AUTOMON
Definition: channel.h:1087
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's connected line information.
Definition: channel.c:10343
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2039
#define ast_channel_lock(chan)
Definition: channel.h:2972
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6679
const char * ast_channel_uniqueid(const struct ast_channel *chan)
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2861
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
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:9098
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:4612
const char * ast_channel_language(const struct ast_channel *chan)
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:8298
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
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:349
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2774
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4234
#define ast_channel_unlock(chan)
Definition: channel.h:2973
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
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:691
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1301
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:1886
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1137
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
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:278
#define AST_APP_ARG(name)
Define an application argument.
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:2154
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
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:297
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:3066
@ AST_CONTROL_RINGING
@ AST_CONTROL_HOLD
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_NOTICE
#define LOG_WARNING
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define ast_mutex_unlock(a)
Definition: lock.h:197
#define ast_mutex_lock(a)
Definition: lock.h:196
int errno
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_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7739
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7749
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:155
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
bridge configuration
Definition: channel.h:1096
Main Channel structure associated with a channel.
const char * data
struct ast_party_caller caller
Channel Caller ID information.
char connprompt[PATH_MAX]
Definition: app_followme.c:182
unsigned int enable_callee_prompt
Definition: app_followme.c:173
char sorryprompt[PATH_MAX]
Definition: app_followme.c:181
char callfromprompt[PATH_MAX]
Definition: app_followme.c:176
char takecall[MAX_YN_STRING]
Definition: app_followme.c:174
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:175
char optionsprompt[PATH_MAX]
Definition: app_followme.c:178
char statusprompt[PATH_MAX]
Definition: app_followme.c:180
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:179
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:168
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:169
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:177
unsigned int active
Definition: app_followme.c:170
char connprompt[PATH_MAX]
Definition: app_followme.c:219
unsigned int pending_in_connected_update
Definition: app_followme.c:200
char namerecloc[PATH_MAX]
Definition: app_followme.c:210
struct fm_args::cnumbers cnumbers
unsigned int enable_callee_prompt
Definition: app_followme.c:206
char sorryprompt[PATH_MAX]
Definition: app_followme.c:218
char callfromprompt[PATH_MAX]
Definition: app_followme.c:213
char takecall[MAX_YN_STRING]
Definition: app_followme.c:211
unsigned int pending_hold
Definition: app_followme.c:204
struct ast_party_connected_line connected_out
Definition: app_followme.c:198
unsigned int pending_out_connected_update
Definition: app_followme.c:202
char suggested_moh[MAX_MUSICCLASS]
Definition: app_followme.c:208
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:212
char * mohclass
Definition: app_followme.c:191
char optionsprompt[PATH_MAX]
Definition: app_followme.c:215
char statusprompt[PATH_MAX]
Definition: app_followme.c:217
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:216
struct ast_flags followmeflags
Definition: app_followme.c:220
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:209
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:214
const char * predial_callee
Definition: app_followme.c:194
struct ast_party_connected_line connected_in
Definition: app_followme.c:196
Channel datastore data for max forwards.
Definition: max_forwards.c:29
Number structure.
Definition: app_followme.c:157
long timeout
Definition: app_followme.c:159
char number[512]
Definition: app_followme.c:158
int order
Definition: app_followme.c:160
const char * args
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2343

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_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, config, fm_args::connected_in, fm_args::connected_out, call_followme::connprompt, fm_args::connprompt, call_followme::context, fm_args::context, create_followme_number(), ast_channel::data, call_followme::enable_callee_prompt, fm_args::enable_callee_prompt, end_bridge_callback(), end_bridge_callback_data_fixup(), errno, 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().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1660 of file app_followme.c.

◆ clear_caller()

static void clear_caller ( struct findme_user tmpuser)
static

Definition at line 606 of file app_followme.c.

607{
608 struct ast_channel *outbound;
609
610 if (!tmpuser->ochan) {
611 /* Call already cleared. */
612 return;
613 }
614
615 outbound = tmpuser->ochan;
616 ast_hangup(outbound);
617 tmpuser->ochan = NULL;
618}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2510
struct ast_channel * ochan
Definition: app_followme.c:224

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

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

◆ clear_unanswered_calls()

static void clear_unanswered_calls ( struct findme_user_listptr findme_user_list)
static

Definition at line 620 of file app_followme.c.

621{
622 struct findme_user *tmpuser;
623
624 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
625 if (!tmpuser->answered) {
626 clear_caller(tmpuser);
627 }
628 }
629}
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:606
struct findme_user::@26 entry
unsigned int answered
Definition: app_followme.c:234

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

Referenced by wait_for_winner().

◆ create_followme_number()

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

Add a new number.

Definition at line 387 of file app_followme.c.

388{
389 struct number *cur;
390 char *buf = ast_strdupa(number);
391 char *tmp;
392
393 if (!(cur = ast_calloc(1, sizeof(*cur))))
394 return NULL;
395
396 cur->timeout = timeout;
397 if ((tmp = strchr(buf, ',')))
398 *tmp = '\0';
399 ast_copy_string(cur->number, buf, sizeof(cur->number));
400 cur->order = numorder;
401 ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
402
403 return cur;
404}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66

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

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

◆ destroy_calling_node()

static void destroy_calling_node ( struct findme_user node)
static

Definition at line 631 of file app_followme.c.

632{
635 ast_free(node);
636}
Definition: test_heap.c:38

References ast_free, ast_party_connected_line_free(), and clear_caller().

Referenced by destroy_calling_tree(), and findmeexec().

◆ destroy_calling_tree()

static void destroy_calling_tree ( struct findme_user_listptr findme_user_list)
static

Definition at line 638 of file app_followme.c.

639{
640 struct findme_user *fmuser;
641
642 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
643 destroy_calling_node(fmuser);
644 }
645}
static void destroy_calling_node(struct findme_user *node)
Definition: app_followme.c:631

References AST_LIST_REMOVE_HEAD, destroy_calling_node(), and findme_user::entry.

Referenced by findmeexec().

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 1325 of file app_followme.c.

1326{
1327 char buf[80];
1328 time_t end;
1329 struct ast_channel *chan = data;
1330
1331 time(&end);
1332
1333 ast_channel_lock(chan);
1334 snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
1335 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1336 snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
1337 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1338 ast_channel_unlock(chan);
1339}
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition: channel.c:2814
int ast_channel_get_duration(struct ast_channel *chan)
Obtain how long the channel since the channel was created.
Definition: channel.c:2799
char * end
Definition: eagi_proxy.c:73
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.

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

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

1342{
1343 bconfig->end_bridge_callback_data = originator;
1344}
void * end_bridge_callback_data
Definition: channel.h:1111

References ast_bridge_config::end_bridge_callback_data.

Referenced by app_exec().

◆ find_realtime()

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

Definition at line 1243 of file app_followme.c.

1244{
1245 struct ast_variable *var;
1246 struct ast_variable *v;
1247 struct ast_config *cfg;
1248 const char *catg;
1249 struct call_followme *new_follower;
1250 struct ast_str *str;
1251
1252 str = ast_str_create(16);
1253 if (!str) {
1254 return NULL;
1255 }
1256
1257 var = ast_load_realtime("followme", "name", name, SENTINEL);
1258 if (!var) {
1259 ast_free(str);
1260 return NULL;
1261 }
1262
1263 if (!(new_follower = alloc_profile(name))) {
1265 ast_free(str);
1266 return NULL;
1267 }
1268 init_profile(new_follower, 0);
1269
1270 for (v = var; v; v = v->next) {
1271 if (!strcasecmp(v->name, "active")) {
1272 if (ast_false(v->value)) {
1273 ast_mutex_destroy(&new_follower->lock);
1274 ast_free(new_follower);
1276 ast_free(str);
1277 return NULL;
1278 }
1279 } else {
1280 profile_set_param(new_follower, v->name, v->value, 0, 0);
1281 }
1282 }
1283
1285 new_follower->realtime = 1;
1286
1287 /* Load numbers */
1288 cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
1289 name, SENTINEL);
1290 if (!cfg) {
1291 ast_mutex_destroy(&new_follower->lock);
1292 ast_free(new_follower);
1293 ast_free(str);
1294 return NULL;
1295 }
1296
1297 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
1298 const char *numstr;
1299 const char *timeoutstr;
1300 const char *ordstr;
1301 int timeout;
1302 struct number *cur;
1303
1304 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
1305 continue;
1306 }
1307 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
1308 || sscanf(timeoutstr, "%30d", &timeout) != 1
1309 || timeout < 1) {
1310 timeout = 25;
1311 }
1312 /* This one has to exist; it was part of the query */
1313 ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
1314 ast_str_set(&str, 0, "%s", numstr);
1315 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
1316 AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
1317 }
1318 }
1319 ast_config_destroy(cfg);
1320
1321 ast_free(str);
1322 return new_follower;
1323}
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:351
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:314
static void init_profile(struct call_followme *f, int activate)
Definition: app_followme.c:329
const char * str
Definition: app_jack.c:150
#define var
Definition: ast_expr2f.c:605
#define SENTINEL
Definition: compiler.h:87
static const char name[]
Definition: format_mp3.c:68
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3842
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3726
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define ast_mutex_destroy(a)
Definition: lock.h:195
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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:1113
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
struct number::@24 entry

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(), number::entry, init_profile(), call_followme::lock, name, 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().

◆ findmeexec()

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

Definition at line 1032 of file app_followme.c.

1033{
1034 struct number *nm;
1035 struct ast_channel *winner = NULL;
1036 char num[512];
1037 int dg, idx;
1038 char *rest, *number;
1039 struct findme_user *tmpuser;
1040 struct findme_user *fmuser;
1041 struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1043
1044 for (idx = 1; !ast_check_hangup(caller); ++idx) {
1045 /* Find next followme numbers to dial. */
1046 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
1047 if (nm->order == idx) {
1048 break;
1049 }
1050 }
1051 if (!nm) {
1052 ast_verb(3, "No more steps left.\n");
1053 break;
1054 }
1055
1056 ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout);
1057
1058 /*
1059 * Put all active outgoing channels into autoservice.
1060 *
1061 * This needs to be done because ast_exists_extension() may put
1062 * the caller into autoservice.
1063 */
1064 AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1065 if (tmpuser->ochan) {
1066 ast_autoservice_start(tmpuser->ochan);
1067 }
1068 }
1069
1070 /* Create all new outgoing calls */
1071 ast_copy_string(num, nm->number, sizeof(num));
1072 for (number = num; number; number = rest) {
1073 struct ast_channel *outbound;
1074 struct ast_format_cap *caps;
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 /* Capture nativeformats reference in case it gets changed */
1105 ast_channel_lock(caller);
1106 caps = ao2_bump(ast_channel_nativeformats(caller));
1107 ast_channel_unlock(caller);
1108
1109 outbound = ast_request("Local", caps, NULL, caller, tmpuser->dialarg, &dg);
1110
1111 ao2_cleanup(caps);
1112
1113 if (!outbound) {
1114 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
1115 tmpuser->dialarg, ast_cause2str(dg));
1116 ast_free(tmpuser);
1117 continue;
1118 }
1119
1120 ast_channel_lock_both(caller, outbound);
1122 ast_channel_inherit_variables(caller, outbound);
1123 ast_channel_datastore_inherit(caller, outbound);
1125 ast_channel_language_set(outbound, ast_channel_language(caller));
1127 ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
1128 ast_channel_unlock(outbound);
1129 ast_channel_unlock(caller);
1130
1131 tmpuser->ochan = outbound;
1132 tmpuser->state = 0;
1133 AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry);
1134 }
1135
1136 /*
1137 * PREDIAL: Run gosub on all of the new callee channels
1138 *
1139 * We run the callee predial before ast_call() in case the user
1140 * wishes to do something on the newly created channels before
1141 * the channel does anything important.
1142 */
1143 if (tpargs->predial_callee && !AST_LIST_EMPTY(&new_user_list)) {
1144 /* Put caller into autoservice. */
1145 ast_autoservice_start(caller);
1146
1147 /* Run predial on all new outgoing calls. */
1148 AST_LIST_TRAVERSE(&new_user_list, tmpuser, entry) {
1149 ast_pre_call(tmpuser->ochan, tpargs->predial_callee);
1150 }
1151
1152 /* Take caller out of autoservice. */
1153 if (ast_autoservice_stop(caller)) {
1154 /*
1155 * Caller hungup.
1156 *
1157 * Destoy all new outgoing calls.
1158 */
1159 while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
1160 destroy_calling_node(tmpuser);
1161 }
1162
1163 /* Take all active outgoing channels out of autoservice. */
1164 AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1165 if (tmpuser->ochan) {
1166 ast_autoservice_stop(tmpuser->ochan);
1167 }
1168 }
1169 break;
1170 }
1171 }
1172
1173 /* Start all new outgoing calls */
1174 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_user_list, tmpuser, entry) {
1175 ast_verb(3, "calling Local/%s\n", tmpuser->dialarg);
1176 if (ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) {
1177 ast_verb(3, "couldn't reach at this number.\n");
1179
1180 /* Destroy this failed new outgoing call. */
1181 destroy_calling_node(tmpuser);
1182 continue;
1183 }
1184
1185 ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL);
1186 }
1188
1189 /* Take all active outgoing channels out of autoservice. */
1190 AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1191 if (tmpuser->ochan && ast_autoservice_stop(tmpuser->ochan)) {
1192 /* Existing outgoing call hungup. */
1194 destroy_calling_node(tmpuser);
1195 }
1196 }
1198
1199 if (AST_LIST_EMPTY(&new_user_list)) {
1200 /* No new channels remain at this order level. If there were any at all. */
1201 continue;
1202 }
1203
1204 /* Add new outgoing channels to the findme list. */
1205 AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry);
1206
1207 winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
1208 if (!winner) {
1209 /* Remove all dead outgoing nodes. */
1210 AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1211 if (!tmpuser->ochan) {
1213 destroy_calling_node(tmpuser);
1214 }
1215 }
1217 continue;
1218 }
1219
1220 /* Destroy losing calls up to the winner. The rest will be destroyed later. */
1221 while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) {
1222 if (fmuser->ochan == winner) {
1223 /*
1224 * Pass any connected line info up.
1225 *
1226 * NOTE: This code must be in line with destroy_calling_node().
1227 */
1228 tpargs->connected_out = fmuser->connected;
1230 ast_free(fmuser);
1231 break;
1232 } else {
1233 /* Destroy losing call. */
1234 destroy_calling_node(fmuser);
1235 }
1236 }
1237 break;
1238 }
1239 destroy_calling_tree(&findme_user_list);
1240 return winner;
1241}
static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:638
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:647
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6420
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1525
const char * ast_channel_musicclass(const struct ast_channel *chan)
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:2979
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2337
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:6393
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:6735
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:444
const char * ast_cause2str(int cause) attribute_pure
Gives the string form of a given cause code.
Definition: channel.c:611
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:6403
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:6313
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_ERROR
#define ast_verb(level,...)
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:252
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:783
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
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:4190
#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:87
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
char dialarg[768]
Definition: app_followme.c:230
struct ast_party_connected_line connected
Definition: app_followme.c:226
unsigned int pending_connected_update
Definition: app_followme.c:236

References ao2_bump, ao2_cleanup, 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, 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().

◆ free_numbers()

static void free_numbers ( struct call_followme f)
static

Definition at line 291 of file app_followme.c.

292{
293 /* Free numbers attached to the profile */
294 struct number *prev;
295
296 while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
297 /* Free the number */
298 ast_free(prev);
300
301 while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
302 /* Free the blacklisted number */
303 ast_free(prev);
305
306 while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
307 /* Free the whitelisted number */
308 ast_free(prev);
310}

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

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

◆ init_profile()

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

Definition at line 329 of file app_followme.c.

330{
332 f->context[0] = '\0';
333 ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
334 ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
335 ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
343 if (activate) {
344 f->active = 1;
345 }
346}
static char connprompt[PATH_MAX]
Definition: app_followme.c:285
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:284
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:279
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:276
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:277
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:281
static char statusprompt[PATH_MAX]
Definition: app_followme.c:283
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:282
static char norecordingprompt[PATH_MAX]
Definition: app_followme.c:280
static int enable_callee_prompt
Definition: app_followme.c:278
static const char * defaultmoh
Definition: app_followme.c:274

References call_followme::active, ast_copy_string(), call_followme::callfromprompt, callfromprompt, call_followme::connprompt, connprompt, call_followme::context, defaultmoh, call_followme::enable_callee_prompt, enable_callee_prompt, call_followme::moh, call_followme::nextindp, nextindp, call_followme::norecordingprompt, norecordingprompt, call_followme::optionsprompt, optionsprompt, call_followme::plsholdprompt, plsholdprompt, call_followme::sorryprompt, sorryprompt, call_followme::statusprompt, statusprompt, call_followme::takecall, and takecall.

Referenced by find_realtime(), and reload_followme().

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

1641{
1642 if(!reload_followme(0))
1644
1646}
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:407
static int app_exec(struct ast_channel *chan, const char *data)
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640

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

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

352{
353
354 if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
355 ast_copy_string(f->moh, val, sizeof(f->moh));
356 else if (!strcasecmp(param, "context"))
357 ast_copy_string(f->context, val, sizeof(f->context));
358 else if (!strcasecmp(param, "enable_callee_prompt"))
360 else if (!strcasecmp(param, "takecall"))
361 ast_copy_string(f->takecall, val, sizeof(f->takecall));
362 else if (!strcasecmp(param, "declinecall"))
363 ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
364 else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
366 else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
368 else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
370 else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
372 else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
374 else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
376 else if (!strcasecmp(param, "followme-connecting-prompt") || !strcasecmp(param, "connecting_prompt")) {
377 ast_copy_string(f->connprompt, val, sizeof(f->connprompt));
378 } else if (failunknown) {
379 if (linenum >= 0)
380 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
381 else
382 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
383 }
384}
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
Definition: ast_expr2.c:325

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

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

596{
597 struct findme_user *tmpuser;
598
599 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
600 if (tmpuser->ochan && tmpuser->ochan != exception) {
602 }
603 }
604}
jack_status_t status
Definition: app_jack.c:149
FILE * in
Definition: utils/frame.c:33

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

Referenced by wait_for_winner().

◆ reload()

static int reload ( void  )
static

Definition at line 1648 of file app_followme.c.

1649{
1650 reload_followme(1);
1651
1652 return 0;
1653}

References reload_followme().

Referenced by reload_followme().

◆ reload_followme()

static int reload_followme ( int  reload)
static

Reload followme application module.

Definition at line 407 of file app_followme.c.

408{
409 struct call_followme *f;
410 struct ast_config *cfg;
411 char *cat = NULL, *tmp;
412 struct ast_variable *var;
413 struct number *cur, *nm;
414 int timeout;
415 int numorder;
416 const char* enable_callee_prompt_str;
417 const char *takecallstr;
418 const char *declinecallstr;
419 const char *tmpstr;
420 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
421
422 if (!(cfg = ast_config_load("followme.conf", config_flags))) {
423 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
424 return 0;
425 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
426 return 0;
427 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
428 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
429 return 0;
430 }
431
433
434 /* Reset Global Var Values */
435 featuredigittimeout = 5000;
436
437 /* Mark all profiles as inactive for the moment */
438 AST_RWLIST_TRAVERSE(&followmes, f, entry) {
439 f->active = 0;
440 }
441
442 featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
443
445 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
446 featuredigittimeout = 5000;
447 }
448
449 if ((enable_callee_prompt_str = ast_variable_retrieve(cfg, "general",
450 "enable_callee_prompt")) &&
451 !ast_strlen_zero(enable_callee_prompt_str)) {
452 enable_callee_prompt = ast_true(enable_callee_prompt_str);
453 }
454
455 if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
456 ast_copy_string(takecall, takecallstr, sizeof(takecall));
457 }
458
459 if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
460 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
461 }
462
463 if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
465 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
467 }
468
469 if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
471 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
473 }
474
475
476 if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
478 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
480 }
481
482 if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
484 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
486 }
487
488 if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
489 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
490 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
491 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
492 }
493
494 if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
495 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
496 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
497 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
498 }
499
500 if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting-prompt")) && !ast_strlen_zero(tmpstr)) {
501 ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
502 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting_prompt")) && !ast_strlen_zero(tmpstr)) {
503 ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
504 }
505
506
507 /* Chug through config file */
508 while ((cat = ast_category_browse(cfg, cat))) {
509 int new = 0;
510
511 if (!strcasecmp(cat, "general"))
512 continue;
513
514 /* Look for an existing one */
515 AST_LIST_TRAVERSE(&followmes, f, entry) {
516 if (!strcasecmp(f->name, cat))
517 break;
518 }
519
520 ast_debug(1, "New profile %s.\n", cat);
521
522 if (!f) {
523 /* Make one then */
524 f = alloc_profile(cat);
525 new = 1;
526 }
527
528 /* Totally fail if we fail to find/create an entry */
529 if (!f)
530 continue;
531
532 if (!new)
533 ast_mutex_lock(&f->lock);
534 /* Re-initialize the profile */
535 init_profile(f, 1);
536 free_numbers(f);
537 var = ast_variable_browse(cfg, cat);
538 while (var) {
539 if (!strcasecmp(var->name, "number")) {
540 int idx = 0;
541 char copy[strlen(var->value) + 1];
542 char *numberstr;
543
544 /* Add a new number */
545 strcpy(copy, var->value); /* safe */
546 numberstr = copy;
547 if ((tmp = strchr(numberstr, ','))) {
548 *tmp++ = '\0';
549 timeout = atoi(tmp);
550 if (timeout < 0) {
551 timeout = 25;
552 }
553 if ((tmp = strchr(tmp, ','))) {
554 *tmp++ = '\0';
555 numorder = atoi(tmp);
556 if (numorder < 0)
557 numorder = 0;
558 } else
559 numorder = 0;
560 } else {
561 timeout = 25;
562 numorder = 0;
563 }
564
565 if (!numorder) {
566 idx = 1;
567 AST_LIST_TRAVERSE(&f->numbers, nm, entry)
568 idx++;
569 numorder = idx;
570 }
571 cur = create_followme_number(numberstr, timeout, numorder);
572 if (cur) {
573 AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
574 }
575 } else {
576 profile_set_param(f, var->name, var->value, var->lineno, 1);
577 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
578 }
579 var = var->next;
580 } /* End while(var) loop */
581
582 if (!new)
584 else
586 }
587
589
591
592 return 1;
593}
static int featuredigittimeout
Definition: app_followme.c:273
static const char * featuredigittostr
Definition: app_followme.c:272
static int reload(void)
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_config_load(filename, flags)
Load a config file.
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
Structure used to handle boolean flags.
Definition: utils.h:199

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(), callfromprompt, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, connprompt, copy(), create_followme_number(), enable_callee_prompt, featuredigittimeout, featuredigittostr, free_numbers(), init_profile(), call_followme::lock, LOG_ERROR, LOG_WARNING, call_followme::name, nextindp, norecordingprompt, NULL, call_followme::numbers, optionsprompt, plsholdprompt, profile_set_param(), reload(), sorryprompt, statusprompt, takecall, number::timeout, and var.

Referenced by load_module(), and reload().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1612 of file app_followme.c.

1613{
1614 struct call_followme *f;
1615
1617
1618 /* Free Memory. Yeah! I'm free! */
1620 while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1621 free_numbers(f);
1622 ast_free(f);
1623 }
1624
1626
1627 return 0;
1628}
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
struct call_followme::@25 entry

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

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

648{
650 struct ast_channel *watchers[256];
651 int pos;
652 struct ast_channel *winner;
653 struct ast_frame *f;
654 struct findme_user *tmpuser;
655 int to = 0;
656 int livechannels;
657 int tmpto;
658 long totalwait = 0, wtd = 0, towas = 0;
659 char *callfromname;
660 char *pressbuttonname;
661
662 /* ------------ wait_for_winner_channel start --------------- */
663
664 callfromname = ast_strdupa(tpargs->callfromprompt);
665 pressbuttonname = ast_strdupa(tpargs->optionsprompt);
666
667 totalwait = nm->timeout * 1000;
668
669 for (;;) {
670 to = 1000;
671 pos = 1;
672 livechannels = 0;
673 watchers[0] = caller;
674
675 winner = NULL;
676 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
677 if (!tmpuser->ochan) {
678 continue;
679 }
680 if (tmpuser->state == 3) {
681 tmpuser->digts += (towas - wtd);
682 }
683 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
684 ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n",
685 ast_channel_name(tmpuser->ochan));
686 if (tpargs->enable_callee_prompt) {
687 if (!ast_strlen_zero(tpargs->namerecloc)) {
688 tmpuser->state = 1;
689 tmpuser->digts = 0;
690 if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
692 } else {
693 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
694 clear_caller(tmpuser);
695 continue;
696 }
697 } else {
698 tmpuser->state = 2;
699 tmpuser->digts = 0;
700 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
702 else {
703 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
704 clear_caller(tmpuser);
705 continue;
706 }
707 }
708 } else {
709 tmpuser->state = 3;
710 }
711 }
712 if (ast_channel_stream(tmpuser->ochan)) {
714 tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan));
715 if (tmpto > 0 && tmpto < to)
716 to = tmpto;
717 else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
718 ast_stopstream(tmpuser->ochan);
719 switch (tmpuser->state) {
720 case 1:
721 ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n",
722 ast_channel_name(tmpuser->ochan));
723 if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) {
724 tmpuser->state = 2;
725 } else {
726 ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n",
727 ast_channel_name(tmpuser->ochan), tpargs->namerecloc);
728 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
729 tmpuser->ynidx = 0;
730 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
731 tmpuser->state = 3;
732 else {
733 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
734 clear_caller(tmpuser);
735 continue;
736 }
737 }
738 break;
739 case 2:
740 ast_verb(3, "<%s> Playback of name file appears to be done.\n",
741 ast_channel_name(tmpuser->ochan));
742 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
743 tmpuser->ynidx = 0;
744 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
745 tmpuser->state = 3;
746 } else {
747 clear_caller(tmpuser);
748 continue;
749 }
750 break;
751 case 3:
752 ast_verb(3, "<%s> Playback of the next step file appears to be done.\n",
753 ast_channel_name(tmpuser->ochan));
754 tmpuser->digts = 0;
755 break;
756 default:
757 break;
758 }
759 }
760 }
761 watchers[pos++] = tmpuser->ochan;
762 livechannels++;
763 }
764 if (!livechannels) {
765 ast_verb(3, "No live channels left for this step.\n");
766 return NULL;
767 }
768
769 tmpto = to;
770 towas = to;
771 winner = ast_waitfor_n(watchers, pos, &to);
772 tmpto -= to;
773 totalwait -= tmpto;
774 wtd = to;
775 if (totalwait <= 0) {
776 ast_verb(3, "We've hit our timeout for this step. Dropping unanswered calls and starting the next step.\n");
777 clear_unanswered_calls(findme_user_list);
778 return NULL;
779 }
780 if (winner) {
781 /* Need to find out which channel this is */
782 if (winner != caller) {
783 /* The winner is an outgoing channel. */
784 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
785 if (tmpuser->ochan == winner) {
786 break;
787 }
788 }
789 } else {
790 tmpuser = NULL;
791 }
792
793 f = ast_read(winner);
794 if (f) {
795 if (f->frametype == AST_FRAME_CONTROL) {
796 switch (f->subclass.integer) {
798 ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner));
799 if (f->data.uint32) {
801 }
802 if (!tmpuser) {
803 ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
804 publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL");
805 ast_frfree(f);
806 return NULL;
807 }
808 clear_caller(tmpuser);
809 break;
811 if (!tmpuser) {
812 /* The caller answered? We want an outgoing channel to answer. */
813 break;
814 }
815 ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
816 ast_channel_publish_dial(caller, winner, NULL, "ANSWER");
817 publish_dial_end_event(caller, findme_user_list, winner, "CANCEL");
818 tmpuser->answered = 1;
819 /* If call has been answered, then the eventual hangup is likely to be normal hangup */
822 if (tpargs->enable_callee_prompt) {
823 ast_verb(3, "Starting playback of %s\n", callfromname);
824 if (!ast_strlen_zero(tpargs->namerecloc)) {
825 if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) {
827 tmpuser->state = 1;
828 } else {
829 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
830 clear_caller(tmpuser);
831 }
832 } else {
833 tmpuser->state = 2;
834 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
836 else {
837 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
838 clear_caller(tmpuser);
839 }
840 }
841 } else {
842 ast_debug(1, "Taking call with no prompt\n");
843 ast_frfree(f);
844 return tmpuser->ochan;
845 }
846 break;
847 case AST_CONTROL_BUSY:
848 ast_verb(3, "%s is busy\n", ast_channel_name(winner));
849 if (tmpuser) {
850 /* Outbound call was busy. Drop it. */
851 ast_channel_publish_dial(caller, winner, NULL, "BUSY");
852 clear_caller(tmpuser);
853 }
854 break;
856 ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
857 if (tmpuser) {
858 /* Outbound call was congested. Drop it. */
859 ast_channel_publish_dial(caller, winner, NULL, "CONGESTION");
860 clear_caller(tmpuser);
861 }
862 break;
864 ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
865 ast_channel_publish_dial(caller, winner, NULL, "RINGING");
866 break;
868 ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
869 ast_channel_publish_dial(caller, winner, NULL, "PROGRESS");
870 break;
872 ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
873 break;
875 ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
876 break;
878 ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
879 ast_channel_publish_dial(caller, winner, NULL, "PROCEEDING");
880 break;
881 case AST_CONTROL_HOLD:
882 ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
883 if (!tmpuser) {
884 /* Caller placed outgoing calls on hold. */
885 tpargs->pending_hold = 1;
886 if (f->data.ptr) {
888 sizeof(tpargs->suggested_moh));
889 } else {
890 tpargs->suggested_moh[0] = '\0';
891 }
892 } else {
893 /*
894 * Outgoing call placed caller on hold.
895 *
896 * Ignore because the outgoing call should not be able to place
897 * the caller on hold until after they are bridged.
898 */
899 }
900 break;
902 ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
903 if (!tmpuser) {
904 /* Caller removed outgoing calls from hold. */
905 tpargs->pending_hold = 0;
906 } else {
907 /*
908 * Outgoing call removed caller from hold.
909 *
910 * Ignore because the outgoing call should not be able to place
911 * the caller on hold until after they are bridged.
912 */
913 }
914 break;
917 /* Ignore going off hook and flash */
918 break;
921 ast_verb(3, "Connected line update from %s prevented.\n",
922 ast_channel_name(winner));
923 break;
924 }
925 if (!tmpuser) {
926 /*
927 * Hold connected line update from caller until we have a
928 * winner.
929 */
930 ast_verb(3,
931 "%s connected line has changed. Saving it until we have a winner.\n",
932 ast_channel_name(winner));
936 &connected, NULL);
937 tpargs->pending_in_connected_update = 1;
938 }
940 } else {
941 ast_verb(3,
942 "%s connected line has changed. Saving it until answer.\n",
943 ast_channel_name(winner));
947 &connected, NULL);
948 tmpuser->pending_connected_update = 1;
949 }
951 }
952 break;
954 /*
955 * Ignore because we are masking the FollowMe search progress to
956 * the caller.
957 */
958 break;
960 ast_indicate_data(caller, f->subclass.integer, f->data.ptr, f->datalen);
961 break;
962 case -1:
963 ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
964 break;
965 default:
966 ast_debug(1, "Dunno what to do with control type %d from %s\n",
967 f->subclass.integer, ast_channel_name(winner));
968 break;
969 }
970 }
971 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
972 int cmp_len;
973
974 if (ast_channel_stream(winner))
975 ast_stopstream(winner);
976 tmpuser->digts = 0;
977 ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
978 if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
979 tmpuser->yn[tmpuser->ynidx++] = f->subclass.integer;
980 } else {
981 /* Discard oldest digit. */
982 memmove(tmpuser->yn, tmpuser->yn + 1,
983 sizeof(tmpuser->yn) - 2 * sizeof(tmpuser->yn[0]));
984 tmpuser->yn[ARRAY_LEN(tmpuser->yn) - 2] = f->subclass.integer;
985 }
986 ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
987 cmp_len = strlen(tpargs->takecall);
988 if (cmp_len <= tmpuser->ynidx
989 && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->takecall)) {
990 ast_debug(1, "Match to take the call!\n");
991 ast_frfree(f);
992 return tmpuser->ochan;
993 }
994 cmp_len = strlen(tpargs->nextindp);
995 if (cmp_len <= tmpuser->ynidx
996 && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->nextindp)) {
997 ast_debug(1, "Declined to take the call.\n");
998 clear_caller(tmpuser);
999 }
1000 }
1001
1002 ast_frfree(f);
1003 } else {
1004 ast_debug(1, "we didn't get a frame. hanging up.\n");
1005 if (!tmpuser) {
1006 /* Caller hung up. */
1007 ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
1008 return NULL;
1009 }
1010 /* Outgoing channel hung up. */
1011 ast_channel_publish_dial(caller, winner, NULL, "NOANSWER");
1012 clear_caller(tmpuser);
1013 }
1014 } else {
1015 ast_debug(1, "timed out waiting for action\n");
1016 }
1017 }
1018
1019 /* Unreachable. */
1020}
static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:620
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:595
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
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:3125
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:2021
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4214
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:8790
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
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:2012
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
char connected
Definition: eagi_proxy.c:82
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_SRCUPDATE
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_BUSY
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_HANGUP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_FLASH
@ AST_CONTROL_PVT_CAUSE_CODE
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
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:433
Data structure associated with a single frame of data.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Connected Line/Party information.
Definition: channel.h:458
char yn[MAX_YN_STRING]
Definition: app_followme.c:232
#define ARRAY_LEN(a)
Definition: utils.h:666

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, connected, fm_args::connected_in, ast_frame::data, ast_frame::datalen, findme_user::digts, fm_args::enable_callee_prompt, findme_user::entry, featuredigittimeout, 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().

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

Definition at line 1660 of file app_followme.c.

◆ app

char* app = "FollowMe"
static

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

◆ callfromprompt

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

Definition at line 279 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ connprompt

char connprompt[PATH_MAX] = ""
static

Definition at line 285 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ defaultmoh

const char* defaultmoh = "default"
static

Default Music-On-Hold Class

Definition at line 274 of file app_followme.c.

Referenced by init_profile().

◆ enable_callee_prompt

int enable_callee_prompt = 1
static

Definition at line 278 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ featuredigittimeout

int featuredigittimeout = 5000
static

Feature Digit Timeout

Definition at line 273 of file app_followme.c.

Referenced by reload_followme(), and wait_for_winner().

◆ featuredigittostr

const char* featuredigittostr
static

Definition at line 272 of file app_followme.c.

Referenced by reload_followme().

◆ 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 270 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 277 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ norecordingprompt

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

Definition at line 280 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ optionsprompt

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

Definition at line 281 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ plsholdprompt

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

Definition at line 282 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ sorryprompt

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

Definition at line 284 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ statusprompt

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

Definition at line 283 of file app_followme.c.

Referenced by init_profile(), and reload_followme().

◆ takecall

char takecall[MAX_YN_STRING] = "1"
static

Definition at line 276 of file app_followme.c.

Referenced by init_profile(), and reload_followme().