64 #include "asterisk/stasis_channels.h"
65 #include "asterisk/max_forwards.h"
67 #define REC_FORMAT "sln"
148 static char *app =
"FollowMe";
151 #define MAX_YN_STRING 20
170 unsigned int enable_callee_prompt:1;
173 char callfromprompt[PATH_MAX];
174 char norecordingprompt[PATH_MAX];
175 char optionsprompt[PATH_MAX];
176 char plsholdprompt[PATH_MAX];
177 char statusprompt[PATH_MAX];
178 char sorryprompt[PATH_MAX];
179 char connprompt[PATH_MAX];
191 const
char *predial_callee;
197 unsigned int pending_in_connected_update:1;
199 unsigned int pending_out_connected_update:1;
201 unsigned int pending_hold:1;
203 unsigned int enable_callee_prompt:1;
207 char namerecloc[PATH_MAX];
209 char nextindp[MAX_YN_STRING];
210 char callfromprompt[PATH_MAX];
211 char norecordingprompt[PATH_MAX];
212 char optionsprompt[PATH_MAX];
213 char plsholdprompt[PATH_MAX];
214 char statusprompt[PATH_MAX];
215 char sorryprompt[PATH_MAX];
216 char connprompt[PATH_MAX];
231 unsigned int answered:1;
233 unsigned int pending_connected_update:1;
238 FOLLOWMEFLAG_STATUSMSG = (1 << 0),
239 FOLLOWMEFLAG_RECORDNAME = (1 << 1),
240 FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2),
241 FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
242 FOLLOWMEFLAG_NOANSWER = (1 << 4),
243 FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5),
244 FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6),
245 FOLLOWMEFLAG_PREDIAL_CALLER = (1 << 7),
246 FOLLOWMEFLAG_PREDIAL_CALLEE = (1 << 8),
250 FOLLOWMEFLAG_ARG_PREDIAL_CALLER,
251 FOLLOWMEFLAG_ARG_PREDIAL_CALLEE,
254 FOLLOWMEFLAG_ARG_ARRAY_SIZE
259 AST_APP_OPTION_ARG(
'B', FOLLOWMEFLAG_PREDIAL_CALLER, FOLLOWMEFLAG_ARG_PREDIAL_CALLER),
260 AST_APP_OPTION_ARG(
'b', FOLLOWMEFLAG_PREDIAL_CALLEE, FOLLOWMEFLAG_ARG_PREDIAL_CALLEE),
269 static const char *featuredigittostr;
275 static int enable_callee_prompt = 1;
276 static char callfromprompt[PATH_MAX] =
"followme/call-from";
277 static char norecordingprompt[PATH_MAX] =
"followme/no-recording";
278 static char optionsprompt[PATH_MAX] =
"followme/options";
279 static char plsholdprompt[PATH_MAX] =
"followme/pls-hold-while-try";
280 static char statusprompt[PATH_MAX] =
"followme/status";
281 static char sorryprompt[PATH_MAX] =
"followme/sorry";
282 static char connprompt[PATH_MAX] =
"";
288 static void free_numbers(
struct call_followme *f)
313 struct call_followme *f;
318 ast_mutex_init(&f->lock);
326 static void init_profile(
struct call_followme *f,
int activate)
348 static void profile_set_param(
struct call_followme *f,
const char *param,
const char *
val,
int linenum,
int failunknown)
351 if (!strcasecmp(param,
"musicclass") || !strcasecmp(param,
"musiconhold") || !strcasecmp(param,
"music"))
353 else if (!strcasecmp(param,
"context"))
355 else if (!strcasecmp(param,
"enable_callee_prompt"))
357 else if (!strcasecmp(param,
"takecall"))
359 else if (!strcasecmp(param,
"declinecall"))
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"))
371 else if (!strcasecmp(param,
"followme-sorry-prompt") || !strcasecmp(param,
"sorry_prompt"))
373 else if (!strcasecmp(param,
"followme-connecting-prompt") || !strcasecmp(param,
"connecting_prompt")) {
375 }
else if (failunknown) {
377 ast_log(LOG_WARNING,
"Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->
name, param, linenum);
379 ast_log(LOG_WARNING,
"Unknown keyword in profile '%s': %s\n", f->
name, param);
394 if ((tmp = strchr(buf,
',')))
397 cur->
order = numorder;
406 struct call_followme *f;
408 char *cat = NULL, *tmp;
410 struct number *cur, *nm;
413 const char* enable_callee_prompt_str;
414 const char *takecallstr;
415 const char *declinecallstr;
420 ast_log(LOG_WARNING,
"No follow me config file (followme.conf), so no follow me\n");
422 }
else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
424 }
else if (cfg == CONFIG_STATUS_FILEINVALID) {
425 ast_log(LOG_ERROR,
"Config file followme.conf is in an invalid format. Aborting.\n");
432 featuredigittimeout = 5000;
435 AST_RWLIST_TRAVERSE(&
followmes, f, entry) {
439 featuredigittostr = ast_variable_retrieve(cfg,
"general",
"featuredigittimeout");
441 if (!ast_strlen_zero(featuredigittostr)) {
442 if (!sscanf(featuredigittostr,
"%30d", &featuredigittimeout))
443 featuredigittimeout = 5000;
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);
452 if ((takecallstr = ast_variable_retrieve(cfg,
"general",
"takecall")) && !ast_strlen_zero(takecallstr)) {
456 if ((declinecallstr = ast_variable_retrieve(cfg,
"general",
"declinecall")) && !ast_strlen_zero(declinecallstr)) {
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)) {
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)) {
473 if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"options-prompt")) && !ast_strlen_zero(tmpstr)) {
475 }
else if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"options_prompt")) && !ast_strlen_zero(tmpstr)) {
479 if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
481 }
else if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
485 if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"status-prompt")) && !ast_strlen_zero(tmpstr)) {
487 }
else if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"status_prompt")) && !ast_strlen_zero(tmpstr)) {
491 if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
493 }
else if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
497 if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"connecting-prompt")) && !ast_strlen_zero(tmpstr)) {
499 }
else if ((tmpstr = ast_variable_retrieve(cfg,
"general",
"connecting_prompt")) && !ast_strlen_zero(tmpstr)) {
508 if (!strcasecmp(cat,
"general"))
513 if (!strcasecmp(f->
name, cat))
530 ast_mutex_lock(&f->lock);
534 var = ast_variable_browse(cfg, cat);
536 if (!strcasecmp(var->
name,
"number")) {
542 strcpy(copy, var->
value);
544 if ((tmp = strchr(numberstr,
','))) {
550 if ((tmp = strchr(tmp,
','))) {
552 numorder = atoi(tmp);
574 ast_debug(2,
"Logging parameter %s with value %s from lineno %d\n", var->
name, var->
value, var->lineno);
580 ast_mutex_unlock(&f->lock);
582 AST_RWLIST_INSERT_HEAD(&
followmes, f, entry);
594 struct findme_user *tmpuser;
597 if (tmpuser->ochan && tmpuser->ochan != exception) {
603 static void clear_caller(
struct findme_user *tmpuser)
607 if (!tmpuser->ochan) {
612 outbound = tmpuser->ochan;
614 tmpuser->ochan = NULL;
619 struct findme_user *tmpuser;
623 clear_caller(tmpuser);
628 static void destroy_calling_node(
struct findme_user *
node)
637 struct findme_user *fmuser;
640 destroy_calling_node(fmuser);
651 struct findme_user *tmpuser;
655 long totalwait = 0, wtd = 0, towas = 0;
657 char *pressbuttonname;
664 totalwait = nm->
timeout * 1000;
670 watchers[0] = caller;
674 if (!tmpuser->ochan) {
677 if (tmpuser->state == 3) {
678 tmpuser->digts += (towas - wtd);
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));
684 if (!ast_strlen_zero(tpargs->namerecloc)) {
687 if (!
ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
690 ast_log(LOG_WARNING,
"Unable to playback %s.\n", callfromname);
691 clear_caller(tmpuser);
701 clear_caller(tmpuser);
709 if (ast_channel_stream(tmpuser->ochan)) {
712 if (tmpto > 0 && tmpto < to)
714 else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
716 switch (tmpuser->state) {
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))) {
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));
727 if (!
ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
730 ast_log(LOG_WARNING,
"Unable to playback %s.\n", pressbuttonname);
731 clear_caller(tmpuser);
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));
741 if (!
ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
744 clear_caller(tmpuser);
749 ast_verb(3,
"<%s> Playback of the next step file appears to be done.\n",
750 ast_channel_name(tmpuser->ochan));
758 watchers[pos++] = tmpuser->ochan;
762 ast_verb(3,
"No live channels left for this step.\n");
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);
779 if (winner != caller) {
782 if (tmpuser->ochan == winner) {
795 ast_verb(3,
"%s received a hangup frame.\n", ast_channel_name(winner));
796 if (f->
data.uint32) {
797 ast_channel_hangupcause_set(winner, f->
data.uint32);
800 ast_verb(3,
"The calling channel hungup. Need to drop everyone.\n");
801 publish_dial_end_event(caller, findme_user_list, NULL,
"CANCEL");
805 clear_caller(tmpuser);
812 ast_verb(3,
"%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
814 publish_dial_end_event(caller, findme_user_list, winner,
"CANCEL");
817 ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING);
818 ast_channel_hangupcause_set(caller, AST_CAUSE_NORMAL_CLEARING);
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))) {
826 ast_log(LOG_WARNING,
"Unable to playback %s.\n", callfromname);
827 clear_caller(tmpuser);
835 clear_caller(tmpuser);
839 ast_debug(1,
"Taking call with no prompt\n");
841 return tmpuser->ochan;
845 ast_verb(3,
"%s is busy\n", ast_channel_name(winner));
849 clear_caller(tmpuser);
853 ast_verb(3,
"%s is circuit-busy\n", ast_channel_name(winner));
857 clear_caller(tmpuser);
861 ast_verb(3,
"%s is ringing\n", ast_channel_name(winner));
865 ast_verb(3,
"%s is making progress\n", ast_channel_name(winner));
869 ast_verb(3,
"%s requested a video update\n", ast_channel_name(winner));
872 ast_verb(3,
"%s requested a source update\n", ast_channel_name(winner));
875 ast_verb(3,
"%s is proceeding\n", ast_channel_name(winner));
879 ast_verb(3,
"%s placed call on hold\n", ast_channel_name(winner));
899 ast_verb(3,
"%s removed call from hold\n", ast_channel_name(winner));
917 if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
918 ast_verb(3,
"Connected line update from %s prevented.\n",
919 ast_channel_name(winner));
928 "%s connected line has changed. Saving it until we have a winner.\n",
929 ast_channel_name(winner));
939 "%s connected line has changed. Saving it until answer.\n",
940 ast_channel_name(winner));
960 ast_verb(3,
"%s stopped sounds\n", ast_channel_name(winner));
963 ast_debug(1,
"Dunno what to do with control type %d from %s\n",
968 if (tmpuser && tmpuser->state == 3 && f->
frametype == AST_FRAME_DTMF) {
971 if (ast_channel_stream(winner))
975 if (tmpuser->ynidx < ARRAY_LEN(tmpuser->
yn) - 1) {
979 memmove(tmpuser->
yn, tmpuser->
yn + 1,
980 sizeof(tmpuser->
yn) - 2 *
sizeof(tmpuser->
yn[0]));
985 if (cmp_len <= tmpuser->ynidx
986 && !strcmp(tmpuser->
yn + (tmpuser->ynidx - cmp_len), tpargs->
takecall)) {
987 ast_debug(1,
"Match to take the call!\n");
989 return tmpuser->ochan;
992 if (cmp_len <= tmpuser->ynidx
993 && !strcmp(tmpuser->
yn + (tmpuser->ynidx - cmp_len), tpargs->
nextindp)) {
994 ast_debug(1,
"Declined to take the call.\n");
995 clear_caller(tmpuser);
1001 ast_debug(1,
"we didn't get a frame. hanging up.\n");
1004 ast_verb(3,
"The calling channel hungup. Need to drop everyone.\n");
1009 clear_caller(tmpuser);
1012 ast_debug(1,
"timed out waiting for action\n");
1036 struct findme_user *tmpuser;
1037 struct findme_user *fmuser;
1044 if (nm->
order == idx) {
1049 ast_verb(3,
"No more steps left.\n");
1062 if (tmpuser->ochan) {
1069 for (number = num;
number; number = rest) {
1073 rest = strchr(number,
'&');
1079 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))) {
1080 ast_log(LOG_ERROR,
"Extension '%s@%s' doesn't exist\n", number, tpargs->context);
1089 if (ast_strlen_zero(tpargs->context)) {
1090 snprintf(tmpuser->dialarg,
sizeof(tmpuser->dialarg),
"%s%s",
1092 ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION)
1095 snprintf(tmpuser->dialarg,
sizeof(tmpuser->dialarg),
"%s@%s%s",
1096 number, tpargs->context,
1097 ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION)
1102 ast_channel_lock(caller);
1103 caps =
ao2_bump(ast_channel_nativeformats(caller));
1104 ast_channel_unlock(caller);
1106 outbound =
ast_request(
"Local", caps, NULL, caller, tmpuser->dialarg, &dg);
1111 ast_log(LOG_WARNING,
"Unable to allocate a channel for Local/%s cause: %s\n",
1121 ast_max_forwards_decrement(outbound);
1122 ast_channel_language_set(outbound, ast_channel_language(caller));
1124 ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
1125 ast_channel_unlock(outbound);
1126 ast_channel_unlock(caller);
1128 tmpuser->ochan = outbound;
1157 destroy_calling_node(tmpuser);
1162 if (tmpuser->ochan) {
1172 ast_verb(3,
"calling Local/%s\n", tmpuser->dialarg);
1173 if (
ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) {
1174 ast_verb(3,
"couldn't reach at this number.\n");
1178 destroy_calling_node(tmpuser);
1191 destroy_calling_node(tmpuser);
1204 winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
1208 if (!tmpuser->ochan) {
1210 destroy_calling_node(tmpuser);
1219 if (fmuser->ochan == winner) {
1231 destroy_calling_node(fmuser);
1236 destroy_calling_tree(&findme_user_list);
1240 static struct call_followme *find_realtime(
const char *name)
1246 struct call_followme *new_follower;
1254 var = ast_load_realtime(
"followme",
"name", name, SENTINEL);
1265 init_profile(new_follower, 0);
1267 for (v = var; v; v = v->
next) {
1268 if (!strcasecmp(v->
name,
"active")) {
1270 ast_mutex_destroy(&new_follower->lock);
1271 ast_free(new_follower);
1288 ast_mutex_destroy(&new_follower->lock);
1289 ast_free(new_follower);
1296 const char *timeoutstr;
1301 if (!(numstr = ast_variable_retrieve(cfg, catg,
"phonenumber"))) {
1304 if (!(timeoutstr = ast_variable_retrieve(cfg, catg,
"timeout"))
1305 || sscanf(timeoutstr,
"%30d", &timeout) != 1
1310 ordstr = ast_variable_retrieve(cfg, catg,
"ordinal");
1319 return new_follower;
1322 static void end_bridge_callback(
void *data)
1330 ast_channel_lock(chan);
1335 ast_channel_unlock(chan);
1343 static int app_exec(
struct ast_channel *chan,
const char *data)
1345 struct fm_args *targs;
1347 struct call_followme *f;
1348 struct number *nm, *newnm;
1357 char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
1360 if (ast_strlen_zero(data)) {
1361 ast_log(LOG_WARNING,
"%s requires an argument (followmeid)\n", app);
1365 ast_channel_lock(chan);
1366 max_forwards = ast_max_forwards_get(chan);
1367 ast_channel_unlock(chan);
1369 if (max_forwards <= 0) {
1370 ast_log(LOG_WARNING,
"Unable to execute FollowMe on channel %s. Max forwards exceeded\n",
1371 ast_channel_name(chan));
1379 if (ast_strlen_zero(args.followmeid)) {
1380 ast_log(LOG_WARNING,
"%s requires an argument (followmeid)\n", app);
1390 AST_RWLIST_TRAVERSE(&
followmes, f, entry) {
1391 if (!strcasecmp(f->
name, args.followmeid) && (f->
active))
1396 ast_debug(1,
"New profile %s.\n", args.followmeid);
1399 f = find_realtime(args.followmeid);
1403 ast_log(LOG_WARNING,
"Profile requested, %s, not found in the configuration.\n", args.followmeid);
1414 ast_mutex_lock(&f->lock);
1436 ast_mutex_unlock(&f->lock);
1439 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLEE)
1440 && !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE])) {
1447 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLER)
1448 && !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER])) {
1450 ast_app_exec_sub(NULL, chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER], 0);
1455 ast_clear_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER);
1458 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1466 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_STATUSMSG)) {
1470 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_RECORDNAME)) {
1473 snprintf(targs->namerecloc,
sizeof(targs->namerecloc),
"%s/followme.%s",
1474 ast_config_AST_SPOOL_DIR, ast_channel_uniqueid(chan));
1479 if (!
ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
1480 targs->namerecloc[0] =
'\0';
1484 if (!ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
1494 ast_channel_lock(chan);
1496 ast_channel_unlock(chan);
1498 outbound = findmeexec(targs, chan);
1500 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1508 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) {
1524 memset(&config, 0,
sizeof(config));
1525 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1526 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1527 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1528 config.end_bridge_callback = end_bridge_callback;
1529 config.end_bridge_callback_data = chan;
1530 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1539 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1552 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));
1581 if (!ast_strlen_zero(targs->namerecloc)) {
1583 char fn[PATH_MAX +
sizeof(REC_FORMAT)];
1585 snprintf(fn,
sizeof(fn),
"%s.%s", targs->namerecloc,
1589 ast_log(LOG_NOTICE,
"Failed to delete recorded name file %s: %d (%s)\n",
1590 fn, errno, strerror(errno));
1592 ast_debug(2,
"deleted recorded prompt %s.\n", fn);
1609 static int unload_module(
void)
1611 struct call_followme *f;
1617 while ((f = AST_RWLIST_REMOVE_HEAD(&
followmes, entry))) {
1645 static int reload(
void)
1652 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Find-Me/Follow-Me Application",
1653 .support_level = AST_MODULE_SUPPORT_CORE,
1655 .unload = unload_module,
struct ast_variable * next
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...
Main Channel structure associated with a channel.
char norecordingprompt[PATH_MAX]
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct ast_party_caller caller
Channel Caller ID information.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
unsigned int pending_out_connected_update
char connprompt[PATH_MAX]
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
const char * ast_app_expand_sub_args(struct ast_channel *chan, const char *args)
Add missing context/exten to subroutine argument string.
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...
Support for translation of data formats. translate.c.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
char norecordingprompt[PATH_MAX]
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...
Convenient Signal Processing routines.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
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.
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Structure for variables, used for configurations and for channel variables.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
char callfromprompt[PATH_MAX]
struct ast_party_connected_line connected_out
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
ast_channel_state
ast_channel states
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
Bridge a call, optionally allowing redirection.
char connprompt[PATH_MAX]
const char * ast_cause2str(int cause) attribute_pure
Gives the string form of a given cause code.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
struct call_followme::numbers numbers
char context[AST_MAX_CONTEXT]
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
char plsholdprompt[PATH_MAX]
unsigned int enable_callee_prompt
int ast_unregister_application(const char *app)
Unregister an application.
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
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.
struct ast_frame_subclass subclass
char nextindp[MAX_YN_STRING]
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.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
char callfromprompt[PATH_MAX]
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Configuration File Parser.
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
static int reload_followme(int reload)
Reload followme application module.
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
unsigned int pending_hold
#define ast_config_load(filename, flags)
Load a config file.
struct call_followme::wlnumbers wlnumbers
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Data structure for followme scripts.
static int featuredigittimeout
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
#define ast_strdupa(s)
duplicate a string in memory from the stack
unsigned int pending_in_connected_update
#define AST_MAX_EXTENSION
struct ast_party_connected_line connected
void * end_bridge_callback_data
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
char sorryprompt[PATH_MAX]
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
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.
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
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().
Core PBX routines and definitions.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
static int load_module(void)
Load the module.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
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.
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
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".
char nextindp[MAX_YN_STRING]
Support for dynamic strings.
char optionsprompt[PATH_MAX]
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
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...
Channel datastore data for max forwards.
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.
Connected Line/Party information.
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...
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
struct call_followme::blnumbers blnumbers
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
char name[AST_MAX_EXTENSION]
union ast_frame::@224 data
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
int ast_channel_get_duration(struct ast_channel *chan)
Obtain how long the channel since the channel was created.
#define ast_calloc(num, len)
A wrapper for calloc()
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.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
char statusprompt[PATH_MAX]
Module has failed to load, may be in an inconsistent state.
char suggested_moh[MAX_MUSICCLASS]
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Structure used to handle boolean flags.
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
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...
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
void ast_deactivate_generator(struct ast_channel *chan)
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
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.
char plsholdprompt[PATH_MAX]
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
const char * predial_callee
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
int ast_answer(struct ast_channel *chan)
Answer a channel.
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.
Data structure associated with a single frame of data.
char takecall[MAX_YN_STRING]
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.
Internal Asterisk hangup causes.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
enum ast_frame_type frametype
static const char * defaultmoh
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
char sorryprompt[PATH_MAX]
char takecall[MAX_YN_STRING]
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
char optionsprompt[PATH_MAX]
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Asterisk module definitions.
Persistent data storage (akin to *doze registry)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ast_party_connected_line connected_in
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Structure for mutex and tracking information.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
unsigned int pending_connected_update
char statusprompt[PATH_MAX]
unsigned int enable_callee_prompt