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