Asterisk - The Open Source Telephony Project GIT-master-7e7a603
app_followme.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * A full-featured Find-Me/Follow-Me Application
5 *
6 * Copyright (C) 2005-2006, BJ Weschke All Rights Reserved.
7 *
8 * BJ Weschke <bweschke@btwtech.com>
9 *
10 * This code is released by the author with no restrictions on usage.
11 *
12 * See http://www.asterisk.org for more information about
13 * the Asterisk project. Please do not directly contact
14 * any of the maintainers of this project for assistance;
15 * the project provides a web site, mailing lists and IRC
16 * channels for your use.
17 *
18 */
19
20/*! \file
21 *
22 * \brief Find-Me Follow-Me application
23 *
24 * \author BJ Weschke <bweschke@btwtech.com>
25 *
26 * \ingroup applications
27 */
28
29/*! \li \ref app_followme.c uses the configuration file \ref followme.conf
30 * \addtogroup configuration_file Configuration Files
31 */
32
33/*!
34 * \page followme.conf followme.conf
35 * \verbinclude followme.conf.sample
36 */
37
38/*** MODULEINFO
39 <support_level>core</support_level>
40 ***/
41
42#include "asterisk.h"
43
44#include <signal.h>
45
46#include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */
47#include "asterisk/lock.h"
48#include "asterisk/file.h"
49#include "asterisk/channel.h"
50#include "asterisk/pbx.h"
51#include "asterisk/module.h"
52#include "asterisk/translate.h"
53#include "asterisk/say.h"
54#include "asterisk/features.h"
56#include "asterisk/cli.h"
57#include "asterisk/manager.h"
58#include "asterisk/config.h"
59#include "asterisk/utils.h"
60#include "asterisk/causes.h"
61#include "asterisk/astdb.h"
62#include "asterisk/dsp.h"
63#include "asterisk/app.h"
66
67#define REC_FORMAT "sln"
68
69/*** DOCUMENTATION
70 <application name="FollowMe" language="en_US">
71 <synopsis>
72 Find-Me/Follow-Me application.
73 </synopsis>
74 <syntax>
75 <parameter name="followmeid" required="true" />
76 <parameter name="options">
77 <optionlist>
78 <option name="a">
79 <para>Record the caller's name so it can be announced to the
80 callee on each step.</para>
81 </option>
82 <option name="B" argsep="^">
83 <para>Before initiating the outgoing call(s), Gosub to the specified
84 location using the current channel.</para>
85 <argument name="context" required="false" />
86 <argument name="exten" required="false" />
87 <argument name="priority" required="true" hasparams="optional" argsep="^">
88 <argument name="arg1" multiple="true" required="true" />
89 <argument name="argN" />
90 </argument>
91 </option>
92 <option name="b" argsep="^">
93 <para>Before initiating an outgoing call, Gosub to the specified
94 location using the newly created channel. The Gosub will be
95 executed for each destination channel.</para>
96 <argument name="context" required="false" />
97 <argument name="exten" required="false" />
98 <argument name="priority" required="true" hasparams="optional" argsep="^">
99 <argument name="arg1" multiple="true" required="true" />
100 <argument name="argN" />
101 </argument>
102 </option>
103 <option name="d">
104 <para>Disable the 'Please hold while we try to connect your call' announcement.</para>
105 </option>
106 <option name="I">
107 <para>Asterisk will ignore any connected line update requests
108 it may receive on this dial attempt.</para>
109 </option>
110 <option name="l">
111 <para>Disable local call optimization so that applications with
112 audio hooks between the local bridge don't get dropped when the
113 calls get joined directly.</para>
114 </option>
115 <option name="N">
116 <para>Don't answer the incoming call until we're ready to
117 connect the caller or give up.</para>
118 <note>
119 <para>This option is ignored if the call is already answered.</para>
120 </note>
121 <note>
122 <para>If the call is not already answered, the 'a' and 's'
123 options are ignored while the 'd' option is implicitly enabled.</para>
124 </note>
125 </option>
126 <option name="n">
127 <para>Playback the unreachable status message if we've run out
128 of steps or the callee has elected not to be reachable.</para>
129 </option>
130 <option name="s">
131 <para>Playback the incoming status message prior to starting
132 the follow-me step(s)</para>
133 </option>
134 </optionlist>
135 </parameter>
136 </syntax>
137 <description>
138 <para>This application performs Find-Me/Follow-Me functionality for the caller
139 as defined in the profile matching the <replaceable>followmeid</replaceable> parameter in
140 <filename>followme.conf</filename>. If the specified <replaceable>followmeid</replaceable>
141 profile doesn't exist in <filename>followme.conf</filename>, execution will be returned
142 to the dialplan and call execution will continue at the next priority.</para>
143 <para>Returns -1 on hangup.</para>
144 </description>
145 </application>
146 ***/
147
148static char *app = "FollowMe";
149
150/*! Maximum accept/decline DTMF string plus terminator. */
151#define MAX_YN_STRING 20
152
153/*! \brief Number structure */
154struct number {
155 char number[512]; /*!< Phone Number(s) and/or Extension(s) */
156 long timeout; /*!< Dial Timeout, if used. */
157 int order; /*!< The order to dial in */
158 AST_LIST_ENTRY(number) entry; /*!< Next Number record */
159};
160
161/*! \brief Data structure for followme scripts */
164 char name[AST_MAX_EXTENSION]; /*!< Name - FollowMeID */
165 char moh[MAX_MUSICCLASS]; /*!< Music On Hold Class to be used */
166 char context[AST_MAX_CONTEXT]; /*!< Context to dial from */
167 unsigned int active; /*!< Profile is active (1), or disabled (0). */
168 int realtime; /*!< Cached from realtime */
169 /*! Allow callees to accept/reject the forwarded call */
170 unsigned int enable_callee_prompt:1;
171 char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */
172 char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */
173 char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
174 char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */
175 char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */
176 char plsholdprompt[PATH_MAX]; /*!< Sound prompt name and path */
177 char statusprompt[PATH_MAX]; /*!< Sound prompt name and path */
178 char sorryprompt[PATH_MAX]; /*!< Sound prompt name and path */
179 char connprompt[PATH_MAX]; /*!< Sound prompt name and path */
180
181 AST_LIST_HEAD_NOLOCK(numbers, number) numbers; /*!< Head of the list of follow-me numbers */
182 AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers; /*!< Head of the list of black-listed numbers */
183 AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers; /*!< Head of the list of white-listed numbers */
184 AST_LIST_ENTRY(call_followme) entry; /*!< Next Follow-Me record */
185};
186
187struct fm_args {
188 char *mohclass;
190 /*! Gosub app arguments for outgoing calls. NULL if not supplied. */
191 const char *predial_callee;
192 /*! Accumulated connected line information from inbound call. */
194 /*! Accumulated connected line information from outbound call. */
196 /*! TRUE if connected line information from inbound call changed. */
198 /*! TRUE if connected line information from outbound call is available. */
200 /*! TRUE if caller has a pending hold request for the winning call. */
201 unsigned int pending_hold:1;
202 /*! TRUE if callees will be prompted to answer */
203 unsigned int enable_callee_prompt:1;
204 /*! Music On Hold Class suggested by caller hold for winning call. */
208 char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */
209 char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */
210 char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
211 char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */
212 char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */
213 char plsholdprompt[PATH_MAX]; /*!< Sound prompt name and path */
214 char statusprompt[PATH_MAX]; /*!< Sound prompt name and path */
215 char sorryprompt[PATH_MAX]; /*!< Sound prompt name and path */
216 char connprompt[PATH_MAX]; /*!< Sound prompt name and path */
218};
219
222 /*! Accumulated connected line information from outgoing call. */
224 long digts;
225 int ynidx;
226 int state;
227 char dialarg[768];
228 /*! Collected digits to accept/decline the call. */
230 /*! TRUE if the outgoing call is answered. */
231 unsigned int answered:1;
232 /*! TRUE if connected line information is available. */
235};
236
237enum {
247};
248
249enum {
252
253 /* note: this entry _MUST_ be the last one in the enum */
256
267});
268
269static const char *featuredigittostr;
270static int featuredigittimeout = 5000; /*!< Feature Digit Timeout */
271static const char *defaultmoh = "default"; /*!< Default Music-On-Hold Class */
272
273static char takecall[MAX_YN_STRING] = "1";
274static char nextindp[MAX_YN_STRING] = "2";
275static int enable_callee_prompt = 1;
276static char callfromprompt[PATH_MAX] = "followme/call-from";
277static char norecordingprompt[PATH_MAX] = "followme/no-recording";
278static char optionsprompt[PATH_MAX] = "followme/options";
279static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try";
280static char statusprompt[PATH_MAX] = "followme/status";
281static char sorryprompt[PATH_MAX] = "followme/sorry";
282static char connprompt[PATH_MAX] = "";
283
284
287
288static void free_numbers(struct call_followme *f)
289{
290 /* Free numbers attached to the profile */
291 struct number *prev;
292
293 while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
294 /* Free the number */
295 ast_free(prev);
297
298 while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
299 /* Free the blacklisted number */
300 ast_free(prev);
302
303 while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
304 /* Free the whitelisted number */
305 ast_free(prev);
307}
308
309
310/*! \brief Allocate and initialize followme profile */
311static struct call_followme *alloc_profile(const char *fmname)
312{
313 struct call_followme *f;
314
315 if (!(f = ast_calloc(1, sizeof(*f))))
316 return NULL;
317
318 ast_mutex_init(&f->lock);
319 ast_copy_string(f->name, fmname, sizeof(f->name));
323 return f;
324}
325
326static void init_profile(struct call_followme *f, int activate)
327{
329 f->context[0] = '\0';
330 ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
331 ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
332 ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
340 if (activate) {
341 f->active = 1;
342 }
343}
344
345
346
347/*! \brief Set parameter in profile from configuration file */
348static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
349{
350
351 if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
352 ast_copy_string(f->moh, val, sizeof(f->moh));
353 else if (!strcasecmp(param, "context"))
354 ast_copy_string(f->context, val, sizeof(f->context));
355 else if (!strcasecmp(param, "enable_callee_prompt"))
357 else if (!strcasecmp(param, "takecall"))
358 ast_copy_string(f->takecall, val, sizeof(f->takecall));
359 else if (!strcasecmp(param, "declinecall"))
360 ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
361 else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
363 else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
365 else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
367 else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
369 else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
371 else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
373 else if (!strcasecmp(param, "followme-connecting-prompt") || !strcasecmp(param, "connecting_prompt")) {
374 ast_copy_string(f->connprompt, val, sizeof(f->connprompt));
375 } else if (failunknown) {
376 if (linenum >= 0)
377 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
378 else
379 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
380 }
381}
382
383/*! \brief Add a new number */
384static struct number *create_followme_number(const char *number, int timeout, int numorder)
385{
386 struct number *cur;
387 char *buf = ast_strdupa(number);
388 char *tmp;
389
390 if (!(cur = ast_calloc(1, sizeof(*cur))))
391 return NULL;
392
393 cur->timeout = timeout;
394 if ((tmp = strchr(buf, ',')))
395 *tmp = '\0';
396 ast_copy_string(cur->number, buf, sizeof(cur->number));
397 cur->order = numorder;
398 ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
399
400 return cur;
401}
402
403/*! \brief Reload followme application module */
404static int reload_followme(int reload)
405{
406 struct call_followme *f;
407 struct ast_config *cfg;
408 char *cat = NULL, *tmp;
409 struct ast_variable *var;
410 struct number *cur, *nm;
411 int timeout;
412 int numorder;
413 const char* enable_callee_prompt_str;
414 const char *takecallstr;
415 const char *declinecallstr;
416 const char *tmpstr;
417 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
418
419 if (!(cfg = ast_config_load("followme.conf", config_flags))) {
420 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
421 return 0;
422 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
423 return 0;
424 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
425 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
426 return 0;
427 }
428
430
431 /* Reset Global Var Values */
432 featuredigittimeout = 5000;
433
434 /* Mark all profiles as inactive for the moment */
436 f->active = 0;
437 }
438
439 featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
440
442 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
443 featuredigittimeout = 5000;
444 }
445
446 if ((enable_callee_prompt_str = ast_variable_retrieve(cfg, "general",
447 "enable_callee_prompt")) &&
448 !ast_strlen_zero(enable_callee_prompt_str)) {
449 enable_callee_prompt = ast_true(enable_callee_prompt_str);
450 }
451
452 if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
453 ast_copy_string(takecall, takecallstr, sizeof(takecall));
454 }
455
456 if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
457 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
458 }
459
460 if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
462 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
464 }
465
466 if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
468 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
470 }
471
472
473 if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
475 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
477 }
478
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)) {
483 }
484
485 if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
486 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
487 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
488 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
489 }
490
491 if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
492 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
493 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
494 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
495 }
496
497 if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting-prompt")) && !ast_strlen_zero(tmpstr)) {
498 ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
499 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting_prompt")) && !ast_strlen_zero(tmpstr)) {
500 ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
501 }
502
503
504 /* Chug through config file */
505 while ((cat = ast_category_browse(cfg, cat))) {
506 int new = 0;
507
508 if (!strcasecmp(cat, "general"))
509 continue;
510
511 /* Look for an existing one */
513 if (!strcasecmp(f->name, cat))
514 break;
515 }
516
517 ast_debug(1, "New profile %s.\n", cat);
518
519 if (!f) {
520 /* Make one then */
521 f = alloc_profile(cat);
522 new = 1;
523 }
524
525 /* Totally fail if we fail to find/create an entry */
526 if (!f)
527 continue;
528
529 if (!new)
530 ast_mutex_lock(&f->lock);
531 /* Re-initialize the profile */
532 init_profile(f, 1);
533 free_numbers(f);
534 var = ast_variable_browse(cfg, cat);
535 while (var) {
536 if (!strcasecmp(var->name, "number")) {
537 int idx = 0;
538 char copy[strlen(var->value) + 1];
539 char *numberstr;
540
541 /* Add a new number */
542 strcpy(copy, var->value); /* safe */
543 numberstr = copy;
544 if ((tmp = strchr(numberstr, ','))) {
545 *tmp++ = '\0';
546 timeout = atoi(tmp);
547 if (timeout < 0) {
548 timeout = 25;
549 }
550 if ((tmp = strchr(tmp, ','))) {
551 *tmp++ = '\0';
552 numorder = atoi(tmp);
553 if (numorder < 0)
554 numorder = 0;
555 } else
556 numorder = 0;
557 } else {
558 timeout = 25;
559 numorder = 0;
560 }
561
562 if (!numorder) {
563 idx = 1;
565 idx++;
566 numorder = idx;
567 }
568 cur = create_followme_number(numberstr, timeout, numorder);
569 if (cur) {
571 }
572 } else {
573 profile_set_param(f, var->name, var->value, var->lineno, 1);
574 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
575 }
576 var = var->next;
577 } /* End while(var) loop */
578
579 if (!new)
581 else
583 }
584
586
588
589 return 1;
590}
591
592static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
593{
594 struct findme_user *tmpuser;
595
596 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
597 if (tmpuser->ochan && tmpuser->ochan != exception) {
599 }
600 }
601}
602
603static void clear_caller(struct findme_user *tmpuser)
604{
605 struct ast_channel *outbound;
606
607 if (!tmpuser->ochan) {
608 /* Call already cleared. */
609 return;
610 }
611
612 outbound = tmpuser->ochan;
613 ast_hangup(outbound);
614 tmpuser->ochan = NULL;
615}
616
617static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list)
618{
619 struct findme_user *tmpuser;
620
621 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
622 if (!tmpuser->answered) {
623 clear_caller(tmpuser);
624 }
625 }
626}
627
629{
632 ast_free(node);
633}
634
635static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
636{
637 struct findme_user *fmuser;
638
639 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
640 destroy_calling_node(fmuser);
641 }
642}
643
644static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs)
645{
647 struct ast_channel *watchers[256];
648 int pos;
649 struct ast_channel *winner;
650 struct ast_frame *f;
651 struct findme_user *tmpuser;
652 int to = 0;
653 int livechannels;
654 int tmpto;
655 long totalwait = 0, wtd = 0, towas = 0;
656 char *callfromname;
657 char *pressbuttonname;
658
659 /* ------------ wait_for_winner_channel start --------------- */
660
661 callfromname = ast_strdupa(tpargs->callfromprompt);
662 pressbuttonname = ast_strdupa(tpargs->optionsprompt);
663
664 totalwait = nm->timeout * 1000;
665
666 for (;;) {
667 to = 1000;
668 pos = 1;
669 livechannels = 0;
670 watchers[0] = caller;
671
672 winner = NULL;
673 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
674 if (!tmpuser->ochan) {
675 continue;
676 }
677 if (tmpuser->state == 3) {
678 tmpuser->digts += (towas - wtd);
679 }
680 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
681 ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n",
682 ast_channel_name(tmpuser->ochan));
683 if (tpargs->enable_callee_prompt) {
684 if (!ast_strlen_zero(tpargs->namerecloc)) {
685 tmpuser->state = 1;
686 tmpuser->digts = 0;
687 if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
689 } else {
690 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
691 clear_caller(tmpuser);
692 continue;
693 }
694 } else {
695 tmpuser->state = 2;
696 tmpuser->digts = 0;
697 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
699 else {
700 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
701 clear_caller(tmpuser);
702 continue;
703 }
704 }
705 } else {
706 tmpuser->state = 3;
707 }
708 }
709 if (ast_channel_stream(tmpuser->ochan)) {
711 tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan));
712 if (tmpto > 0 && tmpto < to)
713 to = tmpto;
714 else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
715 ast_stopstream(tmpuser->ochan);
716 switch (tmpuser->state) {
717 case 1:
718 ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n",
719 ast_channel_name(tmpuser->ochan));
720 if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) {
721 tmpuser->state = 2;
722 } else {
723 ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n",
724 ast_channel_name(tmpuser->ochan), tpargs->namerecloc);
725 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
726 tmpuser->ynidx = 0;
727 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
728 tmpuser->state = 3;
729 else {
730 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
731 clear_caller(tmpuser);
732 continue;
733 }
734 }
735 break;
736 case 2:
737 ast_verb(3, "<%s> Playback of name file appears to be done.\n",
738 ast_channel_name(tmpuser->ochan));
739 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
740 tmpuser->ynidx = 0;
741 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
742 tmpuser->state = 3;
743 } else {
744 clear_caller(tmpuser);
745 continue;
746 }
747 break;
748 case 3:
749 ast_verb(3, "<%s> Playback of the next step file appears to be done.\n",
750 ast_channel_name(tmpuser->ochan));
751 tmpuser->digts = 0;
752 break;
753 default:
754 break;
755 }
756 }
757 }
758 watchers[pos++] = tmpuser->ochan;
759 livechannels++;
760 }
761 if (!livechannels) {
762 ast_verb(3, "No live channels left for this step.\n");
763 return NULL;
764 }
765
766 tmpto = to;
767 towas = to;
768 winner = ast_waitfor_n(watchers, pos, &to);
769 tmpto -= to;
770 totalwait -= tmpto;
771 wtd = to;
772 if (totalwait <= 0) {
773 ast_verb(3, "We've hit our timeout for this step. Dropping unanswered calls and starting the next step.\n");
774 clear_unanswered_calls(findme_user_list);
775 return NULL;
776 }
777 if (winner) {
778 /* Need to find out which channel this is */
779 if (winner != caller) {
780 /* The winner is an outgoing channel. */
781 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
782 if (tmpuser->ochan == winner) {
783 break;
784 }
785 }
786 } else {
787 tmpuser = NULL;
788 }
789
790 f = ast_read(winner);
791 if (f) {
792 if (f->frametype == AST_FRAME_CONTROL) {
793 switch (f->subclass.integer) {
795 ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner));
796 if (f->data.uint32) {
798 }
799 if (!tmpuser) {
800 ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
801 publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL");
802 ast_frfree(f);
803 return NULL;
804 }
805 clear_caller(tmpuser);
806 break;
808 if (!tmpuser) {
809 /* The caller answered? We want an outgoing channel to answer. */
810 break;
811 }
812 ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
813 ast_channel_publish_dial(caller, winner, NULL, "ANSWER");
814 publish_dial_end_event(caller, findme_user_list, winner, "CANCEL");
815 tmpuser->answered = 1;
816 /* If call has been answered, then the eventual hangup is likely to be normal hangup */
819 if (tpargs->enable_callee_prompt) {
820 ast_verb(3, "Starting playback of %s\n", callfromname);
821 if (!ast_strlen_zero(tpargs->namerecloc)) {
822 if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) {
824 tmpuser->state = 1;
825 } else {
826 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
827 clear_caller(tmpuser);
828 }
829 } else {
830 tmpuser->state = 2;
831 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
833 else {
834 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
835 clear_caller(tmpuser);
836 }
837 }
838 } else {
839 ast_debug(1, "Taking call with no prompt\n");
840 ast_frfree(f);
841 return tmpuser->ochan;
842 }
843 break;
844 case AST_CONTROL_BUSY:
845 ast_verb(3, "%s is busy\n", ast_channel_name(winner));
846 if (tmpuser) {
847 /* Outbound call was busy. Drop it. */
848 ast_channel_publish_dial(caller, winner, NULL, "BUSY");
849 clear_caller(tmpuser);
850 }
851 break;
853 ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
854 if (tmpuser) {
855 /* Outbound call was congested. Drop it. */
856 ast_channel_publish_dial(caller, winner, NULL, "CONGESTION");
857 clear_caller(tmpuser);
858 }
859 break;
861 ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
862 ast_channel_publish_dial(caller, winner, NULL, "RINGING");
863 break;
865 ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
866 ast_channel_publish_dial(caller, winner, NULL, "PROGRESS");
867 break;
869 ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
870 break;
872 ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
873 break;
875 ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
876 ast_channel_publish_dial(caller, winner, NULL, "PROCEEDING");
877 break;
878 case AST_CONTROL_HOLD:
879 ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
880 if (!tmpuser) {
881 /* Caller placed outgoing calls on hold. */
882 tpargs->pending_hold = 1;
883 if (f->data.ptr) {
885 sizeof(tpargs->suggested_moh));
886 } else {
887 tpargs->suggested_moh[0] = '\0';
888 }
889 } else {
890 /*
891 * Outgoing call placed caller on hold.
892 *
893 * Ignore because the outgoing call should not be able to place
894 * the caller on hold until after they are bridged.
895 */
896 }
897 break;
899 ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
900 if (!tmpuser) {
901 /* Caller removed outgoing calls from hold. */
902 tpargs->pending_hold = 0;
903 } else {
904 /*
905 * Outgoing call removed caller from hold.
906 *
907 * Ignore because the outgoing call should not be able to place
908 * the caller on hold until after they are bridged.
909 */
910 }
911 break;
914 /* Ignore going off hook and flash */
915 break;
918 ast_verb(3, "Connected line update from %s prevented.\n",
919 ast_channel_name(winner));
920 break;
921 }
922 if (!tmpuser) {
923 /*
924 * Hold connected line update from caller until we have a
925 * winner.
926 */
927 ast_verb(3,
928 "%s connected line has changed. Saving it until we have a winner.\n",
929 ast_channel_name(winner));
933 &connected, NULL);
934 tpargs->pending_in_connected_update = 1;
935 }
937 } else {
938 ast_verb(3,
939 "%s connected line has changed. Saving it until answer.\n",
940 ast_channel_name(winner));
944 &connected, NULL);
945 tmpuser->pending_connected_update = 1;
946 }
948 }
949 break;
951 /*
952 * Ignore because we are masking the FollowMe search progress to
953 * the caller.
954 */
955 break;
957 ast_indicate_data(caller, f->subclass.integer, f->data.ptr, f->datalen);
958 break;
959 case -1:
960 ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
961 break;
962 default:
963 ast_debug(1, "Dunno what to do with control type %d from %s\n",
964 f->subclass.integer, ast_channel_name(winner));
965 break;
966 }
967 }
968 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
969 int cmp_len;
970
971 if (ast_channel_stream(winner))
972 ast_stopstream(winner);
973 tmpuser->digts = 0;
974 ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
975 if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
976 tmpuser->yn[tmpuser->ynidx++] = f->subclass.integer;
977 } else {
978 /* Discard oldest digit. */
979 memmove(tmpuser->yn, tmpuser->yn + 1,
980 sizeof(tmpuser->yn) - 2 * sizeof(tmpuser->yn[0]));
981 tmpuser->yn[ARRAY_LEN(tmpuser->yn) - 2] = f->subclass.integer;
982 }
983 ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
984 cmp_len = strlen(tpargs->takecall);
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");
988 ast_frfree(f);
989 return tmpuser->ochan;
990 }
991 cmp_len = strlen(tpargs->nextindp);
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);
996 }
997 }
998
999 ast_frfree(f);
1000 } else {
1001 ast_debug(1, "we didn't get a frame. hanging up.\n");
1002 if (!tmpuser) {
1003 /* Caller hung up. */
1004 ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
1005 return NULL;
1006 }
1007 /* Outgoing channel hung up. */
1008 ast_channel_publish_dial(caller, winner, NULL, "NOANSWER");
1009 clear_caller(tmpuser);
1010 }
1011 } else {
1012 ast_debug(1, "timed out waiting for action\n");
1013 }
1014 }
1015
1016 /* Unreachable. */
1017}
1018
1019/*!
1020 * \internal
1021 * \brief Find an extension willing to take the call.
1022 *
1023 * \param tpargs Active Followme config.
1024 * \param caller Channel initiating the outgoing calls.
1025 *
1026 * \retval winner Winning outgoing call.
1027 * \retval NULL if could not find someone to take the call.
1028 */
1029static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
1030{
1031 struct number *nm;
1032 struct ast_channel *winner = NULL;
1033 char num[512];
1034 int dg, idx;
1035 char *rest, *number;
1036 struct findme_user *tmpuser;
1037 struct findme_user *fmuser;
1038 struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1040
1041 for (idx = 1; !ast_check_hangup(caller); ++idx) {
1042 /* Find next followme numbers to dial. */
1043 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
1044 if (nm->order == idx) {
1045 break;
1046 }
1047 }
1048 if (!nm) {
1049 ast_verb(3, "No more steps left.\n");
1050 break;
1051 }
1052
1053 ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout);
1054
1055 /*
1056 * Put all active outgoing channels into autoservice.
1057 *
1058 * This needs to be done because ast_exists_extension() may put
1059 * the caller into autoservice.
1060 */
1061 AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1062 if (tmpuser->ochan) {
1063 ast_autoservice_start(tmpuser->ochan);
1064 }
1065 }
1066
1067 /* Create all new outgoing calls */
1068 ast_copy_string(num, nm->number, sizeof(num));
1069 for (number = num; number; number = rest) {
1070 struct ast_channel *outbound;
1071 struct ast_format_cap *caps;
1072
1073 rest = strchr(number, '&');
1074 if (rest) {
1075 *rest++ = 0;
1076 }
1077
1078 /* We check if the extension exists, before creating the ast_channel struct */
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);
1081 continue;
1082 }
1083
1084 tmpuser = ast_calloc(1, sizeof(*tmpuser));
1085 if (!tmpuser) {
1086 continue;
1087 }
1088
1089 if (ast_strlen_zero(tpargs->context)) {
1090 snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s%s",
1091 number,
1093 ? "/n" : "/m");
1094 } else {
1095 snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s@%s%s",
1096 number, tpargs->context,
1098 ? "/n" : "/m");
1099 }
1100
1101 /* Capture nativeformats reference in case it gets changed */
1102 ast_channel_lock(caller);
1103 caps = ao2_bump(ast_channel_nativeformats(caller));
1104 ast_channel_unlock(caller);
1105
1106 outbound = ast_request("Local", caps, NULL, caller, tmpuser->dialarg, &dg);
1107
1108 ao2_cleanup(caps);
1109
1110 if (!outbound) {
1111 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
1112 tmpuser->dialarg, ast_cause2str(dg));
1113 ast_free(tmpuser);
1114 continue;
1115 }
1116
1117 ast_channel_lock_both(caller, outbound);
1119 ast_channel_inherit_variables(caller, outbound);
1120 ast_channel_datastore_inherit(caller, 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);
1127
1128 tmpuser->ochan = outbound;
1129 tmpuser->state = 0;
1130 AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry);
1131 }
1132
1133 /*
1134 * PREDIAL: Run gosub on all of the new callee channels
1135 *
1136 * We run the callee predial before ast_call() in case the user
1137 * wishes to do something on the newly created channels before
1138 * the channel does anything important.
1139 */
1140 if (tpargs->predial_callee && !AST_LIST_EMPTY(&new_user_list)) {
1141 /* Put caller into autoservice. */
1142 ast_autoservice_start(caller);
1143
1144 /* Run predial on all new outgoing calls. */
1145 AST_LIST_TRAVERSE(&new_user_list, tmpuser, entry) {
1146 ast_pre_call(tmpuser->ochan, tpargs->predial_callee);
1147 }
1148
1149 /* Take caller out of autoservice. */
1150 if (ast_autoservice_stop(caller)) {
1151 /*
1152 * Caller hungup.
1153 *
1154 * Destoy all new outgoing calls.
1155 */
1156 while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
1157 destroy_calling_node(tmpuser);
1158 }
1159
1160 /* Take all active outgoing channels out of autoservice. */
1161 AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1162 if (tmpuser->ochan) {
1163 ast_autoservice_stop(tmpuser->ochan);
1164 }
1165 }
1166 break;
1167 }
1168 }
1169
1170 /* Start all new outgoing calls */
1171 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_user_list, tmpuser, entry) {
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");
1176
1177 /* Destroy this failed new outgoing call. */
1178 destroy_calling_node(tmpuser);
1179 continue;
1180 }
1181
1182 ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL);
1183 }
1185
1186 /* Take all active outgoing channels out of autoservice. */
1187 AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1188 if (tmpuser->ochan && ast_autoservice_stop(tmpuser->ochan)) {
1189 /* Existing outgoing call hungup. */
1191 destroy_calling_node(tmpuser);
1192 }
1193 }
1195
1196 if (AST_LIST_EMPTY(&new_user_list)) {
1197 /* No new channels remain at this order level. If there were any at all. */
1198 continue;
1199 }
1200
1201 /* Add new outgoing channels to the findme list. */
1202 AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry);
1203
1204 winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
1205 if (!winner) {
1206 /* Remove all dead outgoing nodes. */
1207 AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1208 if (!tmpuser->ochan) {
1210 destroy_calling_node(tmpuser);
1211 }
1212 }
1214 continue;
1215 }
1216
1217 /* Destroy losing calls up to the winner. The rest will be destroyed later. */
1218 while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) {
1219 if (fmuser->ochan == winner) {
1220 /*
1221 * Pass any connected line info up.
1222 *
1223 * NOTE: This code must be in line with destroy_calling_node().
1224 */
1225 tpargs->connected_out = fmuser->connected;
1227 ast_free(fmuser);
1228 break;
1229 } else {
1230 /* Destroy losing call. */
1231 destroy_calling_node(fmuser);
1232 }
1233 }
1234 break;
1235 }
1236 destroy_calling_tree(&findme_user_list);
1237 return winner;
1238}
1239
1240static struct call_followme *find_realtime(const char *name)
1241{
1242 struct ast_variable *var;
1243 struct ast_variable *v;
1244 struct ast_config *cfg;
1245 const char *catg;
1246 struct call_followme *new_follower;
1247 struct ast_str *str;
1248
1249 str = ast_str_create(16);
1250 if (!str) {
1251 return NULL;
1252 }
1253
1254 var = ast_load_realtime("followme", "name", name, SENTINEL);
1255 if (!var) {
1256 ast_free(str);
1257 return NULL;
1258 }
1259
1260 if (!(new_follower = alloc_profile(name))) {
1262 ast_free(str);
1263 return NULL;
1264 }
1265 init_profile(new_follower, 0);
1266
1267 for (v = var; v; v = v->next) {
1268 if (!strcasecmp(v->name, "active")) {
1269 if (ast_false(v->value)) {
1270 ast_mutex_destroy(&new_follower->lock);
1271 ast_free(new_follower);
1273 ast_free(str);
1274 return NULL;
1275 }
1276 } else {
1277 profile_set_param(new_follower, v->name, v->value, 0, 0);
1278 }
1279 }
1280
1282 new_follower->realtime = 1;
1283
1284 /* Load numbers */
1285 cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
1286 name, SENTINEL);
1287 if (!cfg) {
1288 ast_mutex_destroy(&new_follower->lock);
1289 ast_free(new_follower);
1290 ast_free(str);
1291 return NULL;
1292 }
1293
1294 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
1295 const char *numstr;
1296 const char *timeoutstr;
1297 const char *ordstr;
1298 int timeout;
1299 struct number *cur;
1300
1301 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
1302 continue;
1303 }
1304 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
1305 || sscanf(timeoutstr, "%30d", &timeout) != 1
1306 || timeout < 1) {
1307 timeout = 25;
1308 }
1309 /* This one has to exist; it was part of the query */
1310 ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
1311 ast_str_set(&str, 0, "%s", numstr);
1312 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
1313 AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
1314 }
1315 }
1316 ast_config_destroy(cfg);
1317
1318 ast_free(str);
1319 return new_follower;
1320}
1321
1322static void end_bridge_callback(void *data)
1323{
1324 char buf[80];
1325 time_t end;
1326 struct ast_channel *chan = data;
1327
1328 time(&end);
1329
1330 ast_channel_lock(chan);
1331 snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
1332 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1333 snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
1334 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1335 ast_channel_unlock(chan);
1336}
1337
1338static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
1339{
1340 bconfig->end_bridge_callback_data = originator;
1341}
1342
1343static int app_exec(struct ast_channel *chan, const char *data)
1344{
1345 struct fm_args *targs;
1347 struct call_followme *f;
1348 struct number *nm, *newnm;
1349 int res = 0;
1350 char *argstr;
1351 struct ast_channel *caller;
1352 struct ast_channel *outbound;
1354 AST_APP_ARG(followmeid);
1356 );
1357 char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
1358 int max_forwards;
1359
1360 if (ast_strlen_zero(data)) {
1361 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1362 return -1;
1363 }
1364
1365 ast_channel_lock(chan);
1367 ast_channel_unlock(chan);
1368
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));
1372 return -1;
1373 }
1374
1375 argstr = ast_strdupa((char *) data);
1376
1377 AST_STANDARD_APP_ARGS(args, argstr);
1378
1379 if (ast_strlen_zero(args.followmeid)) {
1380 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1381 return -1;
1382 }
1383
1384 targs = ast_calloc(1, sizeof(*targs));
1385 if (!targs) {
1386 return -1;
1387 }
1388
1391 if (!strcasecmp(f->name, args.followmeid) && (f->active))
1392 break;
1393 }
1395
1396 ast_debug(1, "New profile %s.\n", args.followmeid);
1397
1398 if (!f) {
1399 f = find_realtime(args.followmeid);
1400 }
1401
1402 if (!f) {
1403 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1404 ast_free(targs);
1405 return 0;
1406 }
1407
1408 /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1409 if (args.options) {
1410 ast_app_parse_options(followme_opts, &targs->followmeflags, opt_args, args.options);
1411 }
1412
1413 /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1414 ast_mutex_lock(&f->lock);
1416 targs->mohclass = ast_strdupa(f->moh);
1417 ast_copy_string(targs->context, f->context, sizeof(targs->context));
1418 ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall));
1419 ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp));
1420 ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt));
1422 ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt));
1423 ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt));
1424 ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt));
1425 ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt));
1426 ast_copy_string(targs->connprompt, f->connprompt, sizeof(targs->connprompt));
1427 /* Copy the numbers we're going to use into another list in case the master list should get modified
1428 (and locked) while we're trying to do a follow-me */
1430 AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1431 newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1432 if (newnm) {
1433 AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry);
1434 }
1435 }
1437
1438 /* PREDIAL: Preprocess any callee gosub arguments. */
1442 targs->predial_callee =
1444 }
1445
1446 /* PREDIAL: Run gosub on the caller's channel */
1451 }
1452
1453 /* Forget the 'N' option if the call is already up. */
1454 if (ast_channel_state(chan) == AST_STATE_UP) {
1456 }
1457
1460 } else {
1461 /* Answer the call */
1462 if (ast_channel_state(chan) != AST_STATE_UP) {
1463 ast_answer(chan);
1464 }
1465
1467 ast_stream_and_wait(chan, targs->statusprompt, "");
1468 }
1469
1471 int duration = 5;
1472
1473 snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s",
1475 if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration,
1477 goto outrun;
1478 }
1479 if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
1480 targs->namerecloc[0] = '\0';
1481 }
1482 }
1483
1485 if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) {
1486 goto outrun;
1487 }
1488 if (ast_waitstream(chan, "") < 0)
1489 goto outrun;
1490 }
1491 ast_moh_start(chan, targs->mohclass, NULL);
1492 }
1493
1494 ast_channel_lock(chan);
1496 ast_channel_unlock(chan);
1497
1498 outbound = findmeexec(targs, chan);
1499 if (!outbound) {
1501 if (ast_channel_state(chan) != AST_STATE_UP) {
1502 ast_answer(chan);
1503 }
1504 } else {
1505 ast_moh_stop(chan);
1506 }
1507
1509 ast_stream_and_wait(chan, targs->sorryprompt, "");
1510 }
1511 res = 0;
1512 } else {
1513 caller = chan;
1514
1515 /* Play "connecting" message to the winner, if configured. */
1516 if (!ast_strlen_zero(targs->connprompt)) {
1518 ast_stream_and_wait(outbound, targs->connprompt, "");
1520 }
1521
1522 /* Bridge the two channels. */
1523
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;
1531
1532 /* Update connected line to caller if available. */
1533 if (targs->pending_out_connected_update) {
1534 if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0)) {
1536 }
1537 }
1538
1542 }
1543 } else {
1545 }
1546
1547 /* Be sure no generators are left on it */
1549 /* Make sure channels are compatible */
1550 res = ast_channel_make_compatible(caller, outbound);
1551 if (res < 0) {
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));
1554 goto outrun;
1555 }
1556
1557 /* Update connected line to winner if changed. */
1558 if (targs->pending_in_connected_update) {
1559 if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0)) {
1561 }
1562 }
1563
1564 /* Put winner on hold if caller requested. */
1565 if (targs->pending_hold) {
1566 if (ast_strlen_zero(targs->suggested_moh)) {
1568 } else {
1570 targs->suggested_moh, strlen(targs->suggested_moh) + 1);
1571 }
1572 }
1573
1574 res = ast_bridge_call(caller, outbound, &config);
1575 }
1576
1577outrun:
1578 while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) {
1579 ast_free(nm);
1580 }
1581 if (!ast_strlen_zero(targs->namerecloc)) {
1582 int ret;
1583 char fn[PATH_MAX + sizeof(REC_FORMAT)];
1584
1585 snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc,
1586 REC_FORMAT);
1587 ret = unlink(fn);
1588 if (ret != 0) {
1589 ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n",
1590 fn, errno, strerror(errno));
1591 } else {
1592 ast_debug(2, "deleted recorded prompt %s.\n", fn);
1593 }
1594 }
1595 ast_free((char *) targs->predial_callee);
1598 ast_free(targs);
1599
1600 if (f->realtime) {
1601 /* Not in list */
1602 free_numbers(f);
1603 ast_free(f);
1604 }
1605
1606 return res;
1607}
1608
1609static int unload_module(void)
1610{
1611 struct call_followme *f;
1612
1614
1615 /* Free Memory. Yeah! I'm free! */
1617 while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1618 free_numbers(f);
1619 ast_free(f);
1620 }
1621
1623
1624 return 0;
1625}
1626
1627/*!
1628 * \brief Load the module
1629 *
1630 * Module loading including tests for configuration or dependencies.
1631 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1632 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1633 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1634 * configuration file or other non-critical problem return
1635 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1636 */
1637static int load_module(void)
1638{
1639 if(!reload_followme(0))
1641
1643}
1644
1645static int reload(void)
1646{
1647 reload_followme(1);
1648
1649 return 0;
1650}
1651
1652AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
1653 .support_level = AST_MODULE_SUPPORT_CORE,
1654 .load = load_module,
1655 .unload = unload_module,
1656 .reload = reload,
static char connprompt[PATH_MAX]
Definition: app_followme.c:282
static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
Set parameter in profile from configuration file.
Definition: app_followme.c:348
@ FOLLOWMEFLAG_UNREACHABLEMSG
Definition: app_followme.c:240
@ FOLLOWMEFLAG_DISABLEHOLDPROMPT
Definition: app_followme.c:241
@ FOLLOWMEFLAG_NOANSWER
Definition: app_followme.c:242
@ FOLLOWMEFLAG_PREDIAL_CALLER
Definition: app_followme.c:245
@ FOLLOWMEFLAG_IGNORE_CONNECTEDLINE
Definition: app_followme.c:244
@ FOLLOWMEFLAG_RECORDNAME
Definition: app_followme.c:239
@ FOLLOWMEFLAG_DISABLEOPTIMIZATION
Definition: app_followme.c:243
@ FOLLOWMEFLAG_PREDIAL_CALLEE
Definition: app_followme.c:246
@ FOLLOWMEFLAG_STATUSMSG
Definition: app_followme.c:238
#define REC_FORMAT
Definition: app_followme.c:67
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:281
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:404
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:276
#define MAX_YN_STRING
Definition: app_followme.c:151
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:273
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:311
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:603
static struct ast_channel * findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:617
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:274
static int featuredigittimeout
Definition: app_followme.c:270
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:278
static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:635
static const struct ast_app_option followme_opts[128]
Definition: app_followme.c:267
static void init_profile(struct call_followme *f, int activate)
Definition: app_followme.c:326
static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
Definition: app_followme.c:592
static char statusprompt[PATH_MAX]
Definition: app_followme.c:280
static char * app
Definition: app_followme.c:148
static int app_exec(struct ast_channel *chan, const char *data)
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:279
@ FOLLOWMEFLAG_ARG_ARRAY_SIZE
Definition: app_followme.c:254
@ FOLLOWMEFLAG_ARG_PREDIAL_CALLER
Definition: app_followme.c:250
@ FOLLOWMEFLAG_ARG_PREDIAL_CALLEE
Definition: app_followme.c:251
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:384
static int load_module(void)
Load the module.
static struct call_followme * find_realtime(const char *name)
static const char * featuredigittostr
Definition: app_followme.c:269
static void end_bridge_callback(void *data)
static int unload_module(void)
static int reload(void)
static char norecordingprompt[PATH_MAX]
Definition: app_followme.c:277
static void destroy_calling_node(struct findme_user *node)
Definition: app_followme.c:628
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static int enable_callee_prompt
Definition: app_followme.c:275
static struct ast_channel * wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs)
Definition: app_followme.c:644
static const char * defaultmoh
Definition: app_followme.c:271
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:288
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition: ast_expr2f.c:605
Persistent data storage (akin to *doze registry)
Asterisk main include file. File version handling, generic pbx functions.
#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_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#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
static int tmp()
Definition: bt_open.c:389
Internal Asterisk hangup causes.
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
static const char config[]
Definition: chan_ooh323.c:111
General Asterisk PBX channel definitions.
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
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6461
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:10338
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1477
const char * ast_channel_musicclass(const struct ast_channel *chan)
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
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:3157
#define ast_channel_lock(chan)
Definition: channel.h:2922
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6720
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
@ AST_FEATURE_REDIRECT
Definition: channel.h:1064
@ AST_FEATURE_AUTOMON
Definition: channel.h:1067
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2054
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2929
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const 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:2368
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:6434
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2893
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
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:9093
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:6771
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:8785
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
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:4653
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
#define AST_MAX_CONTEXT
Definition: channel.h:135
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition: channel.c:2845
const char * ast_channel_language(const struct ast_channel *chan)
const char * ast_cause2str(int cause) attribute_pure
Gives the string form of a given cause code.
Definition: channel.c:612
struct ast_sched_context * ast_channel_sched(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:8293
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
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:6444
int ast_channel_get_duration(struct ast_channel *chan)
Obtain how long the channel since the channel was created.
Definition: channel.c:2830
struct ast_party_caller * ast_channel_caller(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:2045
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:342
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
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:6354
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define AST_MAX_EXTENSION
Definition: channel.h:134
#define MAX_MUSICCLASS
Definition: channel.h:173
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
Standard Command Line Interface.
#define SENTINEL
Definition: compiler.h:87
Convenient Signal Processing routines.
@ 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
char connected
Definition: eagi_proxy.c:82
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
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:685
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
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:1878
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840
static const char name[]
Definition: format_mp3.c:68
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...
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
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.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
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:2144
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#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.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
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:3056
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
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:3622
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
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:783
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3506
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
#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_RINGING
@ AST_CONTROL_HANGUP
@ AST_CONTROL_HOLD
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_FLASH
@ AST_CONTROL_PVT_CAUSE_CODE
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#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_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#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_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#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_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:783
Asterisk locking-related definitions:
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
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_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:315
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ 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:626
Music on hold handling.
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:7766
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7776
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
Core PBX routines and definitions.
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:4175
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 NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
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
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_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
#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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
bridge configuration
Definition: channel.h:1076
void * end_bridge_callback_data
Definition: channel.h:1091
Main Channel structure associated with a channel.
const char * data
struct ast_party_caller caller
Channel Caller ID information.
Structure used to handle boolean flags.
Definition: utils.h:199
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Structure for mutex and tracking information.
Definition: lock.h:135
Connected Line/Party information.
Definition: channel.h:456
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Data structure for followme scripts.
Definition: app_followme.c:162
char connprompt[PATH_MAX]
Definition: app_followme.c:179
struct call_followme::wlnumbers wlnumbers
unsigned int enable_callee_prompt
Definition: app_followme.c:170
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:164
char sorryprompt[PATH_MAX]
Definition: app_followme.c:178
char callfromprompt[PATH_MAX]
Definition: app_followme.c:173
char takecall[MAX_YN_STRING]
Definition: app_followme.c:171
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:172
char optionsprompt[PATH_MAX]
Definition: app_followme.c:175
struct call_followme::blnumbers blnumbers
char statusprompt[PATH_MAX]
Definition: app_followme.c:177
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:176
struct call_followme::@25 entry
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:165
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:166
struct call_followme::numbers numbers
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:174
unsigned int active
Definition: app_followme.c:167
ast_mutex_t lock
Definition: app_followme.c:163
Definition: search.h:40
char dialarg[768]
Definition: app_followme.c:227
struct findme_user::@26 entry
struct ast_channel * ochan
Definition: app_followme.c:221
struct ast_party_connected_line connected
Definition: app_followme.c:223
unsigned int answered
Definition: app_followme.c:231
char yn[MAX_YN_STRING]
Definition: app_followme.c:229
unsigned int pending_connected_update
Definition: app_followme.c:233
char connprompt[PATH_MAX]
Definition: app_followme.c:216
unsigned int pending_in_connected_update
Definition: app_followme.c:197
char namerecloc[PATH_MAX]
Definition: app_followme.c:207
struct fm_args::cnumbers cnumbers
unsigned int enable_callee_prompt
Definition: app_followme.c:203
char sorryprompt[PATH_MAX]
Definition: app_followme.c:215
char callfromprompt[PATH_MAX]
Definition: app_followme.c:210
char takecall[MAX_YN_STRING]
Definition: app_followme.c:208
unsigned int pending_hold
Definition: app_followme.c:201
struct ast_party_connected_line connected_out
Definition: app_followme.c:195
unsigned int pending_out_connected_update
Definition: app_followme.c:199
char suggested_moh[MAX_MUSICCLASS]
Definition: app_followme.c:205
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:209
char * mohclass
Definition: app_followme.c:188
char optionsprompt[PATH_MAX]
Definition: app_followme.c:212
char statusprompt[PATH_MAX]
Definition: app_followme.c:214
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:213
struct ast_flags followmeflags
Definition: app_followme.c:217
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:206
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:211
const char * predial_callee
Definition: app_followme.c:191
struct ast_party_connected_line connected_in
Definition: app_followme.c:193
Channel datastore data for max forwards.
Definition: max_forwards.c:29
Definition: test_heap.c:38
Number structure.
Definition: app_followme.c:154
long timeout
Definition: app_followme.c:156
struct number::@24 entry
char number[512]
Definition: app_followme.c:155
int order
Definition: app_followme.c:157
Definition: ast_expr2.c:325
const char * args
static struct test_options options
Support for translation of data formats. translate.c.
FILE * in
Definition: utils/frame.c:33
Utility functions.
#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
#define ARRAY_LEN(a)
Definition: utils.h:666
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2343