Major changes to res_config to support centralized config, eliminate configuration of res_config_odbc, update config examples, integrate with iax2, remove mysql friends from iax2, put on flame retardant vest...

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3914 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer 2004-10-05 06:46:11 +00:00
parent 1a2ba48fa1
commit ebb18daf22
14 changed files with 746 additions and 852 deletions

View File

@ -730,6 +730,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
int numlines; int numlines;
int sentringing = 0; int sentringing = 0;
int numbusies = 0; int numbusies = 0;
int numnochan = 0;
int orig = *to; int orig = *to;
struct ast_frame *f; struct ast_frame *f;
struct localuser *peer = NULL; struct localuser *peer = NULL;
@ -754,7 +755,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
numlines++; numlines++;
} }
if (found < 0) { if (found < 0) {
if (numlines == numbusies) { if (numlines == (numbusies + numnochan)) {
ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
} else { } else {
ast_log(LOG_NOTICE, "No one is answering queue '%s'\n", queue); ast_log(LOG_NOTICE, "No one is answering queue '%s'\n", queue);
@ -776,6 +777,77 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
*allowdisconnect_out = o->allowdisconnect_out; *allowdisconnect_out = o->allowdisconnect_out;
} }
} else if (o->chan && (o->chan == winner)) { } else if (o->chan && (o->chan == winner)) {
if (!ast_strlen_zero(o->chan->call_forward)) {
char tmpchan[256]="";
char *stuff;
char *tech;
strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
if ((stuff = strchr(tmpchan, '/'))) {
*stuff = '\0';
stuff++;
tech = tmpchan;
} else {
snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
stuff = tmpchan;
tech = "Local";
}
/* Before processing channel, go ahead and check for forwarding */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
/* Setup parameters */
o->chan = ast_request(tech, in->nativeformats, stuff);
if (!o->chan) {
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
o->stillgoing = 0;
numnochan++;
} else {
if (o->chan->cid.cid_num)
free(o->chan->cid.cid_num);
o->chan->cid.cid_num = NULL;
if (o->chan->cid.cid_name)
free(o->chan->cid.cid_name);
o->chan->cid.cid_name = NULL;
if (in->cid.cid_num) {
o->chan->cid.cid_num = strdup(in->cid.cid_num);
if (!o->chan->cid.cid_num)
ast_log(LOG_WARNING, "Out of memory\n");
}
if (in->cid.cid_name) {
o->chan->cid.cid_name = strdup(in->cid.cid_name);
if (!o->chan->cid.cid_name)
ast_log(LOG_WARNING, "Out of memory\n");
}
strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
o->chan->cdrflags = in->cdrflags;
if (in->cid.cid_ani) {
if (o->chan->cid.cid_ani)
free(o->chan->cid.cid_ani);
o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
if (o->chan->cid.cid_ani)
strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
else
ast_log(LOG_WARNING, "Out of memory\n");
}
if (o->chan->cid.cid_rdnis)
free(o->chan->cid.cid_rdnis);
if (!ast_strlen_zero(in->macroexten))
o->chan->cid.cid_rdnis = strdup(in->macroexten);
else
o->chan->cid.cid_rdnis = strdup(in->exten);
if (ast_call(o->chan, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
o->stillgoing = 0;
ast_hangup(o->chan);
o->chan = NULL;
numnochan++;
}
}
/* Hangup the original channel now, in case we needed it */
ast_hangup(winner);
continue;
}
f = ast_read(winner); f = ast_read(winner);
if (f) { if (f) {
if (f->frametype == AST_FRAME_CONTROL) { if (f->frametype == AST_FRAME_CONTROL) {

View File

@ -1859,12 +1859,15 @@ int main(int argc, char *argv[])
printf(term_quit()); printf(term_quit());
exit(1); exit(1);
} }
#if 0
/* This should no longer be necessary */
/* sync cust config and reload some internals in case a custom config handler binded to them */ /* sync cust config and reload some internals in case a custom config handler binded to them */
read_ast_cust_config(); read_ast_cust_config();
reload_logger(0); reload_logger(0);
reload_manager(); reload_manager();
ast_enum_reload(); ast_enum_reload();
ast_rtp_reload(); ast_rtp_reload();
#endif
/* We might have the option of showing a console, but for now just /* We might have the option of showing a console, but for now just

View File

@ -62,9 +62,6 @@
#include <zaptel.h> #include <zaptel.h>
#endif /* __linux__ */ #endif /* __linux__ */
#endif #endif
#ifdef MYSQL_FRIENDS
#include <mysql/mysql.h>
#endif
#include "iax2.h" #include "iax2.h"
#include "iax2-parser.h" #include "iax2-parser.h"
#include "iax2-provision.h" #include "iax2-provision.h"
@ -99,14 +96,6 @@
/* Sample over last 100 units to determine historic jitter */ /* Sample over last 100 units to determine historic jitter */
#define GAMMA (0.01) #define GAMMA (0.01)
#ifdef MYSQL_FRIENDS
AST_MUTEX_DEFINE_STATIC(mysqllock);
static MYSQL *mysql;
static char mydbuser[80];
static char mydbpass[80];
static char mydbhost[80];
static char mydbname[80];
#endif
static char *desc = "Inter Asterisk eXchange (Ver 2)"; static char *desc = "Inter Asterisk eXchange (Ver 2)";
static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)"; static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)";
static char *type = "IAX2"; static char *type = "IAX2";
@ -1990,154 +1979,108 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
return 0; return 0;
} }
#ifdef MYSQL_FRIENDS static struct iax2_peer *build_peer(const char *name, struct ast_variable *v);
static struct iax2_user *build_user(const char *name, struct ast_variable *v);
static void mysql_update_peer(char *peer, struct sockaddr_in *sin) static void destroy_user(struct iax2_user *user);
static void destroy_peer(struct iax2_peer *peer);
static struct iax2_peer *realtime_peer(const char *peername)
{ {
if (mysql && (strlen(peer) < 128)) { struct ast_variable *var;
char query[512]; struct ast_variable *tmp;
char *name; struct iax2_peer *peer=NULL;
char iabuf[INET_ADDRSTRLEN];
time_t nowtime;
name = alloca(strlen(peer) * 2 + 1);
time(&nowtime);
mysql_real_escape_string(mysql, name, peer, strlen(peer));
snprintf(query, sizeof(query), "UPDATE iaxfriends SET ipaddr=\"%s\", port=\"%d\", regseconds=\"%ld\" WHERE name=\"%s\"",
ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), nowtime, name);
ast_mutex_lock(&mysqllock);
if (mysql_real_query(mysql, query, strlen(query)))
ast_log(LOG_WARNING, "Unable to update database\n");
ast_mutex_unlock(&mysqllock);
}
}
static struct iax2_peer *mysql_peer(char *peer)
{
struct iax2_peer *p;
int success = 0;
p = malloc(sizeof(struct iax2_peer));
memset(p, 0, sizeof(struct iax2_peer));
if (mysql && (strlen(peer) < 128)) {
char query[512];
char *name;
int numfields, x;
int port;
time_t regseconds, nowtime; time_t regseconds, nowtime;
MYSQL_RES *result; int dynamic=0;
MYSQL_FIELD *fields; var = ast_load_realtime("iaxfriends", "name", peername);
MYSQL_ROW rowval; if (var) {
name = alloca(strlen(peer) * 2 + 1); /* Make sure it's not a user only... */
mysql_real_escape_string(mysql, name, peer, strlen(peer)); peer = build_peer(peername, var);
snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds FROM iaxfriends WHERE name=\"%s\"", name); if (peer) {
ast_mutex_lock(&mysqllock); /* Add some finishing touches, addresses, etc */
mysql_query(mysql, query); peer->temponly = 1;
if ((result = mysql_store_result(mysql))) { tmp = var;
if ((rowval = mysql_fetch_row(result))) { while(tmp) {
numfields = mysql_num_fields(result); if (!strcasecmp(tmp->name, "type")) {
fields = mysql_fetch_fields(result); if (strcasecmp(tmp->value, "friend") &&
success = 1; strcasecmp(tmp->value, "peer")) {
for (x=0;x<numfields;x++) { /* Whoops, we weren't supposed to exist! */
if (rowval[x]) { destroy_peer(peer);
if (!strcasecmp(fields[x].name, "secret")) { peer = NULL;
strncpy(p->secret, rowval[x], sizeof(p->secret) - 1); break;
} else if (!strcasecmp(fields[x].name, "context")) { }
strncpy(p->context, rowval[x], sizeof(p->context) - 1); } else if (!strcasecmp(tmp->name, "regseconds")) {
} else if (!strcasecmp(fields[x].name, "ipaddr")) { if (sscanf(tmp->value, "%li", &regseconds) != 1)
inet_aton(rowval[x], &p->addr.sin_addr);
} else if (!strcasecmp(fields[x].name, "port")) {
if (sscanf(rowval[x], "%i", &port) != 1)
port = 0;
p->addr.sin_port = htons(port);
} else if (!strcasecmp(fields[x].name, "regseconds")) {
if (sscanf(rowval[x], "%li", &regseconds) != 1)
regseconds = 0; regseconds = 0;
} else if (!strcasecmp(tmp->name, "ipaddr")) {
inet_aton(tmp->value, &(peer->addr.sin_addr));
} else if (!strcasecmp(tmp->name, "port")) {
peer->addr.sin_port = htons(atoi(tmp->value));
} else if (!strcasecmp(tmp->name, "host")) {
if (!strcasecmp(tmp->value, "dynamic"))
dynamic = 1;
} }
tmp = tmp->next;
} }
} if (peer && dynamic) {
time(&nowtime); time(&nowtime);
if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
memset(&p->addr, 0, sizeof(p->addr)); memset(&peer->addr, 0, sizeof(peer->addr));
if (option_debug)
ast_log(LOG_DEBUG, "Bah, we're expired (%ld/%ld/%ld)!\n", nowtime - regseconds, regseconds, nowtime);
} }
mysql_free_result(result);
result = NULL;
} }
ast_mutex_unlock(&mysqllock);
} }
if (!success) { ast_destroy_realtime(var);
free(p);
p = NULL;
} else {
strncpy(p->name, peer, sizeof(p->name) - 1);
p->dynamic = 1;
p->temponly = 1;
p->expire = -1;
p->capability = iax2_capability;
p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
} }
return p; return peer;
} }
static struct iax2_user *mysql_user(char *user)
{
struct iax2_user *p;
struct iax2_context *con;
int success = 0;
p = malloc(sizeof(struct iax2_user)); static struct iax2_user *realtime_user(const char *username)
memset(p, 0, sizeof(struct iax2_user)); {
con = malloc(sizeof(struct iax2_context)); struct ast_variable *var;
memset(con, 0, sizeof(struct iax2_context)); struct ast_variable *tmp;
strncpy(con->context, "default", sizeof(con->context) - 1); struct iax2_user *user=NULL;
p->contexts = con; var = ast_load_realtime("iaxfriends", "name", username);
if (mysql && (strlen(user) < 128)) { if (var) {
char query[512]; /* Make sure it's not a user only... */
char *name; user = build_user(username, var);
int numfields, x; if (user) {
MYSQL_RES *result; /* Add some finishing touches, addresses, etc */
MYSQL_FIELD *fields; user->temponly = 1;
MYSQL_ROW rowval; tmp = var;
name = alloca(strlen(user) * 2 + 1); while(tmp) {
mysql_real_escape_string(mysql, name, user, strlen(user)); if (!strcasecmp(tmp->name, "type")) {
snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds, accountcode FROM iaxfriends WHERE name=\"%s\"", name); if (strcasecmp(tmp->value, "friend") &&
ast_mutex_lock(&mysqllock); strcasecmp(tmp->value, "user")) {
mysql_query(mysql, query); /* Whoops, we weren't supposed to exist! */
if ((result = mysql_store_result(mysql))) { destroy_user(user);
if ((rowval = mysql_fetch_row(result))) { user = NULL;
numfields = mysql_num_fields(result); break;
fields = mysql_fetch_fields(result);
success = 1;
for (x=0;x<numfields;x++) {
if (rowval[x]) {
if (!strcasecmp(fields[x].name, "secret")) {
strncpy(p->secret, rowval[x], sizeof(p->secret) - 1);
} else if (!strcasecmp(fields[x].name, "context")) {
strncpy(p->contexts->context, rowval[x], sizeof(p->contexts->context) - 1);
} else if (!strcasecmp(fields[x].name, "accountcode")) {
strncpy(p->accountcode, rowval[x], sizeof(p->accountcode) - 1);
} }
} }
tmp = tmp->next;
} }
} }
mysql_free_result(result); ast_destroy_realtime(var);
result = NULL;
} }
ast_mutex_unlock(&mysqllock); return user;
}
if (!success) {
if (p->contexts)
free(p->contexts);
free(p);
p = NULL;
} else {
strncpy(p->name, user, sizeof(p->name) - 1);
p->temponly = 1;
p->capability = iax2_capability;
p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
}
return p;
} }
#endif /* MYSQL_FRIENDS */
static void realtime_update(const char *peername, struct sockaddr_in *sin)
{
char port[10];
char ipaddr[20];
char regseconds[20];
time_t nowtime;
time(&nowtime);
snprintf(regseconds, sizeof(regseconds), "%ld", nowtime);
ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin->sin_addr);
snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
ast_update_realtime("iaxfriends", "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, NULL);
}
static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk, int *notransfer, int *usejitterbuf, char *username, int usernlen, char *secret, int seclen, int *ofound, char *peercontext) static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk, int *notransfer, int *usejitterbuf, char *username, int usernlen, char *secret, int seclen, int *ofound, char *peercontext)
{ {
@ -2160,10 +2103,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
p = p->next; p = p->next;
} }
ast_mutex_unlock(&peerl.lock); ast_mutex_unlock(&peerl.lock);
#ifdef MYSQL_FRIENDS
if (!p) if (!p)
p = mysql_peer(peer); p = realtime_peer(peer);
#endif
if (p) { if (p) {
found++; found++;
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
@ -2197,7 +2138,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
*usejitterbuf=p->usejitterbuf; *usejitterbuf=p->usejitterbuf;
} else { } else {
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
p = NULL; p = NULL;
} }
} }
@ -2216,7 +2157,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
} else if (!p) } else if (!p)
return -1; return -1;
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return 0; return 0;
} }
@ -3691,18 +3632,14 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
} }
ast_mutex_unlock(&userl.lock); ast_mutex_unlock(&userl.lock);
user = best; user = best;
#ifdef MYSQL_FRIENDS if (!user && !ast_strlen_zero(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) {
if (!user && mysql && !ast_strlen_zero(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) { user = realtime_user(iaxs[callno]->username);
user = mysql_user(iaxs[callno]->username);
if (user && !ast_strlen_zero(iaxs[callno]->context) && /* No context specified */ if (user && !ast_strlen_zero(iaxs[callno]->context) && /* No context specified */
!apply_context(user->contexts, iaxs[callno]->context)) { /* Context is permitted */ !apply_context(user->contexts, iaxs[callno]->context)) { /* Context is permitted */
if (user->contexts) destroy_user(user);
free(user->contexts);
free(user);
user = NULL; user = NULL;
} }
} }
#endif
if (user) { if (user) {
/* We found our match (use the first) */ /* We found our match (use the first) */
@ -3874,10 +3811,8 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (!strcasecmp(p->name, peer)) if (!strcasecmp(p->name, peer))
break; break;
ast_mutex_unlock(&peerl.lock); ast_mutex_unlock(&peerl.lock);
#ifdef MYSQL_FRIENDS
if (!p) if (!p)
p = mysql_peer(peer); p = realtime_peer(peer);
#endif
if (!p) { if (!p) {
if (authdebug) if (authdebug)
@ -3889,7 +3824,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr)); ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} }
@ -3897,7 +3832,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name); ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} }
strncpy(iaxs[callno]->secret, p->secret, sizeof(iaxs[callno]->secret)-1); strncpy(iaxs[callno]->secret, p->secret, sizeof(iaxs[callno]->secret)-1);
@ -3923,14 +3858,14 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys); ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} }
} else { } else {
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer); ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} }
} else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) { } else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
@ -3939,7 +3874,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name); ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} else } else
iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; iaxs[callno]->state |= IAX_STATE_AUTHENTICATED;
@ -3956,7 +3891,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name, requeststr, md5secret); ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name, requeststr, md5secret);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} else } else
iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; iaxs[callno]->state |= IAX_STATE_AUTHENTICATED;
@ -3964,7 +3899,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Inappropriate authentication received\n"); ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return -1; return -1;
} }
strncpy(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer)-1); strncpy(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer)-1);
@ -3972,7 +3907,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (expire && (expire < iaxs[callno]->expirey)) if (expire && (expire < iaxs[callno]->expirey))
iaxs[callno]->expirey = expire; iaxs[callno]->expirey = expire;
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return 0; return 0;
} }
@ -4342,9 +4277,10 @@ static void register_peer_exten(struct iax2_peer *peer, int onoff)
strncpy(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi) - 1); strncpy(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi) - 1);
stringp = multi; stringp = multi;
while((ext = strsep(&stringp, "&"))) { while((ext = strsep(&stringp, "&"))) {
if (onoff) if (onoff) {
if (!ast_exists_extension(NULL, regcontext, ext, 1, NULL))
ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, type); ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, type);
else } else
ast_context_remove_extension(regcontext, ext, 1, NULL); ast_context_remove_extension(regcontext, ext, 1, NULL);
} }
} }
@ -4422,15 +4358,11 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
break; break;
} }
} }
#ifdef MYSQL_FRIENDS
if (!p) if (!p)
p = mysql_peer(name); p = realtime_peer(name);
#endif
if (p) { if (p) {
#ifdef MYSQL_FRIENDS
if (p->temponly) if (p->temponly)
mysql_update_peer(name, sin); realtime_update(name, sin);
#endif
if (inaddrcmp(&p->addr, sin)) { if (inaddrcmp(&p->addr, sin)) {
if (iax2_regfunk) if (iax2_regfunk)
iax2_regfunk(p->name, 1); iax2_regfunk(p->name, 1);
@ -4490,7 +4422,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
if (version) if (version)
iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version); iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1); return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
} }
ast_log(LOG_WARNING, "No such peer '%s'\n", name); ast_log(LOG_WARNING, "No such peer '%s'\n", name);
@ -4508,10 +4440,8 @@ static int registry_authrequest(char *name, int callno)
} }
} }
ast_mutex_unlock(&peerl.lock); ast_mutex_unlock(&peerl.lock);
#ifdef MYSQL_FRIENDS
if (!p) if (!p)
p = mysql_peer(name); p = realtime_peer(name);
#endif
if (p) { if (p) {
memset(&ied, 0, sizeof(ied)); memset(&ied, 0, sizeof(ied));
iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods); iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
@ -4522,7 +4452,7 @@ static int registry_authrequest(char *name, int callno)
} }
iax_ie_append_str(&ied, IAX_IE_USERNAME, name); iax_ie_append_str(&ied, IAX_IE_USERNAME, name);
if (p->temponly) if (p->temponly)
free(p); destroy_peer(p);
return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);; return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
} }
ast_log(LOG_WARNING, "No such peer '%s'\n", name); ast_log(LOG_WARNING, "No such peer '%s'\n", name);
@ -6375,7 +6305,7 @@ static int get_auth_methods(char *value)
return methods; return methods;
} }
static struct iax2_peer *build_peer(char *name, struct ast_variable *v) static struct iax2_peer *build_peer(const char *name, struct ast_variable *v)
{ {
struct iax2_peer *peer; struct iax2_peer *peer;
struct iax2_peer *prev; struct iax2_peer *prev;
@ -6540,7 +6470,7 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
return peer; return peer;
} }
static struct iax2_user *build_user(char *name, struct ast_variable *v) static struct iax2_user *build_user(const char *name, struct ast_variable *v)
{ {
struct iax2_user *prev, *user; struct iax2_user *prev, *user;
struct iax2_context *con, *conl = NULL; struct iax2_context *con, *conl = NULL;
@ -6702,6 +6632,13 @@ static void delete_users(void)
ast_mutex_unlock(&peerl.lock); ast_mutex_unlock(&peerl.lock);
} }
static void destroy_user(struct iax2_user *user)
{
ast_free_ha(user->ha);
free_context(user->contexts);
free(user);
}
static void prune_users(void) static void prune_users(void)
{ {
struct iax2_user *user, *usernext, *userlast = NULL; struct iax2_user *user, *usernext, *userlast = NULL;
@ -6709,9 +6646,7 @@ static void prune_users(void)
for (user=userl.users;user;) { for (user=userl.users;user;) {
usernext = user->next; usernext = user->next;
if (user->delme) { if (user->delme) {
ast_free_ha(user->ha); destroy_user(user);
free_context(user->contexts);
free(user);
if (userlast) if (userlast)
userlast->next = usernext; userlast->next = usernext;
else else
@ -6723,15 +6658,9 @@ static void prune_users(void)
ast_mutex_unlock(&userl.lock); ast_mutex_unlock(&userl.lock);
} }
static void prune_peers(void){ static void destroy_peer(struct iax2_peer *peer)
/* Prune peers who still are supposed to be deleted */ {
struct iax2_peer *peer, *peerlast, *peernext;
int x; int x;
ast_mutex_lock(&peerl.lock);
peerlast = NULL;
for (peer=peerl.peers;peer;) {
peernext = peer->next;
if (peer->delme) {
ast_free_ha(peer->ha); ast_free_ha(peer->ha);
for (x=0;x<IAX_MAX_CALLS;x++) { for (x=0;x<IAX_MAX_CALLS;x++) {
ast_mutex_lock(&iaxsl[x]); ast_mutex_lock(&iaxsl[x]);
@ -6749,6 +6678,17 @@ static void prune_peers(void){
iax2_destroy(peer->callno); iax2_destroy(peer->callno);
register_peer_exten(peer, 0); register_peer_exten(peer, 0);
free(peer); free(peer);
}
static void prune_peers(void){
/* Prune peers who still are supposed to be deleted */
struct iax2_peer *peer, *peerlast, *peernext;
ast_mutex_lock(&peerl.lock);
peerlast = NULL;
for (peer=peerl.peers;peer;) {
peernext = peer->next;
if (peer->delme) {
destroy_peer(peer);
if (peerlast) if (peerlast)
peerlast->next = peernext; peerlast->next = peernext;
else else
@ -6894,16 +6834,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
} else { } else {
amaflags = format; amaflags = format;
} }
#ifdef MYSQL_FRIENDS
} else if (!strcasecmp(v->name, "dbuser")) {
strncpy(mydbuser, v->value, sizeof(mydbuser) - 1);
} else if (!strcasecmp(v->name, "dbpass")) {
strncpy(mydbpass, v->value, sizeof(mydbpass) - 1);
} else if (!strcasecmp(v->name, "dbhost")) {
strncpy(mydbhost, v->value, sizeof(mydbhost) - 1);
} else if (!strcasecmp(v->name, "dbname")) {
strncpy(mydbname, v->value, sizeof(mydbname) - 1);
#endif
} else if (!strcasecmp(v->name, "language")) { } else if (!strcasecmp(v->name, "language")) {
strncpy(language, v->value, sizeof(language) - 1); strncpy(language, v->value, sizeof(language) - 1);
} //else if (strcasecmp(v->name,"type")) } //else if (strcasecmp(v->name,"type"))
@ -6943,21 +6873,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
} }
ast_destroy(cfg); ast_destroy(cfg);
set_timing(); set_timing();
#ifdef MYSQL_FRIENDS
/* Connect to db if appropriate */
if (!mysql && !ast_strlen_zero(mydbname)) {
mysql = mysql_init(NULL);
if (!mysql_real_connect(mysql, mydbhost[0] ? mydbhost : NULL, mydbuser, mydbpass, mydbname, 0, NULL, 0)) {
memset(mydbpass, '*', strlen(mydbpass));
ast_log(LOG_WARNING, "Database connection failed (db=%s, host=%s, user=%s, pass=%s)!\n",
mydbname, mydbhost, mydbuser, mydbpass);
free(mysql);
mysql = NULL;
} else
ast_verbose(VERBOSE_PREFIX_1 "Connected to database '%s' on '%s' as '%s'\n",
mydbname, mydbhost, mydbuser);
}
#endif
return capability; return capability;
} }

669
config.c
View File

@ -29,74 +29,45 @@
static int ast_cust_config=0; static int ast_cust_config=0;
struct ast_config *(*global_load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int struct ast_config *(*global_load_func)(const char *dbname, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int);
#ifdef PRESERVE_COMMENTS
,struct ast_comment_struct * static struct ast_config_map {
#endif struct ast_config_map *next;
); char *name;
char *driver;
char *database;
char *table;
char stuff[0];
} *maps = NULL;
AST_MUTEX_DEFINE_STATIC(ast_cust_config_lock); AST_MUTEX_DEFINE_STATIC(ast_cust_config_lock);
static struct ast_config_reg *ast_cust_config_list; static struct ast_config_reg *ast_cust_config_list;
static char *config_conf_file = "extconfig.conf"; static char *config_conf_file = "extconfig.conf";
static char *strip(char *buf) void ast_destroy_realtime(struct ast_variable *v)
{ {
char *start; struct ast_variable *vn;
/* Strip off trailing whitespace, returns, etc */ while(v) {
while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33)) vn = v;
buf[strlen(buf)-1] = '\0'; v = v->next;
start = buf; free(vn);
/* Strip off leading whitespace, returns, etc */
while (*start && (*start < 33))
*start++ = '\0';
return start;
}
#ifdef PRESERVE_COMMENTS
static void free_comments(struct ast_comment *com)
{
struct ast_comment *l;
while (com) {
l = com;
com = com->next;
free(l);
} }
} }
#endif
void ast_destroy(struct ast_config *ast) void ast_destroy(struct ast_config *ast)
{ {
struct ast_category *cat, *catn; struct ast_category *cat, *catn;
struct ast_variable *v, *vn;
if (!ast) if (!ast)
return; return;
cat = ast->root; cat = ast->root;
while(cat) { while(cat) {
v = cat->root; ast_destroy_realtime(cat->root);
while(v) {
vn = v;
free(v->name);
free(v->value);
#ifdef PRESERVE_COMMENTS
free_comments(v->precomments);
free_comments(v->sameline);
#endif
v = v->next;
free(vn);
}
catn = cat; catn = cat;
#ifdef PRESERVE_COMMENTS
free_comments(cat->precomments);
free_comments(cat->sameline);
#endif
cat = cat->next; cat = cat->next;
free(catn); free(catn);
} }
#ifdef PRESERVE_COMMENTS
free_comments(ast->trailingcomments);
#endif
free(ast); free(ast);
} }
@ -180,222 +151,6 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val
return NULL; return NULL;
} }
#ifdef PRESERVE_COMMENTS
int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value)
{
struct ast_variable *v, *pv, *bv, *bpv;
struct ast_category *cat;
cat = cfg->root;
while(cat) {
if (cat->name == category) {
break;
}
cat = cat->next;
}
if (!cat) {
cat = cfg->root;
while(cat) {
if (!strcasecmp(cat->name, category)) {
break;
}
cat = cat->next;
}
}
if (!cat)
return -1;
v = cat->root;
pv = NULL;
while (v) {
if ((variable == v->name) && (!value || !strcmp(v->value, value)))
break;
pv = v;
v=v->next;
}
if (!v) {
/* Get the last one that looks like it */
bv = NULL;
bpv = NULL;
v = cat->root;
pv = NULL;
while (v) {
if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) {
bv = v;
bpv = pv;
}
pv = v;
v=v->next;
}
v = bv;
}
if (v) {
/* Unlink from original position */
if (pv)
pv->next = v->next;
else
cat->root = v->next;
v->next = NULL;
free(v->name);
if (v->value)
free(v->value);
free_comments(v->sameline);
free_comments(v->precomments);
return 0;
}
return -1;
}
int ast_category_delete(struct ast_config *cfg, char *category)
{
struct ast_variable *v, *pv;
struct ast_category *cat, *cprev;
cat = cfg->root;
cprev = NULL;
while(cat) {
if (cat->name == category) {
break;
}
cprev = cat;
cat = cat->next;
}
if (!cat) {
cat = cfg->root;
cprev = NULL;
while(cat) {
if (!strcasecmp(cat->name, category)) {
break;
}
cprev = cat;
cat = cat->next;
}
}
if (!cat)
return -1;
/* Unlink it */
if (cprev)
cprev->next = cat->next;
else
cfg->root = cat->next;
v = cat->root;
while (v) {
pv = v;
v=v->next;
if (pv->value)
free(pv->value);
if (pv->name)
free(pv->name);
free_comments(pv->sameline);
free_comments(pv->precomments);
free(pv);
}
free_comments(cat->sameline);
free_comments(cat->precomments);
free(cat);
return 0;
}
struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move)
{
struct ast_variable *v, *pv=NULL, *bv, *bpv;
struct ast_category *cat, *pcat;
cat = config->root;
if (!newcat) {
while(cat) {
if (cat->name == category) {
break;
}
cat = cat->next;
}
if (!cat) {
cat = config->root;
while(cat) {
if (!strcasecmp(cat->name, category)) {
break;
}
cat = cat->next;
}
}
}
if (!cat) {
cat = malloc(sizeof(struct ast_category));
if (!cat)
return NULL;
memset(cat, 0, sizeof(struct ast_category));
strncpy(cat->name, category, sizeof(cat->name) - 1);
if (config->root) {
/* Put us at the end */
pcat = config->root;
while(pcat->next)
pcat = pcat->next;
pcat->next = cat;
} else {
/* We're the first one */
config->root = cat;
}
}
if (!newvar) {
v = cat->root;
pv = NULL;
while (v) {
if (variable == v->name)
break;
pv = v;
v=v->next;
}
if (!v) {
/* Get the last one that looks like it */
bv = NULL;
bpv = NULL;
v = cat->root;
pv = NULL;
while (v) {
if (!strcasecmp(variable, v->name)) {
bv = v;
bpv = pv;
}
pv = v;
v=v->next;
}
v = bv;
}
} else v = NULL;
if (v && move) {
/* Unlink from original position */
if (pv)
pv->next = v->next;
else
cat->root = v->next;
v->next = NULL;
}
if (!v) {
v = malloc(sizeof(struct ast_variable));
if (!v)
return NULL;
memset(v, 0, sizeof(struct ast_variable));
v->name = strdup(variable);
move = 1;
}
if (v->value)
free(v->value);
if (value)
v->value = strdup(value);
else
v->value = strdup("");
if (move) {
if (cat->root) {
pv = cat->root;
while (pv->next)
pv = pv->next;
pv->next = v;
} else {
cat->root = v;
}
}
return v;
}
#endif
int ast_category_exist(struct ast_config *config, char *category_name) int ast_category_exist(struct ast_config *config, char *category_name)
{ {
struct ast_category *category = NULL; struct ast_category *category = NULL;
@ -411,65 +166,73 @@ int ast_category_exist(struct ast_config *config, char *category_name)
return 0; return 0;
} }
#ifdef PRESERVE_COMMENTS
static struct ast_comment *build_comment(char *cmt) static struct ast_config_reg *get_ast_cust_config_keyword(const char *name, char *database, int dbsiz, char *table, int tabsiz)
{ {
struct ast_comment *c; struct ast_config_reg *reg,*ret=NULL;
int len = strlen(cmt) + 1; struct ast_config_map *map;
c = malloc(sizeof(struct ast_comment) + len);
if (c) { ast_mutex_lock(&ast_cust_config_lock);
/* Memset the header */ map = maps;
memset(c, 0, sizeof(struct ast_comment)); while(map) {
/* Copy the rest */ if (!strcasecmp(name, map->name)) {
strcpy(c->cmt, cmt); strncpy(database, map->database, dbsiz - 1);
if (map->table)
strncpy(table, map->table, tabsiz - 1);
else
strncpy(table, name, tabsiz - 1);
break;
} }
return c; map = map->next;
}
if (map) {
for (reg=ast_cust_config_list;reg && !ret;reg=reg->next) {
if (!strcmp(reg->name,map->driver))
ret=reg;
}
}
ast_mutex_unlock(&ast_cust_config_lock);
return ret;
} }
#endif
static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel void ast_config_destroy_all(void)
#ifdef PRESERVE_COMMENTS {
, struct ast_comment_struct *acs struct ast_config_reg *key;
#endif ast_mutex_lock(&ast_cust_config_lock);
); for (key=ast_cust_config_list;key;key=key->next) {
ast_config_deregister(key);
}
ast_cust_config_list = NULL;
ast_mutex_unlock(&ast_cust_config_lock);
}
static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel static struct ast_config_reg *get_config_registrations(void)
#ifdef PRESERVE_COMMENTS {
,struct ast_comment_struct *acs return ast_cust_config_list;
#endif }
)
static struct ast_config *__ast_load(const char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel);
static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, const char *configfile, int includelevel )
{ {
char *c; char *c;
char *cur; char *cur;
char *arg=NULL; char *arg=NULL;
struct ast_config_reg *reg=NULL;
struct ast_config *(*load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int
#ifdef PRESERVE_COMMENTS
,struct ast_comment_struct *
#endif
);
struct ast_variable *v; struct ast_variable *v;
#ifdef PRESERVE_COMMENTS
struct ast_comment *com = NULL;
#endif
int object; int object;
/* Strip off lines using ; as comment */ /* Strip off lines using ; as comment */
c = strchr(buf, ';'); c = strchr(buf, ';');
while (c) { while (c) {
if ((c == buf) || (*(c-1) != '\\')) { if ((c == buf) || (*(c-1) != '\\')) {
*c = '\0'; *c = '\0';
#ifdef PRESERVE_COMMENTS
c++;
if (*c != '!')
com = build_comment(c);
#endif
} else { } else {
*(c-1) = ';'; *(c-1) = ';';
memmove(c, c + 1, strlen(c + 1)); memmove(c, c + 1, strlen(c + 1));
} }
c = strchr(c + 1, ';'); c = strchr(c + 1, ';');
} }
cur = strip(buf); cur = ast_strip(buf);
if (!ast_strlen_zero(cur)) { if (!ast_strlen_zero(cur)) {
/* Actually parse the entry */ /* Actually parse the entry */
if (cur[0] == '[') { if (cur[0] == '[') {
@ -487,20 +250,12 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
memset(*_tmpc, 0, sizeof(struct ast_category)); memset(*_tmpc, 0, sizeof(struct ast_category));
strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1); strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1);
(*_tmpc)->root = NULL; (*_tmpc)->root = NULL;
#ifdef PRESERVE_COMMENTS
(*_tmpc)->precomments = acs->root;
(*_tmpc)->sameline = com;
#endif
if (!tmp->prev) if (!tmp->prev)
tmp->root = *_tmpc; tmp->root = *_tmpc;
else else
tmp->prev->next = *_tmpc; tmp->prev->next = *_tmpc;
tmp->prev = *_tmpc; tmp->prev = *_tmpc;
#ifdef PRESERVE_COMMENTS
acs->root = NULL;
acs->prev = NULL;
#endif
*_last = NULL; *_last = NULL;
} else { } else {
ast_log(LOG_WARNING, ast_log(LOG_WARNING,
@ -542,28 +297,9 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
if (includelevel < MAX_INCLUDE_LEVEL) { if (includelevel < MAX_INCLUDE_LEVEL) {
if(arg && cur) { if(arg && cur) {
load_func = NULL; ast_log(LOG_WARNING, "Including files with explicit config engine no longer permitted. Please use extconfig.conf to specify all mappings\n");
if(ast_cust_config_list) } else {
reg = get_ast_cust_config(cur); __ast_load(cur, tmp, _tmpc, _last, includelevel + 1);
if(reg && reg->func)
load_func = reg->func;
if(load_func) {
ast_log(LOG_NOTICE,"External Include '%s' via '%s' config engine\n",arg,cur);
load_func(arg,tmp, _tmpc, _last, includelevel
#ifdef PRESERVE_COMMENTS
,&acs
#endif
);
}
else
ast_log(LOG_WARNING,"Cant Find Registered Config Engine [%s] for [%s]\n",cur,arg);
}
else {
__ast_load(cur, tmp, _tmpc, _last, includelevel + 1
#ifdef PRESERVE_COMMENTS
,acs
#endif
);
} }
} else } else
ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel); ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel);
@ -591,21 +327,12 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
c++; c++;
} else } else
object = 0; object = 0;
v = malloc(sizeof(struct ast_variable)); v = ast_new_variable(ast_strip(cur), ast_strip(c));
if (v) { if (v) {
memset(v, 0, sizeof(struct ast_variable));
v->next = NULL; v->next = NULL;
v->name = strdup(strip(cur));
v->value = strdup(strip(c));
v->lineno = lineno; v->lineno = lineno;
v->object = object; v->object = object;
/* Put and reset comments */ /* Put and reset comments */
#ifdef PRESERVE_COMMENTS
v->precomments = acs->root;
v->sameline = com;
acs->prev = NULL;
acs->root = NULL;
#endif
v->blanklines = 0; v->blanklines = 0;
if (*_last) if (*_last)
(*_last)->next = v; (*_last)->next = v;
@ -622,34 +349,10 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
} }
} }
} else {
/* store any comments if there are any */
#ifdef PRESERVE_COMMENTS
if (com) {
if (acs->prev)
acs->prev->next = com;
else
acs->root = com;
acs->prev = com;
} else {
if (*_last)
(*_last)->blanklines++;
}
#endif
} }
return 0; return 0;
} }
#ifdef PRESERVE_COMMENTS
static void dump_comments(FILE *f, struct ast_comment *comment)
{
while (comment) {
fprintf(f, ";%s", comment->cmt);
comment = comment->next;
}
}
#endif
int ast_save(char *configfile, struct ast_config *cfg, char *generator) int ast_save(char *configfile, struct ast_config *cfg, char *generator)
{ {
FILE *f; FILE *f;
@ -677,22 +380,10 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator)
fprintf(f, ";!\n"); fprintf(f, ";!\n");
cat = cfg->root; cat = cfg->root;
while(cat) { while(cat) {
#ifdef PRESERVE_COMMENTS
/* Dump any precomments */
dump_comments(f, cat->precomments);
#endif
/* Dump section with any appropriate comment */ /* Dump section with any appropriate comment */
#ifdef PRESERVE_COMMENTS
if (cat->sameline)
fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->cmt);
else
#endif
fprintf(f, "[%s]\n", cat->name); fprintf(f, "[%s]\n", cat->name);
var = cat->root; var = cat->root;
while(var) { while(var) {
#ifdef PRESERVE_COMMENTS
dump_comments(f, var->precomments);
#endif
if (var->sameline) if (var->sameline)
fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt); fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
else else
@ -713,9 +404,6 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator)
#endif #endif
cat = cat->next; cat = cat->next;
} }
#ifdef PRESERVE_COMMENTS
dump_comments(f, cfg->trailingcomments);
#endif
} else { } else {
if (option_debug) if (option_debug)
printf("Unable to open for writing: %s\n", fn); printf("Unable to open for writing: %s\n", fn);
@ -727,46 +415,63 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator)
return 0; return 0;
} }
static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel
#ifdef PRESERVE_COMMENTS struct ast_variable *ast_load_realtime(const char *family, const char *keyfield, const char *lookup)
, struct ast_comment_struct *acs {
#endif struct ast_config_reg *reg;
) char db[256]="";
char table[256]="";
reg = get_ast_cust_config_keyword(family, db, sizeof(db), table, sizeof(table));
if (reg && reg->realtime_func)
return reg->realtime_func(db, table, keyfield, lookup);
return NULL;
}
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
{
struct ast_config_reg *reg;
int res = -1;
char db[256]="";
char table[256]="";
va_list ap;
va_start(ap, lookup);
reg = get_ast_cust_config_keyword(family, db, sizeof(db), table, sizeof(table));
if (reg && reg->update_func)
res = reg->update_func(db, table, keyfield, lookup, ap);
va_end(ap);
return res;
}
static struct ast_config *__ast_load(const char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel)
{ {
char fn[256]; char fn[256];
char buf[8192]; char buf[8192];
char db[256];
char table[256];
FILE *f; FILE *f;
int lineno=0; int lineno=0;
int master=0; int master=0;
struct ast_config_reg *reg=NULL; struct ast_config_reg *reg=NULL;
struct ast_config *(*load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int struct ast_config *(*load_func)(const char *database, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int);
#ifdef PRESERVE_COMMENTS
,struct ast_comment_struct *
#endif
);
load_func=NULL; load_func=NULL;
if (strcmp(configfile,config_conf_file) && strcmp(configfile,"asterisk.conf") && ast_cust_config_list) { if (strcmp(configfile,config_conf_file) && strcmp(configfile,"asterisk.conf") && ast_cust_config_list) {
if (global_load_func) { if (global_load_func) {
load_func = global_load_func; load_func = global_load_func;
} else { } else {
reg = get_ast_cust_config_keyword(configfile); reg = get_ast_cust_config_keyword(configfile, db, sizeof(db), table, sizeof(table));
if (reg && reg->func) { if (reg && reg->static_func) {
load_func = reg->func; load_func = reg->static_func;
} else { } else {
reg = get_ast_cust_config_keyword("global"); reg = get_ast_cust_config_keyword(configfile, db, sizeof(db), table, sizeof(table));
if (reg && reg->func) if (reg && reg->static_func)
global_load_func = load_func = reg->func; global_load_func = load_func = reg->static_func;
} }
} }
if (load_func) { if (load_func) {
ast_log(LOG_NOTICE,"Loading Config %s via %s engine\n",configfile,reg && reg->name ? reg->name : "global"); ast_log(LOG_NOTICE,"Loading Config %s via %s engine\n",configfile,reg && reg->name ? reg->name : "global");
tmp = load_func(configfile,tmp, _tmpc, _last, includelevel tmp = load_func(db, table, configfile,tmp, _tmpc, _last, includelevel);
#ifdef PRESERVE_COMMENTS
,&acs
#endif
);
if (tmp) if (tmp)
return tmp; return tmp;
@ -802,11 +507,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
while(!feof(f)) { while(!feof(f)) {
lineno++; lineno++;
if (fgets(buf, sizeof(buf), f)) { if (fgets(buf, sizeof(buf), f)) {
if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel)) {
#ifdef PRESERVE_COMMENTS
, acs
#endif
)) {
fclose(f); fclose(f);
return NULL; return NULL;
} }
@ -819,65 +520,13 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
else if (option_verbose > 1) else if (option_verbose > 1)
ast_verbose( "Not found (%s)\n", strerror(errno)); ast_verbose( "Not found (%s)\n", strerror(errno));
} }
#ifdef PRESERVE_COMMENTS
if (master) {
/* Keep trailing comments */
tmp->trailingcomments = acs->root;
acs->root = NULL;
acs->prev = NULL;
}
#endif
return tmp; return tmp;
} }
struct ast_config_reg *get_ast_cust_config_keyword(char *name)
{
struct ast_config_reg *reg,*ret=NULL;
int x=0;
ast_mutex_lock(&ast_cust_config_lock);
for (reg=ast_cust_config_list;reg && !ret;reg=reg->next) {
for (x=0;x<reg->keycount && !ret ;x++) {
if (!strcmp(reg->keywords[x],name))
ret=reg;
}
}
ast_mutex_unlock(&ast_cust_config_lock);
return ret;
}
struct ast_config_reg *get_ast_cust_config(char *name)
{
struct ast_config_reg *ptr=NULL;
ast_mutex_lock(&ast_cust_config_lock);
for (ptr=ast_cust_config_list;ptr;ptr=ptr->next) {
if (!strcmp(name,ptr->name))
break;
}
ast_mutex_unlock(&ast_cust_config_lock);
return ptr;
}
void ast_config_destroy_all(void)
{
struct ast_config_reg *key;
ast_mutex_lock(&ast_cust_config_lock);
for (key=ast_cust_config_list;key;key=key->next) {
ast_config_deregister(key);
}
ast_cust_config_list = NULL;
ast_mutex_unlock(&ast_cust_config_lock);
}
struct ast_config_reg *get_config_registrations(void)
{
return ast_cust_config_list;
}
int ast_config_register(struct ast_config_reg *new) int ast_config_register(struct ast_config_reg *new)
{ {
struct ast_config_reg *ptr; struct ast_config_reg *ptr;
ast_mutex_lock(&ast_cust_config_lock); ast_mutex_lock(&ast_cust_config_lock);
new->keycount = 0;
if (!ast_cust_config_list) { if (!ast_cust_config_list) {
ast_cust_config_list = new; ast_cust_config_list = new;
} else { } else {
@ -920,17 +569,7 @@ struct ast_config *ast_load(char *configfile)
struct ast_category *tmpc=NULL; struct ast_category *tmpc=NULL;
struct ast_variable *last = NULL; struct ast_variable *last = NULL;
return __ast_load(configfile, NULL, &tmpc, &last, 0);
#ifdef PRESERVE_COMMENTS
struct ast_comment_struct acs = { NULL, NULL };
#endif
return __ast_load(configfile, NULL, &tmpc, &last, 0
#ifdef PRESERVE_COMMENTS
,&acs
#endif
);
} }
char *ast_category_browse(struct ast_config *config, char *prev) char *ast_category_browse(struct ast_config *config, char *prev)
@ -991,27 +630,16 @@ struct ast_category *ast_new_category(char *name)
struct ast_variable *ast_new_variable(char *name, char *value) struct ast_variable *ast_new_variable(char *name, char *value)
{ {
struct ast_variable *variable; struct ast_variable *variable;
variable = malloc(sizeof(struct ast_variable)); int length = strlen(name) + strlen(value) + 2 + sizeof(struct ast_variable);
variable = malloc(length);
if (variable) { if (variable) {
memset(variable,0,sizeof(struct ast_variable)); memset(variable, 0, length);
variable->name = variable->stuff;
variable->value = variable->stuff + strlen(name) + 1;
variable->object=0; variable->object=0;
variable->name = malloc(strlen(name)+1);
if (variable->name) {
strcpy(variable->name,name); strcpy(variable->name,name);
variable->value = malloc(strlen(value)+1);
if (variable->value) {
strcpy(variable->value,value); strcpy(variable->value,value);
} else {
free(variable->name);
variable->name = NULL;
} }
}
}
if (!variable->value) {
free(variable);
variable = NULL;
}
return variable; return variable;
} }
@ -1030,29 +658,33 @@ int ast_cust_config_deregister(struct ast_config_reg *new)
static void clear_cust_keywords(void) static void clear_cust_keywords(void)
{ {
struct ast_config_reg *key; struct ast_config_map *map, *prev;
int x;
ast_mutex_lock(&ast_cust_config_lock); ast_mutex_lock(&ast_cust_config_lock);
for (key=get_config_registrations();key;key=key->next) { map = maps;
for (x=0;x<key->keycount;x++) { while(map) {
key->keywords[x][0] = '\0'; prev = map;
} map = map->next;
key->keycount=0; free(prev);
} }
maps = NULL;
ast_mutex_unlock(&ast_cust_config_lock); ast_mutex_unlock(&ast_cust_config_lock);
} }
static int config_command(int fd, int argc, char **argv) static int config_command(int fd, int argc, char **argv)
{ {
struct ast_config_reg *key; struct ast_config_reg *key;
int x; struct ast_config_map *map;
ast_cli(fd,"\n\n"); ast_cli(fd,"\n\n");
ast_mutex_lock(&ast_cust_config_lock); ast_mutex_lock(&ast_cust_config_lock);
for (key=get_config_registrations();key;key=key->next) { for (key=get_config_registrations();key;key=key->next) {
ast_cli(fd,"\nConfig Engine: %s\n",key->name); ast_cli(fd,"\nConfig Engine: %s\n",key->name);
for (x=0;x<key->keycount;x++) map = maps;
ast_cli(fd,"===>%s\n",key->keywords[x]); while(map) {
if (!strcasecmp(map->driver, key->name))
ast_cli(fd,"===> %s (db=%s, table=%s)\n",map->name, map->database, map->table ? map->table : map->name);
map = map->next;
}
} }
ast_mutex_unlock(&ast_cust_config_lock); ast_mutex_unlock(&ast_cust_config_lock);
ast_cli(fd,"\n\n"); ast_cli(fd,"\n\n");
@ -1074,29 +706,46 @@ int read_ast_cust_config(void)
char *cfg = config_conf_file; char *cfg = config_conf_file;
struct ast_config *config; struct ast_config *config;
struct ast_variable *v; struct ast_variable *v;
struct ast_config_reg *ptr; struct ast_config_map *map;
struct ast_config_reg *test = NULL; int length;
char *driver, *table, *database, *stringp;
clear_cust_keywords(); clear_cust_keywords();
config = ast_load(cfg); config = ast_load(cfg);
if (config) { if (config) {
for (v = ast_variable_browse(config,"settings");v;v=v->next) { for (v = ast_variable_browse(config,"settings");v;v=v->next) {
stringp = v->value;
driver = strsep(&stringp, ",");
database = strsep(&stringp, ",");
table = strsep(&stringp, ",");
ptr = get_ast_cust_config(v->value); if (!strcmp(v->name,config_conf_file) || !strcmp(v->name,"asterisk.conf")) {
if (ptr) { ast_log(LOG_WARNING, "Cannot bind asterisk.conf or extconfig.conf!\n");
if (ptr->keycount >= CONFIG_KEYWORD_ARRAYLEN) { } else if (driver && database) {
ast_log(LOG_WARNING,"Max Number of Bindings exceeded for %s->%s %d/%d\n",v->name,v->value,ptr->keycount,CONFIG_KEYWORD_ARRAYLEN); length = sizeof(struct ast_config_map);
} else { length += strlen(v->name) + 1;
if (strcmp(v->name,config_conf_file) && strcmp(v->name,"asterisk.conf")) { length += strlen(driver) + 1;
if (!(test = get_ast_cust_config_keyword(v->name))) { length += strlen(database) + 1;
ast_log(LOG_NOTICE,"Binding: %s to %s\n",v->name,v->value); if (table)
strncpy(ptr->keywords[ptr->keycount],v->name,sizeof(ptr->keywords[ptr->keycount]) - 1); length += strlen(table) + 1;
ptr->keywords[ptr->keycount][sizeof(ptr->keywords[ptr->keycount])-1] = '\0'; map = malloc(length);
ptr->keycount++; if (map) {
} memset(map, 0, length);
} else { map->name = map->stuff;
ast_log(LOG_WARNING,"Cannot bind %s, Permission Denied\n",v->name); strcpy(map->name, v->name);
} map->driver = map->name + strlen(map->name) + 1;
strcpy(map->driver, driver);
map->database = map->driver + strlen(map->driver) + 1;
strcpy(map->database, database);
if (table) {
map->table = map->database + strlen(map->database) + 1;
strcpy(map->table, table);
} else
map->table = NULL;
map->next = maps;
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Binding %s to %s/%s/%s\n",map->name,map->driver, map->database, map->table ? map->table : map->name);
maps = map;
} }
} }
} }

View File

@ -1,6 +1,28 @@
;
; Static and realtime external configuration
; engine configuration
;
[settings] [settings]
;
; Static configuration files:
;
; file.conf => driver,database[,table]
;
; maps a particular configuration file to the given
; database driver, database and table (or uses the
; name of the file as the table if not specified)
;
;uncomment to load queues.conf via the odbc engine.
;
;queues.conf => odbc,asterisk,ast_config
;uncomment to load queues.conf via the db engine. ;
;queues.conf => odbc ; Realtime configuration engine
;
; maps a particular family of realtime
; configuration to a given database driver,
; database and table (or uses the name of
; the family if the table is not specified
;
;iaxfriends => odbc,asterisk

View File

@ -1,3 +0,0 @@
[settings]
table => ast_config
connection => mysql1

38
doc/README.extconfig Executable file
View File

@ -0,0 +1,38 @@
Asterisk external configuration
===============================
The Asterisk external configuration engine is the result of work by
Anthony Minessale II and Mark Spencer. It is designed to provide a
flexible, seamless integration between Asterisk's internal
configuration structure and external SQL other other databases
(maybe even LDAP one day).
External configuration is configured in /etc/asterisk/extconfig.conf
allowing you to map any configuration file (static mappings) to
be pulled from the database, or to map special runtime entries which
permit the dynamic creation of objects, entities, peers, etc. without
the necessity of a reload.
Generally speaking, the columns in your tables should line up with the
fields you would specify in the given entity declaration. If an entry
would appear more than once, in the column it should be separated by a
semicolon. For example, an entity that looks like:
[foo]
host=dynamic
secret=bar
context=default
context=local
could be stored in a table like this:
+------+--------+-------+--------------+----------+-----+-----------+
| name | host | secret| context | ipaddr | port| regseconds|
+------+--------+-------+--------------+----------+-----+-----------+
| foo | dynamic| bar | default;local| 127.0.0.1| 4569| 1096954152|
+------+--------+-------+--------------+----------+-----+-----------+
Note that for use with IAX or SIP, the table will also need the "name",
"ipaddr", "port", "regseconds" columns. If you wanted to be able to
configure the callerid, you could just add a callerid column to the
table, for example.

View File

@ -34,6 +34,7 @@ struct ast_variable {
struct ast_comment *precomments; struct ast_comment *precomments;
struct ast_comment *sameline; struct ast_comment *sameline;
struct ast_variable *next; struct ast_variable *next;
char stuff[0];
}; };
//! Load a config file //! Load a config file
@ -103,12 +104,37 @@ int ast_false(char *val);
* Browse config structure and check for category duplicity Return non-zero if found */ * Browse config structure and check for category duplicity Return non-zero if found */
int ast_category_exist(struct ast_config *config, char *category_name); int ast_category_exist(struct ast_config *config, char *category_name);
/* These are only in the config engine at this point */ //! Retrieve realtime configuration
struct ast_variable *ast_variable_append_modify(struct ast_config *cfg, char *category, char *variable, char *newvalue, int newcat, int newvar, int move); /*!
* \param family which family/config to lookup
* \param keyfield which field to use as the key
* \param lookup which value to look for in the key field to match the entry.
* This will use builtin configuration backends to look up a particular
* entity in realtime and return a variable list of its parameters. Note
* that unlike the variables in ast_config, the resulting list of variables
* MUST be fred with ast_free_runtime() as there is no container.
*/
struct ast_variable *ast_load_realtime(const char *family, const char *keyfield, const char *lookup);
int ast_category_delete(struct ast_config *cfg, char *category); //! Update realtime configuration
int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value); /*!
int ast_save(char *filename, struct ast_config *cfg, char *generator); * \param family which family/config to be updated
* \param keyfield which field to use as the key
* \param lookup which value to look for in the key field to match the entry.
* \param variable which variable should be updated in the config, NULL to end list
* \param value the value to be assigned to that variable in the given entity.
* This function is used to update a parameter in realtime configuration space.
*
*/
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...);
//! Free realtime configuration
/*!
* \param var the linked list of variables to free
* This command free's a list of variables and should ONLY be used
* in conjunction with ast_load_realtime and not with the regular ast_load.
*/
void ast_destroy_realtime(struct ast_variable *var);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }

View File

@ -4,6 +4,7 @@
extern "C" { extern "C" {
#endif #endif
#include <stdarg.h>
#define CONFIG_KEYWORD_STRLEN 128 #define CONFIG_KEYWORD_STRLEN 128
#define CONFIG_KEYWORD_ARRAYLEN 512 #define CONFIG_KEYWORD_ARRAYLEN 512
#include <asterisk/config.h> #include <asterisk/config.h>
@ -14,10 +15,6 @@ struct ast_category {
char name[80]; char name[80];
struct ast_variable *root; struct ast_variable *root;
struct ast_category *next; struct ast_category *next;
#ifdef PRESERVE_COMMENTS
struct ast_comment *precomments;
struct ast_comment *sameline;
#endif
}; };
struct ast_config { struct ast_config {
@ -25,43 +22,25 @@ struct ast_config {
for now */ for now */
struct ast_category *root; struct ast_category *root;
struct ast_category *prev; struct ast_category *prev;
#ifdef PRESERVE_COMMENTS
struct ast_comment *trailingcomments;
#endif
}; };
#ifdef PRESERVE_COMMENTS
struct ast_comment_struct
{
struct ast_comment *root;
struct ast_comment *prev;
};
#endif
struct ast_category; struct ast_category;
struct ast_config_reg { struct ast_config_reg {
char name[CONFIG_KEYWORD_STRLEN]; char name[CONFIG_KEYWORD_STRLEN];
struct ast_config *(*func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int struct ast_config *(*static_func)(const char *database, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int);
#ifdef PRESERVE_COMMENTS struct ast_variable *(*realtime_func)(const char *database, const char *table, const char *keyfield, const char *entity);
,struct ast_comment_struct * int (*update_func)(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
#endif
);
char keywords[CONFIG_KEYWORD_STRLEN][CONFIG_KEYWORD_ARRAYLEN];
int keycount;
struct ast_config_reg *next; struct ast_config_reg *next;
}; };
int ast_config_register(struct ast_config_reg *new); int ast_config_register(struct ast_config_reg *new);
int ast_config_deregister(struct ast_config_reg *del); int ast_config_deregister(struct ast_config_reg *del);
void ast_cust_config_on(void); void ast_cust_config_on(void);
void ast_cust_config_off(void); void ast_cust_config_off(void);
int ast_cust_config_active(void); int ast_cust_config_active(void);
struct ast_config_reg *get_config_registrations(void);
struct ast_config_reg *get_ast_cust_config(char *name);
struct ast_config_reg *get_ast_cust_config_keyword(char *name);
void ast_config_destroy_all(void); void ast_config_destroy_all(void);

View File

@ -45,7 +45,7 @@ odbc_status odbc_obj_connect(odbc_obj *obj);
odbc_status odbc_obj_disconnect(odbc_obj *obj); odbc_status odbc_obj_disconnect(odbc_obj *obj);
void destroy_obdc_obj(odbc_obj **obj); void destroy_obdc_obj(odbc_obj **obj);
int register_odbc_obj(char *name,odbc_obj *obj); int register_odbc_obj(char *name,odbc_obj *obj);
odbc_obj *fetch_odbc_obj(char *name); odbc_obj *fetch_odbc_obj(const char *name);
int odbc_dump_fd(int fd,odbc_obj *obj); int odbc_dump_fd(int fd,odbc_obj *obj);
#endif #endif

View File

@ -26,6 +26,8 @@ struct ast_hostent {
char buf[1024]; char buf[1024];
}; };
extern char *ast_strip(char *buf);
extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp); extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp);
extern int ast_base64encode(char *dst, unsigned char *src, int srclen, int max); extern int ast_base64encode(char *dst, unsigned char *src, int srclen, int max);
extern int ast_base64decode(unsigned char *dst, char *src, int max); extern int ast_base64decode(unsigned char *dst, char *src, int max);

View File

@ -1,9 +1,9 @@
/* /*
* Asterisk -- A telephony toolkit for Linux. * Asterisk -- A telephony toolkit for Linux.
* *
* Copyright (C) 1999, Mark Spencer * Copyright (C) 1999-2004, Digium, Inc.
* *
* Mark Spencer <markster@linux-support.net> * Mark Spencer <markster@digium.com>
* *
* res_config_odbc.c <odbc+odbc plugin for portable configuration engine > * res_config_odbc.c <odbc+odbc plugin for portable configuration engine >
* Copyright (C) 2004 Anthony Minessale II <anthmct@yahoo.com> * Copyright (C) 2004 Anthony Minessale II <anthmct@yahoo.com>
@ -17,10 +17,12 @@
#include <asterisk/config_pvt.h> #include <asterisk/config_pvt.h>
#include <asterisk/module.h> #include <asterisk/module.h>
#include <asterisk/lock.h> #include <asterisk/lock.h>
#include <asterisk/options.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <asterisk/res_odbc.h> #include <asterisk/res_odbc.h>
#include <asterisk/utils.h>
static char *tdesc = "ODBC Configuration"; static char *tdesc = "ODBC Configuration";
static struct ast_config_reg reg1; static struct ast_config_reg reg1;
@ -29,18 +31,200 @@ STANDARD_LOCAL_USER;
LOCAL_USER_DECL; LOCAL_USER_DECL;
static struct ast_config *config_odbc (char *file, struct ast_config *new_config_s, struct ast_category **new_cat_p, struct ast_variable **new_v_p, int recur static struct ast_variable *realtime_odbc(const char *database, const char *table, const char *keyfield, const char *lookup)
#ifdef PRESERVE_COMMENTS
, struct ast_comment_struct *acs
#endif
)
{ {
struct ast_config *config, *new; odbc_obj *obj;
struct ast_variable *v, *cur_v, *new_v; SQLHSTMT stmt;
char sql[256];
char coltitle[256];
char rowdata[2048];
char *stringp;
char *chunk;
SQLSMALLINT collen;
int res;
int x;
struct ast_variable *var=NULL, *prev=NULL;
SQLLEN rowcount=0;
SQLULEN colsize;
SQLSMALLINT colcount=0;
SQLSMALLINT datatype;
SQLSMALLINT decimaldigits;
SQLSMALLINT nullable;
if (!table)
return NULL;
obj = fetch_odbc_obj(database);
if (!obj)
return NULL;
res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
return NULL;
}
snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s=?", table, keyfield);
res = SQLPrepare(stmt, sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return NULL;
}
SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
res = SQLExecute(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return NULL;
}
res = SQLRowCount(stmt, &rowcount);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return NULL;
}
res = SQLNumResultCols(stmt, &colcount);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return NULL;
}
if (rowcount) {
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return NULL;
}
for (x=0;x<colcount;x++) {
collen = sizeof(coltitle);
res = SQLDescribeCol(stmt, x + 1, coltitle, sizeof(coltitle), &collen,
&datatype, &colsize, &decimaldigits, &nullable);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
if (var)
ast_destroy_realtime(var);
return NULL;
}
res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
if (var)
ast_destroy_realtime(var);
return NULL;
}
stringp = rowdata;
while(stringp) {
chunk = strsep(&stringp, ";");
if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
if (prev) {
prev->next = ast_new_variable(coltitle, chunk);
if (prev->next)
prev = prev->next;
} else
prev = var = ast_new_variable(coltitle, chunk);
}
}
}
}
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return var;
}
static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
{
odbc_obj *obj;
SQLHSTMT stmt;
char sql[256];
SQLLEN rowcount=0;
const char *newparam, *newval;
int res;
int x;
va_list aq;
va_copy(aq, ap);
if (!table)
return -1;
obj = fetch_odbc_obj (database);
if (!obj)
return -1;
res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
return -1;
}
newparam = va_arg(aq, const char *);
if (!newparam) {
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return -1;
}
newval = va_arg(aq, const char *);
snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
while((newparam = va_arg(aq, const char *))) {
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
newval = va_arg(aq, const char *);
}
va_end(aq);
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
res = SQLPrepare(stmt, sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return -1;
}
/* Now bind the parameters */
x = 1;
while((newparam = va_arg(ap, const char *))) {
newval = va_arg(ap, const char *);
SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
}
SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
res = SQLExecute(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return -1;
}
res = SQLRowCount(stmt, &rowcount);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
return -1;
}
if (rowcount)
return 0;
return -1;
}
static struct ast_config *config_odbc (const char *database, const char *table, const char *file, struct ast_config *new_config_s, struct ast_category **new_cat_p, struct ast_variable **new_v_p, int recur)
{
struct ast_config *new;
struct ast_variable *cur_v, *new_v;
struct ast_category *cur_cat, *new_cat; struct ast_category *cur_cat, *new_cat;
char table[128] = ""; int res = 0;
char connection[128] = "";
int configured = 0, res = 0;
odbc_obj *obj; odbc_obj *obj;
SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0; SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0;
SQLBIGINT id; SQLBIGINT id;
@ -51,40 +235,16 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
int cat_started = 0; int cat_started = 0;
int var_started = 0; int var_started = 0;
if (new_config_s) {
new = new_config_s;
cat_started++;
} else {
new = ast_new_config ();
}
last[0] = '\0';
if (!file || !strcmp (file, "res_config_odbc.conf")) if (!file || !strcmp (file, "res_config_odbc.conf"))
return NULL; // cant configure myself with myself ! return NULL; // cant configure myself with myself !
config = ast_load ("res_config_odbc.conf"); obj = fetch_odbc_obj(database);
if (config) {
for (v = ast_variable_browse (config, "settings"); v; v = v->next) {
if (!strcmp (v->name, "table")) {
strncpy(table, v->value, sizeof(table) - 1);
configured++;
} else if (!strcmp (v->name, "connection")) {
strncpy(connection, v->value, sizeof(connection) - 1);
configured++;
}
}
ast_destroy (config);
}
if (configured < 2)
return NULL;
obj = fetch_odbc_obj (connection);
if (!obj) if (!obj)
return NULL; return NULL;
last[0] = '\0';
res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
SQLBindCol (stmt, 1, SQL_C_ULONG, &id, sizeof (id), &err); SQLBindCol (stmt, 1, SQL_C_ULONG, &id, sizeof (id), &err);
@ -96,7 +256,7 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
SQLBindCol (stmt, 7, SQL_C_CHAR, &var_name, sizeof (var_name), &err); SQLBindCol (stmt, 7, SQL_C_CHAR, &var_name, sizeof (var_name), &err);
SQLBindCol (stmt, 8, SQL_C_CHAR, &var_val, sizeof (var_val), &err); SQLBindCol (stmt, 8, SQL_C_CHAR, &var_val, sizeof (var_val), &err);
snprintf(sql, sizeof(sql), "select * from %s where filename='%s' and commented=0 order by filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file); snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE filename='%s' and commented=0 ORDER BY filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file);
res = SQLExecDirect (stmt, sql, SQL_NTS); res = SQLExecDirect (stmt, sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
@ -111,6 +271,19 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
return NULL; return NULL;
} }
if (new_config_s) {
new = new_config_s;
cat_started++;
} else {
new = ast_new_config ();
}
if (!new) {
ast_log(LOG_WARNING, "Out of memory!\n");
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
return NULL;
}
if (rowcount) { if (rowcount) {
res = SQLFetch (stmt); res = SQLFetch (stmt);
cat_started = 0; cat_started = 0;
@ -126,11 +299,7 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
while (res != SQL_NO_DATA) { while (res != SQL_NO_DATA) {
if (!strcmp (var_name, "#include") && recur < MAX_INCLUDE_LEVEL) { if (!strcmp (var_name, "#include") && recur < MAX_INCLUDE_LEVEL) {
config_odbc (var_val, new, &cur_cat, &cur_v, recur + 1 config_odbc(database, table, var_val, new, &cur_cat, &cur_v, recur + 1);
#ifdef PRESERVE_COMMENTS
, acs
#endif
);
} else { } else {
if (strcmp (last, category) || last_cat_metric != cat_metric) { if (strcmp (last, category) || last_cat_metric != cat_metric) {
strncpy(last, category, sizeof(last) - 1); strncpy(last, category, sizeof(last) - 1);
@ -176,7 +345,8 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
int unload_module (void) int unload_module (void)
{ {
ast_cust_config_deregister (&reg1); ast_cust_config_deregister (&reg1);
ast_log (LOG_NOTICE, "res_config_odbc unloaded.\n"); if (option_verbose)
ast_verbose("res_config_odbc unloaded.\n");
STANDARD_HANGUP_LOCALUSERS; STANDARD_HANGUP_LOCALUSERS;
return 0; return 0;
} }
@ -185,9 +355,12 @@ int load_module (void)
{ {
memset (&reg1, 0, sizeof (struct ast_config_reg)); memset (&reg1, 0, sizeof (struct ast_config_reg));
strncpy(reg1.name, "odbc", sizeof(reg1.name) - 1); strncpy(reg1.name, "odbc", sizeof(reg1.name) - 1);
reg1.func = config_odbc; reg1.static_func = config_odbc;
reg1.realtime_func = realtime_odbc;
reg1.update_func = update_odbc;
ast_cust_config_register (&reg1); ast_cust_config_register (&reg1);
ast_log (LOG_NOTICE, "res_config_odbc loaded.\n"); if (option_verbose)
ast_verbose("res_config_odbc loaded.\n");
return 0; return 0;
} }

View File

@ -1,9 +1,9 @@
/* /*
* Asterisk -- A telephony toolkit for Linux. * Asterisk -- A telephony toolkit for Linux.
* *
* Copyright (C) 1999, Mark Spencer * Copyright (C) 1999-2004, Digium, Inc.
* *
* Mark Spencer <markster@linux-support.net> * Mark Spencer <markster@digium.com>
* *
* res_odbc.c <ODBC resource manager> * res_odbc.c <ODBC resource manager>
* Copyright (C) 2004 Anthony Minessale II <anthmct@yahoo.com> * Copyright (C) 2004 Anthony Minessale II <anthmct@yahoo.com>
@ -45,7 +45,7 @@ static void odbc_destroy(void)
} }
} }
static odbc_obj *odbc_read(struct odbc_list *registry, char *name) static odbc_obj *odbc_read(struct odbc_list *registry, const char *name)
{ {
int x = 0; int x = 0;
for (x = 0; x < MAX_ODBC_HANDLES; x++) { for (x = 0; x < MAX_ODBC_HANDLES; x++) {
@ -124,7 +124,7 @@ static int load_odbc_config(void)
password = v->value; password = v->value;
} }
if (enabled && dsn && username && password) { if (enabled && dsn) {
obj = new_odbc_obj(cat, dsn, username, password); obj = new_odbc_obj(cat, dsn, username, password);
if (obj) { if (obj) {
register_odbc_obj(cat, obj); register_odbc_obj(cat, obj);
@ -212,7 +212,7 @@ int register_odbc_obj(char *name, odbc_obj * obj)
return 0; return 0;
} }
odbc_obj *fetch_odbc_obj(char *name) odbc_obj *fetch_odbc_obj(const char *name)
{ {
return (odbc_obj *) odbc_read(ODBC_REGISTRY, name); return (odbc_obj *) odbc_read(ODBC_REGISTRY, name);
} }
@ -233,18 +233,22 @@ odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password)
if (new->dsn == NULL) if (new->dsn == NULL)
return NULL; return NULL;
if (username) {
new->username = malloc(strlen(username) + 1); new->username = malloc(strlen(username) + 1);
if (new->username == NULL) if (new->username == NULL)
return NULL; return NULL;
strcpy(new->username, username);
}
if (password) {
new->password = malloc(strlen(password) + 1); new->password = malloc(strlen(password) + 1);
if (new->password == NULL) if (new->password == NULL)
return NULL; return NULL;
strcpy(new->password, password);
}
strcpy(new->name, name); strcpy(new->name, name);
strcpy(new->dsn, dsn); strcpy(new->dsn, dsn);
strcpy(new->username, username);
strcpy(new->password, password);
new->up = 0; new->up = 0;
ast_mutex_init(&new->lock); ast_mutex_init(&new->lock);
return new; return new;
@ -261,7 +265,9 @@ void destroy_obdc_obj(odbc_obj ** obj)
free((*obj)->name); free((*obj)->name);
free((*obj)->dsn); free((*obj)->dsn);
if ((*obj)->username)
free((*obj)->username); free((*obj)->username);
if ((*obj)->password)
free((*obj)->password); free((*obj)->password);
ast_mutex_unlock(&(*obj)->lock); ast_mutex_unlock(&(*obj)->lock);
free(*obj); free(*obj);
@ -332,6 +338,7 @@ odbc_status odbc_obj_connect(odbc_obj * obj)
SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
} }
ast_log(LOG_NOTICE, "Calling %p/%p\n", obj->username, obj->password);
res = SQLConnect(obj->con, res = SQLConnect(obj->con,
(SQLCHAR *) obj->dsn, SQL_NTS, (SQLCHAR *) obj->dsn, SQL_NTS,
(SQLCHAR *) obj->username, SQL_NTS, (SQLCHAR *) obj->username, SQL_NTS,
@ -340,12 +347,10 @@ odbc_status odbc_obj_connect(odbc_obj * obj)
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
SQLFreeHandle(SQL_HANDLE_ENV, obj->env); SQLFreeHandle(SQL_HANDLE_ENV, obj->env);
if (option_verbose > 3)
ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%ld %s\n", res, err, msg); ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%ld %s\n", res, err, msg);
return ODBC_FAIL; return ODBC_FAIL;
} else { } else {
if (option_verbose > 3)
ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->name, obj->dsn); ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->name, obj->dsn);
obj->up = 1; obj->up = 1;
} }

13
utils.c
View File

@ -28,6 +28,19 @@
static char base64[64]; static char base64[64];
static char b2a[256]; static char b2a[256];
char *ast_strip(char *buf)
{
char *start;
/* Strip off trailing whitespace, returns, etc */
while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33))
buf[strlen(buf)-1] = '\0';
start = buf;
/* Strip off leading whitespace, returns, etc */
while (*start && (*start < 33))
*start++ = '\0';
return start;
}
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
/* duh? ERANGE value copied from web... */ /* duh? ERANGE value copied from web... */