include "logger.h" and errno.h from asterisk.h - usage shows that they
[asterisk/asterisk.git] / apps / app_followme.c
index bd14b2c..57f440b 100644 (file)
  *
  * \author BJ Weschke <bweschke@btwtech.com>
  *
+ * \arg See \ref Config_followme
+ *
  * \ingroup applications
  */
 
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$revision$")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <signal.h>
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
-#include "asterisk/logger.h"
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/options.h"
@@ -58,10 +54,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$revision$")
 #include "asterisk/app.h"
 
 static char *app = "FollowMe";
-static char *synopsis = 
-"Find-Me/Follow-Me.";
+static char *synopsis = "Find-Me/Follow-Me application";
 static char *descrip = 
-"  FollowMe(followmeid|options):\n"
+"  FollowMe(followmeid[,options]):\n"
 "This application performs Find-Me/Follow-Me functionality for the caller\n"
 "as defined in the profile matching the <followmeid> parameter in\n"
 "followme.conf. If the specified <followmeid> profile doesn't exist in\n"
@@ -71,11 +66,10 @@ static char *descrip =
 "    s    - Playback the incoming status message prior to starting the follow-me step(s)\n"
 "    a    - Record the caller's name so it can be announced to the callee on each step\n" 
 "    n    - Playback the unreachable status message if we've run out of steps to reach the\n"
-"           or the callee has elected not to be reachable.\n" 
-
-
-LOCAL_USER_DECL;
+"           or the callee has elected not to be reachable.\n"
+"Returns -1 on hangup\n";
 
+/*! \brief Number structure */
 struct number {
        char number[512];       /*!< Phone Number(s) and/or Extension(s) */
        long timeout;           /*!< Dial Timeout, if used. */
@@ -83,7 +77,8 @@ struct number {
        AST_LIST_ENTRY(number) entry; /*!< Next Number record */
 };
 
-struct ast_call_followme {
+/*! \brief Data structure for followme scripts */
+struct call_followme {
        ast_mutex_t lock;
        char name[AST_MAX_EXTENSION];   /*!< Name - FollowMeID */
        char moh[AST_MAX_CONTEXT];      /*!< Music On Hold Class to be used */
@@ -91,17 +86,17 @@ struct ast_call_followme {
        unsigned int active;            /*!< Profile is active (1), or disabled (0). */
        char takecall[20];              /*!< Digit mapping to take a call */
        char nextindp[20];              /*!< Digit mapping to decline a call */
-       char callfromprompt[AST_CONFIG_MAX_PATH];
-       char norecordingprompt[AST_CONFIG_MAX_PATH];
-       char optionsprompt[AST_CONFIG_MAX_PATH];
-       char plsholdprompt[AST_CONFIG_MAX_PATH];
-       char statusprompt[AST_CONFIG_MAX_PATH];
-       char sorryprompt[AST_CONFIG_MAX_PATH];
+       char callfromprompt[PATH_MAX];  /*!< Sound prompt name and path */
+       char norecordingprompt[PATH_MAX];       /*!< Sound prompt name and path */
+       char optionsprompt[PATH_MAX];   /*!< Sound prompt name and path */
+       char plsholdprompt[PATH_MAX];   /*!< Sound prompt name and path */
+       char statusprompt[PATH_MAX];    /*!< Sound prompt name and path */
+       char sorryprompt[PATH_MAX];     /*!< Sound prompt name and path */
 
        AST_LIST_HEAD_NOLOCK(numbers, number) numbers;     /*!< Head of the list of follow-me numbers */
        AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers; /*!< Head of the list of black-listed numbers */
        AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers; /*!< Head of the list of white-listed numbers */
-       AST_LIST_ENTRY(ast_call_followme) entry;           /*!< Next Follow-Me record */
+       AST_LIST_ENTRY(call_followme) entry;           /*!< Next Follow-Me record */
 };
 
 struct fm_args {
@@ -114,12 +109,12 @@ struct fm_args {
        struct ast_channel *outbound;
        char takecall[20];              /*!< Digit mapping to take a call */
        char nextindp[20];              /*!< Digit mapping to decline a call */
-       char callfromprompt[AST_CONFIG_MAX_PATH];
-       char norecordingprompt[AST_CONFIG_MAX_PATH];
-       char optionsprompt[AST_CONFIG_MAX_PATH];
-       char plsholdprompt[AST_CONFIG_MAX_PATH];
-       char statusprompt[AST_CONFIG_MAX_PATH];
-       char sorryprompt[AST_CONFIG_MAX_PATH];
+       char callfromprompt[PATH_MAX];  /*!< Sound prompt name and path */
+       char norecordingprompt[PATH_MAX];       /*!< Sound prompt name and path */
+       char optionsprompt[PATH_MAX];   /*!< Sound prompt name and path */
+       char plsholdprompt[PATH_MAX];   /*!< Sound prompt name and path */
+       char statusprompt[PATH_MAX];    /*!< Sound prompt name and path */
+       char sorryprompt[PATH_MAX];     /*!< Sound prompt name and path */
        struct ast_flags followmeflags;
 };
 
@@ -147,74 +142,74 @@ AST_APP_OPTIONS(followme_opts, {
 });
 
 static int ynlongest = 0;
-static char toast[80];
 static time_t start_time, answer_time, end_time;
 
-static char *featuredigittostr;
+static const char *featuredigittostr;
 static int featuredigittimeout = 5000;         /*!< Feature Digit Timeout */
 static const char *defaultmoh = "default";     /*!< Default Music-On-Hold Class */
 
 static char takecall[20] = "1", nextindp[20] = "2";
-static char callfromprompt[AST_CONFIG_MAX_PATH] = "followme/call-from";
-static char norecordingprompt[AST_CONFIG_MAX_PATH] = "followme/no-recording";
-static char optionsprompt[AST_CONFIG_MAX_PATH] = "followme/followme-options";
-static char plsholdprompt[AST_CONFIG_MAX_PATH] = "followme/pls-hold-while-try";
-static char statusprompt[AST_CONFIG_MAX_PATH] = "followme/followme-status";
-static char sorryprompt[AST_CONFIG_MAX_PATH] = "followme/followme-sorry";
+static char callfromprompt[PATH_MAX] = "followme/call-from";
+static char norecordingprompt[PATH_MAX] = "followme/no-recording";
+static char optionsprompt[PATH_MAX] = "followme/options";
+static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try";
+static char statusprompt[PATH_MAX] = "followme/status";
+static char sorryprompt[PATH_MAX] = "followme/sorry";
 
 
-static AST_LIST_HEAD_STATIC(followmes, ast_call_followme);
-static AST_LIST_HEAD_NOLOCK(findme_user_listptr, findme_user);
+static AST_RWLIST_HEAD_STATIC(followmes, call_followme);
+AST_LIST_HEAD_NOLOCK(findme_user_listptr, findme_user);
 
-static void free_numbers(struct ast_call_followme *f)
+static void free_numbers(struct call_followme *f)
 {
        /* Free numbers attached to the profile */
        struct number *prev;
 
        while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
                /* Free the number */
-               free(prev);
+               ast_free(prev);
        AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
 
        while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
                /* Free the blacklisted number */
-               free(prev);
+               ast_free(prev);
        AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
 
        while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
                /* Free the whitelisted number */
-               free(prev);
+               ast_free(prev);
        AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
        
 }
 
 
-static struct ast_call_followme *alloc_profile(const char *fmname)
+/*! \brief Allocate and initialize followme profile */
+static struct call_followme *alloc_profile(const char *fmname)
 {
-       struct ast_call_followme *f;
-
-       f = ast_calloc(1, sizeof(*f));
-       if (f) {
-               ast_mutex_init(&f->lock);
-               ast_copy_string(f->name, fmname, sizeof(f->name));
-               ast_copy_string(f->moh, "", sizeof(f->moh));
-               ast_copy_string(f->context, "", sizeof(f->context));
-               ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
-               ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
-               ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
-               ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt));
-               ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt));
-               ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
-               ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
-               ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
-               AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
-               AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
-               AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
-       }
+       struct call_followme *f;
+
+       if (!(f = ast_calloc(1, sizeof(*f))))
+               return NULL;
+
+       ast_mutex_init(&f->lock);
+       ast_copy_string(f->name, fmname, sizeof(f->name));
+       f->moh[0] = '\0';
+       f->context[0] = '\0';
+       ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
+       ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
+       ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
+       ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt));
+       ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt));
+       ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
+       ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
+       ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
+       AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
+       AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
+       AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
        return f;
 }
 
-static void init_profile(struct ast_call_followme *f)
+static void init_profile(struct call_followme *f)
 {
        f->active = 1;
        ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
@@ -222,30 +217,31 @@ static void init_profile(struct ast_call_followme *f)
 
    
    
-static void profile_set_param(struct ast_call_followme *f, const char *param, const char *val, int linenum, int failunknown)
+/*! \brief Set parameter in profile from configuration file */
+static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
 {
 
        if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music")) 
                ast_copy_string(f->moh, val, sizeof(f->moh));
-       else if (!strcasecmp(param, "context")) {
+       else if (!strcasecmp(param, "context")) 
                ast_copy_string(f->context, val, sizeof(f->context));
-       } else if (!strcasecmp(param, "takecall")) {
+       else if (!strcasecmp(param, "takecall"))
                ast_copy_string(f->takecall, val, sizeof(f->takecall));
-       } else if (!strcasecmp(param, "declinecall")) {
+       else if (!strcasecmp(param, "declinecall"))
                ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
-       } else if (!strcasecmp(param, "call-from-prompt")) {
+       else if (!strcasecmp(param, "call-from-prompt"))
                ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt));
-       } else if (!strcasecmp(param, "followme-recording-prompt")) {
+       else if (!strcasecmp(param, "followme-norecording-prompt")) 
                ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt));
-       } else if (!strcasecmp(param, "followme-options-prompt")) {
+       else if (!strcasecmp(param, "followme-options-prompt")) 
                ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt));
-       } else if (!strcasecmp(param, "followme-pls-hold-prompt")) {
+       else if (!strcasecmp(param, "followme-pls-hold-prompt"))
                ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt));
-       } else if (!strcasecmp(param, "followme-status-prompt")) {
+       else if (!strcasecmp(param, "followme-status-prompt")) 
                ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
-       } else if (!strcasecmp(param, "followme-sorry-prompt")) {
+       else if (!strcasecmp(param, "followme-sorry-prompt")) 
                ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
-       } else if (failunknown) {
+       else if (failunknown) {
                if (linenum >= 0)
                        ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
                else
@@ -253,65 +249,65 @@ static void profile_set_param(struct ast_call_followme *f, const char *param, co
        }
 }
 
+/*! \brief Add a new number */
 static struct number *create_followme_number(char *number, int timeout, int numorder)
 {
        struct number *cur;
        char *tmp;
        
-       /* Add a new number */
 
-       cur = ast_calloc(1, sizeof(*cur));
+       if (!(cur = ast_calloc(1, sizeof(*cur))))
+               return NULL;
 
-       if (cur) {
-               cur->timeout = timeout;
-               if ((tmp = strchr(number, ','))) { 
-                       *tmp = '\0';
-               }
-               ast_copy_string(cur->number, number, sizeof(cur->number));
-               cur->order = numorder;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
-       }
+       cur->timeout = timeout;
+       if ((tmp = strchr(number, ','))) 
+               *tmp = '\0';
+       ast_copy_string(cur->number, number, sizeof(cur->number));
+       cur->order = numorder;
+       ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
 
        return cur;
 }
 
-static int reload_followme(void)
+/*! \brief Reload followme application module */
+static int reload_followme(int reload)
 {
-       struct ast_call_followme *f;
+       struct call_followme *f;
        struct ast_config *cfg;
-       char *cat, *tmp;
+       char *cat = NULL, *tmp;
        struct ast_variable *var;
        struct number *cur, *nm;
-       int new, idx;
        char numberstr[90];
        int timeout;
        char *timeoutstr;
        int numorder;   
-       char *takecallstr;
-       char *declinecallstr;
-       char *tmpstr;
+       const char *takecallstr;
+       const char *declinecallstr;
+       const char *tmpstr;
+       struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 
-       cfg = ast_config_load("followme.conf");
-       if (!cfg) {
+       if (!(cfg = ast_config_load("followme.conf", config_flags))) {
                ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
                return 0;
-       }
+       } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
+               return 0;
 
-       AST_LIST_LOCK(&followmes);
+       AST_RWLIST_WRLOCK(&followmes);
 
        /* Reset Global Var Values */
        featuredigittimeout = 5000;
 
        /* Mark all profiles as inactive for the moment */
-       AST_LIST_TRAVERSE(&followmes, f, entry) {
+       AST_RWLIST_TRAVERSE(&followmes, f, entry) {
                f->active = 0;
        }
+
        featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
        
-       if (!ast_strlen_zero(featuredigittostr)) 
-               if (!scanf("%d", &featuredigittimeout))
+       if (!ast_strlen_zero(featuredigittostr)) {
+               if (!sscanf(featuredigittostr, "%d", &featuredigittimeout))
                        featuredigittimeout = 5000;
+       }
 
        takecallstr = ast_variable_retrieve(cfg, "general", "takecall");
        if (!ast_strlen_zero(takecallstr))
@@ -325,102 +321,105 @@ static int reload_followme(void)
        if (!ast_strlen_zero(tmpstr))
                ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
 
-       tmpstr = ast_variable_retrieve(cfg, "general", "followme-norecording-prompt");
+       tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt");
        if (!ast_strlen_zero(tmpstr))
                ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
 
-       tmpstr = ast_variable_retrieve(cfg, "general", "followme-options-prompt");
+       tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt");
        if (!ast_strlen_zero(tmpstr))
                ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
 
-       tmpstr = ast_variable_retrieve(cfg, "general", "followme-pls-hold-prompt");
+       tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt");
        if (!ast_strlen_zero(tmpstr))
                ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
 
-       tmpstr = ast_variable_retrieve(cfg, "general", "followme-status-prompt");
+       tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt");
        if (!ast_strlen_zero(tmpstr))
                ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
 
-       tmpstr = ast_variable_retrieve(cfg, "general", "followme-sorry-prompt");
+       tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt");
        if (!ast_strlen_zero(tmpstr))
                ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
 
        /* Chug through config file */
-       cat = ast_category_browse(cfg, NULL);
-       while(cat) {
-               /* Define a new profile */
+       while ((cat = ast_category_browse(cfg, cat))) {
+               int new = 0;
+
+               if (!strcasecmp(cat, "general"))
+                       continue;
+
                /* Look for an existing one */
                AST_LIST_TRAVERSE(&followmes, f, entry) {
                        if (!strcasecmp(f->name, cat))
                                break;
                }
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "New profile %s.\n", cat);
+
+               ast_debug(1, "New profile %s.\n", cat);
+
                if (!f) {
                        /* Make one then */
                        f = alloc_profile(cat);
                        new = 1;
-               } else
-                       new = 0;
-       
-               if (f) {
-                       if (!new)
-                               ast_mutex_lock(&f->lock);
-                       /* Re-initialize the profile */
-                       init_profile(f);
-                       free_numbers(f);
-                       var = ast_variable_browse(cfg, cat);
-                       while(var) {
-                               if (!strcasecmp(var->name, "number")) {
-                                       /* Add a new number */
-                                       ast_copy_string(numberstr, var->value, sizeof(numberstr));
-                                       if ((tmp = strchr(numberstr, ','))) {
-                                               *tmp = '\0';
-                                               tmp++;
-                                               timeoutstr = ast_strdupa(tmp);
-                                               if ((tmp = strchr(timeoutstr, ','))) {
-                                                       *tmp = '\0';
-                                                       tmp++;
-                                                       numorder = atoi(tmp);
-                                                       if (numorder < 0)
-                                                               numorder = 0;
-                                               } else 
+               }
+
+               /* Totally fail if we fail to find/create an entry */
+               if (!f)
+                       continue;
+               
+               if (!new)
+                       ast_mutex_lock(&f->lock);
+               /* Re-initialize the profile */
+               init_profile(f);
+               free_numbers(f);
+               var = ast_variable_browse(cfg, cat);
+               while(var) {
+                       if (!strcasecmp(var->name, "number")) {
+                               int idx = 0;
+
+                               /* Add a new number */
+                               ast_copy_string(numberstr, var->value, sizeof(numberstr));
+                               if ((tmp = strchr(numberstr, ','))) {
+                                       *tmp++ = '\0';
+                                       timeoutstr = ast_strdupa(tmp);
+                                       if ((tmp = strchr(timeoutstr, ','))) {
+                                               *tmp++ = '\0';
+                                               numorder = atoi(tmp);
+                                               if (numorder < 0)
                                                        numorder = 0;
-                                               timeout = atoi(timeoutstr);
-                                               if (timeout < 0) 
-                                                       timeout = 25;
-                                       } else {
-                                               timeout = 25;
+                                       } else 
                                                numorder = 0;
-                                       }
-
-                                       if (!numorder) {        
-                                               idx = 1;
-                                               AST_LIST_TRAVERSE(&f->numbers, nm, entry) 
-                                                       idx++;
-                                               numorder = idx;
-                                       }
-                                       cur = create_followme_number(numberstr, timeout, numorder);
-                                       AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
+                                       timeout = atoi(timeoutstr);
+                                       if (timeout < 0) 
+                                               timeout = 25;
                                } else {
-                                       profile_set_param(f, var->name, var->value, var->lineno, 1);
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
+                                       timeout = 25;
+                                       numorder = 0;
                                }
-                               var = var->next;
-                       } /* End while(var) loop */
-
-                       if (!new) 
-                               ast_mutex_unlock(&f->lock);
-                       if (new) {
-                               AST_LIST_INSERT_HEAD(&followmes, f, entry);
+                               
+                               if (!numorder) {        
+                                       idx = 1;
+                                       AST_LIST_TRAVERSE(&f->numbers, nm, entry) 
+                                               idx++;
+                                       numorder = idx;
+                               }
+                               cur = create_followme_number(numberstr, timeout, numorder);
+                               AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
+                       } else {
+                               profile_set_param(f, var->name, var->value, var->lineno, 1);
+                               ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
                        }
-               }
-               cat = ast_category_browse(cfg, cat);
+                       var = var->next;
+               } /* End while(var) loop */
+               
+               if (!new) 
+                       ast_mutex_unlock(&f->lock);
+               else
+                       AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
        }
+
        ast_config_destroy(cfg);
 
-       AST_LIST_UNLOCK(&followmes);
+       AST_RWLIST_UNLOCK(&followmes);
 
        return 1;
 }
@@ -438,13 +437,14 @@ static void clear_caller(struct findme_user *tmpuser)
                }
                if (outbound->cdr) {
                        char tmp[256];
+
                        snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg);
-                       ast_cdr_setapp(outbound->cdr,"FollowMe",tmp);
+                       ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
                        ast_cdr_update(outbound);
                        ast_cdr_start(outbound->cdr);
                        ast_cdr_end(outbound->cdr);
                        /* If the cause wasn't handled properly */
-                       if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
+                       if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause))
                                ast_cdr_failed(outbound->cdr);
                } else
                        ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
@@ -472,13 +472,13 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
        int pos;
        struct ast_channel *winner;
        struct ast_frame *f;
-       int ctstatus;
+       int ctstatus = 0;
        int dg;
        struct findme_user *tmpuser;
        int to = 0;
        int livechannels = 0;
        int tmpto;
-       long totalwait = 0, wtd, towas = 0;
+       long totalwait = 0, wtd = 0, towas = 0;
        char *callfromname;
        char *pressbuttonname;
 
@@ -487,276 +487,244 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
        callfromname = ast_strdupa(tpargs->callfromprompt);
        pressbuttonname = ast_strdupa(tpargs->optionsprompt);   
 
-       if (!AST_LIST_EMPTY(findme_user_list))
-       {
-               if (!caller) {
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "Original caller hungup. Cleanup.\n");
-                       clear_calling_tree(findme_user_list);
-                       return NULL;
-               }
-               ctstatus = 0;
-               totalwait = nm->timeout * 1000;
-               wtd = 0;
-               while (!ctstatus) {
-                       to = 1000;
-                       pos = 1; 
-                       livechannels = 0;
-                       watchers[0] = caller;
+       if (AST_LIST_EMPTY(findme_user_list)) {
+               ast_verb(3, "couldn't reach at this number.\n");
+               return NULL;
+       }
+       
+       if (!caller) {
+               ast_verb(3, "Original caller hungup. Cleanup.\n");
+               clear_calling_tree(findme_user_list);
+               return NULL;
+       }
+       
+       totalwait = nm->timeout * 1000;
+       
+       while (!ctstatus) {
+               to = 1000;
+               pos = 1; 
+               livechannels = 0;
+               watchers[0] = caller;
                
-                       dg = 0; 
-                       winner = NULL;  
-                       AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
-                               if (tmpuser->state >= 0 && tmpuser->ochan) {
-                                       if (tmpuser->state == 3) {
-                                               tmpuser->digts += (towas - wtd);
-                                       }
-                                       if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "We've been waiting for digits longer than we should have.\n");
-                                               if (!ast_strlen_zero(namerecloc)) {
-                                                       tmpuser->state = 1;
-                                                       tmpuser->digts = 0;
-                                                       if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) {
-                                                               ast_sched_runq(tmpuser->ochan->sched);
-                                                       } else {
-                                                               ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
-                                                               return NULL;
-                                                       }                                                       
+               dg = 0; 
+               winner = NULL;  
+               AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
+                       if (tmpuser->state >= 0 && tmpuser->ochan) {
+                               if (tmpuser->state == 3) 
+                                       tmpuser->digts += (towas - wtd);
+                               if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
+                                       ast_verb(3, "We've been waiting for digits longer than we should have.\n");
+                                       if (!ast_strlen_zero(namerecloc)) {
+                                               tmpuser->state = 1;
+                                               tmpuser->digts = 0;
+                                               if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) {
+                                                       ast_sched_runq(tmpuser->ochan->sched);
                                                } else {
-                                                       tmpuser->state = 2;
-                                                       tmpuser->digts = 0;
-                                                       if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
-                                                               ast_sched_runq(tmpuser->ochan->sched);
-                                                       else {
-                                                               ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
-                                                               return NULL;
-                                                       }
+                                                       ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
+                                                       return NULL;
+                                               }                                                       
+                                       } else {
+                                               tmpuser->state = 2;
+                                               tmpuser->digts = 0;
+                                               if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
+                                                       ast_sched_runq(tmpuser->ochan->sched);
+                                               else {
+                                                       ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
+                                                       return NULL;
                                                }
                                        }
-                                       if (tmpuser->ochan->stream) {
-                                               ast_sched_runq(tmpuser->ochan->sched);
-                                               tmpto = ast_sched_wait(tmpuser->ochan->sched);
-                                               if (tmpto > 0 && tmpto < to)
-                                                       to = tmpto;
-                                               else if (tmpto < 0 && !tmpuser->ochan->timingfunc) {
-                                                       ast_stopstream(tmpuser->ochan);
-                                                       if (tmpuser->state == 1) {
-                                                               if (option_verbose > 2)
-                                                                       ast_verbose(VERBOSE_PREFIX_3 "Playback of the call-from file appears to be done.\n");
-                                                               if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) {
-                                                                       tmpuser->state = 2;
-                                                               } else {
-                                                                       ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc);
-                                                                       memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
-                                                                       tmpuser->ynidx = 0;
-                                                                       if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language))
-                                                                               tmpuser->state = 3;
-                                                                       else {
-                                                                               ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
-                                                                               return NULL;
-                                                                       } 
-                                                               }
-                                                       } else if (tmpuser->state == 2) {
-                                                               if (option_verbose > 2)
-                                                                       ast_verbose(VERBOSE_PREFIX_3 "Playback of name file appears to be done.\n");
+                               }
+                               if (tmpuser->ochan->stream) {
+                                       ast_sched_runq(tmpuser->ochan->sched);
+                                       tmpto = ast_sched_wait(tmpuser->ochan->sched);
+                                       if (tmpto > 0 && tmpto < to)
+                                               to = tmpto;
+                                       else if (tmpto < 0 && !tmpuser->ochan->timingfunc) {
+                                               ast_stopstream(tmpuser->ochan);
+                                               if (tmpuser->state == 1) {
+                                                       ast_verb(3, "Playback of the call-from file appears to be done.\n");
+                                                       if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) {
+                                                               tmpuser->state = 2;
+                                                       } else {
+                                                               ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc);
                                                                memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
                                                                tmpuser->ynidx = 0;
-                                                               if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) {
+                                                               if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language))
                                                                        tmpuser->state = 3;
-                                                                       
-                                                               } else {
+                                                               else {
+                                                                       ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
                                                                        return NULL;
                                                                } 
-                                                       } else if (tmpuser->state == 3) {
-                                                               if (option_verbose > 2)
-                                                                       ast_verbose(VERBOSE_PREFIX_3 "Playback of the next step file appears to be done.\n");
-                                                               tmpuser->digts = 0;
                                                        }
+                                               } else if (tmpuser->state == 2) {
+                                                       ast_verb(3, "Playback of name file appears to be done.\n");
+                                                       memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
+                                                       tmpuser->ynidx = 0;
+                                                       if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) {
+                                                               tmpuser->state = 3;
+                                                               
+                                                       } else {
+                                                               return NULL;
+                                                       } 
+                                               } else if (tmpuser->state == 3) {
+                                                       ast_verb(3, "Playback of the next step file appears to be done.\n");
+                                                       tmpuser->digts = 0;
                                                }
                                        }
+                               }
                                watchers[pos++] = tmpuser->ochan;
                                livechannels++;
-                               }
-                       }
-
-                       tmpto = to;
-                       if (to < 0) {
-                               to = 1000;
-                               tmpto = 1000;
                        }
-                       towas = to;
-                       winner = ast_waitfor_n(watchers, pos, &to);
-                       tmpto -= to;
-                       totalwait -= tmpto;
-                       wtd = to;       
-                       if (totalwait <= 0) {
-                               if (option_verbose > 2) 
-                                       ast_verbose(VERBOSE_PREFIX_3 "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
-                               clear_calling_tree(findme_user_list);
-                               return NULL;
-                       }
-                       if (winner) {
-                               /* Need to find out which channel this is */
-                               dg = 0;
-                               while ((winner != watchers[dg]) && (dg < 256))
-                                       dg++;
-                               AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry)
-                                       if (tmpuser->ochan == winner)
+               }
+               
+               tmpto = to;
+               if (to < 0) {
+                       to = 1000;
+                       tmpto = 1000;
+               }
+               towas = to;
+               winner = ast_waitfor_n(watchers, pos, &to);
+               tmpto -= to;
+               totalwait -= tmpto;
+               wtd = to;       
+               if (totalwait <= 0) {
+                       ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
+                       clear_calling_tree(findme_user_list);
+                       return NULL;
+               }
+               if (winner) {
+                       /* Need to find out which channel this is */
+                       dg = 0;
+                       while ((winner != watchers[dg]) && (dg < 256))
+                               dg++;
+                       AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry)
+                               if (tmpuser->ochan == winner)
+                                       break;
+                       f = ast_read(winner);
+                       if (f) {
+                               if (f->frametype == AST_FRAME_CONTROL) {
+                                       switch(f->subclass) {
+                                       case AST_CONTROL_HANGUP:
+                                               if (option_verbose > 2)
+                                                       ast_verb(3, "%s received a hangup frame.\n", winner->name);
+                                               if (dg == 0) {
+                                                       ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n");
+                                                       clear_calling_tree(findme_user_list);
+                                                       ctstatus = -1;
+                                               }
                                                break;
-                               f = ast_read(winner);
-                               if (f) {
-                                       if (f->frametype == AST_FRAME_CONTROL) {
-                                               switch(f->subclass) {
-                                               case AST_CONTROL_HANGUP:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "%s received a hangup frame.\n", winner->name);
-                                                       if (dg == 0) {
-                                                               if (option_verbose > 2)
-                                                                       ast_verbose( VERBOSE_PREFIX_3 "The calling channel hungup. Need to drop everyone else.\n");
-                                                               clear_calling_tree(findme_user_list);
-                                                               ctstatus = -1;
-                                                       }
-                                                       break;
-                                               case AST_CONTROL_ANSWER:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", winner->name, caller->name);
-                                                       /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 
-                                                       winner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
-                                                       caller->hangupcause = AST_CAUSE_NORMAL_CLEARING;
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "Starting playback of %s\n", callfromname);
-                                                       if (dg > 0) {
-                                                               if (!ast_strlen_zero(namerecloc)) {
-                                                                       if (!ast_streamfile(winner, callfromname, winner->language)) {
-                                                                               ast_sched_runq(winner->sched);
-                                                                               tmpuser->state = 1;
-                                                                       } else {
-                                                                               ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
-                                                                               ast_frfree(f);
-                                                                               return NULL;
-                                                                       }                               
-                                                               } else {                        
-                                                                       tmpuser->state = 2;
-                                                                       if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
-                                                                               ast_sched_runq(tmpuser->ochan->sched);
-                                                                       else {
-                                                                               ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
-                                                                               ast_frfree(f);
-                                                                               return NULL;
-                                                                       }
+                                       case AST_CONTROL_ANSWER:
+                                               if (option_verbose > 2)
+                                                       ast_verb(3, "%s answered %s\n", winner->name, caller->name);
+                                               /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 
+                                               winner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+                                               caller->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+                                               ast_verb(3, "Starting playback of %s\n", callfromname);
+                                               if (dg > 0) {
+                                                       if (!ast_strlen_zero(namerecloc)) {
+                                                               if (!ast_streamfile(winner, callfromname, winner->language)) {
+                                                                       ast_sched_runq(winner->sched);
+                                                                       tmpuser->state = 1;
+                                                               } else {
+                                                                       ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
+                                                                       ast_frfree(f);
+                                                                       return NULL;
+                                                               }                               
+                                                       } else {                        
+                                                               tmpuser->state = 2;
+                                                               if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
+                                                                       ast_sched_runq(tmpuser->ochan->sched);
+                                                               else {
+                                                                       ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
+                                                                       ast_frfree(f);
+                                                                       return NULL;
                                                                }
                                                        }
-                                                       break;
-                                               case AST_CONTROL_BUSY:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", winner->name);
-                                                       break;
-                                               case AST_CONTROL_CONGESTION:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", winner->name);
-                                                       break;
-                                               case AST_CONTROL_RINGING:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", winner->name);
-                                                       break;
-                                               case AST_CONTROL_PROGRESS:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", winner->name,caller->name);
-                                                       break;
-                                               case AST_CONTROL_VIDUPDATE:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", winner->name,caller->name);
-                                                       break;
-                                               case AST_CONTROL_PROCEEDING:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose ( VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", winner->name,caller->name);
-                                                       break;
-                                               case AST_CONTROL_HOLD:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", winner->name);
-                                                       break;
-                                               case AST_CONTROL_UNHOLD:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", winner->name);
-                                                       break;
-                                               case AST_CONTROL_OFFHOOK:
-                                               case AST_CONTROL_FLASH:
-                                                       /* Ignore going off hook and flash */
-                                                       break;
-                                               case -1:
-                                                       if (option_verbose > 2)
-                                                               ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", winner->name);
-                                                       break;
-                                               default:
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
-                                                       break;
                                                }
-                                       } 
-                                       if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
-                                               if (winner->stream)
-                                                       ast_stopstream(winner);
-                                                       tmpuser->digts = 0;
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "DTMF received: %c\n",(char) f->subclass);
-                                               tmpuser->yn[tmpuser->ynidx] = (char) f->subclass;
-                                               tmpuser->ynidx++;
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "DTMF string: %s\n", tmpuser->yn);
-                                               if (tmpuser->ynidx >= ynlongest) {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "reached longest possible match - doing evals\n");
-                                                       if (!strcmp(tmpuser->yn, tpargs->takecall)) {
-                                                               if (option_debug)
-                                                                       ast_log(LOG_DEBUG, "Match to take the call!\n");
-                                                               ast_frfree(f);
-                                                               return tmpuser->ochan;  
-                                                       }
-                                                       if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
-                                                               if (option_debug)
-                                                                       ast_log(LOG_DEBUG, "Next in dial plan step requested.\n");
-                                                               *status = 1;
-                                                               ast_frfree(f);
-                                                               return NULL;
-                                                       }       
-
+                                               break;
+                                       case AST_CONTROL_BUSY:
+                                               ast_verb(3, "%s is busy\n", winner->name);
+                                               break;
+                                       case AST_CONTROL_CONGESTION:
+                                               ast_verb(3, "%s is circuit-busy\n", winner->name);
+                                               break;
+                                       case AST_CONTROL_RINGING:
+                                               ast_verb(3, "%s is ringing\n", winner->name);
+                                               break;
+                                       case AST_CONTROL_PROGRESS:
+                                               ast_verb(3, "%s is making progress passing it to %s\n", winner->name, caller->name);
+                                               break;
+                                       case AST_CONTROL_VIDUPDATE:
+                                               ast_verb(3, "%s requested a video update, passing it to %s\n", winner->name, caller->name);
+                                               break;
+                                       case AST_CONTROL_PROCEEDING:
+                                               ast_verb(3, "%s is proceeding passing it to %s\n", winner->name,caller->name);
+                                               break;
+                                       case AST_CONTROL_HOLD:
+                                               ast_verb(3, "Call on %s placed on hold\n", winner->name);
+                                               break;
+                                       case AST_CONTROL_UNHOLD:
+                                               ast_verb(3, "Call on %s left from hold\n", winner->name);
+                                               break;
+                                       case AST_CONTROL_OFFHOOK:
+                                       case AST_CONTROL_FLASH:
+                                               /* Ignore going off hook and flash */
+                                               break;
+                                       case -1:
+                                               ast_verb(3, "%s stopped sounds\n", winner->name);
+                                               break;
+                                       default:
+                                               ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
+                                               break;
+                                       }
+                               } 
+                               if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
+                                       if (winner->stream)
+                                               ast_stopstream(winner);
+                                       tmpuser->digts = 0;
+                                       ast_debug(1, "DTMF received: %c\n",(char) f->subclass);
+                                       tmpuser->yn[tmpuser->ynidx] = (char) f->subclass;
+                                       tmpuser->ynidx++;
+                                       ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
+                                       if (tmpuser->ynidx >= ynlongest) {
+                                               ast_debug(1, "reached longest possible match - doing evals\n");
+                                               if (!strcmp(tmpuser->yn, tpargs->takecall)) {
+                                                       ast_debug(1, "Match to take the call!\n");
+                                                       ast_frfree(f);
+                                                       return tmpuser->ochan;  
                                                }
+                                               if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
+                                                       ast_debug(1, "Next in dial plan step requested.\n");
+                                                       *status = 1;
+                                                       ast_frfree(f);
+                                                       return NULL;
+                                               }       
+                                               
                                        }
-                                       
-                                       ast_frfree(f);
-                               } else {
-                                       if (winner) {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "we didn't get a frame. hanging up. dg is %d\n",dg);                                       
-                                               if (!dg) {
-                                                       clear_calling_tree(findme_user_list);
+                               }
+                               
+                               ast_frfree(f);
+                       } else {
+                               if (winner) {
+                                       ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg);                                             
+                                       if (!dg) {
+                                               clear_calling_tree(findme_user_list);
+                                               return NULL;
+                                       } else {
+                                               tmpuser->state = -1;
+                                               ast_hangup(winner);  
+                                               livechannels--;
+                                               ast_debug(1, "live channels left %d\n", livechannels);
+                                               if (!livechannels) {
+                                                       ast_verb(3, "no live channels left. exiting.\n");
                                                        return NULL;
-                                               } else {
-                                                       tmpuser->state = -1;
-                                                       ast_hangup(winner);  
-                                                       livechannels--;
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "live channels left %d\n", livechannels);
-                                                       if (!livechannels) {
-                                                               if (option_verbose > 2)
-                                                                       ast_verbose(VERBOSE_PREFIX_3 "no live channels left. exiting.\n");
-                                                               return NULL;
-                                                       }
                                                }
                                        }
-                               }                                       
-                               
-                       } else
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "timed out waiting for action\n");
-               }
-               
-       }
-       else
-       {
-               if (option_verbose > 2)
-                       ast_verbose(VERBOSE_PREFIX_3 "couldn't reach at this number.\n");
+                               }
+                       }                                       
+                       
+               } else
+                       ast_debug(1, "timed out waiting for action\n");
        }
        
        /* --- WAIT FOR WINNER NUMBER END! -----------*/
@@ -796,13 +764,11 @@ static void findmeexec(struct fm_args *tpargs)
 
        while (nm) {
 
-               if (option_debug)       
-                       ast_log(LOG_DEBUG, "Number %s timeout %ld\n",nm->number,nm->timeout);
+               ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout);
                time(&start_time);
 
                number = ast_strdupa(nm->number);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "examining %s\n", number);
+               ast_debug(3, "examining %s\n", number);
                do {
                        rest = strchr(number, '&');
                        if (rest) {
@@ -818,6 +784,7 @@ static void findmeexec(struct fm_args *tpargs)
                        tmpuser = ast_calloc(1, sizeof(*tmpuser));
                        if (!tmpuser) {
                                ast_log(LOG_WARNING, "Out of memory!\n");
+                               ast_free(findme_user_list);
                                return;
                        }
                                        
@@ -825,8 +792,7 @@ static void findmeexec(struct fm_args *tpargs)
                        if (outbound) {
                                ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num);
                                ast_channel_inherit_variables(tpargs->chan, outbound);
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "calling %s\n", dialarg);
+                               ast_verb(3, "calling %s\n", dialarg);
                                if (!ast_call(outbound,dialarg,0)) {
                                        tmpuser->ochan = outbound;
                                        tmpuser->state = 0;
@@ -834,17 +800,16 @@ static void findmeexec(struct fm_args *tpargs)
                                        ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
                                        AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
                                } else {
-                                       if (option_verbose > 2) 
-                                               ast_verbose(VERBOSE_PREFIX_3 "couldn't reach at this number.\n"); 
+                                       ast_verb(3, "couldn't reach at this number.\n"); 
                                        if (outbound) {
-                                               if (!outbound->cdr) {
+                                               if (!outbound->cdr) 
                                                        outbound->cdr = ast_cdr_alloc();
-                                               }
                                                if (outbound->cdr) {
                                                        char tmp[256];
+
                                                        ast_cdr_init(outbound->cdr, outbound);
-                                                       snprintf(tmp, 256, "%s/%s", "Local", dialarg);
-                                                       ast_cdr_setapp(outbound->cdr,"FollowMe",tmp);
+                                                       snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
+                                                       ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
                                                        ast_cdr_update(outbound);
                                                        ast_cdr_start(outbound->cdr);
                                                        ast_cdr_end(outbound->cdr);
@@ -852,7 +817,7 @@ static void findmeexec(struct fm_args *tpargs)
                                                        if (ast_cdr_disposition(outbound->cdr,outbound->hangupcause))
                                                                ast_cdr_failed(outbound->cdr);
                                                } else {
-                                                       ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
+                                                       ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
                                                        ast_hangup(outbound);
                                                        outbound = NULL;
                                                }
@@ -870,13 +835,12 @@ static void findmeexec(struct fm_args *tpargs)
                        winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
                
                                        
-               AST_LIST_TRAVERSE_SAFE_BEGIN(findme_user_list, fmuser, entry) {
+               while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
                        if (!fmuser->cleared && fmuser->ochan != winner)
                                clear_caller(fmuser);
-                       AST_LIST_REMOVE_CURRENT(findme_user_list, entry);
-                       free(fmuser);
+                       ast_free(fmuser);
                }
-               AST_LIST_TRAVERSE_SAFE_END
+
                fmuser = NULL;
                tmpuser = NULL;
                headuser = NULL;        
@@ -885,6 +849,7 @@ static void findmeexec(struct fm_args *tpargs)
 
                if (!caller) {
                        tpargs->status = 1;
+                       ast_free(findme_user_list);
                        return; 
                }
 
@@ -894,7 +859,7 @@ static void findmeexec(struct fm_args *tpargs)
                                break;
 
        }
-       free(findme_user_list);
+       ast_free(findme_user_list);
        if (!winner) 
                tpargs->status = 1;
        else {
@@ -911,211 +876,185 @@ static int app_exec(struct ast_channel *chan, void *data)
 {
        struct fm_args targs;
        struct ast_bridge_config config;
-       struct ast_call_followme *f;
+       struct call_followme *f;
        struct number *nm, *newnm;
        int res = 0;
-       struct localuser *u;
        char *argstr;
        char namerecloc[255];
        int duration = 0;
        struct ast_channel *caller;
        struct ast_channel *outbound;
+       static char toast[80];
        
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(followmeid);
                AST_APP_ARG(options);
        );
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
+               return -1;
+       }
        
        if (!(argstr = ast_strdupa((char *)data))) {
                ast_log(LOG_ERROR, "Out of memory!\n");
                return -1;
        }
 
-       if (!data) {
-               ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n",app);
+       AST_STANDARD_APP_ARGS(args, argstr);
+
+       if (ast_strlen_zero(args.followmeid)) {
+               ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
                return -1;
        }
 
-       LOCAL_USER_ADD(u);
+       AST_RWLIST_RDLOCK(&followmes);
+       AST_RWLIST_TRAVERSE(&followmes, f, entry) {
+               if (!strcasecmp(f->name, args.followmeid) && (f->active))
+                       break;
+       }
+       AST_RWLIST_UNLOCK(&followmes);
+       
+       ast_debug(1, "New profile %s.\n", args.followmeid);
 
-       AST_STANDARD_APP_ARGS(args, argstr);
+       if (!f) {
+               ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
+               return 0;
+       }
 
-       if (!ast_strlen_zero(args.followmeid)) 
+       /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
+       if (args.options) 
+               ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
        
-                       AST_LIST_LOCK(&followmes);
-                       AST_LIST_TRAVERSE(&followmes, f, entry) {
-                               if (!strcasecmp(f->name, args.followmeid) && (f->active))
-                                       break;
-                       }
-                       AST_LIST_UNLOCK(&followmes);
-
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "New profile %s.\n", args.followmeid);
-                       if (!f)
-                       { 
-                               ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.", args.followmeid);
-                               res = -1;
-                       }
-                       else
-                       {
+       /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
+       ast_mutex_lock(&f->lock);
+       targs.mohclass = ast_strdupa(f->moh);
+       ast_copy_string(targs.context, f->context, sizeof(targs.context));
+       ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
+       ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
+       ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
+       ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt));
+       ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
+       ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
+       ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
+       ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
+       /* Copy the numbers we're going to use into another list in case the master list should get modified 
+          (and locked) while we're trying to do a follow-me */
+       AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers);
+       AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
+               newnm = create_followme_number(nm->number, nm->timeout, nm->order);
+               AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
+       }
+       ast_mutex_unlock(&f->lock);
        
-                               /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
-
-
-                               if (args.options) {
-                                       ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
-                               }
-
-                               /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
-                               ast_mutex_lock(&f->lock);
-                               targs.mohclass = ast_strdupa(f->moh);
-                               ast_copy_string(targs.context, f->context, sizeof(targs.context));
-                               ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
-                               ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
-                               ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
-                               ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt));
-                               ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
-                               ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
-                               ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
-                               ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
-                               /* Copy the numbers we're going to use into another list in case the master list should get modified 
-                                  (and locked) while we're trying to do a follow-me */
-                               AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers);
-                               AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
-                                       newnm = create_followme_number(nm->number, nm->timeout, nm->order);
-                                       AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
-                               }
-                               ast_mutex_unlock(&f->lock);
-
-                               if (targs.followmeflags.flags & FOLLOWMEFLAG_STATUSMSG) 
-                                       ast_stream_and_wait(chan, targs.statusprompt, chan->language, "");
-
-                               snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
-                               duration = 5;
-
-                               if (targs.followmeflags.flags & FOLLOWMEFLAG_RECORDNAME) 
-                                       if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, 128, 0, NULL) < 0)
-                                               goto outrun;
-
-                               /* The following call looks like we're going to playback the file, but we're actually   */
-                               /* just checking to see if we *can* play it.                                            */
-                               if (ast_streamfile(chan, namerecloc, chan->language))
-                                       ast_copy_string(namerecloc, "", sizeof(namerecloc));                                    
-                               else
-                                       ast_stopstream(chan);
-
-                               if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
-                                       goto outrun;
-                               if (ast_waitstream(chan, "") < 0)
-                                       goto outrun;
-                               if (!strcmp(targs.mohclass, ""))
-                                       ast_moh_start(chan, NULL);
-                               else
-                                       ast_moh_start(chan, targs.mohclass);
-
-
-                               targs.status = 0;
-                               targs.chan = chan;
-
-                               ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
-
-                               findmeexec(&targs);             
-                               
-                               AST_LIST_TRAVERSE_SAFE_BEGIN(&targs.cnumbers, nm, entry)        {
-                                       AST_LIST_REMOVE_CURRENT(&targs.cnumbers, entry);
-                                       free(nm);
-                               }
-                               AST_LIST_TRAVERSE_SAFE_END
+       if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 
+               ast_stream_and_wait(chan, targs.statusprompt, "");
        
-                               if (!ast_strlen_zero(namerecloc))
-                                       unlink(namerecloc);     
-
-                               if (targs.status != 100)
-                               {
-                                       ast_moh_stop(chan);
-                                       if (targs.followmeflags.flags & FOLLOWMEFLAG_UNREACHABLEMSG) 
-                                               ast_stream_and_wait(chan, targs.sorryprompt, chan->language, "");
-                                       res = 0;
-                               }
-                               else
-                               {
-                                                       
-                                       caller = chan;
-                                       outbound = targs.outbound;
-                                       /* Bridge the two channels. */
-
-                                       memset(&config,0,sizeof(struct ast_bridge_config));
-                                       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
-                                       ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
-                                       ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
-                               
-                                       ast_moh_stop(caller);
-                                       /* Be sure no generators are left on it */
-                                       ast_deactivate_generator(caller);
-                                       /* Make sure channels are compatible */
-                                       res = ast_channel_make_compatible(caller, outbound);
-                                       if (res < 0) {
-                                               ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
-                                               ast_hangup(outbound);
-                                               goto outrun;
-                                       }
-                                       time(&answer_time);
-                                       res = ast_bridge_call(caller,outbound,&config);
-                                       time(&end_time);
-                                       snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
-                                       pbx_builtin_setvar_helper(caller, "DIALEDTIME", toast);
-                                       snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
-                                       pbx_builtin_setvar_helper(caller, "ANSWEREDTIME", toast);
-                                       if (outbound)
-                                               ast_hangup(outbound);
-                                       res = 1;
-                                       
-                               }
-                               
-                       }
+       snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
+       duration = 5;
+       
+       if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 
+               if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, 128, 0, NULL) < 0)
+                       goto outrun;
+       
+       if (!ast_fileexists(namerecloc, NULL, chan->language))
+               ast_copy_string(namerecloc, "", sizeof(namerecloc));                                    
+       
+       if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
+               goto outrun;
+       if (ast_waitstream(chan, "") < 0)
+               goto outrun;
+       ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
+       
+       targs.status = 0;
+       targs.chan = chan;
+       ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
+       
+       findmeexec(&targs);             
+       
+       while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry)))
+               ast_free(nm);
+               
+       if (!ast_strlen_zero(namerecloc))
+               unlink(namerecloc);     
+       
+       if (targs.status != 100) {
+               ast_moh_stop(chan);
+               if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 
+                       ast_stream_and_wait(chan, targs.sorryprompt, "");
+               res = 0;
+       } else {
+               caller = chan;
+               outbound = targs.outbound;
+               /* Bridge the two channels. */
+               
+               memset(&config,0,sizeof(struct ast_bridge_config));
+               ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
+               ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
+               ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
+               
+               ast_moh_stop(caller);
+               /* Be sure no generators are left on it */
+               ast_deactivate_generator(caller);
+               /* Make sure channels are compatible */
+               res = ast_channel_make_compatible(caller, outbound);
+               if (res < 0) {
+                       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
+                       ast_hangup(outbound);
+                       goto outrun;
+               }
+               time(&answer_time);
+               res = ast_bridge_call(caller,outbound,&config);
+               time(&end_time);
+               snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
+               pbx_builtin_setvar_helper(caller, "DIALEDTIME", toast);
+               snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
+               pbx_builtin_setvar_helper(caller, "ANSWEREDTIME", toast);
+               if (outbound)
+                       ast_hangup(outbound);
+               res = 1;
+       }
+
        outrun:
        
-       LOCAL_USER_REMOVE(u);
        return res;
 }
 
-static int unload_module(void *mod)
+static int unload_module(void)
 {
-       STANDARD_HANGUP_LOCALUSERS;
+       struct call_followme *f;
+
        ast_unregister_application(app);
-       struct ast_call_followme *f;
+
        /* Free Memory. Yeah! I'm free! */
-       AST_LIST_LOCK(&followmes);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&followmes, f, entry) {
+       AST_RWLIST_WRLOCK(&followmes);
+       while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
                free_numbers(f);
-               AST_LIST_REMOVE_CURRENT(&followmes, entry);
-               free(f);
+               ast_free(f);
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&followmes);
+
+       AST_RWLIST_UNLOCK(&followmes);
+
        return 0;
 }
 
-static int load_module(void *mod)
+static int load_module(void)
 {
-       reload_followme();
+       if(!reload_followme(0))
+               return AST_MODULE_LOAD_DECLINE;
+
        return ast_register_application(app, app_exec, synopsis, descrip);
 }
 
-static const char *description(void)
+static int reload(void)
 {
-       return "Find-Me/Follow-Me Application";
-}
+       reload_followme(1);
 
-static int reload(void *mod)
-{
-       reload_followme();
        return 0;       
 }
 
-static const char *key(void)
-{
-       return ASTERISK_GPL_KEY;
-}
-
-STD_MOD(MOD_1, reload, NULL, NULL);
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
+               .load = load_module,
+               .unload = unload_module,
+               .reload = reload,
+              );