Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 <since>
72 <version>1.6.1.0</version>
73 </since>
74 <synopsis>
75 Find-Me/Follow-Me application.
76 </synopsis>
77 <syntax>
78 <parameter name="followmeid" required="true" />
79 <parameter name="options">
80 <optionlist>
81 <option name="a">
82 <para>Record the caller's name so it can be announced to the
83 callee on each step.</para>
84 </option>
85 <option name="B" argsep="^">
86 <para>Before initiating the outgoing call(s), Gosub to the specified
87 location using the current channel.</para>
88 <argument name="context" required="false" />
89 <argument name="exten" required="false" />
90 <argument name="priority" required="true" hasparams="optional" argsep="^">
91 <argument name="arg1" multiple="true" required="true" />
92 <argument name="argN" />
93 </argument>
94 </option>
95 <option name="b" argsep="^">
96 <para>Before initiating an outgoing call, Gosub to the specified
97 location using the newly created channel. The Gosub will be
98 executed for each destination channel.</para>
99 <argument name="context" required="false" />
100 <argument name="exten" required="false" />
101 <argument name="priority" required="true" hasparams="optional" argsep="^">
102 <argument name="arg1" multiple="true" required="true" />
103 <argument name="argN" />
104 </argument>
105 </option>
106 <option name="d">
107 <para>Disable the 'Please hold while we try to connect your call' announcement.</para>
108 </option>
109 <option name="I">
110 <para>Asterisk will ignore any connected line update requests
111 it may receive on this dial attempt.</para>
112 </option>
113 <option name="l">
114 <para>Disable local call optimization so that applications with
115 audio hooks between the local bridge don't get dropped when the
116 calls get joined directly.</para>
117 </option>
118 <option name="N">
119 <para>Don't answer the incoming call until we're ready to
120 connect the caller or give up.</para>
121 <note>
122 <para>This option is ignored if the call is already answered.</para>
123 </note>
124 <note>
125 <para>If the call is not already answered, the 'a' and 's'
126 options are ignored while the 'd' option is implicitly enabled.</para>
127 </note>
128 </option>
129 <option name="n">
130 <para>Playback the unreachable status message if we've run out
131 of steps or the callee has elected not to be reachable.</para>
132 </option>
133 <option name="s">
134 <para>Playback the incoming status message prior to starting
135 the follow-me step(s)</para>
136 </option>
137 </optionlist>
138 </parameter>
139 </syntax>
140 <description>
141 <para>This application performs Find-Me/Follow-Me functionality for the caller
142 as defined in the profile matching the <replaceable>followmeid</replaceable> parameter in
143 <filename>followme.conf</filename>. If the specified <replaceable>followmeid</replaceable>
144 profile doesn't exist in <filename>followme.conf</filename>, execution will be returned
145 to the dialplan and call execution will continue at the next priority.</para>
146 <para>Returns -1 on hangup.</para>
147 </description>
148 </application>
149 ***/
150
151static char *app = "FollowMe";
152
153/*! Maximum accept/decline DTMF string plus terminator. */
154#define MAX_YN_STRING 20
155
156/*! \brief Number structure */
157struct number {
158 char number[512]; /*!< Phone Number(s) and/or Extension(s) */
159 long timeout; /*!< Dial Timeout, if used. */
160 int order; /*!< The order to dial in */
161 AST_LIST_ENTRY(number) entry; /*!< Next Number record */
162};
163
164/*! \brief Data structure for followme scripts */
167 char name[AST_MAX_EXTENSION]; /*!< Name - FollowMeID */
168 char moh[MAX_MUSICCLASS]; /*!< Music On Hold Class to be used */
169 char context[AST_MAX_CONTEXT]; /*!< Context to dial from */
170 unsigned int active; /*!< Profile is active (1), or disabled (0). */
171 int realtime; /*!< Cached from realtime */
172 /*! Allow callees to accept/reject the forwarded call */
173 unsigned int enable_callee_prompt:1;
174 char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */
175 char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */
176 char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
177 char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */
178 char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */
179 char plsholdprompt[PATH_MAX]; /*!< Sound prompt name and path */
180 char statusprompt[PATH_MAX]; /*!< Sound prompt name and path */
181 char sorryprompt[PATH_MAX]; /*!< Sound prompt name and path */
182 char connprompt[PATH_MAX]; /*!< Sound prompt name and path */
183
184 AST_LIST_HEAD_NOLOCK(numbers, number) numbers; /*!< Head of the list of follow-me numbers */
185 AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers; /*!< Head of the list of black-listed numbers */
186 AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers; /*!< Head of the list of white-listed numbers */
187 AST_LIST_ENTRY(call_followme) entry; /*!< Next Follow-Me record */
188};
189
190struct fm_args {
191 char *mohclass;
193 /*! Gosub app arguments for outgoing calls. NULL if not supplied. */
194 const char *predial_callee;
195 /*! Accumulated connected line information from inbound call. */
197 /*! Accumulated connected line information from outbound call. */
199 /*! TRUE if connected line information from inbound call changed. */
201 /*! TRUE if connected line information from outbound call is available. */
203 /*! TRUE if caller has a pending hold request for the winning call. */
204 unsigned int pending_hold:1;
205 /*! TRUE if callees will be prompted to answer */
206 unsigned int enable_callee_prompt:1;
207 /*! Music On Hold Class suggested by caller hold for winning call. */
211 char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */
212 char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */
213 char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
214 char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */
215 char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */
216 char plsholdprompt[PATH_MAX]; /*!< Sound prompt name and path */
217 char statusprompt[PATH_MAX]; /*!< Sound prompt name and path */
218 char sorryprompt[PATH_MAX]; /*!< Sound prompt name and path */
219 char connprompt[PATH_MAX]; /*!< Sound prompt name and path */
221};
222
225 /*! Accumulated connected line information from outgoing call. */
227 long digts;
228 int ynidx;
229 int state;
230 char dialarg[768];
231 /*! Collected digits to accept/decline the call. */
233 /*! TRUE if the outgoing call is answered. */
234 unsigned int answered:1;
235 /*! TRUE if connected line information is available. */
238};
239
240enum {
250};
251
252enum {
255
256 /* note: this entry _MUST_ be the last one in the enum */
259
270});
271
272static const char *featuredigittostr;
273static int featuredigittimeout = 5000; /*!< Feature Digit Timeout */
274static const char *defaultmoh = "default"; /*!< Default Music-On-Hold Class */
275
276static char takecall[MAX_YN_STRING] = "1";
277static char nextindp[MAX_YN_STRING] = "2";
278static int enable_callee_prompt = 1;
279static char callfromprompt[PATH_MAX] = "followme/call-from";
280static char norecordingprompt[PATH_MAX] = "followme/no-recording";
281static char optionsprompt[PATH_MAX] = "followme/options";
282static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try";
283static char statusprompt[PATH_MAX] = "followme/status";
284static char sorryprompt[PATH_MAX] = "followme/sorry";
285static char connprompt[PATH_MAX] = "";
286
287
290
291static void free_numbers(struct call_followme *f)
292{
293 /* Free numbers attached to the profile */
294 struct number *prev;
295
296 while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
297 /* Free the number */
298 ast_free(prev);
300
301 while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
302 /* Free the blacklisted number */
303 ast_free(prev);
305
306 while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
307 /* Free the whitelisted number */
308 ast_free(prev);
310}
311
312
313/*! \brief Allocate and initialize followme profile */
314static struct call_followme *alloc_profile(const char *fmname)
315{
316 struct call_followme *f;
317
318 if (!(f = ast_calloc(1, sizeof(*f))))
319 return NULL;
320
321 ast_mutex_init(&f->lock);
322 ast_copy_string(f->name, fmname, sizeof(f->name));
326 return f;
327}
328
329static void init_profile(struct call_followme *f, int activate)
330{
332 f->context[0] = '\0';
333 ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
334 ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
335 ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
343 if (activate) {
344 f->active = 1;
345 }
346}
347
348
349
350/*! \brief Set parameter in profile from configuration file */
351static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
352{
353
354 if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
355 ast_copy_string(f->moh, val, sizeof(f->moh));
356 else if (!strcasecmp(param, "context"))
357 ast_copy_string(f->context, val, sizeof(f->context));
358 else if (!strcasecmp(param, "enable_callee_prompt"))
360 else if (!strcasecmp(param, "takecall"))
361 ast_copy_string(f->takecall, val, sizeof(f->takecall));
362 else if (!strcasecmp(param, "declinecall"))
363 ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
364 else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
366 else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
368 else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
370 else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
372 else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
374 else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
376 else if (!strcasecmp(param, "followme-connecting-prompt") || !strcasecmp(param, "connecting_prompt")) {
377 ast_copy_string(f->connprompt, val, sizeof(f->connprompt));
378 } else if (failunknown) {
379 if (linenum >= 0)
380 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
381 else
382 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
383 }
384}
385
386/*! \brief Add a new number */
387static struct number *create_followme_number(const char *number, int timeout, int numorder)
388{
389 struct number *cur;
390 char *buf = ast_strdupa(number);
391 char *tmp;
392
393 if (!(cur = ast_calloc(1, sizeof(*cur))))
394 return NULL;
395
396 cur->timeout = timeout;
397 if ((tmp = strchr(buf, ',')))
398 *tmp = '\0';
399 ast_copy_string(cur->number, buf, sizeof(cur->number));
400 cur->order = numorder;
401 ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
402
403 return cur;
404}
405
406/*! \brief Reload followme application module */
407static int reload_followme(int reload)
408{
409 struct call_followme *f;
410 struct ast_config *cfg;
411 char *cat = NULL, *tmp;
412 struct ast_variable *var;
413 struct number *cur, *nm;
414 int timeout;
415 int numorder;
416 const char* enable_callee_prompt_str;
417 const char *takecallstr;
418 const char *declinecallstr;
419 const char *tmpstr;
420 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
421
422 if (!(cfg = ast_config_load("followme.conf", config_flags))) {
423 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
424 return 0;
425 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
426 return 0;
427 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
428 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
429 return 0;
430 }
431
433
434 /* Reset Global Var Values */
435 featuredigittimeout = 5000;
436
437 /* Mark all profiles as inactive for the moment */
438 AST_RWLIST_TRAVERSE(&followmes, f, entry) {
439 f->active = 0;
440 }
441
442 featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
443
445 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
446 featuredigittimeout = 5000;
447 }
448
449 if ((enable_callee_prompt_str = ast_variable_retrieve(cfg, "general",
450 "enable_callee_prompt")) &&
451 !ast_strlen_zero(enable_callee_prompt_str)) {
452 enable_callee_prompt = ast_true(enable_callee_prompt_str);
453 }
454
455 if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
456 ast_copy_string(takecall, takecallstr, sizeof(takecall));
457 }
458
459 if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
460 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
461 }
462
463 if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
465 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
467 }
468
469 if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
471 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
473 }
474
475
476 if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
478 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
480 }
481
482 if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
484 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
486 }
487
488 if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
489 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
490 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
491 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
492 }
493
494 if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
495 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
496 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
497 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
498 }
499
500 if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting-prompt")) && !ast_strlen_zero(tmpstr)) {
501 ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
502 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting_prompt")) && !ast_strlen_zero(tmpstr)) {
503 ast_copy_string(connprompt, tmpstr, sizeof(connprompt));
504 }
505
506
507 /* Chug through config file */
508 while ((cat = ast_category_browse(cfg, cat))) {
509 int new = 0;
510
511 if (!strcasecmp(cat, "general"))
512 continue;
513
514 /* Look for an existing one */
515 AST_LIST_TRAVERSE(&followmes, f, entry) {
516 if (!strcasecmp(f->name, cat))
517 break;
518 }
519
520 ast_debug(1, "New profile %s.\n", cat);
521
522 if (!f) {
523 /* Make one then */
524 f = alloc_profile(cat);
525 new = 1;
526 }
527
528 /* Totally fail if we fail to find/create an entry */
529 if (!f)
530 continue;
531
532 if (!new)
533 ast_mutex_lock(&f->lock);
534 /* Re-initialize the profile */
535 init_profile(f, 1);
536 free_numbers(f);
537 var = ast_variable_browse(cfg, cat);
538 while (var) {
539 if (!strcasecmp(var->name, "number")) {
540 int idx = 0;
541 char copy[strlen(var->value) + 1];
542 char *numberstr;
543
544 /* Add a new number */
545 strcpy(copy, var->value); /* safe */
546 numberstr = copy;
547 if ((tmp = strchr(numberstr, ','))) {
548 *tmp++ = '\0';
549 timeout = atoi(tmp);
550 if (timeout < 0) {
551 timeout = 25;
552 }
553 if ((tmp = strchr(tmp, ','))) {
554 *tmp++ = '\0';
555 numorder = atoi(tmp);
556 if (numorder < 0)
557 numorder = 0;
558 } else
559 numorder = 0;
560 } else {
561 timeout = 25;
562 numorder = 0;
563 }
564
565 if (!numorder) {
566 idx = 1;
567 AST_LIST_TRAVERSE(&f->numbers, nm, entry)
568 idx++;
569 numorder = idx;
570 }
571 cur = create_followme_number(numberstr, timeout, numorder);
572 if (cur) {
573 AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
574 }
575 } else {
576 profile_set_param(f, var->name, var->value, var->lineno, 1);
577 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
578 }
579 var = var->next;
580 } /* End while(var) loop */
581
582 if (!new)
584 else
586 }
587
589
591
592 return 1;
593}
594
595static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
596{
597 struct findme_user *tmpuser;
598
599 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
600 if (tmpuser->ochan && tmpuser->ochan != exception) {
602 }
603 }
604}
605
606static void clear_caller(struct findme_user *tmpuser)
607{
608 struct ast_channel *outbound;
609
610 if (!tmpuser->ochan) {
611 /* Call already cleared. */
612 return;
613 }
614
615 outbound = tmpuser->ochan;
616 ast_hangup(outbound);
617 tmpuser->ochan = NULL;
618}
619
620static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list)
621{
622 struct findme_user *tmpuser;
623
624 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
625 if (!tmpuser->answered) {
626 clear_caller(tmpuser);
627 }
628 }
629}
630
632{
635 ast_free(node);
636}
637
638static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
639{
640 struct findme_user *fmuser;
641
642 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
643 destroy_calling_node(fmuser);
644 }
645}
646
647static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs)
648{
650 struct ast_channel *watchers[256];
651 int pos;
652 struct ast_channel *winner;
653 struct ast_frame *f;
654 struct findme_user *tmpuser;
655 int to = 0;
656 int livechannels;
657 int tmpto;
658 long totalwait = 0, wtd = 0, towas = 0;
659 char *callfromname;
660 char *pressbuttonname;
661
662 /* ------------ wait_for_winner_channel start --------------- */
663
664 callfromname = ast_strdupa(tpargs->callfromprompt);
665 pressbuttonname = ast_strdupa(tpargs->optionsprompt);
666
667 totalwait = nm->timeout * 1000;
668
669 for (;;) {
670 to = 1000;
671 pos = 1;
672 livechannels = 0;
673 watchers[0] = caller;
674
675 winner = NULL;
676 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
677 if (!tmpuser->ochan) {
678 continue;
679 }
680 if (tmpuser->state == 3) {
681 tmpuser->digts += (towas - wtd);
682 }
683 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
684 ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n",
685 ast_channel_name(tmpuser->ochan));
686 if (tpargs->enable_callee_prompt) {
687 if (!ast_strlen_zero(tpargs->namerecloc)) {
688 tmpuser->state = 1;
689 tmpuser->digts = 0;
690 if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
692 } else {
693 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
694 clear_caller(tmpuser);
695 continue;
696 }
697 } else {
698 tmpuser->state = 2;
699 tmpuser->digts = 0;
700 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
702 else {
703 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
704 clear_caller(tmpuser);
705 continue;
706 }
707 }
708 } else {
709 tmpuser->state = 3;
710 }
711 }
712 if (ast_channel_stream(tmpuser->ochan)) {
714 tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan));
715 if (tmpto > 0 && tmpto < to)
716 to = tmpto;
717 else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
718 ast_stopstream(tmpuser->ochan);
719 switch (tmpuser->state) {
720 case 1:
721 ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n",
722 ast_channel_name(tmpuser->ochan));
723 if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) {
724 tmpuser->state = 2;
725 } else {
726 ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n",
727 ast_channel_name(tmpuser->ochan), tpargs->namerecloc);
728 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
729 tmpuser->ynidx = 0;
730 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
731 tmpuser->state = 3;
732 else {
733 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
734 clear_caller(tmpuser);
735 continue;
736 }
737 }
738 break;
739 case 2:
740 ast_verb(3, "<%s> Playback of name file appears to be done.\n",
741 ast_channel_name(tmpuser->ochan));
742 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
743 tmpuser->ynidx = 0;
744 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
745 tmpuser->state = 3;
746 } else {
747 clear_caller(tmpuser);
748 continue;
749 }
750 break;
751 case 3:
752 ast_verb(3, "<%s> Playback of the next step file appears to be done.\n",
753 ast_channel_name(tmpuser->ochan));
754 tmpuser->digts = 0;
755 break;
756 default:
757 break;
758 }
759 }
760 }
761 watchers[pos++] = tmpuser->ochan;
762 livechannels++;
763 }
764 if (!livechannels) {
765 ast_verb(3, "No live channels left for this step.\n");
766 return NULL;
767 }
768
769 tmpto = to;
770 towas = to;
771 winner = ast_waitfor_n(watchers, pos, &to);
772 tmpto -= to;
773 totalwait -= tmpto;
774 wtd = to;
775 if (totalwait <= 0) {
776 ast_verb(3, "We've hit our timeout for this step. Dropping unanswered calls and starting the next step.\n");
777 clear_unanswered_calls(findme_user_list);
778 return NULL;
779 }
780 if (winner) {
781 /* Need to find out which channel this is */
782 if (winner != caller) {
783 /* The winner is an outgoing channel. */
784 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
785 if (tmpuser->ochan == winner) {
786 break;
787 }
788 }
789 } else {
790 tmpuser = NULL;
791 }
792
793 f = ast_read(winner);
794 if (f) {
795 if (f->frametype == AST_FRAME_CONTROL) {
796 switch (f->subclass.integer) {
798 ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner));
799 if (f->data.uint32) {
801 }
802 if (!tmpuser) {
803 ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
804 publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL");
805 ast_frfree(f);
806 return NULL;
807 }
808 clear_caller(tmpuser);
809 break;
811 if (!tmpuser) {
812 /* The caller answered? We want an outgoing channel to answer. */
813 break;
814 }
815 ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
816 ast_channel_publish_dial(caller, winner, NULL, "ANSWER");
817 publish_dial_end_event(caller, findme_user_list, winner, "CANCEL");
818 tmpuser->answered = 1;
819 /* If call has been answered, then the eventual hangup is likely to be normal hangup */
822 if (tpargs->enable_callee_prompt) {
823 ast_verb(3, "Starting playback of %s\n", callfromname);
824 if (!ast_strlen_zero(tpargs->namerecloc)) {
825 if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) {
827 tmpuser->state = 1;
828 } else {
829 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
830 clear_caller(tmpuser);
831 }
832 } else {
833 tmpuser->state = 2;
834 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
836 else {
837 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
838 clear_caller(tmpuser);
839 }
840 }
841 } else {
842 ast_debug(1, "Taking call with no prompt\n");
843 ast_frfree(f);
844 return tmpuser->ochan;
845 }
846 break;
847 case AST_CONTROL_BUSY:
848 ast_verb(3, "%s is busy\n", ast_channel_name(winner));
849 if (tmpuser) {
850 /* Outbound call was busy. Drop it. */
851 ast_channel_publish_dial(caller, winner, NULL, "BUSY");
852 clear_caller(tmpuser);
853 }
854 break;
856 ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
857 if (tmpuser) {
858 /* Outbound call was congested. Drop it. */
859 ast_channel_publish_dial(caller, winner, NULL, "CONGESTION");
860 clear_caller(tmpuser);
861 }
862 break;
864 ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
865 ast_channel_publish_dial(caller, winner, NULL, "RINGING");
866 break;
868 ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
869 ast_channel_publish_dial(caller, winner, NULL, "PROGRESS");
870 break;
872 ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
873 break;
875 ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
876 break;
878 ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
879 ast_channel_publish_dial(caller, winner, NULL, "PROCEEDING");
880 break;
881 case AST_CONTROL_HOLD:
882 ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
883 if (!tmpuser) {
884 /* Caller placed outgoing calls on hold. */
885 tpargs->pending_hold = 1;
886 if (f->data.ptr) {
888 sizeof(tpargs->suggested_moh));
889 } else {
890 tpargs->suggested_moh[0] = '\0';
891 }
892 } else {
893 /*
894 * Outgoing call placed caller on hold.
895 *
896 * Ignore because the outgoing call should not be able to place
897 * the caller on hold until after they are bridged.
898 */
899 }
900 break;
902 ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
903 if (!tmpuser) {
904 /* Caller removed outgoing calls from hold. */
905 tpargs->pending_hold = 0;
906 } else {
907 /*
908 * Outgoing call removed caller from hold.
909 *
910 * Ignore because the outgoing call should not be able to place
911 * the caller on hold until after they are bridged.
912 */
913 }
914 break;
917 /* Ignore going off hook and flash */
918 break;
921 ast_verb(3, "Connected line update from %s prevented.\n",
922 ast_channel_name(winner));
923 break;
924 }
925 if (!tmpuser) {
926 /*
927 * Hold connected line update from caller until we have a
928 * winner.
929 */
930 ast_verb(3,
931 "%s connected line has changed. Saving it until we have a winner.\n",
932 ast_channel_name(winner));
936 &connected, NULL);
937 tpargs->pending_in_connected_update = 1;
938 }
940 } else {
941 ast_verb(3,
942 "%s connected line has changed. Saving it until answer.\n",
943 ast_channel_name(winner));
947 &connected, NULL);
948 tmpuser->pending_connected_update = 1;
949 }
951 }
952 break;
954 /*
955 * Ignore because we are masking the FollowMe search progress to
956 * the caller.
957 */
958 break;
960 ast_indicate_data(caller, f->subclass.integer, f->data.ptr, f->datalen);
961 break;
962 case -1:
963 ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
964 break;
965 default:
966 ast_debug(1, "Dunno what to do with control type %d from %s\n",
967 f->subclass.integer, ast_channel_name(winner));
968 break;
969 }
970 }
971 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
972 int cmp_len;
973
974 if (ast_channel_stream(winner))
975 ast_stopstream(winner);
976 tmpuser->digts = 0;
977 ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
978 if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
979 tmpuser->yn[tmpuser->ynidx++] = f->subclass.integer;
980 } else {
981 /* Discard oldest digit. */
982 memmove(tmpuser->yn, tmpuser->yn + 1,
983 sizeof(tmpuser->yn) - 2 * sizeof(tmpuser->yn[0]));
984 tmpuser->yn[ARRAY_LEN(tmpuser->yn) - 2] = f->subclass.integer;
985 }
986 ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
987 cmp_len = strlen(tpargs->takecall);
988 if (cmp_len <= tmpuser->ynidx
989 && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->takecall)) {
990 ast_debug(1, "Match to take the call!\n");
991 ast_frfree(f);
992 return tmpuser->ochan;
993 }
994 cmp_len = strlen(tpargs->nextindp);
995 if (cmp_len <= tmpuser->ynidx
996 && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->nextindp)) {
997 ast_debug(1, "Declined to take the call.\n");
998 clear_caller(tmpuser);
999 }
1000 }
1001
1002 ast_frfree(f);
1003 } else {
1004 ast_debug(1, "we didn't get a frame. hanging up.\n");
1005 if (!tmpuser) {
1006 /* Caller hung up. */
1007 ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
1008 return NULL;
1009 }
1010 /* Outgoing channel hung up. */
1011 ast_channel_publish_dial(caller, winner, NULL, "NOANSWER");
1012 clear_caller(tmpuser);
1013 }
1014 } else {
1015 ast_debug(1, "timed out waiting for action\n");
1016 }
1017 }
1018
1019 /* Unreachable. */
1020}
1021
1022/*!
1023 * \internal
1024 * \brief Find an extension willing to take the call.
1025 *
1026 * \param tpargs Active Followme config.
1027 * \param caller Channel initiating the outgoing calls.
1028 *
1029 * \retval winner Winning outgoing call.
1030 * \retval NULL if could not find someone to take the call.
1031 */
1032static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
1033{
1034 struct number *nm;
1035 struct ast_channel *winner = NULL;
1036 char num[512];
1037 int dg, idx;
1038 char *rest, *number;
1039 struct findme_user *tmpuser;
1040 struct findme_user *fmuser;
1041 struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1043
1044 for (idx = 1; !ast_check_hangup(caller); ++idx) {
1045 /* Find next followme numbers to dial. */
1046 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
1047 if (nm->order == idx) {
1048 break;
1049 }
1050 }
1051 if (!nm) {
1052 ast_verb(3, "No more steps left.\n");
1053 break;
1054 }
1055
1056 ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout);
1057
1058 /*
1059 * Put all active outgoing channels into autoservice.
1060 *
1061 * This needs to be done because ast_exists_extension() may put
1062 * the caller into autoservice.
1063 */
1064 AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1065 if (tmpuser->ochan) {
1066 ast_autoservice_start(tmpuser->ochan);
1067 }
1068 }
1069
1070 /* Create all new outgoing calls */
1071 ast_copy_string(num, nm->number, sizeof(num));
1072 for (number = num; number; number = rest) {
1073 struct ast_channel *outbound;
1074 struct ast_format_cap *caps;
1075
1076 rest = strchr(number, '&');
1077 if (rest) {
1078 *rest++ = 0;
1079 }
1080
1081 /* We check if the extension exists, before creating the ast_channel struct */
1082 if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(ast_channel_caller(caller)->id.number.valid, ast_channel_caller(caller)->id.number.str, NULL))) {
1083 ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
1084 continue;
1085 }
1086
1087 tmpuser = ast_calloc(1, sizeof(*tmpuser));
1088 if (!tmpuser) {
1089 continue;
1090 }
1091
1092 if (ast_strlen_zero(tpargs->context)) {
1093 snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s%s",
1094 number,
1096 ? "/n" : "/m");
1097 } else {
1098 snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s@%s%s",
1099 number, tpargs->context,
1101 ? "/n" : "/m");
1102 }
1103
1104 /* Capture nativeformats reference in case it gets changed */
1105 ast_channel_lock(caller);
1106 caps = ao2_bump(ast_channel_nativeformats(caller));
1107 ast_channel_unlock(caller);
1108
1109 outbound = ast_request("Local", caps, NULL, caller, tmpuser->dialarg, &dg);
1110
1111 ao2_cleanup(caps);
1112
1113 if (!outbound) {
1114 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
1115 tmpuser->dialarg, ast_cause2str(dg));
1116 ast_free(tmpuser);
1117 continue;
1118 }
1119
1120 ast_channel_lock_both(caller, outbound);
1122 ast_channel_inherit_variables(caller, outbound);
1123 ast_channel_datastore_inherit(caller, outbound);
1125 ast_channel_language_set(outbound, ast_channel_language(caller));
1127 ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
1128 ast_channel_unlock(outbound);
1129 ast_channel_unlock(caller);
1130
1131 tmpuser->ochan = outbound;
1132 tmpuser->state = 0;
1133 AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry);
1134 }
1135
1136 /*
1137 * PREDIAL: Run gosub on all of the new callee channels
1138 *
1139 * We run the callee predial before ast_call() in case the user
1140 * wishes to do something on the newly created channels before
1141 * the channel does anything important.
1142 */
1143 if (tpargs->predial_callee && !AST_LIST_EMPTY(&new_user_list)) {
1144 /* Put caller into autoservice. */
1145 ast_autoservice_start(caller);
1146
1147 /* Run predial on all new outgoing calls. */
1148 AST_LIST_TRAVERSE(&new_user_list, tmpuser, entry) {
1149 ast_pre_call(tmpuser->ochan, tpargs->predial_callee);
1150 }
1151
1152 /* Take caller out of autoservice. */
1153 if (ast_autoservice_stop(caller)) {
1154 /*
1155 * Caller hungup.
1156 *
1157 * Destoy all new outgoing calls.
1158 */
1159 while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
1160 destroy_calling_node(tmpuser);
1161 }
1162
1163 /* Take all active outgoing channels out of autoservice. */
1164 AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
1165 if (tmpuser->ochan) {
1166 ast_autoservice_stop(tmpuser->ochan);
1167 }
1168 }
1169 break;
1170 }
1171 }
1172
1173 /* Start all new outgoing calls */
1174 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_user_list, tmpuser, entry) {
1175 ast_verb(3, "calling Local/%s\n", tmpuser->dialarg);
1176 if (ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) {
1177 ast_verb(3, "couldn't reach at this number.\n");
1179
1180 /* Destroy this failed new outgoing call. */
1181 destroy_calling_node(tmpuser);
1182 continue;
1183 }
1184
1185 ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL);
1186 }
1188
1189 /* Take all active outgoing channels out of autoservice. */
1190 AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1191 if (tmpuser->ochan && ast_autoservice_stop(tmpuser->ochan)) {
1192 /* Existing outgoing call hungup. */
1194 destroy_calling_node(tmpuser);
1195 }
1196 }
1198
1199 if (AST_LIST_EMPTY(&new_user_list)) {
1200 /* No new channels remain at this order level. If there were any at all. */
1201 continue;
1202 }
1203
1204 /* Add new outgoing channels to the findme list. */
1205 AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry);
1206
1207 winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
1208 if (!winner) {
1209 /* Remove all dead outgoing nodes. */
1210 AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
1211 if (!tmpuser->ochan) {
1213 destroy_calling_node(tmpuser);
1214 }
1215 }
1217 continue;
1218 }
1219
1220 /* Destroy losing calls up to the winner. The rest will be destroyed later. */
1221 while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) {
1222 if (fmuser->ochan == winner) {
1223 /*
1224 * Pass any connected line info up.
1225 *
1226 * NOTE: This code must be in line with destroy_calling_node().
1227 */
1228 tpargs->connected_out = fmuser->connected;
1230 ast_free(fmuser);
1231 break;
1232 } else {
1233 /* Destroy losing call. */
1234 destroy_calling_node(fmuser);
1235 }
1236 }
1237 break;
1238 }
1239 destroy_calling_tree(&findme_user_list);
1240 return winner;
1241}
1242
1243static struct call_followme *find_realtime(const char *name)
1244{
1245 struct ast_variable *var;
1246 struct ast_variable *v;
1247 struct ast_config *cfg;
1248 const char *catg;
1249 struct call_followme *new_follower;
1250 struct ast_str *str;
1251
1252 str = ast_str_create(16);
1253 if (!str) {
1254 return NULL;
1255 }
1256
1257 var = ast_load_realtime("followme", "name", name, SENTINEL);
1258 if (!var) {
1259 ast_free(str);
1260 return NULL;
1261 }
1262
1263 if (!(new_follower = alloc_profile(name))) {
1265 ast_free(str);
1266 return NULL;
1267 }
1268 init_profile(new_follower, 0);
1269
1270 for (v = var; v; v = v->next) {
1271 if (!strcasecmp(v->name, "active")) {
1272 if (ast_false(v->value)) {
1273 ast_mutex_destroy(&new_follower->lock);
1274 ast_free(new_follower);
1276 ast_free(str);
1277 return NULL;
1278 }
1279 } else {
1280 profile_set_param(new_follower, v->name, v->value, 0, 0);
1281 }
1282 }
1283
1285 new_follower->realtime = 1;
1286
1287 /* Load numbers */
1288 cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
1289 name, SENTINEL);
1290 if (!cfg) {
1291 ast_mutex_destroy(&new_follower->lock);
1292 ast_free(new_follower);
1293 ast_free(str);
1294 return NULL;
1295 }
1296
1297 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
1298 const char *numstr;
1299 const char *timeoutstr;
1300 const char *ordstr;
1301 int timeout;
1302 struct number *cur;
1303
1304 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
1305 continue;
1306 }
1307 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
1308 || sscanf(timeoutstr, "%30d", &timeout) != 1
1309 || timeout < 1) {
1310 timeout = 25;
1311 }
1312 /* This one has to exist; it was part of the query */
1313 ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
1314 ast_str_set(&str, 0, "%s", numstr);
1315 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
1316 AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
1317 }
1318 }
1319 ast_config_destroy(cfg);
1320
1321 ast_free(str);
1322 return new_follower;
1323}
1324
1325static void end_bridge_callback(void *data)
1326{
1327 char buf[80];
1328 time_t end;
1329 struct ast_channel *chan = data;
1330
1331 time(&end);
1332
1333 ast_channel_lock(chan);
1334 snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
1335 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1336 snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
1337 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1338 ast_channel_unlock(chan);
1339}
1340
1341static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
1342{
1343 bconfig->end_bridge_callback_data = originator;
1344}
1345
1346static int app_exec(struct ast_channel *chan, const char *data)
1347{
1348 struct fm_args *targs;
1350 struct call_followme *f;
1351 struct number *nm, *newnm;
1352 int res = 0;
1353 char *argstr;
1354 struct ast_channel *caller;
1355 struct ast_channel *outbound;
1357 AST_APP_ARG(followmeid);
1359 );
1360 char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
1361 int max_forwards;
1362
1363 if (ast_strlen_zero(data)) {
1364 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1365 return -1;
1366 }
1367
1368 ast_channel_lock(chan);
1370 ast_channel_unlock(chan);
1371
1372 if (max_forwards <= 0) {
1373 ast_log(LOG_WARNING, "Unable to execute FollowMe on channel %s. Max forwards exceeded\n",
1374 ast_channel_name(chan));
1375 return -1;
1376 }
1377
1378 argstr = ast_strdupa((char *) data);
1379
1380 AST_STANDARD_APP_ARGS(args, argstr);
1381
1382 if (ast_strlen_zero(args.followmeid)) {
1383 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1384 return -1;
1385 }
1386
1387 targs = ast_calloc(1, sizeof(*targs));
1388 if (!targs) {
1389 return -1;
1390 }
1391
1393 AST_RWLIST_TRAVERSE(&followmes, f, entry) {
1394 if (!strcasecmp(f->name, args.followmeid) && (f->active))
1395 break;
1396 }
1398
1399 ast_debug(1, "New profile %s.\n", args.followmeid);
1400
1401 if (!f) {
1402 f = find_realtime(args.followmeid);
1403 }
1404
1405 if (!f) {
1406 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1407 ast_free(targs);
1408 return 0;
1409 }
1410
1411 /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1412 if (args.options) {
1413 ast_app_parse_options(followme_opts, &targs->followmeflags, opt_args, args.options);
1414 }
1415
1416 /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1417 ast_mutex_lock(&f->lock);
1419 targs->mohclass = ast_strdupa(f->moh);
1420 ast_copy_string(targs->context, f->context, sizeof(targs->context));
1421 ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall));
1422 ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp));
1423 ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt));
1425 ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt));
1426 ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt));
1427 ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt));
1428 ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt));
1429 ast_copy_string(targs->connprompt, f->connprompt, sizeof(targs->connprompt));
1430 /* Copy the numbers we're going to use into another list in case the master list should get modified
1431 (and locked) while we're trying to do a follow-me */
1433 AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1434 newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1435 if (newnm) {
1436 AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry);
1437 }
1438 }
1440
1441 /* PREDIAL: Preprocess any callee gosub arguments. */
1445 targs->predial_callee =
1447 }
1448
1449 /* PREDIAL: Run gosub on the caller's channel */
1454 }
1455
1456 /* Forget the 'N' option if the call is already up. */
1457 if (ast_channel_state(chan) == AST_STATE_UP) {
1459 }
1460
1463 } else {
1464 /* Answer the call */
1465 if (ast_channel_state(chan) != AST_STATE_UP) {
1466 ast_answer(chan);
1467 }
1468
1470 ast_stream_and_wait(chan, targs->statusprompt, "");
1471 }
1472
1474 int duration = 5;
1475
1476 snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s",
1478 if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration,
1480 goto outrun;
1481 }
1482 if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
1483 targs->namerecloc[0] = '\0';
1484 }
1485 }
1486
1488 if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) {
1489 goto outrun;
1490 }
1491 if (ast_waitstream(chan, "") < 0)
1492 goto outrun;
1493 }
1494 ast_moh_start(chan, targs->mohclass, NULL);
1495 }
1496
1497 ast_channel_lock(chan);
1499 ast_channel_unlock(chan);
1500
1501 outbound = findmeexec(targs, chan);
1502 if (!outbound) {
1504 if (ast_channel_state(chan) != AST_STATE_UP) {
1505 ast_answer(chan);
1506 }
1507 } else {
1508 ast_moh_stop(chan);
1509 }
1510
1512 ast_stream_and_wait(chan, targs->sorryprompt, "");
1513 }
1514 res = 0;
1515 } else {
1516 caller = chan;
1517
1518 /* Play "connecting" message to the winner, if configured. */
1519 if (!ast_strlen_zero(targs->connprompt)) {
1521 ast_stream_and_wait(outbound, targs->connprompt, "");
1523 }
1524
1525 /* Bridge the two channels. */
1526
1527 memset(&config, 0, sizeof(config));
1528 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1529 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1530 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1531 config.end_bridge_callback = end_bridge_callback;
1532 config.end_bridge_callback_data = chan;
1533 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1534
1535 /* Update connected line to caller if available. */
1536 if (targs->pending_out_connected_update) {
1537 if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0)) {
1539 }
1540 }
1541
1545 }
1546 } else {
1548 }
1549
1550 /* Be sure no generators are left on it */
1552 /* Make sure channels are compatible */
1553 res = ast_channel_make_compatible(caller, outbound);
1554 if (res < 0) {
1555 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(caller), ast_channel_name(outbound));
1557 goto outrun;
1558 }
1559
1560 /* Update connected line to winner if changed. */
1561 if (targs->pending_in_connected_update) {
1562 if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0)) {
1564 }
1565 }
1566
1567 /* Put winner on hold if caller requested. */
1568 if (targs->pending_hold) {
1569 if (ast_strlen_zero(targs->suggested_moh)) {
1571 } else {
1573 targs->suggested_moh, strlen(targs->suggested_moh) + 1);
1574 }
1575 }
1576
1577 res = ast_bridge_call(caller, outbound, &config);
1578 }
1579
1580outrun:
1581 while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) {
1582 ast_free(nm);
1583 }
1584 if (!ast_strlen_zero(targs->namerecloc)) {
1585 int ret;
1586 char fn[PATH_MAX + sizeof(REC_FORMAT)];
1587
1588 snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc,
1589 REC_FORMAT);
1590 ret = unlink(fn);
1591 if (ret != 0) {
1592 ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n",
1593 fn, errno, strerror(errno));
1594 } else {
1595 ast_debug(2, "deleted recorded prompt %s.\n", fn);
1596 }
1597 }
1598 ast_free((char *) targs->predial_callee);
1601 ast_free(targs);
1602
1603 if (f->realtime) {
1604 /* Not in list */
1605 free_numbers(f);
1606 ast_free(f);
1607 }
1608
1609 return res;
1610}
1611
1612static int unload_module(void)
1613{
1614 struct call_followme *f;
1615
1617
1618 /* Free Memory. Yeah! I'm free! */
1620 while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1621 free_numbers(f);
1622 ast_free(f);
1623 }
1624
1626
1627 return 0;
1628}
1629
1630/*!
1631 * \brief Load the module
1632 *
1633 * Module loading including tests for configuration or dependencies.
1634 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1635 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1636 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1637 * configuration file or other non-critical problem return
1638 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1639 */
1640static int load_module(void)
1641{
1642 if(!reload_followme(0))
1644
1646}
1647
1648static int reload(void)
1649{
1650 reload_followme(1);
1651
1652 return 0;
1653}
1654
1655AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
1656 .support_level = AST_MODULE_SUPPORT_CORE,
1657 .load = load_module,
1658 .unload = unload_module,
1659 .reload = reload,
static char connprompt[PATH_MAX]
Definition: app_followme.c:285
static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
Set parameter in profile from configuration file.
Definition: app_followme.c:351
@ FOLLOWMEFLAG_UNREACHABLEMSG
Definition: app_followme.c:243
@ FOLLOWMEFLAG_DISABLEHOLDPROMPT
Definition: app_followme.c:244
@ FOLLOWMEFLAG_NOANSWER
Definition: app_followme.c:245
@ FOLLOWMEFLAG_PREDIAL_CALLER
Definition: app_followme.c:248
@ FOLLOWMEFLAG_IGNORE_CONNECTEDLINE
Definition: app_followme.c:247
@ FOLLOWMEFLAG_RECORDNAME
Definition: app_followme.c:242
@ FOLLOWMEFLAG_DISABLEOPTIMIZATION
Definition: app_followme.c:246
@ FOLLOWMEFLAG_PREDIAL_CALLEE
Definition: app_followme.c:249
@ FOLLOWMEFLAG_STATUSMSG
Definition: app_followme.c:241
#define REC_FORMAT
Definition: app_followme.c:67
static char sorryprompt[PATH_MAX]
Definition: app_followme.c:284
static int reload_followme(int reload)
Reload followme application module.
Definition: app_followme.c:407
static char callfromprompt[PATH_MAX]
Definition: app_followme.c:279
#define MAX_YN_STRING
Definition: app_followme.c:154
static char takecall[MAX_YN_STRING]
Definition: app_followme.c:276
static struct call_followme * alloc_profile(const char *fmname)
Allocate and initialize followme profile.
Definition: app_followme.c:314
static void clear_caller(struct findme_user *tmpuser)
Definition: app_followme.c:606
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:620
static char nextindp[MAX_YN_STRING]
Definition: app_followme.c:277
static int featuredigittimeout
Definition: app_followme.c:273
static char optionsprompt[PATH_MAX]
Definition: app_followme.c:281
static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
Definition: app_followme.c:638
static const struct ast_app_option followme_opts[128]
Definition: app_followme.c:270
static void init_profile(struct call_followme *f, int activate)
Definition: app_followme.c:329
static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
Definition: app_followme.c:595
static char statusprompt[PATH_MAX]
Definition: app_followme.c:283
static char * app
Definition: app_followme.c:151
static int app_exec(struct ast_channel *chan, const char *data)
static char plsholdprompt[PATH_MAX]
Definition: app_followme.c:282
@ FOLLOWMEFLAG_ARG_ARRAY_SIZE
Definition: app_followme.c:257
@ FOLLOWMEFLAG_ARG_PREDIAL_CALLER
Definition: app_followme.c:253
@ FOLLOWMEFLAG_ARG_PREDIAL_CALLEE
Definition: app_followme.c:254
static struct number * create_followme_number(const char *number, int timeout, int numorder)
Add a new number.
Definition: app_followme.c:387
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:272
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:280
static void destroy_calling_node(struct findme_user *node)
Definition: app_followme.c:631
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:278
static struct ast_channel * wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs)
Definition: app_followme.c:647
static const char * defaultmoh
Definition: app_followme.c:274
static void free_numbers(struct call_followme *f)
Definition: app_followme.c:291
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
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
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
@ AST_FEATURE_REDIRECT
Definition: channel.h:1084
@ AST_FEATURE_AUTOMON
Definition: channel.h:1087
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6478
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:10364
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1523
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:2099
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:3185
#define ast_channel_lock(chan)
Definition: channel.h:2970
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6737
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
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:2081
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2977
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:2397
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:6451
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2921
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:4274
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:9119
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:6793
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:8811
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:4670
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:2874
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:8319
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:6461
int ast_channel_get_duration(struct ast_channel *chan)
Obtain how long the channel since the channel was created.
Definition: channel.c:2859
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:2072
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:349
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2834
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4294
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:6371
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define AST_MAX_EXTENSION
Definition: channel.h:134
#define MAX_MUSICCLASS
Definition: channel.h:175
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:691
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:1301
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1886
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1137
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
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:2154
#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:3066
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:3842
@ CONFIG_FLAG_FILEUNCHANGED
#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:869
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3726
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#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:190
#define ast_mutex_unlock(a)
Definition: lock.h:194
#define ast_mutex_destroy(a)
Definition: lock.h:192
#define ast_mutex_lock(a)
Definition: lock.h:193
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:329
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ 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:640
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:7787
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7797
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:4190
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:1096
void * end_bridge_callback_data
Definition: channel.h:1111
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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Structure for mutex and tracking information.
Definition: lock.h:139
Connected Line/Party information.
Definition: channel.h:458
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:165
char connprompt[PATH_MAX]
Definition: app_followme.c:182
struct call_followme::wlnumbers wlnumbers
unsigned int enable_callee_prompt
Definition: app_followme.c:173
char name[AST_MAX_EXTENSION]
Definition: app_followme.c:167
char sorryprompt[PATH_MAX]
Definition: app_followme.c:181
char callfromprompt[PATH_MAX]
Definition: app_followme.c:176
char takecall[MAX_YN_STRING]
Definition: app_followme.c:174
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:175
char optionsprompt[PATH_MAX]
Definition: app_followme.c:178
struct call_followme::blnumbers blnumbers
char statusprompt[PATH_MAX]
Definition: app_followme.c:180
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:179
struct call_followme::@25 entry
char moh[MAX_MUSICCLASS]
Definition: app_followme.c:168
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:169
struct call_followme::numbers numbers
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:177
unsigned int active
Definition: app_followme.c:170
ast_mutex_t lock
Definition: app_followme.c:166
char dialarg[768]
Definition: app_followme.c:230
struct findme_user::@26 entry
struct ast_channel * ochan
Definition: app_followme.c:224
struct ast_party_connected_line connected
Definition: app_followme.c:226
unsigned int answered
Definition: app_followme.c:234
char yn[MAX_YN_STRING]
Definition: app_followme.c:232
unsigned int pending_connected_update
Definition: app_followme.c:236
char connprompt[PATH_MAX]
Definition: app_followme.c:219
unsigned int pending_in_connected_update
Definition: app_followme.c:200
char namerecloc[PATH_MAX]
Definition: app_followme.c:210
struct fm_args::cnumbers cnumbers
unsigned int enable_callee_prompt
Definition: app_followme.c:206
char sorryprompt[PATH_MAX]
Definition: app_followme.c:218
char callfromprompt[PATH_MAX]
Definition: app_followme.c:213
char takecall[MAX_YN_STRING]
Definition: app_followme.c:211
unsigned int pending_hold
Definition: app_followme.c:204
struct ast_party_connected_line connected_out
Definition: app_followme.c:198
unsigned int pending_out_connected_update
Definition: app_followme.c:202
char suggested_moh[MAX_MUSICCLASS]
Definition: app_followme.c:208
char nextindp[MAX_YN_STRING]
Definition: app_followme.c:212
char * mohclass
Definition: app_followme.c:191
char optionsprompt[PATH_MAX]
Definition: app_followme.c:215
char statusprompt[PATH_MAX]
Definition: app_followme.c:217
char plsholdprompt[PATH_MAX]
Definition: app_followme.c:216
struct ast_flags followmeflags
Definition: app_followme.c:220
char context[AST_MAX_CONTEXT]
Definition: app_followme.c:209
char norecordingprompt[PATH_MAX]
Definition: app_followme.c:214
const char * predial_callee
Definition: app_followme.c:194
struct ast_party_connected_line connected_in
Definition: app_followme.c:196
Channel datastore data for max forwards.
Definition: max_forwards.c:29
Definition: test_heap.c:38
Number structure.
Definition: app_followme.c:157
long timeout
Definition: app_followme.c:159
struct number::@24 entry
char number[512]
Definition: app_followme.c:158
int order
Definition: app_followme.c:160
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