Merged revisions 333203 via svnmerge from
[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         char *timeoutstr;
327         int numorder;
328         const char *takecallstr;
329         const char *declinecallstr;
330         const char *tmpstr;
331         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
332
333         if (!(cfg = ast_config_load("followme.conf", config_flags))) {
334                 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
335                 return 0;
336         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
337                 return 0;
338         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
339                 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format.  Aborting.\n");
340                 return 0;
341         }
342
343         AST_RWLIST_WRLOCK(&followmes);
344
345         /* Reset Global Var Values */
346         featuredigittimeout = 5000;
347
348         /* Mark all profiles as inactive for the moment */
349         AST_RWLIST_TRAVERSE(&followmes, f, entry) {
350                 f->active = 0;
351         }
352
353         featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
354
355         if (!ast_strlen_zero(featuredigittostr)) {
356                 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
357                         featuredigittimeout = 5000;
358         }
359
360         if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
361                 ast_copy_string(takecall, takecallstr, sizeof(takecall));
362         }
363
364         if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
365                 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
366         }
367
368         if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
369                 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
370         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
371                 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
372         }
373
374         if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
375                 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
376         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
377                 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
378         }
379
380
381         if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
382                 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
383         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
384                 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
385         }
386
387         if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
388                 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
389         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
390                 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
391         }
392
393         if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
394                 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
395         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
396                 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
397         }
398
399         if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
400                 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
401         } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
402                 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
403         }
404
405         /* Chug through config file */
406         while ((cat = ast_category_browse(cfg, cat))) {
407                 int new = 0;
408
409                 if (!strcasecmp(cat, "general"))
410                         continue;
411
412                 /* Look for an existing one */
413                 AST_LIST_TRAVERSE(&followmes, f, entry) {
414                         if (!strcasecmp(f->name, cat))
415                                 break;
416                 }
417
418                 ast_debug(1, "New profile %s.\n", cat);
419
420                 if (!f) {
421                         /* Make one then */
422                         f = alloc_profile(cat);
423                         new = 1;
424                 }
425
426                 /* Totally fail if we fail to find/create an entry */
427                 if (!f)
428                         continue;
429
430                 if (!new)
431                         ast_mutex_lock(&f->lock);
432                 /* Re-initialize the profile */
433                 init_profile(f);
434                 free_numbers(f);
435                 var = ast_variable_browse(cfg, cat);
436                 while (var) {
437                         if (!strcasecmp(var->name, "number")) {
438                                 int idx = 0;
439
440                                 /* Add a new number */
441                                 ast_copy_string(numberstr, var->value, sizeof(numberstr));
442                                 if ((tmp = strchr(numberstr, ','))) {
443                                         *tmp++ = '\0';
444                                         timeoutstr = ast_strdupa(tmp);
445                                         if ((tmp = strchr(timeoutstr, ','))) {
446                                                 *tmp++ = '\0';
447                                                 numorder = atoi(tmp);
448                                                 if (numorder < 0)
449                                                         numorder = 0;
450                                         } else 
451                                                 numorder = 0;
452                                         timeout = atoi(timeoutstr);
453                                         if (timeout < 0) 
454                                                 timeout = 25;
455                                 } else {
456                                         timeout = 25;
457                                         numorder = 0;
458                                 }
459
460                                 if (!numorder) {
461                                         idx = 1;
462                                         AST_LIST_TRAVERSE(&f->numbers, nm, entry) 
463                                                 idx++;
464                                         numorder = idx;
465                                 }
466                                 cur = create_followme_number(numberstr, timeout, numorder);
467                                 AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
468                         } else {
469                                 profile_set_param(f, var->name, var->value, var->lineno, 1);
470                                 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
471                         }
472                         var = var->next;
473                 } /* End while(var) loop */
474
475                 if (!new) 
476                         ast_mutex_unlock(&f->lock);
477                 else
478                         AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
479         }
480
481         ast_config_destroy(cfg);
482
483         AST_RWLIST_UNLOCK(&followmes);
484
485         return 1;
486 }
487
488 static void clear_caller(struct findme_user *tmpuser)
489 {
490         struct ast_channel *outbound;
491
492         if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) {
493                 outbound = tmpuser->ochan;
494                 if (!outbound->cdr) {
495                         outbound->cdr = ast_cdr_alloc();
496                         if (outbound->cdr)
497                                 ast_cdr_init(outbound->cdr, outbound);
498                 }
499                 if (outbound->cdr) {
500                         char tmp[256];
501
502                         snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg);
503                         ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
504                         ast_cdr_update(outbound);
505                         ast_cdr_start(outbound->cdr);
506                         ast_cdr_end(outbound->cdr);
507                         /* If the cause wasn't handled properly */
508                         if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause))
509                                 ast_cdr_failed(outbound->cdr);
510                 } else
511                         ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
512                 ast_hangup(tmpuser->ochan);
513         }
514
515 }
516
517 static void clear_calling_tree(struct findme_user_listptr *findme_user_list) 
518 {
519         struct findme_user *tmpuser;
520
521         AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
522                 clear_caller(tmpuser);
523                 tmpuser->cleared = 1;
524         }
525 }
526
527
528
529 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) 
530 {
531         struct ast_channel *watchers[256];
532         int pos;
533         struct ast_channel *winner;
534         struct ast_frame *f;
535         int ctstatus = 0;
536         int dg;
537         struct findme_user *tmpuser;
538         int to = 0;
539         int livechannels = 0;
540         int tmpto;
541         long totalwait = 0, wtd = 0, towas = 0;
542         char *callfromname;
543         char *pressbuttonname;
544
545         /* ------------ wait_for_winner_channel start --------------- */ 
546
547         callfromname = ast_strdupa(tpargs->callfromprompt);
548         pressbuttonname = ast_strdupa(tpargs->optionsprompt);
549
550         if (AST_LIST_EMPTY(findme_user_list)) {
551                 ast_verb(3, "couldn't reach at this number.\n");
552                 return NULL;
553         }
554
555         if (!caller) {
556                 ast_verb(3, "Original caller hungup. Cleanup.\n");
557                 clear_calling_tree(findme_user_list);
558                 return NULL;
559         }
560
561         totalwait = nm->timeout * 1000;
562
563         while (!ctstatus) {
564                 to = 1000;
565                 pos = 1; 
566                 livechannels = 0;
567                 watchers[0] = caller;
568
569                 dg = 0;
570                 winner = NULL;
571                 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
572                         if (tmpuser->state >= 0 && tmpuser->ochan) {
573                                 if (tmpuser->state == 3) 
574                                         tmpuser->digts += (towas - wtd);
575                                 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
576                                         ast_verb(3, "We've been waiting for digits longer than we should have.\n");
577                                         if (!ast_strlen_zero(namerecloc)) {
578                                                 tmpuser->state = 1;
579                                                 tmpuser->digts = 0;
580                                                 if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) {
581                                                         ast_sched_runq(tmpuser->ochan->sched);
582                                                 } else {
583                                                         ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
584                                                         return NULL;
585                                                 }
586                                         } else {
587                                                 tmpuser->state = 2;
588                                                 tmpuser->digts = 0;
589                                                 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
590                                                         ast_sched_runq(tmpuser->ochan->sched);
591                                                 else {
592                                                         ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
593                                                         return NULL;
594                                                 }
595                                         }
596                                 }
597                                 if (tmpuser->ochan->stream) {
598                                         ast_sched_runq(tmpuser->ochan->sched);
599                                         tmpto = ast_sched_wait(tmpuser->ochan->sched);
600                                         if (tmpto > 0 && tmpto < to)
601                                                 to = tmpto;
602                                         else if (tmpto < 0 && !tmpuser->ochan->timingfunc) {
603                                                 ast_stopstream(tmpuser->ochan);
604                                                 if (tmpuser->state == 1) {
605                                                         ast_verb(3, "Playback of the call-from file appears to be done.\n");
606                                                         if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) {
607                                                                 tmpuser->state = 2;
608                                                         } else {
609                                                                 ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc);
610                                                                 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
611                                                                 tmpuser->ynidx = 0;
612                                                                 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language))
613                                                                         tmpuser->state = 3;
614                                                                 else {
615                                                                         ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
616                                                                         return NULL;
617                                                                 } 
618                                                         }
619                                                 } else if (tmpuser->state == 2) {
620                                                         ast_verb(3, "Playback of name file appears to be done.\n");
621                                                         memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
622                                                         tmpuser->ynidx = 0;
623                                                         if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) {
624                                                                 tmpuser->state = 3;
625                                                         } else {
626                                                                 return NULL;
627                                                         } 
628                                                 } else if (tmpuser->state == 3) {
629                                                         ast_verb(3, "Playback of the next step file appears to be done.\n");
630                                                         tmpuser->digts = 0;
631                                                 }
632                                         }
633                                 }
634                                 watchers[pos++] = tmpuser->ochan;
635                                 livechannels++;
636                         }
637                 }
638
639                 tmpto = to;
640                 if (to < 0) {
641                         to = 1000;
642                         tmpto = 1000;
643                 }
644                 towas = to;
645                 winner = ast_waitfor_n(watchers, pos, &to);
646                 tmpto -= to;
647                 totalwait -= tmpto;
648                 wtd = to;
649                 if (totalwait <= 0) {
650                         ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
651                         clear_calling_tree(findme_user_list);
652                         return NULL;
653                 }
654                 if (winner) {
655                         /* Need to find out which channel this is */
656                         dg = 0;
657                         while ((winner != watchers[dg]) && (dg < 256))
658                                 dg++;
659                         AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry)
660                                 if (tmpuser->ochan == winner)
661                                         break;
662                         f = ast_read(winner);
663                         if (f) {
664                                 if (f->frametype == AST_FRAME_CONTROL) {
665                                         switch (f->subclass.integer) {
666                                         case AST_CONTROL_HANGUP:
667                                                 ast_verb(3, "%s received a hangup frame.\n", winner->name);
668                                                 if (f->data.uint32) {
669                                                         winner->hangupcause = f->data.uint32;
670                                                 }
671                                                 if (dg == 0) {
672                                                         ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n");
673                                                         clear_calling_tree(findme_user_list);
674                                                         ctstatus = -1;
675                                                 }
676                                                 break;
677                                         case AST_CONTROL_ANSWER:
678                                                 ast_verb(3, "%s answered %s\n", winner->name, caller->name);
679                                                 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 
680                                                 winner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
681                                                 caller->hangupcause = AST_CAUSE_NORMAL_CLEARING;
682                                                 ast_verb(3, "Starting playback of %s\n", callfromname);
683                                                 if (dg > 0) {
684                                                         if (!ast_strlen_zero(namerecloc)) {
685                                                                 if (!ast_streamfile(winner, callfromname, winner->language)) {
686                                                                         ast_sched_runq(winner->sched);
687                                                                         tmpuser->state = 1;
688                                                                 } else {
689                                                                         ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
690                                                                         ast_frfree(f);
691                                                                         return NULL;
692                                                                 }
693                                                         } else {
694                                                                 tmpuser->state = 2;
695                                                                 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
696                                                                         ast_sched_runq(tmpuser->ochan->sched);
697                                                                 else {
698                                                                         ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
699                                                                         ast_frfree(f);
700                                                                         return NULL;
701                                                                 }
702                                                         }
703                                                 }
704                                                 break;
705                                         case AST_CONTROL_BUSY:
706                                                 ast_verb(3, "%s is busy\n", winner->name);
707                                                 break;
708                                         case AST_CONTROL_CONGESTION:
709                                                 ast_verb(3, "%s is circuit-busy\n", winner->name);
710                                                 break;
711                                         case AST_CONTROL_RINGING:
712                                                 ast_verb(3, "%s is ringing\n", winner->name);
713                                                 break;
714                                         case AST_CONTROL_PROGRESS:
715                                                 ast_verb(3, "%s is making progress passing it to %s\n", winner->name, caller->name);
716                                                 break;
717                                         case AST_CONTROL_VIDUPDATE:
718                                                 ast_verb(3, "%s requested a video update, passing it to %s\n", winner->name, caller->name);
719                                                 break;
720                                         case AST_CONTROL_SRCUPDATE:
721                                                 ast_verb(3, "%s requested a source update, passing it to %s\n", winner->name, caller->name);
722                                                 break;
723                                         case AST_CONTROL_PROCEEDING:
724                                                 ast_verb(3, "%s is proceeding passing it to %s\n", winner->name,caller->name);
725                                                 break;
726                                         case AST_CONTROL_HOLD:
727                                                 ast_verb(3, "Call on %s placed on hold\n", winner->name);
728                                                 break;
729                                         case AST_CONTROL_UNHOLD:
730                                                 ast_verb(3, "Call on %s left from hold\n", winner->name);
731                                                 break;
732                                         case AST_CONTROL_OFFHOOK:
733                                         case AST_CONTROL_FLASH:
734                                                 /* Ignore going off hook and flash */
735                                                 break;
736                                         case -1:
737                                                 ast_verb(3, "%s stopped sounds\n", winner->name);
738                                                 break;
739                                         default:
740                                                 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
741                                                 break;
742                                         }
743                                 } 
744                                 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
745                                         if (winner->stream)
746                                                 ast_stopstream(winner);
747                                         tmpuser->digts = 0;
748                                         ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
749                                         tmpuser->yn[tmpuser->ynidx] = (char) f->subclass.integer;
750                                         tmpuser->ynidx++;
751                                         ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
752                                         if (tmpuser->ynidx >= ynlongest) {
753                                                 ast_debug(1, "reached longest possible match - doing evals\n");
754                                                 if (!strcmp(tmpuser->yn, tpargs->takecall)) {
755                                                         ast_debug(1, "Match to take the call!\n");
756                                                         ast_frfree(f);
757                                                         return tmpuser->ochan;
758                                                 }
759                                                 if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
760                                                         ast_debug(1, "Next in dial plan step requested.\n");
761                                                         *status = 1;
762                                                         ast_frfree(f);
763                                                         return NULL;
764                                                 }
765
766                                         }
767                                 }
768
769                                 ast_frfree(f);
770                         } else {
771                                 if (winner) {
772                                         ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg);                                             
773                                         if (!dg) {
774                                                 clear_calling_tree(findme_user_list);
775                                                 return NULL;
776                                         } else {
777                                                 tmpuser->state = -1;
778                                                 ast_hangup(winner);  
779                                                 livechannels--;
780                                                 ast_debug(1, "live channels left %d\n", livechannels);
781                                                 if (!livechannels) {
782                                                         ast_verb(3, "no live channels left. exiting.\n");
783                                                         return NULL;
784                                                 }
785                                         }
786                                 }
787                         }
788
789                 } else
790                         ast_debug(1, "timed out waiting for action\n");
791         }
792
793         /* --- WAIT FOR WINNER NUMBER END! -----------*/
794         return NULL;
795 }
796
797 static void findmeexec(struct fm_args *tpargs)
798 {
799         struct number *nm;
800         struct ast_channel *outbound;
801         struct ast_channel *caller;
802         struct ast_channel *winner = NULL;
803         char dialarg[512];
804         int dg, idx;
805         char *rest, *number;
806         struct findme_user *tmpuser;
807         struct findme_user *fmuser;
808         struct findme_user_listptr *findme_user_list;
809         int status;
810
811         findme_user_list = ast_calloc(1, sizeof(*findme_user_list));
812         AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
813
814         /* We're going to figure out what the longest possible string of digits to collect is */
815         ynlongest = 0;
816         if (strlen(tpargs->takecall) > ynlongest)
817                 ynlongest = strlen(tpargs->takecall);
818         if (strlen(tpargs->nextindp) > ynlongest)
819                 ynlongest = strlen(tpargs->nextindp);
820
821         idx = 1;
822         caller = tpargs->chan;
823         AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry)
824                 if (nm->order == idx)
825                         break;
826
827         while (nm) {
828                 ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout);
829
830                 number = ast_strdupa(nm->number);
831                 ast_debug(3, "examining %s\n", number);
832                 do {
833                         rest = strchr(number, '&');
834                         if (rest) {
835                                 *rest = 0;
836                                 rest++;
837                         }
838
839                         /* We check if that context exists, before creating the ast_channel struct needed */
840                         if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL))) {
841                                 /* XXX Should probably restructure to simply skip this item, instead of returning. XXX */
842                                 ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
843                                 free(findme_user_list);
844                                 return;
845                         }
846
847                         if (!strcmp(tpargs->context, ""))
848                                 snprintf(dialarg, sizeof(dialarg), "%s%s", number, ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION) ? "/n" : "");
849                         else
850                                 snprintf(dialarg, sizeof(dialarg), "%s@%s%s", number, tpargs->context, ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION) ? "/n" : "");
851
852                         tmpuser = ast_calloc(1, sizeof(*tmpuser));
853                         if (!tmpuser) {
854                                 ast_free(findme_user_list);
855                                 return;
856                         }
857
858                         outbound = ast_request("Local", caller->nativeformats, caller, dialarg, &dg);
859                         if (outbound) {
860                                 ast_set_callerid(outbound,
861                                         S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL),
862                                         S_COR(caller->caller.id.name.valid, caller->caller.id.name.str, NULL),
863                                         S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL));
864                                 ast_channel_inherit_variables(tpargs->chan, outbound);
865                                 ast_channel_datastore_inherit(tpargs->chan, outbound);
866                                 ast_string_field_set(outbound, language, tpargs->chan->language);
867                                 ast_string_field_set(outbound, accountcode, tpargs->chan->accountcode);
868                                 ast_string_field_set(outbound, musicclass, tpargs->chan->musicclass);
869                                 ast_verb(3, "calling %s\n", dialarg);
870                                 if (!ast_call(outbound,dialarg,0)) {
871                                         tmpuser->ochan = outbound;
872                                         tmpuser->state = 0;
873                                         tmpuser->cleared = 0;
874                                         ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
875                                         AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
876                                 } else {
877                                         ast_verb(3, "couldn't reach at this number.\n"); 
878                                         if (outbound) {
879                                                 if (!outbound->cdr) 
880                                                         outbound->cdr = ast_cdr_alloc();
881                                                 if (outbound->cdr) {
882                                                         char tmp[256];
883
884                                                         ast_cdr_init(outbound->cdr, outbound);
885                                                         snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
886                                                         ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
887                                                         ast_cdr_update(outbound);
888                                                         ast_cdr_start(outbound->cdr);
889                                                         ast_cdr_end(outbound->cdr);
890                                                         /* If the cause wasn't handled properly */
891                                                         if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
892                                                                 ast_cdr_failed(outbound->cdr);
893                                                 } else {
894                                                         ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
895                                                         ast_hangup(outbound);
896                                                         outbound = NULL;
897                                                 }
898                                         }
899                                 }
900                         } else 
901                                 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
902
903                         number = rest;
904                 } while (number);
905
906                 status = 0;
907                 if (!AST_LIST_EMPTY(findme_user_list))
908                         winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
909
910                 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
911                         if (!fmuser->cleared && fmuser->ochan != winner)
912                                 clear_caller(fmuser);
913                         ast_free(fmuser);
914                 }
915
916                 fmuser = NULL;
917                 tmpuser = NULL;
918                 if (winner)
919                         break;
920
921                 if (!caller || ast_check_hangup(caller)) {
922                         tpargs->status = 1;
923                         ast_free(findme_user_list);
924                         return;
925                 }
926
927                 idx++;
928                 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
929                         if (nm->order == idx)
930                                 break;
931                 }
932         }
933         ast_free(findme_user_list);
934         if (!winner) 
935                 tpargs->status = 1;
936         else {
937                 tpargs->status = 100;
938                 tpargs->outbound = winner;
939         }
940
941         return;
942 }
943
944 static struct call_followme *find_realtime(const char *name)
945 {
946         struct ast_variable *var = ast_load_realtime("followme", "name", name, SENTINEL), *v;
947         struct ast_config *cfg;
948         const char *catg;
949         struct call_followme *new;
950         struct ast_str *str = ast_str_create(16);
951
952         if (!var) {
953                 return NULL;
954         }
955
956         if (!(new = alloc_profile(name))) {
957                 return NULL;
958         }
959
960         for (v = var; v; v = v->next) {
961                 if (!strcasecmp(v->name, "active")) {
962                         if (ast_false(v->value)) {
963                                 ast_mutex_destroy(&new->lock);
964                                 ast_free(new);
965                                 return NULL;
966                         }
967                 } else {
968                         profile_set_param(new, v->name, v->value, 0, 0);
969                 }
970         }
971
972         ast_variables_destroy(var);
973         new->realtime = 1;
974
975         /* Load numbers */
976         if (!(cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name", name, SENTINEL))) {
977                 ast_mutex_destroy(&new->lock);
978                 ast_free(new);
979                 return NULL;
980         }
981
982         for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
983                 const char *numstr, *timeoutstr, *ordstr;
984                 int timeout;
985                 struct number *cur;
986                 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
987                         continue;
988                 }
989                 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout")) || sscanf(timeoutstr, "%30d", &timeout) != 1 || timeout < 1) {
990                         timeout = 25;
991                 }
992                 /* This one has to exist; it was part of the query */
993                 ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
994                 ast_str_set(&str, 0, "%s", numstr);
995                 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
996                         AST_LIST_INSERT_TAIL(&new->numbers, cur, entry);
997                 }
998         }
999         ast_config_destroy(cfg);
1000
1001         return new;
1002 }
1003
1004 static void end_bridge_callback(void *data)
1005 {
1006         char buf[80];
1007         time_t end;
1008         struct ast_channel *chan = data;
1009
1010         time(&end);
1011
1012         ast_channel_lock(chan);
1013         if (chan->cdr->answer.tv_sec) {
1014                 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec);
1015                 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
1016         }
1017
1018         if (chan->cdr->start.tv_sec) {
1019                 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec);
1020                 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
1021         }
1022         ast_channel_unlock(chan);
1023 }
1024
1025 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
1026 {
1027         bconfig->end_bridge_callback_data = originator;
1028 }
1029
1030 static int app_exec(struct ast_channel *chan, const char *data)
1031 {
1032         struct fm_args targs = { 0, };
1033         struct ast_bridge_config config;
1034         struct call_followme *f;
1035         struct number *nm, *newnm;
1036         int res = 0;
1037         char *argstr;
1038         char namerecloc[255];
1039         int duration = 0;
1040         struct ast_channel *caller;
1041         struct ast_channel *outbound;
1042         AST_DECLARE_APP_ARGS(args,
1043                 AST_APP_ARG(followmeid);
1044                 AST_APP_ARG(options);
1045         );
1046
1047         if (ast_strlen_zero(data)) {
1048                 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1049                 return -1;
1050         }
1051
1052         if (!(argstr = ast_strdupa((char *)data))) {
1053                 ast_log(LOG_ERROR, "Out of memory!\n");
1054                 return -1;
1055         }
1056
1057         AST_STANDARD_APP_ARGS(args, argstr);
1058
1059         if (ast_strlen_zero(args.followmeid)) {
1060                 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
1061                 return -1;
1062         }
1063
1064         AST_RWLIST_RDLOCK(&followmes);
1065         AST_RWLIST_TRAVERSE(&followmes, f, entry) {
1066                 if (!strcasecmp(f->name, args.followmeid) && (f->active))
1067                         break;
1068         }
1069         AST_RWLIST_UNLOCK(&followmes);
1070
1071         ast_debug(1, "New profile %s.\n", args.followmeid);
1072
1073         if (!f) {
1074                 f = find_realtime(args.followmeid);
1075         }
1076
1077         if (!f) {
1078                 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
1079                 return 0;
1080         }
1081
1082         /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
1083         if (args.options) 
1084                 ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
1085
1086         /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
1087         ast_mutex_lock(&f->lock);
1088         targs.mohclass = ast_strdupa(f->moh);
1089         ast_copy_string(targs.context, f->context, sizeof(targs.context));
1090         ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
1091         ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
1092         ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
1093         ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt));
1094         ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
1095         ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
1096         ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
1097         ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
1098         /* Copy the numbers we're going to use into another list in case the master list should get modified 
1099            (and locked) while we're trying to do a follow-me */
1100         AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers);
1101         AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
1102                 newnm = create_followme_number(nm->number, nm->timeout, nm->order);
1103                 AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
1104         }
1105         ast_mutex_unlock(&f->lock);
1106
1107         snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
1108         duration = 5;
1109
1110         if (!ast_fileexists(namerecloc, NULL, chan->language))
1111                 ast_copy_string(namerecloc, "", sizeof(namerecloc));
1112
1113         if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1114                 if (chan->_state != AST_STATE_UP) {
1115                         ast_indicate(chan, AST_CONTROL_RINGING);
1116                 }
1117         } else {
1118                 /* Answer the call */
1119                 if (chan->_state != AST_STATE_UP)
1120                         ast_answer(chan);
1121
1122                 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 
1123                         ast_stream_and_wait(chan, targs.statusprompt, "");
1124
1125                 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 
1126                         if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0)
1127                                 goto outrun;
1128
1129                 if (!ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
1130                         if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
1131                                 goto outrun;
1132                         if (ast_waitstream(chan, "") < 0)
1133                                 goto outrun;
1134                 }
1135                 ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
1136         }
1137
1138         targs.status = 0;
1139         targs.chan = chan;
1140         ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
1141
1142         findmeexec(&targs);
1143
1144         while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry)))
1145                 ast_free(nm);
1146
1147         if (!ast_strlen_zero(namerecloc))
1148                 unlink(namerecloc);
1149
1150         if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
1151                 if (chan->_state != AST_STATE_UP) {
1152                         ast_answer(chan);
1153                 }
1154         } else {
1155                 ast_moh_stop(chan);
1156         }
1157
1158         if (targs.status != 100) {
1159                 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 
1160                         ast_stream_and_wait(chan, targs.sorryprompt, "");
1161                 res = 0;
1162         } else {
1163                 caller = chan;
1164                 outbound = targs.outbound;
1165                 /* Bridge the two channels. */
1166
1167                 memset(&config, 0, sizeof(config));
1168                 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1169                 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1170                 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1171                 config.end_bridge_callback = end_bridge_callback;
1172                 config.end_bridge_callback_data = chan;
1173                 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
1174
1175                 /* Be sure no generators are left on it */
1176                 ast_deactivate_generator(caller);
1177                 /* Make sure channels are compatible */
1178                 res = ast_channel_make_compatible(caller, outbound);
1179                 if (res < 0) {
1180                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
1181                         ast_hangup(outbound);
1182                         goto outrun;
1183                 }
1184                 res = ast_bridge_call(caller, outbound, &config);
1185                 if (outbound)
1186                         ast_hangup(outbound);
1187         }
1188
1189         outrun:
1190
1191         if (f->realtime) {
1192                 /* Not in list */
1193                 free_numbers(f);
1194                 ast_free(f);
1195         }
1196
1197         return res;
1198 }
1199
1200 static int unload_module(void)
1201 {
1202         struct call_followme *f;
1203
1204         ast_unregister_application(app);
1205
1206         /* Free Memory. Yeah! I'm free! */
1207         AST_RWLIST_WRLOCK(&followmes);
1208         while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
1209                 free_numbers(f);
1210                 ast_free(f);
1211         }
1212
1213         AST_RWLIST_UNLOCK(&followmes);
1214
1215         return 0;
1216 }
1217
1218 static int load_module(void)
1219 {
1220         if(!reload_followme(0))
1221                 return AST_MODULE_LOAD_DECLINE;
1222
1223         return ast_register_application_xml(app, app_exec);
1224 }
1225
1226 static int reload(void)
1227 {
1228         reload_followme(1);
1229
1230         return 0;
1231 }
1232
1233 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
1234                 .load = load_module,
1235                 .unload = unload_module,
1236                 .reload = reload,
1237                );