diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-09-16 23:53:58 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-09-16 23:53:58 +0000 |
commit | 5c0e56df213e669dd543a5996c77383a17a6ecd2 (patch) | |
tree | 1298da607ca8facdbaf23866e9294b57e39057d9 | |
parent | 5b13041e0f380ccdf5ce117653086312c4a3a7be (diff) |
merge markster's usersconf branch with some slight changes
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@43052 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | apps/app_directory.c | 64 | ||||
-rw-r--r-- | apps/app_voicemail.c | 92 | ||||
-rw-r--r-- | channels/chan_iax2.c | 200 | ||||
-rw-r--r-- | channels/chan_sip.c | 86 | ||||
-rw-r--r-- | channels/chan_zap.c | 392 | ||||
-rw-r--r-- | configs/extensions.conf.sample | 17 | ||||
-rw-r--r-- | configs/users.conf.sample | 41 | ||||
-rw-r--r-- | configs/voicemail.conf.sample | 7 | ||||
-rw-r--r-- | include/asterisk/config.h | 1 | ||||
-rw-r--r-- | include/asterisk/pbx.h | 1 | ||||
-rw-r--r-- | main/asterisk.c | 8 | ||||
-rw-r--r-- | main/config.c | 10 | ||||
-rw-r--r-- | main/manager.c | 7 | ||||
-rw-r--r-- | main/pbx.c | 18 | ||||
-rw-r--r-- | pbx/pbx_config.c | 106 |
15 files changed, 769 insertions, 281 deletions
diff --git a/apps/app_directory.c b/apps/app_directory.c index 6f660e326..ff644566b 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -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; diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index f519602c0..70ebc9f1d 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -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")) { diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 6400ca22f..501f28d02 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -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); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 362713293..a9de2e3f0 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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); diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 05e062336..4d8f010cc 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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++) { diff --git a/configs/extensions.conf.sample b/configs/extensions.conf.sample index 864644c2f..ff9a305b5 100644 --- a/configs/extensions.conf.sample +++ b/configs/extensions.conf.sample @@ -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 index 000000000..d3257a175 --- /dev/null +++ b/configs/users.conf.sample @@ -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 diff --git a/configs/voicemail.conf.sample b/configs/voicemail.conf.sample index 53d16278b..27c364246 100644 --- a/configs/voicemail.conf.sample +++ b/configs/voicemail.conf.sample @@ -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 diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 43e1d7480..720d6b971 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -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); diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 397c49d76..c558289c7 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -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 diff --git a/main/asterisk.c b/main/asterisk.c index 9cf309872..e5b117baf 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -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) diff --git a/main/config.c b/main/config.c index ee3922a2a..6d88aebec 100644 --- a/main/config.c +++ b/main/config.c @@ -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; diff --git a/main/manager.c b/main/manager.c index efa86401a..90719a0f9 100644 --- a/main/manager.c +++ b/main/manager.c @@ -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; } diff --git a/main/pbx.c b/main/pbx.c index e875c8810..f07ac5875 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -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 { diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 0689691f4..e63ab74ae 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -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));) |