merge markster's usersconf branch with some slight changes
authorKevin P. Fleming <kpfleming@digium.com>
Sat, 16 Sep 2006 23:53:58 +0000 (23:53 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Sat, 16 Sep 2006 23:53:58 +0000 (23:53 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43052 65c4cc65-6c06-0410-ace0-fbb531ad65f3

15 files changed:
apps/app_directory.c
apps/app_voicemail.c
channels/chan_iax2.c
channels/chan_sip.c
channels/chan_zap.c
configs/extensions.conf.sample
configs/users.conf.sample [new file with mode: 0644]
configs/voicemail.conf.sample
include/asterisk/config.h
include/asterisk/pbx.h
main/asterisk.c
main/config.c
main/manager.c
main/pbx.c
pbx/pbx_config.c

index 6f660e3..ff64456 100644 (file)
@@ -393,10 +393,10 @@ static struct ast_config *realtime_directory(char *context)
        return cfg;
 }
 
-static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm)
+static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm)
 {
        /* Read in the first three digits..  "digit" is the first digit, already read */
-       char ext[NUMDIGITS + 1];
+       char ext[NUMDIGITS + 1], *cat;
        char name[80] = "";
        struct ast_variable *v;
        int res;
@@ -499,6 +499,58 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *
                        }
                }
 
+               if (!res && ucfg) {
+                       /* Search users.conf for all names which start with those digits */
+                       for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) {
+                               if (!strcasecmp(cat, "general"))
+                                       continue;
+                               if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
+                                       continue;
+                               
+                               /* Find all candidate extensions */
+                               if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) {
+                                       ast_copy_string(name, pos, sizeof(name));
+                                       /* Grab the last name */
+                                       if (last && strrchr(pos,' '))
+                                               pos = strrchr(pos, ' ') + 1;
+                                       conv = convert(pos);
+                                       if (conv) {
+                                               if (!strcmp(conv, ext)) {
+                                                       /* Match! */
+                                                       found++;
+                                                       /* We have a match -- play a greeting if they have it */
+                                                       res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm);
+                                                       switch (res) {
+                                                       case -1:
+                                                               /* user pressed '1' but extension does not exist, or
+                                                                * user hungup
+                                                                */
+                                                               lastuserchoice = 0;
+                                                               break;
+                                                       case '1':
+                                                               /* user pressed '1' and extensions exists;
+                                                                  play_mailbox_owner will already have done
+                                                                  a goto() on the channel
+                                                                */
+                                                               lastuserchoice = res;
+                                                               break;
+                                                       case '*':
+                                                               /* user pressed '*' to skip something found */
+                                                               lastuserchoice = res;
+                                                               res = 0;
+                                                               break;
+                                                       default:
+                                                               break;
+                                                       }
+                                                       free(conv);
+                                                       break;
+                                               }
+                                               free(conv);
+                                       }
+                               }
+                       }
+               }
+                       
                if (lastuserchoice != '1') {
                        res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language);
                        if (!res)
@@ -514,7 +566,7 @@ static int directory_exec(struct ast_channel *chan, void *data)
 {
        int res = 0;
        struct ast_module_user *u;
-       struct ast_config *cfg;
+       struct ast_config *cfg, *ucfg;
        int last = 1;
        int readext = 0;
        int fromappvm = 0;
@@ -554,6 +606,8 @@ static int directory_exec(struct ast_channel *chan, void *data)
                ast_module_user_remove(u);
                return -1;
        }
+       
+       ucfg = ast_config_load("users.conf");
 
        dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
        if (ast_strlen_zero(dirintro))
@@ -571,7 +625,7 @@ static int directory_exec(struct ast_channel *chan, void *data)
                if (!res)
                        res = ast_waitfordigit(chan, 5000);
                if (res > 0) {
-                       res = do_directory(chan, cfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm);
+                       res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm);
                        if (res > 0) {
                                res = ast_waitstream(chan, AST_DIGIT_ANY);
                                ast_stopstream(chan);
@@ -581,6 +635,8 @@ static int directory_exec(struct ast_channel *chan, void *data)
                }
                break;
        }
+       if (ucfg)
+               ast_config_destroy(ucfg);
        ast_config_destroy(cfg);
        ast_module_user_remove(u);
        return res;
index f519602..70ebc9f 100644 (file)
@@ -404,6 +404,8 @@ static char ext_pass_cmd[128];
 #define tdesc "Comedian Mail (Voicemail System)"
 #endif
 
+static char userscontext[AST_MAX_EXTENSION] = "default";
+
 static char *addesc = "Comedian Mail";
 
 static char *synopsis_vm =
@@ -641,9 +643,32 @@ static void apply_options(struct ast_vm_user *vmu, const char *options)
        }       
 }
 
+static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
+{
+       struct ast_variable *tmp;
+       tmp = var;
+       while (tmp) {
+               if (!strcasecmp(tmp->name, "password")) {
+                       ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
+               } else if (!strcasecmp(tmp->name, "uniqueid")) {
+                       ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
+               } else if (!strcasecmp(tmp->name, "pager")) {
+                       ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
+               } else if (!strcasecmp(tmp->name, "email")) {
+                       ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
+               } else if (!strcasecmp(tmp->name, "fullname")) {
+                       ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
+               } else if (!strcasecmp(tmp->name, "context")) {
+                       ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
+               } else
+                       apply_option(retval, tmp->name, tmp->value);
+               tmp = tmp->next;
+       } 
+}
+
 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
 {
-       struct ast_variable *var, *tmp;
+       struct ast_variable *var;
        struct ast_vm_user *retval;
 
        if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
@@ -659,25 +684,7 @@ static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const cha
                else
                        var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
                if (var) {
-                       tmp = var;
-                       while (tmp) {
-                               printf("%s => %s\n", tmp->name, tmp->value);
-                               if (!strcasecmp(tmp->name, "password")) {
-                                       ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
-                               } else if (!strcasecmp(tmp->name, "uniqueid")) {
-                                       ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
-                               } else if (!strcasecmp(tmp->name, "pager")) {
-                                       ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
-                               } else if (!strcasecmp(tmp->name, "email")) {
-                                       ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
-                               } else if (!strcasecmp(tmp->name, "fullname")) {
-                                       ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
-                               } else if (!strcasecmp(tmp->name, "context")) {
-                                       ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
-                               } else
-                                       apply_option(retval, tmp->name, tmp->value);
-                               tmp = tmp->next;
-                       } 
+                       apply_options_full(retval, var);
                        ast_variables_destroy(var);
                } else { 
                        if (!ivm) 
@@ -6573,6 +6580,26 @@ static int vm_exec(struct ast_channel *chan, void *data)
        return res;
 }
 
+static struct ast_vm_user *find_or_create(char *context, char *mbox)
+{
+       struct ast_vm_user *vmu;
+       AST_LIST_TRAVERSE(&users, vmu, list) {
+               if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox))
+                       break;
+               if (context && (!strcasecmp(context, vmu->context)) && (!strcasecmp(mbox, vmu->mailbox)))
+                       break;
+       }
+       
+       if (!vmu) {
+               if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
+                       ast_copy_string(vmu->context, context, sizeof(vmu->context));
+                       ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
+                       AST_LIST_INSERT_TAIL(&users, vmu, list);
+               }
+       }
+       return vmu;
+}
+
 static int append_mailbox(char *context, char *mbox, char *data)
 {
        /* Assumes lock is already held */
@@ -6582,10 +6609,7 @@ static int append_mailbox(char *context, char *mbox, char *data)
        struct ast_vm_user *vmu;
 
        ast_copy_string(tmp, data, sizeof(tmp));
-       if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
-               ast_copy_string(vmu->context, context, sizeof(vmu->context));
-               ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
-
+       if ((vmu = find_or_create(context, mbox))) {
                populate_defaults(vmu);
 
                stringp = tmp;
@@ -6599,8 +6623,6 @@ static int append_mailbox(char *context, char *mbox, char *data)
                        ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
                if (stringp && (s = strsep(&stringp, ","))) 
                        apply_options(vmu, s);
-               
-               AST_LIST_INSERT_TAIL(&users, vmu, list);
        }
        return 0;
 }
@@ -6813,7 +6835,7 @@ static int load_config(void)
 {
        struct ast_vm_user *cur;
        struct vm_zone *zcur;
-       struct ast_config *cfg;
+       struct ast_config *cfg, *ucfg;
        char *cat;
        struct ast_variable *var;
        char *notifystr = NULL;
@@ -6843,6 +6865,7 @@ static int load_config(void)
        char *thresholdstr;
        char *fmt;
        char *astemail;
+       char *ucontext;
        char *astmailcmd = SENDMAIL;
        char *astforcename;
        char *astforcegreet;
@@ -6874,6 +6897,9 @@ static int load_config(void)
        if (cfg) {
                /* General settings */
 
+               if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
+                       ucontext = "default";
+               ast_copy_string(userscontext, ucontext, sizeof(userscontext));
                /* Attach voice message to mail message ? */
                if (!(astattach = ast_variable_retrieve(cfg, "general", "attach"))) 
                        astattach = "yes";
@@ -7159,6 +7185,18 @@ static int load_config(void)
                if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
                        astdirfwd = "no";
                ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);    
+               if ((ucfg = ast_config_load("users.conf"))) {   
+                       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
+                               if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
+                                       continue;
+                               if ((cur = find_or_create(userscontext, cat))) {
+                                       populate_defaults(cur);
+                                       apply_options_full(cur, ast_variable_browse(ucfg, cat));
+                                       ast_copy_string(cur->context, userscontext, sizeof(cur->context));
+                               }
+                       }
+                       ast_config_destroy(ucfg);
+               }
                cat = ast_category_browse(cfg, NULL);
                while (cat) {
                        if (strcasecmp(cat, "general")) {
index 6400ca2..501f28d 100644 (file)
@@ -798,8 +798,8 @@ static int send_command_locked(unsigned short callno, char, int, unsigned int, c
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
 static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
 static struct ast_frame *iax2_read(struct ast_channel *c);
-static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly);
-static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
+static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
+static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
 static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime);
 static void destroy_user(struct iax2_user *user);
 static void prune_peers(void);
@@ -2446,7 +2446,7 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
        if (!var)
                return NULL;
 
-       peer = build_peer(peername, var, ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
+       peer = build_peer(peername, var, NULL, ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
        
        if (!peer)
                return NULL;
@@ -2534,7 +2534,7 @@ static struct iax2_user *realtime_user(const char *username)
                tmp = tmp->next;
        }
 
-       user = build_user(username, var, !ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS));
+       user = build_user(username, var, NULL, !ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS));
        if (!user)
                return NULL;
 
@@ -8216,17 +8216,20 @@ static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr)
 
                
 /*! \brief Create peer structure based on configuration */
-static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly)
+static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
 {
        struct iax2_peer *peer = NULL;
        struct ast_ha *oldha = NULL;
        int maskfound=0;
        int found=0;
+       int firstpass=1;
 
        AST_LIST_LOCK(&peers);
        if (!temponly) {
                AST_LIST_TRAVERSE(&peers, peer, entry) {
                        if (!strcmp(peer->name, name)) {        
+                               if (!ast_test_flag(peer, IAX_DELME))
+                                       firstpass = 0;
                                break;
                        }
                }
@@ -8234,8 +8237,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                peer = NULL;    
        if (peer) {
                found++;
-               oldha = peer->ha;
-               peer->ha = NULL;
+               if (firstpass) {
+                       oldha = peer->ha;
+                       peer->ha = NULL;
+               }
                AST_LIST_REMOVE(&peers, peer, entry);
                AST_LIST_UNLOCK(&peers);
        } else {
@@ -8251,25 +8256,29 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                }
        }
        if (peer) {
-               ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
-               peer->encmethods = iax2_encryption;
-               peer->adsi = adsi;
-               /* NOT ANY MORE: peer->secret[0] = '\0'; */
-               ast_string_field_set(peer,secret,"");
-               if (!found) {
-                       ast_string_field_set(peer, name, name);
-                       peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
-                       peer->expiry = min_reg_expire;
-               }
-               peer->prefs = prefs;
-               peer->capability = iax2_capability;
-               peer->smoothing = 0;
-               peer->pokefreqok = DEFAULT_FREQ_OK;
-               peer->pokefreqnotok = DEFAULT_FREQ_NOTOK;
-               /* NO MORE: peer->context[0] = '\0';
-                  peer->peercontext[0] = '\0'; */
-               ast_string_field_set(peer,context,"");
-               ast_string_field_set(peer,peercontext,"");
+               if (firstpass) {
+                       ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
+                       peer->encmethods = iax2_encryption;
+                       peer->adsi = adsi;
+                       ast_string_field_set(peer,secret,"");
+                       if (!found) {
+                               ast_string_field_set(peer, name, name);
+                               peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
+                               peer->expiry = min_reg_expire;
+                       }
+                       peer->prefs = prefs;
+                       peer->capability = iax2_capability;
+                       peer->smoothing = 0;
+                       peer->pokefreqok = DEFAULT_FREQ_OK;
+                       peer->pokefreqnotok = DEFAULT_FREQ_NOTOK;
+                       ast_string_field_set(peer,context,"");
+                       ast_string_field_set(peer,peercontext,"");
+               }
+
+               if (!v) {
+                       v = alt;
+                       alt = NULL;
+               }
                while(v) {
                        if (!strcasecmp(v->name, "secret")) {
                                ast_string_field_set(peer, secret, v->value);
@@ -8376,6 +8385,12 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                                ast_string_field_set(peer, cid_name, name2);
                                ast_string_field_set(peer, cid_num, num2);
                                ast_set_flag(peer, IAX_HASCALLERID);    
+                       } else if (!strcasecmp(v->name, "fullname")) {
+                               ast_string_field_set(peer, cid_name, v->value);
+                               ast_set_flag(peer, IAX_HASCALLERID);    
+                       } else if (!strcasecmp(v->name, "cid_number")) {
+                               ast_string_field_set(peer, cid_num, v->value);
+                               ast_set_flag(peer, IAX_HASCALLERID);    
                        } else if (!strcasecmp(v->name, "sendani")) {
                                ast_set2_flag(peer, ast_true(v->value), IAX_SENDANI);   
                        } else if (!strcasecmp(v->name, "inkeys")) {
@@ -8407,7 +8422,11 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                                peer->adsi = ast_true(v->value);
                        }/* else if (strcasecmp(v->name,"type")) */
                        /*      ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
-                       v=v->next;
+                       v = v->next;
+                       if (!v) {
+                               v = alt;
+                               alt = NULL;
+                       }
                }
                if (!peer->authmethods)
                        peer->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
@@ -8421,13 +8440,14 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
 }
 
 /*! \brief Create in-memory user structure from configuration */
-static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly)
+static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
 {
        struct iax2_user *user = NULL;
        struct iax2_context *con, *conl = NULL;
        struct ast_ha *oldha = NULL;
        struct iax2_context *oldcon = NULL;
        int format;
+       int firstpass=1;
        int oldcurauthreq = 0;
        char *varname = NULL, *varval = NULL;
        struct ast_variable *tmpvar = NULL;
@@ -8436,18 +8456,22 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
        if (!temponly) {
                AST_LIST_TRAVERSE(&users, user, entry) {
                        if (!strcmp(user->name, name)) {        
+                               if (!ast_test_flag(user, IAX_DELME))
+                                       firstpass = 0;
                                break;
                        }
                }
        } else
                user = NULL;
-       
+
        if (user) {
-               oldcurauthreq = user->curauthreq;
-               oldha = user->ha;
-               oldcon = user->contexts;
-               user->ha = NULL;
-               user->contexts = NULL;
+               if (firstpass) {
+                       oldcurauthreq = user->curauthreq;
+                       oldha = user->ha;
+                       oldcon = user->contexts;
+                       user->ha = NULL;
+                       user->contexts = NULL;
+               }
                /* Already in the list, remove it and it will be added back (or FREE'd) */
                AST_LIST_REMOVE(&users, user, entry);
                AST_LIST_UNLOCK(&users);
@@ -8455,22 +8479,30 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
                AST_LIST_UNLOCK(&users);
                /* This is going to memset'd to 0 in the next block */
                user = ast_calloc(sizeof(*user),1);
-               if (ast_string_field_init(user, 32)) {
-                       free(user);
-                       user = NULL;
-               }
        }
        
        if (user) {
-               user->maxauthreq = maxauthreq;
-               user->curauthreq = oldcurauthreq;
-               user->prefs = prefs;
-               user->capability = iax2_capability;
-               user->encmethods = iax2_encryption;
-               user->adsi = adsi;
-               ast_string_field_set(user, name, name);
-               ast_string_field_set(user, language, language);
-               ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP); 
+               if (firstpass) {
+                       ast_string_field_free_all(user);
+                       memset(user, 0, sizeof(struct iax2_user));
+                       if (ast_string_field_init(user, 32)) {
+                               free(user);
+                               user = NULL;
+                       }
+                       user->maxauthreq = maxauthreq;
+                       user->curauthreq = oldcurauthreq;
+                       user->prefs = prefs;
+                       user->capability = iax2_capability;
+                       user->encmethods = iax2_encryption;
+                       user->adsi = adsi;
+                       ast_string_field_set(user, name, name);
+                       ast_string_field_set(user, language, language);
+                       ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP); 
+               }
+               if (!v) {
+                       v = alt;
+                       alt = NULL;
+               }
                while(v) {
                        if (!strcasecmp(v->name, "context")) {
                                con = build_context(v->value);
@@ -8550,6 +8582,12 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
                                ast_string_field_set(user, cid_name, name2);
                                ast_string_field_set(user, cid_num, num2);
                                ast_set_flag(user, IAX_HASCALLERID);    
+                       } else if (!strcasecmp(v->name, "fullname")) {
+                               ast_string_field_set(user, cid_name, v->value);
+                               ast_set_flag(user, IAX_HASCALLERID);    
+                       } else if (!strcasecmp(v->name, "cid_number")) {
+                               ast_string_field_set(user, cid_num, v->value);
+                               ast_set_flag(user, IAX_HASCALLERID);    
                        } else if (!strcasecmp(v->name, "accountcode")) {
                                ast_string_field_set(user, accountcode, v->value);
                        } else if (!strcasecmp(v->name, "mohinterpret")) {
@@ -8576,6 +8614,10 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
                        }/* else if (strcasecmp(v->name,"type")) */
                        /*      ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
                        v = v->next;
+                       if (!v) {
+                               v = alt;
+                               alt = NULL;
+                       }
                }
                if (!user->authmethods) {
                        if (!ast_strlen_zero(user->secret)) {
@@ -8722,7 +8764,7 @@ static void set_timing(void)
 /*! \brief Load configuration */
 static int set_config(char *config_file, int reload)
 {
-       struct ast_config *cfg;
+       struct ast_config *cfg, *ucfg;
        int capability=iax2_capability;
        struct ast_variable *v;
        char *cat;
@@ -8975,13 +9017,71 @@ static int set_config(char *config_file, int reload)
                min_reg_expire = max_reg_expire;
        }
        iax2_capability = capability;
+       
+       ucfg = ast_config_load("users.conf");
+       if (ucfg) {
+               struct ast_variable *gen;
+               int genhasiax;
+               int genregisteriax;
+               char *hasiax, *registeriax;
+               
+               genhasiax = ast_true(ast_variable_retrieve(ucfg, "general", "hasiax"));
+               genregisteriax = ast_true(ast_variable_retrieve(ucfg, "general", "registeriax"));
+               gen = ast_variable_browse(ucfg, "general");
+               cat = ast_category_browse(ucfg, NULL);
+               while (cat) {
+                       if (strcasecmp(cat, "general")) {
+                               hasiax = ast_variable_retrieve(ucfg, cat, "hasiax");
+                               registeriax = ast_variable_retrieve(ucfg, cat, "registeriax");
+                               if (ast_true(hasiax) || (!hasiax && genhasiax)) {
+                                       /* Start with general parameters, then specific parameters, user and peer */
+                                       user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
+                                       if (user) {
+                                               AST_LIST_LOCK(&users);
+                                               AST_LIST_INSERT_HEAD(&users, user, entry);
+                                               AST_LIST_UNLOCK(&users);
+                                       }
+                                       peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
+                                       if (peer) {
+                                               AST_LIST_LOCK(&peers);
+                                               AST_LIST_INSERT_HEAD(&peers, peer, entry);
+                                               AST_LIST_UNLOCK(&peers);
+                                               if (ast_test_flag(peer, IAX_DYNAMIC))
+                                                       reg_source_db(peer);
+                                       }
+                               }
+                               if (ast_true(registeriax) || (!registeriax && genregisteriax)) {
+                                       char tmp[256];
+                                       char *host = ast_variable_retrieve(ucfg, cat, "host");
+                                       char *username = ast_variable_retrieve(ucfg, cat, "username");
+                                       char *secret = ast_variable_retrieve(ucfg, cat, "secret");
+                                       if (!host)
+                                               host = ast_variable_retrieve(ucfg, "general", "host");
+                                       if (!username)
+                                               username = ast_variable_retrieve(ucfg, "general", "username");
+                                       if (!secret)
+                                               secret = ast_variable_retrieve(ucfg, "general", "secret");
+                                       if (!ast_strlen_zero(username) && !ast_strlen_zero(host)) {
+                                               if (!ast_strlen_zero(secret))
+                                                       snprintf(tmp, sizeof(tmp), "%s:%s@%s", username, secret, host);
+                                               else
+                                                       snprintf(tmp, sizeof(tmp), "%s@%s", username, host);
+                                               iax2_register(tmp, 0);
+                                       }
+                               }
+                       }
+                       cat = ast_category_browse(ucfg, cat);
+               }
+               ast_config_destroy(ucfg);
+       }
+       
        cat = ast_category_browse(cfg, NULL);
        while(cat) {
                if (strcasecmp(cat, "general")) {
                        utype = ast_variable_retrieve(cfg, cat, "type");
                        if (utype) {
                                if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
-                                       user = build_user(cat, ast_variable_browse(cfg, cat), 0);
+                                       user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
                                        if (user) {
                                                AST_LIST_LOCK(&users);
                                                AST_LIST_INSERT_HEAD(&users, user, entry);
@@ -8989,7 +9089,7 @@ static int set_config(char *config_file, int reload)
                                        }
                                }
                                if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
-                                       peer = build_peer(cat, ast_variable_browse(cfg, cat), 0);
+                                       peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
                                        if (peer) {
                                                AST_LIST_LOCK(&peers);
                                                AST_LIST_INSERT_HEAD(&peers, peer, entry);
index 3627132..a9de2e3 100644 (file)
@@ -1365,7 +1365,7 @@ static void sip_dump_history(struct sip_pvt *dialog);
 
 /*--- Device object handling */
 static struct sip_peer *temp_peer(const char *name);
-static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int realtime);
+static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
 static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime);
 static int update_call_counter(struct sip_pvt *fup, int event);
 static void sip_destroy_peer(struct sip_peer *peer);
@@ -2357,7 +2357,7 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i
        }
 
        /* Peer found in realtime, now build it in memory */
-       peer = build_peer(newpeername, var, !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS));
+       peer = build_peer(newpeername, var, NULL, !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS));
        if (!peer) {
                ast_variables_destroy(var);
                return NULL;
@@ -15118,6 +15118,10 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v, int
                        ast_copy_string(user->md5secret, v->value, sizeof(user->md5secret));
                } else if (!strcasecmp(v->name, "callerid")) {
                        ast_callerid_split(v->value, user->cid_name, sizeof(user->cid_name), user->cid_num, sizeof(user->cid_num));
+               } else if (!strcasecmp(v->name, "fullname")) {
+                       ast_copy_string(user->cid_name, v->value, sizeof(user->cid_name));
+               } else if (!strcasecmp(v->name, "cid_number")) {
+                       ast_copy_string(user->cid_num, v->value, sizeof(user->cid_num));
                } else if (!strcasecmp(v->name, "callgroup")) {
                        user->callgroup = ast_get_group(v->value);
                } else if (!strcasecmp(v->name, "pickupgroup")) {
@@ -15243,12 +15247,13 @@ static struct sip_peer *temp_peer(const char *name)
 }
 
 /*! \brief Build peer from configuration (file or realtime static/dynamic) */
-static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int realtime)
+static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
 {
        struct sip_peer *peer = NULL;
        struct ast_ha *oldha = NULL;
        int obproxyfound=0;
        int found=0;
+       int firstpass=1;
        int format=0;           /* Ama flags */
        time_t regseconds = 0;
        char *varname = NULL, *varval = NULL;
@@ -15268,6 +15273,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
        if (peer) {
                /* Already in the list, remove it and it will be added back (or FREE'd)  */
                found++;
+               if (!(peer->objflags & ASTOBJ_FLAG_MARKED))
+                       firstpass = 0;
        } else {
                if (!(peer = ast_calloc(1, sizeof(*peer))))
                        return NULL;
@@ -15279,11 +15286,12 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                ASTOBJ_INIT(peer);
        }
        /* Note that our peer HAS had its reference count incrased */
-
-       peer->lastmsgssent = -1;
-       oldha = peer->ha;
-       peer->ha = NULL;
-       set_peer_defaults(peer);        /* Set peer defaults */
+       if (firstpass) {
+               peer->lastmsgssent = -1;
+               oldha = peer->ha;
+               peer->ha = NULL;
+               set_peer_defaults(peer);        /* Set peer defaults */
+       }
        if (!found && name)
                        ast_copy_string(peer->name, name, sizeof(peer->name));
 
@@ -15293,7 +15301,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                peer->chanvars = NULL;
                /* XXX should unregister ? */
        }
-       for (; v; v = v->next) {
+       for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
                if (handle_common_options(&peerflags[0], &mask[0], v))
                        continue;
                if (realtime && !strcasecmp(v->name, "regseconds")) {
@@ -15313,6 +15321,10 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                        peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno);
                else if (!strcasecmp(v->name, "callerid")) {
                        ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num));
+               } else if (!strcasecmp(v->name, "fullname")) {
+                       ast_copy_string(peer->cid_name, v->value, sizeof(peer->cid_name));
+               } else if (!strcasecmp(v->name, "cid_number")) {
+                       ast_copy_string(peer->cid_num, v->value, sizeof(peer->cid_num));
                } else if (!strcasecmp(v->name, "context")) {
                        ast_copy_string(peer->context, v->value, sizeof(peer->context));
                } else if (!strcasecmp(v->name, "subscribecontext")) {
@@ -15501,7 +15513,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
  */
 static int reload_config(enum channelreloadreason reason)
 {
-       struct ast_config *cfg;
+       struct ast_config *cfg, *ucfg;
        struct ast_variable *v;
        struct sip_peer *peer;
        struct sip_user *user;
@@ -15863,6 +15875,58 @@ static int reload_config(enum channelreloadreason reason)
                        authl = add_realm_authentication(authl, v->value, v->lineno);
        }
        
+       ucfg = ast_config_load("users.conf");
+       if (ucfg) {
+               struct ast_variable *gen;
+               int genhassip, genregistersip;
+               char *hassip, *registersip;
+               
+               genhassip = ast_true(ast_variable_retrieve(ucfg, "general", "hassip"));
+               genregistersip = ast_true(ast_variable_retrieve(ucfg, "general", "registersip"));
+               gen = ast_variable_browse(ucfg, "general");
+               cat = ast_category_browse(ucfg, NULL);
+               while (cat) {
+                       if (strcasecmp(cat, "general")) {
+                               hassip = ast_variable_retrieve(ucfg, cat, "hassip");
+                               registersip = ast_variable_retrieve(ucfg, cat, "registersip");
+                               if (ast_true(hassip) || (!hassip && genhassip)) {
+                                       peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
+                                       if (peer) {
+                                               ASTOBJ_CONTAINER_LINK(&peerl,peer);
+                                               ASTOBJ_UNREF(peer, sip_destroy_peer);
+                                               peer_count++;
+                                       }
+                               }
+                               if (ast_true(registersip) || (!registersip && genregistersip)) {
+                                       char tmp[256];
+                                       char *host = ast_variable_retrieve(ucfg, cat, "host");
+                                       char *username = ast_variable_retrieve(ucfg, cat, "username");
+                                       char *secret = ast_variable_retrieve(ucfg, cat, "secret");
+                                       char *contact = ast_variable_retrieve(ucfg, cat, "contact");
+                                       if (!host)
+                                               host = ast_variable_retrieve(ucfg, "general", "host");
+                                       if (!username)
+                                               username = ast_variable_retrieve(ucfg, "general", "username");
+                                       if (!secret)
+                                               secret = ast_variable_retrieve(ucfg, "general", "secret");
+                                       if (!contact)
+                                               contact = "s";
+                                       if (!ast_strlen_zero(username) && !ast_strlen_zero(host)) {
+                                               if (!ast_strlen_zero(secret))
+                                                       snprintf(tmp, sizeof(tmp), "%s:%s@%s/%s", username, secret, host, contact);
+                                               else
+                                                       snprintf(tmp, sizeof(tmp), "%s@%s/%s", username, host, contact);
+                                               if (sip_register(tmp, 0) == 0)
+                                                       registry_count++;
+                                       }
+                               }
+                       }
+                       cat = ast_category_browse(ucfg, cat);
+               }
+               ast_config_destroy(ucfg);
+       }
+       
+
        /* Load peers, users and friends */
        cat = NULL;
        while ( (cat = ast_category_browse(cfg, cat)) ) {
@@ -15894,7 +15958,7 @@ static int reload_config(enum channelreloadreason reason)
                                }
                        }
                        if (is_peer) {
-                               peer = build_peer(cat, ast_variable_browse(cfg, cat), 0);
+                               peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
                                if (peer) {
                                        ASTOBJ_CONTAINER_LINK(&peerl,peer);
                                        ASTOBJ_UNREF(peer, sip_destroy_peer);
index 05e0623..4d8f010 100644 (file)
@@ -219,6 +219,7 @@ static int use_callerid = 1;
 static int cid_signalling = CID_SIG_BELL;
 static int cid_start = CID_START_RING;
 static int zaptrcallerid = 0;
+static int cur_radio = 0;
 static int cur_signalling = -1;
 static int cur_outsignalling = -1;
 
@@ -10282,202 +10283,115 @@ static int unload_module(void)
 #endif
        return __unload_module();
 }
-               
-static int setup_zap(int reload)
+
+static int build_channels(int iscrv, char *value, int reload, int lineno, int *found_pseudo)
 {
-       struct ast_config *cfg;
-       struct ast_variable *v;
-       struct ast_variable *vjb;
+       char *c, *chan;
+       int x, y, start, finish;
        struct zt_pvt *tmp;
-       char *chan;
-       char *c;
-       char *ringc;
-       int start, finish,x;
-       int y;
-       int found_pseudo = 0;
-       int cur_radio = 0;
 #ifdef HAVE_PRI
-       int spanno;
-       int i;
-       int logicalspan;
-       int trunkgroup;
-       int dchannels[NUM_DCHANS];
        struct zt_pri *pri;
+       int trunkgroup;
 #endif
-
-       cfg = ast_config_load(config);
-
-       /* Error if we have no config file */
-       if (!cfg) {
-               ast_log(LOG_ERROR, "Unable to load config %s\n", config);
-               return 0;
+       
+       if ((reload == 0) && (cur_signalling < 0)) {
+               ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
+               return -1;
        }
 
-       /* It's a little silly to lock it, but we mind as well just to be sure */
-       ast_mutex_lock(&iflock);
+       c = value;
+
 #ifdef HAVE_PRI
-       if (!reload) {
-               /* Process trunkgroups first */
-               v = ast_variable_browse(cfg, "trunkgroups");
-               while (v) {
-                       if (!strcasecmp(v->name, "trunkgroup")) {
-                               trunkgroup = atoi(v->value);
-                               if (trunkgroup > 0) {
-                                       if ((c = strchr(v->value, ','))) {
-                                               i = 0;
-                                               memset(dchannels, 0, sizeof(dchannels));
-                                               while (c && (i < NUM_DCHANS)) {
-                                                       dchannels[i] = atoi(c + 1);
-                                                       if (dchannels[i] < 0) {
-                                                               ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of zapata.conf\n", trunkgroup, v->lineno);
-                                                       } else
-                                                               i++;
-                                                       c = strchr(c + 1, ',');
-                                               }
-                                               if (i) {
-                                                       if (pri_create_trunkgroup(trunkgroup, dchannels)) {
-                                                               ast_log(LOG_WARNING, "Unable to create trunk group %d with Primary D-channel %d at line %d of zapata.conf\n", trunkgroup, dchannels[0], v->lineno);
-                                                       } else if (option_verbose > 1)
-                                                               ast_verbose(VERBOSE_PREFIX_2 "Created trunk group %d with Primary D-channel %d and %d backup%s\n", trunkgroup, dchannels[0], i - 1, (i == 1) ? "" : "s");
-                                               } else
-                                                       ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of zapata.conf\n", trunkgroup, v->lineno);
-                                       } else
-                                               ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of zapata.conf\n", trunkgroup, v->lineno);
-                               } else
-                                       ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of zapata.conf\n", v->lineno);
-                       } else if (!strcasecmp(v->name, "spanmap")) {
-                               spanno = atoi(v->value);
-                               if (spanno > 0) {
-                                       if ((c = strchr(v->value, ','))) {
-                                               trunkgroup = atoi(c + 1);
-                                               if (trunkgroup > 0) {
-                                                       if ((c = strchr(c + 1, ','))) 
-                                                               logicalspan = atoi(c + 1);
-                                                       else
-                                                               logicalspan = 0;
-                                                       if (logicalspan >= 0) {
-                                                               if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
-                                                                       ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
-                                                               } else if (option_verbose > 1) 
-                                                                       ast_verbose(VERBOSE_PREFIX_2 "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
-                                                       } else
-                                                               ast_log(LOG_WARNING, "Logical span must be a postive number, or '0' (for unspecified) at line %d of zapata.conf\n", v->lineno);
-                                               } else
-                                                       ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of zapata.conf\n", v->lineno);
-                                       } else
-                                               ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of zapata.conf\n", v->lineno);
-                               } else
-                                       ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of zapata.conf\n", v->lineno);
-                       } else {
-                               ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
+       pri = NULL;
+       if (iscrv) {
+               if (sscanf(c, "%d:%n", &trunkgroup, &y) != 1) {
+                       ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d\n", lineno);
+                       return -1;
+               }
+               if (trunkgroup < 1) {
+                       ast_log(LOG_WARNING, "CRV trunk group must be a positive number at line %d\n", lineno);
+                       return -1;
+               }
+               c += y;
+               for (y = 0; y < NUM_SPANS; y++) {
+                       if (pris[y].trunkgroup == trunkgroup) {
+                               pri = pris + y;
+                               break;
                        }
-                       v = v->next;
+               }
+               if (!pri) {
+                       ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d\n", trunkgroup, lineno);
+                       return -1;
                }
        }
-#endif
-       v = ast_variable_browse(cfg, "channels");
-       /* Copy the default jb config over global_jbconf */
-       memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-       /* Traverse all variables to handle jb conf */
-       for (vjb = v; vjb; vjb = vjb->next)
-               ast_jb_read_conf(&global_jbconf, vjb->name, vjb->value);
-       while(v) {
-               /* Create the interface list */
-               if (!strcasecmp(v->name, "channel")
+#endif                 
+
+       while ((chan = strsep(&c, ","))) {
+               if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
+                       /* Range */
+               } else if (sscanf(chan, "%d", &start)) {
+                       /* Just one */
+                       finish = start;
+               } else if (!strcasecmp(chan, "pseudo")) {
+                       finish = start = CHAN_PSEUDO;
+                       if (found_pseudo)
+                               *found_pseudo = 1;
+               } else {
+                       ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
+                       return -1;
+               }
+               if (finish < start) {
+                       ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
+                       x = finish;
+                       finish = start;
+                       start = x;
+               }
+
+               for (x = start; x <= finish; x++) {
 #ifdef HAVE_PRI
-                       || !strcasecmp(v->name, "crv")
+                       tmp = mkintf(x, cur_signalling, cur_outsignalling, cur_radio, pri, reload);
+#else                  
+                       tmp = mkintf(x, cur_signalling, cur_outsignalling, cur_radio, NULL, reload);
 #endif                 
-                                       ) {
-                       if (reload == 0) {
-                               if (cur_signalling < 0) {
-                                       ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
-                                       ast_config_destroy(cfg);
-                                       ast_mutex_unlock(&iflock);
-                                       return -1;
-                               }
-                       }
-                       c = v->value;
 
+                       if (tmp) {
+                               if (option_verbose > 2) {
 #ifdef HAVE_PRI
-                       pri = NULL;
-                       if (!strcasecmp(v->name, "crv")) {
-                               if (sscanf(c, "%d:%n", &trunkgroup, &y) != 1) {
-                                       ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d\n", v->lineno);
-                                       ast_config_destroy(cfg);
-                                       ast_mutex_unlock(&iflock);
-                                       return -1;
-                               }
-                               if (trunkgroup < 1) {
-                                       ast_log(LOG_WARNING, "CRV trunk group must be a postive number at line %d\n", v->lineno);
-                                       ast_config_destroy(cfg);
-                                       ast_mutex_unlock(&iflock);
-                                       return -1;
-                               }
-                               c += y;
-                               for (y = 0; y < NUM_SPANS; y++) {
-                                       if (pris[y].trunkgroup == trunkgroup) {
-                                               pri = pris + y;
-                                               break;
-                                       }
-                               }
-                               if (!pri) {
-                                       ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d\n", trunkgroup, v->lineno);
-                                       ast_config_destroy(cfg);
-                                       ast_mutex_unlock(&iflock);
-                                       return -1;
+                                       if (pri)
+                                               ast_verbose(VERBOSE_PREFIX_3 "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig));
+                                       else
+#endif
+                                               ast_verbose(VERBOSE_PREFIX_3 "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
                                }
+                       } else {
+                               ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
+                                       (reload == 1) ? "reconfigure" : "register", value);
+                               return -1;
                        }
-#endif                 
-                       chan = strsep(&c, ",");
-                       while (chan) {
-                               if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
-                                       /* Range */
-                               } else if (sscanf(chan, "%d", &start)) {
-                                       /* Just one */
-                                       finish = start;
-                               } else if (!strcasecmp(chan, "pseudo")) {
-                                       finish = start = CHAN_PSEUDO;
-                                       found_pseudo = 1;
-                               } else {
-                                       ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", v->value, chan);
-                                       ast_config_destroy(cfg);
-                                       ast_mutex_unlock(&iflock);
-                                       return -1;
-                               }
-                               if (finish < start) {
-                                       ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
-                                       x = finish;
-                                       finish = start;
-                                       start = x;
-                               }
+               }
+       }
 
-                               for (x = start; x <= finish; x++) {
-#ifdef HAVE_PRI
-                                       tmp = mkintf(x, cur_signalling, cur_outsignalling, cur_radio, pri, reload);
-#else                                  
-                                       tmp = mkintf(x, cur_signalling, cur_outsignalling, cur_radio, NULL, reload);
-#endif                                 
+       return 0;
+}
 
-                                       if (tmp) {
-                                               if (option_verbose > 2) {
+static int process_zap(struct ast_variable *v, int reload, int skipchannels)
+{
+       struct zt_pvt *tmp;
+       char *ringc;
+       int y;
+       int found_pseudo = 0;
+       char *c;
+
+       while(v) {
+               /* Create the interface list */
+               if (!strcasecmp(v->name, "channel")
 #ifdef HAVE_PRI
-                                                       if (pri)
-                                                               ast_verbose(VERBOSE_PREFIX_3 "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup,x, sig2str(tmp->sig));
-                                                       else
-#endif
-                                                               ast_verbose(VERBOSE_PREFIX_3 "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
-                                               }
-                                       } else {
-                                               if (reload == 1)
-                                                       ast_log(LOG_ERROR, "Unable to reconfigure channel '%s'\n", v->value);
-                                               else
-                                                       ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
-                                               ast_config_destroy(cfg);
-                                               ast_mutex_unlock(&iflock);
-                                               return -1;
-                                       }
-                               }
-                               chan = strsep(&c, ",");
+                   || !strcasecmp(v->name, "crv")
+#endif                 
+                       ) {
+                       if (!skipchannels) {
+                               if (build_channels(!strcasecmp(v->name, "crv"), v->value, reload, v->lineno, &found_pseudo))
+                                       return -1;
                        }
                } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
                        if (ast_true(v->value))
@@ -10645,7 +10559,11 @@ static int setup_zap(int reload)
                                cid_name[0] = '\0';
                        } else {
                                ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
-                       }
+                       } 
+               } else if (!strcasecmp(v->name, "fullname")) {
+                       ast_copy_string(cid_name, v->value, sizeof(cid_name));
+               } else if (!strcasecmp(v->name, "cid_number")) {
+                       ast_copy_string(cid_num, v->value, sizeof(cid_num));
                } else if (!strcasecmp(v->name, "useincomingcalleridonzaptransfer")) {
                        zaptrcallerid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "restrictcid")) {
@@ -10870,8 +10788,6 @@ static int setup_zap(int reload)
                                        switchtype = PRI_SWITCH_QSIG;
                                else {
                                        ast_log(LOG_ERROR, "Unknown switchtype '%s'\n", v->value);
-                                       ast_config_destroy(cfg);
-                                       ast_mutex_unlock(&iflock);
                                        return -1;
                                }
                        } else if (!strcasecmp(v->name, "nsf")) {
@@ -11084,12 +11000,11 @@ static int setup_zap(int reload)
                        } else if (!strcasecmp(v->name, "defaultozz")) {
                                ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
                        } 
-               } else 
+               } else if (!skipchannels)
                        ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
                v = v->next;
        }
        if (!found_pseudo && reload == 0) {
-       
                /* Make sure pseudo isn't a member of any groups if
                   we're automatically making it. */    
                cur_group = 0;
@@ -11105,8 +11020,123 @@ static int setup_zap(int reload)
                        ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
                }
        }
+       return 0;
+}
+               
+static int setup_zap(int reload)
+{
+       int x;
+       struct ast_config *cfg;
+       struct ast_variable *v;
+       struct ast_variable *vjb;
+       char *c;
+       int res;
+
+#ifdef HAVE_PRI
+       int spanno;
+       int i;
+       int logicalspan;
+       int trunkgroup;
+       int dchannels[NUM_DCHANS];
+#endif
+
+       cfg = ast_config_load(config);
+
+       /* Error if we have no config file */
+       if (!cfg) {
+               ast_log(LOG_ERROR, "Unable to load config %s\n", config);
+               return 0;
+       }
+
+       /* It's a little silly to lock it, but we mind as well just to be sure */
+       ast_mutex_lock(&iflock);
+#ifdef HAVE_PRI
+       if (!reload) {
+               /* Process trunkgroups first */
+               v = ast_variable_browse(cfg, "trunkgroups");
+               while (v) {
+                       if (!strcasecmp(v->name, "trunkgroup")) {
+                               trunkgroup = atoi(v->value);
+                               if (trunkgroup > 0) {
+                                       if ((c = strchr(v->value, ','))) {
+                                               i = 0;
+                                               memset(dchannels, 0, sizeof(dchannels));
+                                               while (c && (i < NUM_DCHANS)) {
+                                                       dchannels[i] = atoi(c + 1);
+                                                       if (dchannels[i] < 0) {
+                                                               ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of zapata.conf\n", trunkgroup, v->lineno);
+                                                       } else
+                                                               i++;
+                                                       c = strchr(c + 1, ',');
+                                               }
+                                               if (i) {
+                                                       if (pri_create_trunkgroup(trunkgroup, dchannels)) {
+                                                               ast_log(LOG_WARNING, "Unable to create trunk group %d with Primary D-channel %d at line %d of zapata.conf\n", trunkgroup, dchannels[0], v->lineno);
+                                                       } else if (option_verbose > 1)
+                                                               ast_verbose(VERBOSE_PREFIX_2 "Created trunk group %d with Primary D-channel %d and %d backup%s\n", trunkgroup, dchannels[0], i - 1, (i == 1) ? "" : "s");
+                                               } else
+                                                       ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of zapata.conf\n", trunkgroup, v->lineno);
+                                       } else
+                                               ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of zapata.conf\n", trunkgroup, v->lineno);
+                               } else
+                                       ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of zapata.conf\n", v->lineno);
+                       } else if (!strcasecmp(v->name, "spanmap")) {
+                               spanno = atoi(v->value);
+                               if (spanno > 0) {
+                                       if ((c = strchr(v->value, ','))) {
+                                               trunkgroup = atoi(c + 1);
+                                               if (trunkgroup > 0) {
+                                                       if ((c = strchr(c + 1, ','))) 
+                                                               logicalspan = atoi(c + 1);
+                                                       else
+                                                               logicalspan = 0;
+                                                       if (logicalspan >= 0) {
+                                                               if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
+                                                                       ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
+                                                               } else if (option_verbose > 1) 
+                                                                       ast_verbose(VERBOSE_PREFIX_2 "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
+                                                       } else
+                                                               ast_log(LOG_WARNING, "Logical span must be a postive number, or '0' (for unspecified) at line %d of zapata.conf\n", v->lineno);
+                                               } else
+                                                       ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of zapata.conf\n", v->lineno);
+                                       } else
+                                               ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of zapata.conf\n", v->lineno);
+                               } else
+                                       ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of zapata.conf\n", v->lineno);
+                       } else {
+                               ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
+                       }
+                       v = v->next;
+               }
+       }
+#endif
+       v = ast_variable_browse(cfg, "channels");
+       /* Copy the default jb config over global_jbconf */
+       memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
+       /* Traverse all variables to handle jb conf */
+       for (vjb = v; vjb; vjb = vjb->next)
+               ast_jb_read_conf(&global_jbconf, vjb->name, vjb->value);
+       res = process_zap(v, reload, 0);
        ast_mutex_unlock(&iflock);
        ast_config_destroy(cfg);
+       if (res)
+               return res;
+       cfg = ast_config_load("users.conf");
+       if (cfg) {
+               char *cat;
+               char *chans;
+               process_zap(ast_variable_browse(cfg, "general"), 1, 1);
+               for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
+                       if (!strcasecmp(cat, "general"))
+                               continue;
+                       chans = ast_variable_retrieve(cfg, cat, "zapchan");
+                       if (!ast_strlen_zero(chans)) {
+                               process_zap(ast_variable_browse(cfg, cat), 1, 1);
+                               build_channels(0, chans, 1, 0, NULL);
+                       }
+               }
+               ast_config_destroy(cfg);
+       }
 #ifdef HAVE_PRI
        if (!reload) {
                for (x = 0; x < NUM_SPANS; x++) {
index 864644c..ff9a305 100644 (file)
@@ -53,6 +53,11 @@ clearglobalvars=no
 ;
 ;priorityjumping=yes
 ;
+; User context is where entries from users.conf are registered.  The
+; default value is 'default'
+;
+;userscontext=default
+;
 ; You can include other config files, use the #include command
 ; (without the ';'). Note that this is different from the "include" command
 ; that includes contexts within other contexts. The #include command works
@@ -316,6 +321,18 @@ include => parkedcalls
 ;
 ; eswitch => IAX2/context@${CURSERVER}
 
+[macro-trunkdial]
+;
+; Standard trunk dial macro (hangs up on a dialstatus that should 
+; terminate call)
+;   ${ARG1} - What to dial
+;
+exten => s,1,Dial(${ARG1})
+exten => s,n,Goto(s-${DIALSTATUS},1)
+exten => s-NOANSWER,1,Hangup
+exten => s-BUSY,1,Hangup
+exten => _s-.,1,NoOp
+
 [macro-stdexten];
 ;
 ; Standard extension macro:
diff --git a/configs/users.conf.sample b/configs/users.conf.sample
new file mode 100644 (file)
index 0000000..d3257a1
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; User configuration
+;
+; Creating entries in users.conf is a "shorthand" for creating individual
+; entries in each configuration file.  Using users.conf is not intended to 
+; provide you with as much flexibility as using the separate configuration
+; files (e.g. sip.conf, iax.conf, etc) but is intended to accelerate the
+; simple task of adding users.  Note that creating individual items (e.g.
+; custom SIP peers, IAX friends, etc.) will allow you to override specific 
+; parameters within this file.
+;
+
+[general]
+fullname = New User
+userbase = 6000
+hasvoicemail = yes
+hassip = yes
+hasiax = yes
+hasmanager = no
+callwaiting = yes
+threewaycalling = yes
+callwaitingcallerid = yes
+transfer = yes
+canpark = yes
+cancallforward = yes
+callreturn = yes
+callgroup = 1
+pickupgroup = 1
+
+
+;[6000]
+;fullname = Joe User
+;email = joe@foo.bar
+;secret = 1234
+;zapchan = 1
+;hasvoicemail = yes
+;hassip = yes
+;hasiax = no
+;hasmanager = no
+;callwaiting = no
+;context = international
index 53d1627..27c3642 100644 (file)
@@ -49,7 +49,12 @@ maxsilence=10
 silencethreshold=128
 ; Max number of failed login attempts
 maxlogins=3
-
+;
+; User context is where entries from users.conf are registered.  The
+; default value is 'default'
+;
+;userscontext=default
+;
 ; If you need to have an external program, i.e. /usr/bin/myapp
 ; called when a voicemail is left, delivered, or your voicemailbox 
 ; is checked, uncomment this.  It can also be set to 'smdi' to use
index 43e1d74..720d6b9 100644 (file)
@@ -172,6 +172,7 @@ int read_config_maps(void);
 struct ast_config *ast_config_new(void);
 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg);
 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
+char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var);
 
 struct ast_category *ast_category_new(const char *name);
 void ast_category_append(struct ast_config *config, struct ast_category *cat);
index 397c49d..c558289 100644 (file)
@@ -174,6 +174,7 @@ int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
  * \return NULL on failure, and an ast_context structure on success
  */
 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar);
 
 /*!
  * \brief Merge the temporary contexts into a global contexts list and delete from the 
index 9cf3098..e5b117b 100644 (file)
@@ -649,10 +649,14 @@ int ast_safe_system(const char *s)
        struct rusage rusage;
        int status;
 
-#if HAVE_WORKING_FORK
-       ast_replace_sigchld();
+#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
+       ast_replace_sigchld();
 
+#ifdef HAVE_WORKING_VFORK
+       pid = vfork();
+#else
        pid = fork();
+#endif 
 
        if (pid == 0) {
                if (ast_opt_high_priority)
index ee3922a..6d88aeb 100644 (file)
@@ -147,6 +147,16 @@ struct ast_variable *ast_variable_browse(const struct ast_config *config, const
        return (cat) ? cat->root : NULL;
 }
 
+char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
+{
+       char *tmp;
+       tmp = ast_variable_retrieve(cfg, cat, var);
+       if (!tmp)
+               tmp = ast_variable_retrieve(cfg, "general", var);
+       return tmp;
+}
+
+
 char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
 {
        struct ast_variable *v;
index efa8640..90719a0 100644 (file)
@@ -947,6 +947,7 @@ static char mandescr_updateconfig[] =
 "Variables (X's represent 6 digit number beginning with 000000):\n"
 "   SrcFilename:   Configuration filename to read(e.g. foo.conf)\n"
 "   DstFilename:   Configuration filename to write(e.g. foo.conf)\n"
+"   Reload:        Whether or not a reload should take place (or name of specific module)\n"
 "   Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,Update,Delete,Append)\n"
 "   Cat-XXXXXX:    Category to operate on\n"
 "   Var-XXXXXX:    Variable to work on\n"
@@ -961,6 +962,7 @@ static int action_updateconfig(struct mansession *s, struct message *m)
        int res;
        char idText[256] = "";
        char *id = astman_get_header(m, "ActionID");
+       char *rld = astman_get_header(m, "Reload");
 
        if (!ast_strlen_zero(id))
                snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
@@ -981,6 +983,11 @@ static int action_updateconfig(struct mansession *s, struct message *m)
                return 0;
        }
        astman_append(s, "Response: Success\r\n%s\r\n", idText);
+       if (!ast_strlen_zero(rld)) {
+               if (ast_true(rld))
+                       rld = NULL;
+               ast_module_reload(rld); 
+       }
        return 0;
 }
 
index e875c88..f07ac58 100644 (file)
@@ -3491,7 +3491,7 @@ int ast_unregister_application(const char *app)
        return tmp ? 0 : -1;
 }
 
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
 {
        struct ast_context *tmp, **local_contexts;
        int length = sizeof(struct ast_context) + strlen(name) + 1;
@@ -3504,10 +3504,13 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c
 
        for (tmp = *local_contexts; tmp; tmp = tmp->next) {
                if (!strcasecmp(tmp->name, name)) {
-                       ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
+                       if (!existsokay) {
+                               ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
+                               tmp = NULL;
+                       }
                        if (!extcontexts)
                                ast_mutex_unlock(&conlock);
-                       return NULL;
+                       return tmp;
                }
        }
        if ((tmp = ast_calloc(1, length))) {
@@ -3531,6 +3534,15 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c
        return tmp;
 }
 
+struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+{
+       return __ast_context_create(extcontexts, name, registrar, 0);
+}
+
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+{
+       return __ast_context_create(extcontexts, name, registrar, 1);
+}
 void __ast_context_destroy(struct ast_context *con, const char *registrar);
 
 struct store_hint {
index 0689691..e63ab74 100644 (file)
@@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 static char *config = "extensions.conf";
 static char *registrar = "pbx_config";
+static char userscontext[AST_MAX_EXTENSION] = "default";
 
 static int static_config = 0;
 static int write_protect_config = 1;
@@ -1357,6 +1358,11 @@ static int pbx_load_config(const char *config_file)
        autofallthrough_config = ast_true(ast_variable_retrieve(cfg, "general", "autofallthrough"));
        clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
        ast_set2_flag(&ast_options, ast_true(ast_variable_retrieve(cfg, "general", "priorityjumping")), AST_OPT_FLAG_PRIORITY_JUMPING);
+
+       if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext"))) 
+               ast_copy_string(userscontext, cxt, sizeof(userscontext));
+       else
+               ast_copy_string(userscontext, "default", sizeof(userscontext));
                                                                    
        for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
                memset(realvalue, 0, sizeof(realvalue));
@@ -1364,11 +1370,10 @@ static int pbx_load_config(const char *config_file)
                pbx_builtin_setvar_helper(NULL, v->name, realvalue);
        }
        for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
-
                /* All categories but "general" or "globals" are considered contexts */
                if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
                        continue;
-               con=ast_context_create(&local_contexts,cxt, registrar);
+               con=ast_context_find_or_create(&local_contexts,cxt, registrar);
                if (con == NULL)
                        continue;
 
@@ -1494,12 +1499,109 @@ static int pbx_load_config(const char *config_file)
        return 1;
 }
 
+static void append_interface(char *iface, int maxlen, char *add)
+{
+       int len = strlen(iface);
+       if (strlen(add) + len < maxlen - 2) {
+               if (strlen(iface)) {
+                       iface[len] = '&';
+                       strcpy(iface + len + 1, add);
+               } else
+                       strcpy(iface, add);
+       }
+}
+
+static void pbx_load_users(void)
+{
+       struct ast_config *cfg;
+       char *cat, *chan;
+       char *zapchan;
+       char *hasexten;
+       char tmp[256];
+       char iface[256];
+       char zapcopy[256];
+       char *c;
+       int len;
+       int hasvoicemail;
+       int start, finish, x;
+       struct ast_context *con;
+       
+       cfg = ast_config_load("users.conf");
+       if (!cfg)
+               return;
+       con = ast_context_find_or_create(&local_contexts, userscontext, registrar);
+       if (!con)
+               return;
+
+       for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
+               if (!strcasecmp(cat, "general"))
+                       continue;
+               iface[0] = '\0';
+               len = sizeof(iface);
+               if (ast_true(ast_config_option(cfg, cat, "hassip"))) {
+                       snprintf(tmp, sizeof(tmp), "SIP/%s", cat);
+                       append_interface(iface, sizeof(iface), tmp);
+               }
+               if (ast_true(ast_config_option(cfg, cat, "hasiax"))) {
+                       snprintf(tmp, sizeof(tmp), "IAX/%s", cat);
+                       append_interface(iface, sizeof(iface), tmp);
+               }
+               hasexten = ast_config_option(cfg, cat, "hasexten");
+               if (hasexten && !ast_true(hasexten))
+                       continue;
+               hasvoicemail = ast_true(ast_config_option(cfg, cat, "hasvoicemail"));
+               zapchan = ast_variable_retrieve(cfg, cat, "zapchan");
+               if (!zapchan)
+                       zapchan = ast_variable_retrieve(cfg, "general", "zapchan");
+               if (!ast_strlen_zero(zapchan)) {
+                       ast_copy_string(zapcopy, zapchan, sizeof(zapcopy));
+                       c = zapcopy;
+                       chan = strsep(&c, ",");
+                       while (chan) {
+                               if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
+                                       /* Range */
+                               } else if (sscanf(chan, "%d", &start)) {
+                                       /* Just one */
+                                       finish = start;
+                               } else {
+                                       start = 0; finish = 0;
+                               }
+                               if (finish < start) {
+                                       x = finish;
+                                       finish = start;
+                                       start = x;
+                               }
+                               for (x = start; x <= finish; x++) {
+                                       snprintf(tmp, sizeof(tmp), "Zap/%d", x);
+                                       append_interface(iface, sizeof(iface), tmp);
+                               }
+                               chan = strsep(&c, ",");
+                       }
+               }
+               if (!ast_strlen_zero(iface)) {
+                       /* Add hint */
+                       ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, strdup(""), ast_free, registrar);
+                       /* If voicemail, use "stdexten" else use plain old dial */
+                       if (hasvoicemail) {
+                               snprintf(tmp, sizeof(tmp), "stdexten|%s|${HINT}", cat);
+                               ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", strdup(tmp), ast_free, registrar);
+                       } else {
+                               ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", strdup("${HINT}"), ast_free, registrar);
+                       }
+               }
+       }
+       ast_config_destroy(cfg);
+}
+
 static int pbx_load_module(void)
 {
        struct ast_context *con;
 
        if(!pbx_load_config(config))
                return AST_MODULE_LOAD_DECLINE;
+       
+       pbx_load_users();
+
        ast_merge_contexts_and_delete(&local_contexts, registrar);
 
        for (con = NULL; (con = ast_walk_contexts(con));)