70b87cb90e4edc0a47e69209aca41362b8e2ed80
[asterisk/asterisk.git] / apps / app_followme.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
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  * \arg See \ref Config_followme
27  *
28  * \ingroup applications
29  */
30
31 /*** MODULEINFO
32         <depend>chan_local</depend>
33         <support_level>core</support_level>
34  ***/
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include <signal.h>
41
42 #include "asterisk/paths.h"     /* use ast_config_AST_SPOOL_DIR */
43 #include "asterisk/lock.h"
44 #include "asterisk/file.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/module.h"
48 #include "asterisk/translate.h"
49 #include "asterisk/say.h"
50 #include "asterisk/features.h"
51 #include "asterisk/musiconhold.h"
52 #include "asterisk/cli.h"
53 #include "asterisk/manager.h"
54 #include "asterisk/config.h"
55 #include "asterisk/utils.h"
56 #include "asterisk/causes.h"
57 #include "asterisk/astdb.h"
58 #include "asterisk/dsp.h"
59 #include "asterisk/app.h"
60
61 /*** DOCUMENTATION
62         <application name="FollowMe" language="en_US">
63                 <synopsis>
64                         Find-Me/Follow-Me application.
65                 </synopsis>
66                 <syntax>
67                         <parameter name="followmeid" required="true" />
68                         <parameter name="options">
69                                 <optionlist>
70                                         <option name="a">
71                                                 <para>Record the caller's name so it can be announced to the
72                                                 callee on each step.</para>
73                                         </option>
74                                         <option name="d">
75                                                 <para>Disable the 'Please hold while we try to connect your call' announcement.</para>
76                                         </option>
77                                         <option name="I">
78                                                 <para>Asterisk will ignore any connected line update requests
79                                                 it may receive on this dial attempt.</para>
80                                         </option>
81                                         <option name="l">
82                                                 <para>Disable local call optimization so that applications with
83                                                 audio hooks between the local bridge don't get dropped when the
84                                                 calls get joined directly.</para>
85                                         </option>
86                                         <option name="N">
87                                                 <para>Don't answer the incoming call until we're ready to
88                                                 connect the caller or give up.</para>
89                                                 <note>
90                                                         <para>This option is ignored if the call is already answered.</para>
91                                                 </note>
92                                                 <note>
93                                                         <para>If the call is not already answered, the 'a' and 's'
94                                                         options are ignored while the 'd' option is implicitly enabled.</para>
95                                                 </note>
96                                         </option>
97                                         <option name="n">
98                                                 <para>Playback the unreachable status message if we've run out
99                                                 of steps or the callee has elected not to be reachable.</para>
100                                         </option>
101                                         <option name="s">
102                                                 <para>Playback the incoming status message prior to starting
103                                                 the follow-me step(s)</para>
104                                         </option>
105                                 </optionlist>
106                         </parameter>
107                 </syntax>
108                 <description>
109                         <para>This application performs Find-Me/Follow-Me functionality for the caller
110                         as defined in the profile matching the <replaceable>followmeid</replaceable> parameter in
111                         <filename>followme.conf</filename>. If the specified <replaceable>followmeid</replaceable>
112                         profile doesn't exist in <filename>followme.conf</filename>, execution will be returned
113                         to the dialplan and call execution will continue at the next priority.</para>
114                         <para>Returns -1 on hangup.</para>
115                 </description>
116         </application>
117  ***/
118
119 static char *app = "FollowMe";
120
121 /*! Maximum accept/decline DTMF string plus terminator. */
122 #define MAX_YN_STRING           20
123
124 /*! \brief Number structure */
125 struct number {
126         char number[512];       /*!< Phone Number(s) and/or Extension(s) */
127         long timeout;           /*!< Dial Timeout, if used. */
128         int order;              /*!< The order to dial in */
129         AST_LIST_ENTRY(number) entry; /*!< Next Number record */
130 };
131
132 /*! \brief Data structure for followme scripts */
133 struct call_followme {
134         ast_mutex_t lock;
135         char name[AST_MAX_EXTENSION];   /*!< Name - FollowMeID */
136         char moh[MAX_MUSICCLASS];       /*!< Music On Hold Class to be used */
137         char context[AST_MAX_CONTEXT];  /*!< Context to dial from */
138         unsigned int active;            /*!< Profile is active (1), or disabled (0). */
139         int realtime;           /*!< Cached from realtime */
140         char takecall[MAX_YN_STRING];   /*!< Digit mapping to take a call */
141         char nextindp[MAX_YN_STRING];   /*!< Digit mapping to decline a call */
142         char callfromprompt[PATH_MAX];  /*!< Sound prompt name and path */
143         char norecordingprompt[PATH_MAX];       /*!< Sound prompt name and path */
144         char optionsprompt[PATH_MAX];   /*!< Sound prompt name and path */
145         char plsholdprompt[PATH_MAX];   /*!< Sound prompt name and path */
146         char statusprompt[PATH_MAX];    /*!< Sound prompt name and path */
147         char sorryprompt[PATH_MAX];     /*!< Sound prompt name and path */
148
149         AST_LIST_HEAD_NOLOCK(numbers, number) numbers;     /*!< Head of the list of follow-me numbers */
150         AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers; /*!< Head of the list of black-listed numbers */
151         AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers; /*!< Head of the list of white-listed numbers */
152         AST_LIST_ENTRY(call_followme) entry;           /*!< Next Follow-Me record */
153 };
154
155 struct fm_args {
156         char *mohclass;
157         AST_LIST_HEAD_NOLOCK(cnumbers, number) cnumbers;
158         /*! Accumulated connected line information from inbound call. */
159         struct ast_party_connected_line connected_in;
160         /*! Accumulated connected line information from outbound call. */
161         struct ast_party_connected_line connected_out;
162         /*! TRUE if connected line information from inbound call changed. */
163         unsigned int pending_in_connected_update:1;
164         /*! TRUE if connected line information from outbound call is available. */
165         unsigned int pending_out_connected_update:1;
166         char context[AST_MAX_CONTEXT];
167         char namerecloc[PATH_MAX];
168         char takecall[MAX_YN_STRING];   /*!< Digit mapping to take a call */
169         char nextindp[MAX_YN_STRING];   /*!< Digit mapping to decline a call */
170         char callfromprompt[PATH_MAX];  /*!< Sound prompt name and path */
171         char norecordingprompt[PATH_MAX];       /*!< Sound prompt name and path */
172         char optionsprompt[PATH_MAX];   /*!< Sound prompt name and path */
173         char plsholdprompt[PATH_MAX];   /*!< Sound prompt name and path */
174         char statusprompt[PATH_MAX];    /*!< Sound prompt name and path */
175         char sorryprompt[PATH_MAX];     /*!< Sound prompt name and path */
176         struct ast_flags followmeflags;
177 };
178
179 struct findme_user {
180         struct ast_channel *ochan;
181         /*! Accumulated connected line information from outgoing call. */
182         struct ast_party_connected_line connected;
183         long digts;
184         int ynidx;
185         int state;
186         char dialarg[256];
187         /*! Collected digits to accept/decline the call. */
188         char yn[MAX_YN_STRING];
189         /*! TRUE if connected line information is available. */
190         unsigned int pending_connected_update:1;
191         AST_LIST_ENTRY(findme_user) entry;
192 };
193
194 enum {
195         FOLLOWMEFLAG_STATUSMSG = (1 << 0),
196         FOLLOWMEFLAG_RECORDNAME = (1 << 1),
197         FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2),
198         FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
199         FOLLOWMEFLAG_NOANSWER = (1 << 4),
200         FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5),
201         FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6),
202 };
203
204 AST_APP_OPTIONS(followme_opts, {
205         AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME),
206         AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT),
207         AST_APP_OPTION('I', FOLLOWMEFLAG_IGNORE_CONNECTEDLINE),
208         AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION),
209         AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER),
210         AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG),
211         AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG),
212 });
213
214 static const char *featuredigittostr;
215 static int featuredigittimeout = 5000;          /*!< Feature Digit Timeout */
216 static const char *defaultmoh = "default";      /*!< Default Music-On-Hold Class */
217
218 static char takecall[MAX_YN_STRING] = "1";
219 static char nextindp[MAX_YN_STRING] = "2";
220 static char callfromprompt[PATH_MAX] = "followme/call-from";
221 static char norecordingprompt[PATH_MAX] = "followme/no-recording";
222 static char optionsprompt[PATH_MAX] = "followme/options";
223 static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try";
224 static char statusprompt[PATH_MAX] = "followme/status";
225 static char sorryprompt[PATH_MAX] = "followme/sorry";
226
227
228 static AST_RWLIST_HEAD_STATIC(followmes, call_followme);
229 AST_LIST_HEAD_NOLOCK(findme_user_listptr, findme_user);
230
231 static void free_numbers(struct call_followme *f)
232 {
233         /* Free numbers attached to the profile */
234         struct number *prev;
235
236         while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
237                 /* Free the number */
238                 ast_free(prev);
239         AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
240
241         while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
242                 /* Free the blacklisted number */
243                 ast_free(prev);
244         AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
245
246         while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
247                 /* Free the whitelisted number */
248                 ast_free(prev);
249         AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
250 }
251
252
253 /*! \brief Allocate and initialize followme profile */
254 static struct call_followme *alloc_profile(const char *fmname)
255 {
256         struct call_followme *f;
257
258         if (!(f = ast_calloc(1, sizeof(*f))))
259                 return NULL;
260
261         ast_mutex_init(&f->lock);
262         ast_copy_string(f->name, fmname, sizeof(f->name));
263         f->moh[0] = '\0';
264         f->context[0] = '\0';
265         ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
266         ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
267         ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
268         ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt));
269         ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt));
270         ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
271         ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
272         ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
273         AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
274         AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
275         AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
276         return f;
277 }
278
279 static void init_profile(struct call_followme *f)
280 {
281         f->active = 1;
282         ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
283 }
284
285    
286    
287 /*! \brief Set parameter in profile from configuration file */
288 static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
289 {
290
291         if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music")) 
292                 ast_copy_string(f->moh, val, sizeof(f->moh));
293         else if (!strcasecmp(param, "context")) 
294                 ast_copy_string(f->context, val, sizeof(f->context));
295         else if (!strcasecmp(param, "takecall"))
296                 ast_copy_string(f->takecall, val, sizeof(f->takecall));
297         else if (!strcasecmp(param, "declinecall"))
298                 ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
299         else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
300                 ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt));
301         else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt")) 
302                 ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt));
303         else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt")) 
304                 ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt));
305         else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
306                 ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt));
307         else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt")) 
308                 ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
309         else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt")) 
310                 ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
311         else if (failunknown) {
312                 if (linenum >= 0)
313                         ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
314                 else
315                         ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
316         }
317 }
318
319 /*! \brief Add a new number */
320 static struct number *create_followme_number(const char *number, int timeout, int numorder)
321 {
322         struct number *cur;
323         char *buf = ast_strdupa(number);
324         char *tmp;
325
326         if (!(cur = ast_calloc(1, sizeof(*cur))))
327                 return NULL;
328
329         cur->timeout = timeout;
330         if ((tmp = strchr(buf, ',')))
331                 *tmp = '\0';
332         ast_copy_string(cur->number, buf, sizeof(cur->number));
333         cur->order = numorder;
334         ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
335
336         return cur;
337 }
338
339 /*! \brief Reload followme application module */
340 static int reload_followme(int reload)
341 {
342         struct call_followme *f;
343         struct ast_config *cfg;
344         char *cat = NULL, *tmp;
345         struct ast_variable *var;
346         struct number *cur, *nm;
347         char numberstr[90];
348         int timeout;
349         int numorder;
350         const char *takecallstr;
351         const char *declinecallstr;
352         const char *tmpstr;
353         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
354
355         if (!(cfg = ast_config_load("followme.conf", config_flags))) {
356                 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
357                 return 0;
358         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
359                 return 0;
360         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
361                 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format.  Aborting.\n");
362                 return 0;
363         }
364
365         AST_RWLIST_WRLOCK(&followmes);
366
367         /* Reset Global Var Values */
368         featuredigittimeout = 5000;
369
370         /* Mark all profiles as inactive for the moment */
371         AST_RWLIST_TRAVERSE(&followmes, f, entry) {
372                 f->active = 0;
373         }
374
375         featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
376
377         if (!ast_strlen_zero(featuredigittostr)) {
378                 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
379                         featuredigittimeout = 5000;
380         }
381
382         if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
383                 ast_copy_string(takecall, takecallstr, sizeof(takecall));
384         }
385
386         if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
387                 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
388         }
389
390         if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
391                 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
392         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
393                 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
394         }
395
396         if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
397                 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
398         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
399                 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
400         }
401
402
403         if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
404                 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
405         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
406                 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
407         }
408
409         if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
410                 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
411         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
412                 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
413         }
414
415         if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
416                 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
417         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
418                 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
419         }
420
421         if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
422                 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
423         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
424                 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
425         }
426
427         /* Chug through config file */
428         while ((cat = ast_category_browse(cfg, cat))) {
429                 int new = 0;
430
431                 if (!strcasecmp(cat, "general"))
432                         continue;
433
434                 /* Look for an existing one */
435                 AST_LIST_TRAVERSE(&followmes, f, entry) {
436                         if (!strcasecmp(f->name, cat))
437                                 break;
438                 }
439
440                 ast_debug(1, "New profile %s.\n", cat);
441
442                 if (!f) {
443                         /* Make one then */
444                         f = alloc_profile(cat);
445                         new = 1;
446                 }
447
448                 /* Totally fail if we fail to find/create an entry */
449                 if (!f)
450                         continue;
451
452                 if (!new)
453                         ast_mutex_lock(&f->lock);
454                 /* Re-initialize the profile */
455                 init_profile(f);
456                 free_numbers(f);
457                 var = ast_variable_browse(cfg, cat);
458                 while (var) {
459                         if (!strcasecmp(var->name, "number")) {
460                                 int idx = 0;
461
462                                 /* Add a new number */
463                                 ast_copy_string(numberstr, var->value, sizeof(numberstr));
464                                 if ((tmp = strchr(numberstr, ','))) {
465                                         *tmp++ = '\0';
466                                         timeout = atoi(tmp);
467                                         if (timeout < 0) {
468                                                 timeout = 25;
469                                         }
470                                         if ((tmp = strchr(tmp, ','))) {
471                                                 *tmp++ = '\0';
472                                                 numorder = atoi(tmp);
473                                                 if (numorder < 0)
474                                                         numorder = 0;
475                                         } else 
476                                                 numorder = 0;
477                                 } else {
478                                         timeout = 25;
479                                         numorder = 0;
480                                 }
481
482                                 if (!numorder) {
483                                         idx = 1;
484                                         AST_LIST_TRAVERSE(&f->numbers, nm, entry) 
485                                                 idx++;
486                                         numorder = idx;
487                                 }
488                                 cur = create_followme_number(numberstr, timeout, numorder);
489                                 if (cur) {
490                                         AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
491                                 }
492                         } else {
493                                 profile_set_param(f, var->name, var->value, var->lineno, 1);
494                                 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
495                         }
496                         var = var->next;
497                 } /* End while(var) loop */
498
499                 if (!new) 
500                         ast_mutex_unlock(&f->lock);
501                 else
502                         AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
503         }
504
505         ast_config_destroy(cfg);
506
507         AST_RWLIST_UNLOCK(&followmes);
508
509         return 1;
510 }
511
512 static void clear_caller(struct findme_user *tmpuser)
513 {
514         struct ast_channel *outbound;
515
516         if (!tmpuser->ochan) {
517                 /* Call already cleared. */
518                 return;
519         }
520
521         outbound = tmpuser->ochan;
522         ast_channel_lock(outbound);
523         if (!ast_channel_cdr(outbound)) {
524                 ast_channel_cdr_set(outbound, ast_cdr_alloc());
525                 if (ast_channel_cdr(outbound)) {
526                         ast_cdr_init(ast_channel_cdr(outbound), outbound);
527                 }
528         }
529         if (ast_channel_cdr(outbound)) {
530                 char tmp[256];
531
532                 snprintf(tmp, sizeof(tmp), "Local/%s", tmpuser->dialarg);
533                 ast_cdr_setapp(ast_channel_cdr(outbound), "FollowMe", tmp);
534                 ast_cdr_update(outbound);
535                 ast_cdr_start(ast_channel_cdr(outbound));
536                 ast_cdr_end(ast_channel_cdr(outbound));
537                 /* If the cause wasn't handled properly */
538                 if (ast_cdr_disposition(ast_channel_cdr(outbound), ast_channel_hangupcause(outbound))) {
539                         ast_cdr_failed(ast_channel_cdr(outbound));
540                 }
541         } else {
542                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
543         }
544         ast_channel_unlock(outbound);
545         ast_hangup(outbound);
546         tmpuser->ochan = NULL;
547 }
548
549 static void clear_calling_tree(struct findme_user_listptr *findme_user_list) 
550 {
551         struct findme_user *tmpuser;
552
553         AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
554                 clear_caller(tmpuser);
555         }
556 }
557
558 static void destroy_calling_node(struct findme_user *node)
559 {
560         clear_caller(node);
561         ast_party_connected_line_free(&node->connected);
562         ast_free(node);
563 }
564
565 static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
566 {
567         struct findme_user *fmuser;
568
569         while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
570                 destroy_calling_node(fmuser);
571         }
572 }
573
574 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)
575 {
576         struct ast_party_connected_line connected;
577         struct ast_channel *watchers[256];
578         int pos;
579         struct ast_channel *winner;
580         struct ast_frame *f;
581         struct findme_user *tmpuser;
582         int to = 0;
583         int livechannels;
584         int tmpto;
585         long totalwait = 0, wtd = 0, towas = 0;
586         char *callfromname;
587         char *pressbuttonname;
588
589         /* ------------ wait_for_winner_channel start --------------- */ 
590
591         callfromname = ast_strdupa(tpargs->callfromprompt);
592         pressbuttonname = ast_strdupa(tpargs->optionsprompt);
593
594         totalwait = nm->timeout * 1000;
595
596         for (;;) {
597                 to = 1000;
598                 pos = 1; 
599                 livechannels = 0;
600                 watchers[0] = caller;
601
602                 winner = NULL;
603                 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
604                         if (!tmpuser->ochan) {
605                                 continue;
606                         }
607                         if (tmpuser->state == 3) {
608                                 tmpuser->digts += (towas - wtd);
609                         }
610                         if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
611                                 ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n",
612                                         ast_channel_name(tmpuser->ochan));
613                                 if (!ast_strlen_zero(tpargs->namerecloc)) {
614                                         tmpuser->state = 1;
615                                         tmpuser->digts = 0;
616                                         if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
617                                                 ast_sched_runq(ast_channel_sched(tmpuser->ochan));
618                                         } else {
619                                                 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
620                                                 clear_caller(tmpuser);
621                                                 continue;
622                                         }
623                                 } else {
624                                         tmpuser->state = 2;
625                                         tmpuser->digts = 0;
626                                         if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
627                                                 ast_sched_runq(ast_channel_sched(tmpuser->ochan));
628                                         else {
629                                                 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
630                                                 clear_caller(tmpuser);
631                                                 continue;
632                                         }
633                                 }
634                         }
635                         if (ast_channel_stream(tmpuser->ochan)) {
636                                 ast_sched_runq(ast_channel_sched(tmpuser->ochan));
637                                 tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan));
638                                 if (tmpto > 0 && tmpto < to)
639                                         to = tmpto;
640                                 else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
641                                         ast_stopstream(tmpuser->ochan);
642                                         switch (tmpuser->state) {
643                                         case 1:
644                                                 ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n",
645                                                         ast_channel_name(tmpuser->ochan));
646                                                 if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) {
647                                                         tmpuser->state = 2;
648                                                 } else {
649                                                         ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n",
650                                                                 ast_channel_name(tmpuser->ochan), tpargs->namerecloc);
651                                                         memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
652                                                         tmpuser->ynidx = 0;
653                                                         if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
654                                                                 tmpuser->state = 3;
655                                                         else {
656                                                                 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
657                                                                 clear_caller(tmpuser);
658                                                                 continue;
659                                                         }
660                                                 }
661                                                 break;
662                                         case 2:
663                                                 ast_verb(3, "<%s> Playback of name file appears to be done.\n",
664                                                         ast_channel_name(tmpuser->ochan));
665                                                 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
666                                                 tmpuser->ynidx = 0;
667                                                 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
668                                                         tmpuser->state = 3;
669                                                 } else {
670                                                         clear_caller(tmpuser);
671                                                         continue;
672                                                 }
673                                                 break;
674                                         case 3:
675                                                 ast_verb(3, "<%s> Playback of the next step file appears to be done.\n",
676                                                         ast_channel_name(tmpuser->ochan));
677                                                 tmpuser->digts = 0;
678                                                 break;
679                                         default:
680                                                 break;
681                                         }
682                                 }
683                         }
684                         watchers[pos++] = tmpuser->ochan;
685                         livechannels++;
686                 }
687                 if (!livechannels) {
688                         ast_verb(3, "No live channels left for this step.\n");
689                         return NULL;
690                 }
691
692                 tmpto = to;
693                 if (to < 0) {
694                         to = 1000;
695                         tmpto = 1000;
696                 }
697                 towas = to;
698                 winner = ast_waitfor_n(watchers, pos, &to);
699                 tmpto -= to;
700                 totalwait -= tmpto;
701                 wtd = to;
702                 if (totalwait <= 0) {
703                         ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
704                         clear_calling_tree(findme_user_list);
705                         return NULL;
706                 }
707                 if (winner) {
708                         /* Need to find out which channel this is */
709                         if (winner != caller) {
710                                 /* The winner is an outgoing channel. */
711                                 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
712                                         if (tmpuser->ochan == winner) {
713                                                 break;
714                                         }
715                                 }
716                         } else {
717                                 tmpuser = NULL;
718                         }
719
720                         f = ast_read(winner);
721                         if (f) {
722                                 if (f->frametype == AST_FRAME_CONTROL) {
723                                         switch (f->subclass.integer) {
724                                         case AST_CONTROL_HANGUP:
725                                                 ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner));
726                                                 if (f->data.uint32) {
727                                                         ast_channel_hangupcause_set(winner, f->data.uint32);
728                                                 }
729                                                 if (!tmpuser) {
730                                                         ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
731                                                         ast_frfree(f);
732                                                         return NULL;
733                                                 }
734                                                 clear_caller(tmpuser);
735                                                 break;
736                                         case AST_CONTROL_ANSWER:
737                                                 if (!tmpuser) {
738                                                         /* The caller answered?  We want an outgoing channel to answer. */
739                                                         break;
740                                                 }
741                                                 ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
742                                                 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 
743                                                 ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING);
744                                                 ast_channel_hangupcause_set(caller, AST_CAUSE_NORMAL_CLEARING);
745                                                 ast_verb(3, "Starting playback of %s\n", callfromname);
746                                                 if (!ast_strlen_zero(tpargs->namerecloc)) {
747                                                         if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) {
748                                                                 ast_sched_runq(ast_channel_sched(winner));
749                                                                 tmpuser->state = 1;
750                                                         } else {
751                                                                 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
752                                                                 clear_caller(tmpuser);
753                                                         }
754                                                 } else {
755                                                         tmpuser->state = 2;
756                                                         if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
757                                                                 ast_sched_runq(ast_channel_sched(tmpuser->ochan));
758                                                         else {
759                                                                 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
760                                                                 clear_caller(tmpuser);
761                                                         }
762                                                 }
763                                                 break;
764                                         case AST_CONTROL_BUSY:
765                                                 ast_verb(3, "%s is busy\n", ast_channel_name(winner));
766                                                 if (tmpuser) {
767                                                         /* Outbound call was busy.  Drop it. */
768                                                         clear_caller(tmpuser);
769                                                 }
770                                                 break;
771                                         case AST_CONTROL_CONGESTION:
772                                                 ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
773                                                 if (tmpuser) {
774                                                         /* Outbound call was congested.  Drop it. */
775                                                         clear_caller(tmpuser);
776                                                 }
777                                                 break;
778                                         case AST_CONTROL_RINGING:
779                                                 ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
780                                                 break;
781                                         case AST_CONTROL_PROGRESS:
782                                                 ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
783                                                 break;
784                                         case AST_CONTROL_VIDUPDATE:
785                                                 ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
786                                                 break;
787                                         case AST_CONTROL_SRCUPDATE:
788                                                 ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
789                                                 break;
790                                         case AST_CONTROL_PROCEEDING:
791                                                 ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
792                                                 break;
793                                         case AST_CONTROL_HOLD:
794                                                 ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
795                                                 break;
796                                         case AST_CONTROL_UNHOLD:
797                                                 ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
798                                                 break;
799                                         case AST_CONTROL_OFFHOOK:
800                                         case AST_CONTROL_FLASH:
801                                                 /* Ignore going off hook and flash */
802                                                 break;
803                                         case AST_CONTROL_CONNECTED_LINE:
804                                                 if (!tmpuser) {
805                                                         /*
806                                                          * Hold connected line update from caller until we have a
807                                                          * winner.
808                                                          */
809                                                         ast_verb(3,
810                                                                 "%s connected line has changed. Saving it until we have a winner.\n",
811                                                                 ast_channel_name(winner));
812                                                         ast_party_connected_line_set_init(&connected, &tpargs->connected_in);
813                                                         if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
814                                                                 ast_party_connected_line_set(&tpargs->connected_in,
815                                                                         &connected, NULL);
816                                                                 tpargs->pending_in_connected_update = 1;
817                                                         }
818                                                         ast_party_connected_line_free(&connected);
819                                                         break;
820                                                 }
821                                                 if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
822                                                         ast_verb(3, "Connected line update from %s prevented.\n",
823                                                                 ast_channel_name(winner));
824                                                 } else {
825                                                         ast_verb(3,
826                                                                 "%s connected line has changed. Saving it until answer.\n",
827                                                                 ast_channel_name(winner));
828                                                         ast_party_connected_line_set_init(&connected, &tmpuser->connected);
829                                                         if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
830                                                                 ast_party_connected_line_set(&tmpuser->connected,
831                                                                         &connected, NULL);
832                                                                 tmpuser->pending_connected_update = 1;
833                                                         }
834                                                         ast_party_connected_line_free(&connected);
835                                                 }
836                                                 break;
837                                         case AST_CONTROL_REDIRECTING:
838                                                 /*
839                                                  * Ignore because we are masking the FollowMe search progress to
840                                                  * the caller.
841                                                  */
842                                                 break;
843                                         case -1:
844                                                 ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
845                                                 break;
846                                         default:
847                                                 ast_debug(1, "Dunno what to do with control type %d from %s\n",
848                                                         f->subclass.integer, ast_channel_name(winner));
849                                                 break;
850                                         }
851                                 } 
852                                 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
853                                         if (ast_channel_stream(winner))
854                                                 ast_stopstream(winner);
855                                         tmpuser->digts = 0;
856                                         ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
857                                         if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
858                                                 tmpuser->yn[tmpuser->ynidx++] = (char) f->subclass.integer;
859                                         }
860                                         ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
861                                         if (!strcmp(tmpuser->yn, tpargs->takecall)) {
862                                                 ast_debug(1, "Match to take the call!\n");
863                                                 ast_frfree(f);
864                                                 return tmpuser->ochan;
865                                         }
866                                         if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
867                                                 ast_debug(1, "Declined to take the call.\n");
868                                                 clear_caller(tmpuser);
869                                         }
870                                 }
871
872                                 ast_frfree(f);
873                         } else {
874                                 ast_debug(1, "we didn't get a frame. hanging up.\n");
875                                 if (!tmpuser) {
876                                         /* Caller hung up. */
877                                         ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
878                                         return NULL;
879                                 }
880                                 /* Outgoing channel hung up. */
881                                 clear_caller(tmpuser);
882                         }
883                 } else {
884                         ast_debug(1, "timed out waiting for action\n");
885                 }
886         }
887
888         /* Unreachable. */
889 }
890
891 /*!
892  * \internal
893  * \brief Find an extension willing to take the call.
894  *
895  * \param tpargs Active Followme config.
896  * \param caller Channel initiating the outgoing calls.
897  *
898  * \retval winner Winning outgoing call.
899  * \retval NULL if could not find someone to take the call.
900  */
901 static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
902 {
903         struct number *nm;
904         struct ast_channel *winner = NULL;
905         char num[512];
906         int dg, idx;
907         char *rest, *number;
908         struct findme_user *tmpuser;
909         struct findme_user *fmuser;
910         struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
911         struct findme_user_listptr new_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
912
913         for (idx = 1; !ast_check_hangup(caller); ++idx) {
914                 /* Find next followme numbers to dial. */
915                 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
916                         if (nm->order == idx) {
917                                 break;
918                         }
919                 }
920                 if (!nm) {
921                         ast_verb(3, "No more steps left.\n");
922                         break;
923                 }
924
925                 ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout);
926
927                 ast_copy_string(num, nm->number, sizeof(num));
928                 for (number = num; number; number = rest) {
929                         struct ast_channel *outbound;
930
931                         rest = strchr(number, '&');
932                         if (rest) {
933                                 *rest++ = 0;
934                         }
935
936                         /* We check if the extension exists, before creating the ast_channel struct */
937                         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))) {
938                                 ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
939                                 continue;
940                         }
941
942                         tmpuser = ast_calloc(1, sizeof(*tmpuser));
943                         if (!tmpuser) {
944                                 continue;
945                         }
946
947                         if (ast_strlen_zero(tpargs->context)) {
948                                 snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s%s",
949                                         number,
950                                         ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION)
951                                                 ? "/n" : "");
952                         } else {
953                                 snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s@%s%s",
954                                         number, tpargs->context,
955                                         ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION)
956                                                 ? "/n" : "");
957                         }
958
959                         outbound = ast_request("Local", ast_channel_nativeformats(caller), caller,
960                                 tmpuser->dialarg, &dg);
961                         if (!outbound) {
962                                 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
963                                         tmpuser->dialarg, ast_cause2str(dg));
964                                 ast_free(tmpuser);
965                                 continue;
966                         }
967
968                         ast_channel_lock_both(caller, outbound);
969                         ast_connected_line_copy_from_caller(ast_channel_connected(outbound), ast_channel_caller(caller));
970                         ast_channel_inherit_variables(caller, outbound);
971                         ast_channel_datastore_inherit(caller, outbound);
972                         ast_channel_language_set(outbound, ast_channel_language(caller));
973                         ast_channel_accountcode_set(outbound, ast_channel_accountcode(caller));
974                         ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
975                         ast_channel_unlock(outbound);
976                         ast_channel_unlock(caller);
977
978                         tmpuser->ochan = outbound;
979                         tmpuser->state = 0;
980
981                         ast_verb(3, "calling Local/%s\n", tmpuser->dialarg);
982                         if (!ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) {
983                                 AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry);
984                         } else {
985                                 ast_verb(3, "couldn't reach at this number.\n");
986
987                                 /* Destroy this failed new outgoing call. */
988                                 ast_channel_lock(tmpuser->ochan);
989                                 if (ast_channel_cdr(tmpuser->ochan)) {
990                                         ast_cdr_init(ast_channel_cdr(tmpuser->ochan), tmpuser->ochan);
991                                 }
992                                 ast_channel_unlock(tmpuser->ochan);
993                                 destroy_calling_node(tmpuser);
994                         }
995                 }
996
997                 if (AST_LIST_EMPTY(&new_user_list)) {
998                         /* No new channels remain at this order level.  If there were any at all. */
999                         continue;
1000                 }
1001
1002                 /* Add new outgoing channels to the findme list. */
1003                 AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry);
1004
1005                 winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
1006                 if (!winner) {
1007                         continue;
1008                 }
1009
1010                 /* Destroy losing calls up to the winner.  The rest will be destroyed later. */
1011                 while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) {
1012                         if (fmuser->ochan == winner) {
1013                                 /*
1014                                  * Pass any connected line info up.
1015                                  *
1016                                  * NOTE: This code must be in line with destroy_calling_node().
1017                                  */
1018                                 tpargs->connected_out = fmuser->connected;
1019                                 tpargs->pending_out_connected_update = fmuser->pending_connected_update;
1020                                 ast_free(fmuser);
1021                                 break;
1022                         } else {
1023                                 /* Destroy losing call. */
1024                                 destroy_calling_node(fmuser);
1025                         }
1026                 }
1027                 break;
1028         }
1029         destroy_calling_tree(&findme_user_list);
1030         return winner;
1031 }
1032
1033 static struct call_followme *find_realtime(const char *name)
1034 {
1035         struct ast_variable *var;
1036         struct ast_variable *v;
1037         struct ast_config *cfg;
1038         const char *catg;
1039         struct call_followme *new_follower;
1040         struct ast_str *str;
1041
1042         str = ast_str_create(16);
1043         if (!str) {
1044                 return NULL;
1045         }
1046
1047         var = ast_load_realtime("followme", "name", name, SENTINEL);
1048         if (!var) {
1049                 ast_free(str);
1050                 return NULL;
1051         }
1052
1053         if (!(new_follower = alloc_profile(name))) {
1054                 ast_variables_destroy(var);
1055                 ast_free(str);
1056                 return NULL;
1057         }
1058
1059         for (v = var; v; v = v->next) {
1060                 if (!strcasecmp(v->name, "active")) {
1061                         if (ast_false(v->value)) {
1062                                 ast_mutex_destroy(&new_follower->lock);
1063                                 ast_free(new_follower);
1064                                 ast_variables_destroy(var);
1065                                 ast_free(str);
1066                                 return NULL;
1067                         }
1068                 } else {
1069                         profile_set_param(new_follower, v->name, v->value, 0, 0);
1070                 }
1071         }
1072
1073         ast_variables_destroy(var);
1074         new_follower->realtime = 1;
1075
1076         /* Load numbers */
1077         cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
1078                 name, SENTINEL);
1079         if (!cfg) {
1080                 ast_mutex_destroy(&new_follower->lock);
1081                 ast_free(new_follower);
1082                 ast_free(str);
1083                 return NULL;
1084         }
1085
1086         for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
1087                 const char *numstr;
1088                 const char *timeoutstr;
1089                 const char *ordstr;
1090                 int timeout;
1091                 struct number *cur;
1092
1093                 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
1094                         continue;
1095                 }
1096                 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
1097                         || sscanf(timeoutstr, "%30d", &timeout) != 1
1098                         || timeout < 1) {
1099                         timeout = 25;
1100                 }
1101                 /* This one has to exist; it was part of the query */
1102                 ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
1103                 ast_str_set(&str, 0, "%s", numstr);
1104                 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
1105                         AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
1106                 }
1107         }
1108         ast_config_destroy(cfg);
1109
1110         ast_free(str);
1111         return new_follower;
1112 }
1113
1114 static void end_bridge_callback(void *data)
1115 {
1116         char buf[80];
1117         time_t end;
1118         struct ast_channel *chan = data;
1119
1120         time(&end);
1121
1122         ast_channel_lock(chan);
1123         if (ast_channel_cdr(chan)->answer.tv_sec) {
1124                 snprintf(buf, sizeof(buf), "%ld", (long) end - ast_channel_cdr(chan)->answer.tv_sec);
1125                 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1126         }
1127
1128         if (ast_channel_cdr(chan)->start.tv_sec) {
1129                 snprintf(buf, sizeof(buf), "%ld", (long) end - ast_channel_cdr(chan)->start.tv_sec);
1130                 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1131         }
1132         ast_channel_unlock(chan);
1133 }
1134
1135 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
1136 {
1137         bconfig->end_bridge_callback_data = originator;
1138 }
1139
1140 static int app_exec(struct ast_channel *chan, const char *data)
1141 {
1142         struct fm_args *targs;
1143         struct ast_bridge_config config;
1144         struct call_followme *f;
1145         struct number *nm, *newnm;
1146         int res = 0;
1147         char *argstr;
1148         struct ast_channel *caller;
1149         struct ast_channel *outbound;
1150         AST_DECLARE_APP_ARGS(args,
1151                 AST_APP_ARG(followmeid);
1152                 AST_APP_ARG(options);
1153         );
1154
1155         if (ast_strlen_zero(data)) {
1156                 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1157                 return -1;
1158         }
1159
1160         argstr = ast_strdupa((char *) data);
1161
1162         AST_STANDARD_APP_ARGS(args, argstr);
1163
1164         if (ast_strlen_zero(args.followmeid)) {
1165                 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1166                 return -1;
1167         }
1168
1169         targs = ast_calloc(1, sizeof(*targs));
1170         if (!targs) {
1171                 return -1;
1172         }
1173
1174         AST_RWLIST_RDLOCK(&followmes);
1175         AST_RWLIST_TRAVERSE(&followmes, f, entry) {
1176                 if (!strcasecmp(f->name, args.followmeid) && (f->active))
1177                         break;
1178         }
1179         AST_RWLIST_UNLOCK(&followmes);
1180
1181         ast_debug(1, "New profile %s.\n", args.followmeid);
1182
1183         if (!f) {
1184                 f = find_realtime(args.followmeid);
1185         }
1186
1187         if (!f) {
1188                 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1189                 ast_free(targs);
1190                 return 0;
1191         }
1192
1193         /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1194         if (args.options) {
1195                 ast_app_parse_options(followme_opts, &targs->followmeflags, NULL, args.options);
1196         }
1197
1198         /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1199         ast_mutex_lock(&f->lock);
1200         targs->mohclass = ast_strdupa(f->moh);
1201         ast_copy_string(targs->context, f->context, sizeof(targs->context));
1202         ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall));
1203         ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp));
1204         ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt));
1205         ast_copy_string(targs->norecordingprompt, f->norecordingprompt, sizeof(targs->norecordingprompt));
1206         ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt));
1207         ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt));
1208         ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt));
1209         ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt));
1210         /* Copy the numbers we're going to use into another list in case the master list should get modified 
1211            (and locked) while we're trying to do a follow-me */
1212         AST_LIST_HEAD_INIT_NOLOCK(&targs->cnumbers);
1213         AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1214                 newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1215                 if (newnm) {
1216                         AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry);
1217                 }
1218         }
1219         ast_mutex_unlock(&f->lock);
1220
1221         /* Forget the 'N' option if the call is already up. */
1222         if (ast_channel_state(chan) == AST_STATE_UP) {
1223                 ast_clear_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER);
1224         }
1225
1226         if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1227                 ast_indicate(chan, AST_CONTROL_RINGING);
1228         } else {
1229                 /* Answer the call */
1230                 if (ast_channel_state(chan) != AST_STATE_UP) {
1231                         ast_answer(chan);
1232                 }
1233
1234                 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_STATUSMSG)) {
1235                         ast_stream_and_wait(chan, targs->statusprompt, "");
1236                 }
1237
1238                 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_RECORDNAME)) {
1239                         int duration = 5;
1240
1241                         snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s",
1242                                 ast_config_AST_SPOOL_DIR, ast_channel_uniqueid(chan));
1243                         if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, "sln", &duration,
1244                                 NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) {
1245                                 goto outrun;
1246                         }
1247                         if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
1248                                 targs->namerecloc[0] = '\0';
1249                         }
1250                 }
1251
1252                 if (!ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
1253                         if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) {
1254                                 goto outrun;
1255                         }
1256                         if (ast_waitstream(chan, "") < 0)
1257                                 goto outrun;
1258                 }
1259                 ast_moh_start(chan, S_OR(targs->mohclass, NULL), NULL);
1260         }
1261
1262         ast_channel_lock(chan);
1263         ast_connected_line_copy_from_caller(&targs->connected_in, ast_channel_caller(chan));
1264         ast_channel_unlock(chan);
1265
1266         outbound = findmeexec(targs, chan);
1267         if (!outbound) {
1268                 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1269                         if (ast_channel_state(chan) != AST_STATE_UP) {
1270                                 ast_answer(chan);
1271                         }
1272                 } else {
1273                         ast_moh_stop(chan);
1274                 }
1275
1276                 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) {
1277                         ast_stream_and_wait(chan, targs->sorryprompt, "");
1278                 }
1279                 res = 0;
1280         } else {
1281                 caller = chan;
1282                 /* Bridge the two channels. */
1283
1284                 memset(&config, 0, sizeof(config));
1285                 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1286                 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1287                 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1288                 config.end_bridge_callback = end_bridge_callback;
1289                 config.end_bridge_callback_data = chan;
1290                 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1291
1292                 /* Update connected line to caller if available. */
1293                 if (targs->pending_out_connected_update) {
1294                         if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0) &&
1295                                 ast_channel_connected_line_macro(outbound, caller, &targs->connected_out, 1, 0)) {
1296                                 ast_channel_update_connected_line(caller, &targs->connected_out, NULL);
1297                         }
1298                 }
1299
1300                 if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1301                         if (ast_channel_state(caller) != AST_STATE_UP) {
1302                                 ast_answer(caller);
1303                         }
1304                 } else {
1305                         ast_moh_stop(caller);
1306                 }
1307
1308                 /* Be sure no generators are left on it */
1309                 ast_deactivate_generator(caller);
1310                 /* Make sure channels are compatible */
1311                 res = ast_channel_make_compatible(caller, outbound);
1312                 if (res < 0) {
1313                         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));
1314                         ast_hangup(outbound);
1315                         goto outrun;
1316                 }
1317
1318                 /* Update connected line to winner if changed. */
1319                 if (targs->pending_in_connected_update) {
1320                         if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0) &&
1321                                 ast_channel_connected_line_macro(caller, outbound, &targs->connected_in, 0, 0)) {
1322                                 ast_channel_update_connected_line(outbound, &targs->connected_in, NULL);
1323                         }
1324                 }
1325
1326                 res = ast_bridge_call(caller, outbound, &config);
1327                 ast_hangup(outbound);
1328         }
1329
1330 outrun:
1331         while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) {
1332                 ast_free(nm);
1333         }
1334         if (!ast_strlen_zero(targs->namerecloc)) {
1335                 unlink(targs->namerecloc);
1336         }
1337         ast_party_connected_line_free(&targs->connected_in);
1338         ast_party_connected_line_free(&targs->connected_out);
1339         ast_free(targs);
1340
1341         if (f->realtime) {
1342                 /* Not in list */
1343                 free_numbers(f);
1344                 ast_free(f);
1345         }
1346
1347         return res;
1348 }
1349
1350 static int unload_module(void)
1351 {
1352         struct call_followme *f;
1353
1354         ast_unregister_application(app);
1355
1356         /* Free Memory. Yeah! I'm free! */
1357         AST_RWLIST_WRLOCK(&followmes);
1358         while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1359                 free_numbers(f);
1360                 ast_free(f);
1361         }
1362
1363         AST_RWLIST_UNLOCK(&followmes);
1364
1365         return 0;
1366 }
1367
1368 static int load_module(void)
1369 {
1370         if(!reload_followme(0))
1371                 return AST_MODULE_LOAD_DECLINE;
1372
1373         return ast_register_application_xml(app, app_exec);
1374 }
1375
1376 static int reload(void)
1377 {
1378         reload_followme(1);
1379
1380         return 0;
1381 }
1382
1383 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
1384                 .load = load_module,
1385                 .unload = unload_module,
1386                 .reload = reload,
1387                );