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 sentringing = 0;
int numbusies = 0;
int numnochan = 0;
int orig = *to;
struct ast_frame *f;
struct localuser *peer = NULL;
@ -754,7 +755,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
numlines++;
}
if (found < 0) {
if (numlines == numbusies) {
if (numlines == (numbusies + numnochan)) {
ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
} else {
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;
}
} 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);
if (f) {
if (f->frametype == AST_FRAME_CONTROL) {

View File

@ -1859,12 +1859,15 @@ int main(int argc, char *argv[])
printf(term_quit());
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 */
read_ast_cust_config();
reload_logger(0);
reload_manager();
ast_enum_reload();
ast_rtp_reload();
#endif
/* We might have the option of showing a console, but for now just

View File

@ -62,9 +62,6 @@
#include <zaptel.h>
#endif /* __linux__ */
#endif
#ifdef MYSQL_FRIENDS
#include <mysql/mysql.h>
#endif
#include "iax2.h"
#include "iax2-parser.h"
#include "iax2-provision.h"
@ -99,14 +96,6 @@
/* Sample over last 100 units to determine historic jitter */
#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 *tdesc = "Inter Asterisk eXchange Driver (Ver 2)";
static char *type = "IAX2";
@ -1990,154 +1979,108 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
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)
{
if (mysql && (strlen(peer) < 128)) {
char query[512];
char *name;
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 void destroy_user(struct iax2_user *user);
static void destroy_peer(struct iax2_peer *peer);
static struct iax2_peer *mysql_peer(char *peer)
static struct iax2_peer *realtime_peer(const char *peername)
{
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;
MYSQL_RES *result;
MYSQL_FIELD *fields;
MYSQL_ROW rowval;
name = alloca(strlen(peer) * 2 + 1);
mysql_real_escape_string(mysql, name, peer, strlen(peer));
snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds FROM iaxfriends WHERE name=\"%s\"", name);
ast_mutex_lock(&mysqllock);
mysql_query(mysql, query);
if ((result = mysql_store_result(mysql))) {
if ((rowval = mysql_fetch_row(result))) {
numfields = mysql_num_fields(result);
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->context, rowval[x], sizeof(p->context) - 1);
} else if (!strcasecmp(fields[x].name, "ipaddr")) {
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;
}
}
struct ast_variable *var;
struct ast_variable *tmp;
struct iax2_peer *peer=NULL;
time_t regseconds, nowtime;
int dynamic=0;
var = ast_load_realtime("iaxfriends", "name", peername);
if (var) {
/* Make sure it's not a user only... */
peer = build_peer(peername, var);
if (peer) {
/* Add some finishing touches, addresses, etc */
peer->temponly = 1;
tmp = var;
while(tmp) {
if (!strcasecmp(tmp->name, "type")) {
if (strcasecmp(tmp->value, "friend") &&
strcasecmp(tmp->value, "peer")) {
/* Whoops, we weren't supposed to exist! */
destroy_peer(peer);
peer = NULL;
break;
}
} else if (!strcasecmp(tmp->name, "regseconds")) {
if (sscanf(tmp->value, "%li", &regseconds) != 1)
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);
if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE)
memset(&p->addr, 0, sizeof(p->addr));
}
mysql_free_result(result);
result = NULL;
}
ast_mutex_unlock(&mysqllock);
}
if (!success) {
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;
}
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));
memset(p, 0, sizeof(struct iax2_user));
con = malloc(sizeof(struct iax2_context));
memset(con, 0, sizeof(struct iax2_context));
strncpy(con->context, "default", sizeof(con->context) - 1);
p->contexts = con;
if (mysql && (strlen(user) < 128)) {
char query[512];
char *name;
int numfields, x;
MYSQL_RES *result;
MYSQL_FIELD *fields;
MYSQL_ROW rowval;
name = alloca(strlen(user) * 2 + 1);
mysql_real_escape_string(mysql, name, user, strlen(user));
snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds, accountcode FROM iaxfriends WHERE name=\"%s\"", name);
ast_mutex_lock(&mysqllock);
mysql_query(mysql, query);
if ((result = mysql_store_result(mysql))) {
if ((rowval = mysql_fetch_row(result))) {
numfields = mysql_num_fields(result);
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);
}
}
if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
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);
ast_destroy_realtime(var);
}
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;
return peer;
}
#endif /* MYSQL_FRIENDS */
static struct iax2_user *realtime_user(const char *username)
{
struct ast_variable *var;
struct ast_variable *tmp;
struct iax2_user *user=NULL;
var = ast_load_realtime("iaxfriends", "name", username);
if (var) {
/* Make sure it's not a user only... */
user = build_user(username, var);
if (user) {
/* Add some finishing touches, addresses, etc */
user->temponly = 1;
tmp = var;
while(tmp) {
if (!strcasecmp(tmp->name, "type")) {
if (strcasecmp(tmp->value, "friend") &&
strcasecmp(tmp->value, "user")) {
/* Whoops, we weren't supposed to exist! */
destroy_user(user);
user = NULL;
break;
}
}
tmp = tmp->next;
}
}
ast_destroy_realtime(var);
}
return user;
}
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)
{
@ -2160,10 +2103,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
p = p->next;
}
ast_mutex_unlock(&peerl.lock);
#ifdef MYSQL_FRIENDS
if (!p)
p = mysql_peer(peer);
#endif
p = realtime_peer(peer);
if (p) {
found++;
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;
} else {
if (p->temponly)
free(p);
destroy_peer(p);
p = NULL;
}
}
@ -2216,7 +2157,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
} else if (!p)
return -1;
if (p->temponly)
free(p);
destroy_peer(p);
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);
user = best;
#ifdef MYSQL_FRIENDS
if (!user && mysql && !ast_strlen_zero(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) {
user = mysql_user(iaxs[callno]->username);
if (!user && !ast_strlen_zero(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) {
user = realtime_user(iaxs[callno]->username);
if (user && !ast_strlen_zero(iaxs[callno]->context) && /* No context specified */
!apply_context(user->contexts, iaxs[callno]->context)) { /* Context is permitted */
if (user->contexts)
free(user->contexts);
free(user);
destroy_user(user);
user = NULL;
}
}
#endif
if (user) {
/* 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))
break;
ast_mutex_unlock(&peerl.lock);
#ifdef MYSQL_FRIENDS
if (!p)
p = mysql_peer(peer);
#endif
p = realtime_peer(peer);
if (!p) {
if (authdebug)
@ -3889,7 +3824,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
if (authdebug)
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)
free(p);
destroy_peer(p);
return -1;
}
@ -3897,7 +3832,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
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);
if (p->temponly)
free(p);
destroy_peer(p);
return -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)
ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
if (p->temponly)
free(p);
destroy_peer(p);
return -1;
}
} else {
if (authdebug)
ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
if (p->temponly)
free(p);
destroy_peer(p);
return -1;
}
} 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)
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)
free(p);
destroy_peer(p);
return -1;
} else
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)
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)
free(p);
destroy_peer(p);
return -1;
} else
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)
ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
if (p->temponly)
free(p);
destroy_peer(p);
return -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))
iaxs[callno]->expirey = expire;
if (p->temponly)
free(p);
destroy_peer(p);
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);
stringp = multi;
while((ext = strsep(&stringp, "&"))) {
if (onoff)
ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, type);
else
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);
} else
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;
}
}
#ifdef MYSQL_FRIENDS
if (!p)
p = mysql_peer(name);
#endif
p = realtime_peer(name);
if (p) {
#ifdef MYSQL_FRIENDS
if (p->temponly)
mysql_update_peer(name, sin);
#endif
realtime_update(name, sin);
if (inaddrcmp(&p->addr, sin)) {
if (iax2_regfunk)
iax2_regfunk(p->name, 1);
@ -4490,7 +4422,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
if (version)
iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
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);
}
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);
#ifdef MYSQL_FRIENDS
if (!p)
p = mysql_peer(name);
#endif
p = realtime_peer(name);
if (p) {
memset(&ied, 0, sizeof(ied));
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);
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);;
}
ast_log(LOG_WARNING, "No such peer '%s'\n", name);
@ -6375,7 +6305,7 @@ static int get_auth_methods(char *value)
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 *prev;
@ -6540,7 +6470,7 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
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_context *con, *conl = NULL;
@ -6702,6 +6632,13 @@ static void delete_users(void)
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)
{
struct iax2_user *user, *usernext, *userlast = NULL;
@ -6709,9 +6646,7 @@ static void prune_users(void)
for (user=userl.users;user;) {
usernext = user->next;
if (user->delme) {
ast_free_ha(user->ha);
free_context(user->contexts);
free(user);
destroy_user(user);
if (userlast)
userlast->next = usernext;
else
@ -6723,32 +6658,37 @@ static void prune_users(void)
ast_mutex_unlock(&userl.lock);
}
static void destroy_peer(struct iax2_peer *peer)
{
int x;
ast_free_ha(peer->ha);
for (x=0;x<IAX_MAX_CALLS;x++) {
ast_mutex_lock(&iaxsl[x]);
if (iaxs[x] && (iaxs[x]->peerpoke == peer)) {
iax2_destroy(x);
}
ast_mutex_unlock(&iaxsl[x]);
}
/* Delete it, it needs to disappear */
if (peer->expire > -1)
ast_sched_del(sched, peer->expire);
if (peer->pokeexpire > -1)
ast_sched_del(sched, peer->pokeexpire);
if (peer->callno > 0)
iax2_destroy(peer->callno);
register_peer_exten(peer, 0);
free(peer);
}
static void prune_peers(void){
/* Prune peers who still are supposed to be deleted */
struct iax2_peer *peer, *peerlast, *peernext;
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);
for (x=0;x<IAX_MAX_CALLS;x++) {
ast_mutex_lock(&iaxsl[x]);
if (iaxs[x] && (iaxs[x]->peerpoke == peer)) {
iax2_destroy(x);
}
ast_mutex_unlock(&iaxsl[x]);
}
/* Delete it, it needs to disappear */
if (peer->expire > -1)
ast_sched_del(sched, peer->expire);
if (peer->pokeexpire > -1)
ast_sched_del(sched, peer->pokeexpire);
if (peer->callno > 0)
iax2_destroy(peer->callno);
register_peer_exten(peer, 0);
free(peer);
destroy_peer(peer);
if (peerlast)
peerlast->next = peernext;
else
@ -6894,16 +6834,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
} else {
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")) {
strncpy(language, v->value, sizeof(language) - 1);
} //else if (strcasecmp(v->name,"type"))
@ -6943,21 +6873,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
}
ast_destroy(cfg);
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;
}

675
config.c
View File

@ -29,74 +29,45 @@
static int ast_cust_config=0;
struct ast_config *(*global_load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int
#ifdef PRESERVE_COMMENTS
,struct ast_comment_struct *
#endif
);
struct ast_config *(*global_load_func)(const char *dbname, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int);
static struct ast_config_map {
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);
static struct ast_config_reg *ast_cust_config_list;
static char *config_conf_file = "extconfig.conf";
static char *strip(char *buf)
void ast_destroy_realtime(struct ast_variable *v)
{
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;
}
#ifdef PRESERVE_COMMENTS
static void free_comments(struct ast_comment *com)
{
struct ast_comment *l;
while (com) {
l = com;
com = com->next;
free(l);
struct ast_variable *vn;
while(v) {
vn = v;
v = v->next;
free(vn);
}
}
#endif
void ast_destroy(struct ast_config *ast)
{
struct ast_category *cat, *catn;
struct ast_variable *v, *vn;
if (!ast)
return;
cat = ast->root;
while(cat) {
v = 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);
}
ast_destroy_realtime(cat->root);
catn = cat;
#ifdef PRESERVE_COMMENTS
free_comments(cat->precomments);
free_comments(cat->sameline);
#endif
cat = cat->next;
free(catn);
}
#ifdef PRESERVE_COMMENTS
free_comments(ast->trailingcomments);
#endif
free(ast);
}
@ -180,222 +151,6 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val
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)
{
struct ast_category *category = NULL;
@ -411,65 +166,73 @@ int ast_category_exist(struct ast_config *config, char *category_name)
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;
int len = strlen(cmt) + 1;
c = malloc(sizeof(struct ast_comment) + len);
if (c) {
/* Memset the header */
memset(c, 0, sizeof(struct ast_comment));
/* Copy the rest */
strcpy(c->cmt, cmt);
struct ast_config_reg *reg,*ret=NULL;
struct ast_config_map *map;
ast_mutex_lock(&ast_cust_config_lock);
map = maps;
while(map) {
if (!strcasecmp(name, map->name)) {
strncpy(database, map->database, dbsiz - 1);
if (map->table)
strncpy(table, map->table, tabsiz - 1);
else
strncpy(table, name, tabsiz - 1);
break;
}
map = map->next;
}
return c;
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
#ifdef PRESERVE_COMMENTS
, struct ast_comment_struct *acs
#endif
);
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);
}
static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel
#ifdef PRESERVE_COMMENTS
,struct ast_comment_struct *acs
#endif
)
static struct ast_config_reg *get_config_registrations(void)
{
return ast_cust_config_list;
}
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 *cur;
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;
#ifdef PRESERVE_COMMENTS
struct ast_comment *com = NULL;
#endif
int object;
/* Strip off lines using ; as comment */
c = strchr(buf, ';');
while (c) {
if ((c == buf) || (*(c-1) != '\\')) {
*c = '\0';
#ifdef PRESERVE_COMMENTS
c++;
if (*c != '!')
com = build_comment(c);
#endif
} else {
*(c-1) = ';';
memmove(c, c + 1, strlen(c + 1));
}
c = strchr(c + 1, ';');
}
cur = strip(buf);
cur = ast_strip(buf);
if (!ast_strlen_zero(cur)) {
/* Actually parse the entry */
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));
strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1);
(*_tmpc)->root = NULL;
#ifdef PRESERVE_COMMENTS
(*_tmpc)->precomments = acs->root;
(*_tmpc)->sameline = com;
#endif
if (!tmp->prev)
tmp->root = *_tmpc;
else
tmp->prev->next = *_tmpc;
tmp->prev = *_tmpc;
#ifdef PRESERVE_COMMENTS
acs->root = NULL;
acs->prev = NULL;
#endif
*_last = NULL;
} else {
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(arg && cur) {
load_func = NULL;
if(ast_cust_config_list)
reg = get_ast_cust_config(cur);
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
);
ast_log(LOG_WARNING, "Including files with explicit config engine no longer permitted. Please use extconfig.conf to specify all mappings\n");
} else {
__ast_load(cur, tmp, _tmpc, _last, includelevel + 1);
}
} else
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++;
} else
object = 0;
v = malloc(sizeof(struct ast_variable));
v = ast_new_variable(ast_strip(cur), ast_strip(c));
if (v) {
memset(v, 0, sizeof(struct ast_variable));
v->next = NULL;
v->name = strdup(strip(cur));
v->value = strdup(strip(c));
v->lineno = lineno;
v->object = object;
/* Put and reset comments */
#ifdef PRESERVE_COMMENTS
v->precomments = acs->root;
v->sameline = com;
acs->prev = NULL;
acs->root = NULL;
#endif
v->blanklines = 0;
if (*_last)
(*_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;
}
#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)
{
FILE *f;
@ -677,22 +380,10 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator)
fprintf(f, ";!\n");
cat = cfg->root;
while(cat) {
#ifdef PRESERVE_COMMENTS
/* Dump any precomments */
dump_comments(f, cat->precomments);
#endif
/* 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;
while(var) {
#ifdef PRESERVE_COMMENTS
dump_comments(f, var->precomments);
#endif
if (var->sameline)
fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
else
@ -713,9 +404,6 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator)
#endif
cat = cat->next;
}
#ifdef PRESERVE_COMMENTS
dump_comments(f, cfg->trailingcomments);
#endif
} else {
if (option_debug)
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;
}
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_comment_struct *acs
#endif
)
struct ast_variable *ast_load_realtime(const char *family, const char *keyfield, const char *lookup)
{
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 buf[8192];
char db[256];
char table[256];
FILE *f;
int lineno=0;
int master=0;
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_config *(*load_func)(const char *database, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int);
load_func=NULL;
if (strcmp(configfile,config_conf_file) && strcmp(configfile,"asterisk.conf") && ast_cust_config_list) {
if (global_load_func) {
load_func = global_load_func;
} else {
reg = get_ast_cust_config_keyword(configfile);
if (reg && reg->func) {
load_func = reg->func;
reg = get_ast_cust_config_keyword(configfile, db, sizeof(db), table, sizeof(table));
if (reg && reg->static_func) {
load_func = reg->static_func;
} else {
reg = get_ast_cust_config_keyword("global");
if (reg && reg->func)
global_load_func = load_func = reg->func;
reg = get_ast_cust_config_keyword(configfile, db, sizeof(db), table, sizeof(table));
if (reg && reg->static_func)
global_load_func = load_func = reg->static_func;
}
}
if (load_func) {
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
#ifdef PRESERVE_COMMENTS
,&acs
#endif
);
tmp = load_func(db, table, configfile,tmp, _tmpc, _last, includelevel);
if (tmp)
return tmp;
@ -802,11 +507,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
while(!feof(f)) {
lineno++;
if (fgets(buf, sizeof(buf), f)) {
if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel
#ifdef PRESERVE_COMMENTS
, acs
#endif
)) {
if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel)) {
fclose(f);
return NULL;
}
@ -819,65 +520,13 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
else if (option_verbose > 1)
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;
}
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)
{
struct ast_config_reg *ptr;
ast_mutex_lock(&ast_cust_config_lock);
new->keycount = 0;
if (!ast_cust_config_list) {
ast_cust_config_list = new;
} else {
@ -920,17 +569,7 @@ struct ast_config *ast_load(char *configfile)
struct ast_category *tmpc=NULL;
struct ast_variable *last = NULL;
#ifdef PRESERVE_COMMENTS
struct ast_comment_struct acs = { NULL, NULL };
#endif
return __ast_load(configfile, NULL, &tmpc, &last, 0
#ifdef PRESERVE_COMMENTS
,&acs
#endif
);
return __ast_load(configfile, NULL, &tmpc, &last, 0);
}
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 *variable;
variable = malloc(sizeof(struct ast_variable));
int length = strlen(name) + strlen(value) + 2 + sizeof(struct ast_variable);
variable = malloc(length);
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->name = malloc(strlen(name)+1);
if (variable->name) {
strcpy(variable->name,name);
variable->value = malloc(strlen(value)+1);
if (variable->value) {
strcpy(variable->value,value);
} else {
free(variable->name);
variable->name = NULL;
}
}
strcpy(variable->name,name);
strcpy(variable->value,value);
}
if (!variable->value) {
free(variable);
variable = NULL;
}
return variable;
}
@ -1030,29 +658,33 @@ int ast_cust_config_deregister(struct ast_config_reg *new)
static void clear_cust_keywords(void)
{
struct ast_config_reg *key;
int x;
struct ast_config_map *map, *prev;
ast_mutex_lock(&ast_cust_config_lock);
for (key=get_config_registrations();key;key=key->next) {
for (x=0;x<key->keycount;x++) {
key->keywords[x][0] = '\0';
}
key->keycount=0;
map = maps;
while(map) {
prev = map;
map = map->next;
free(prev);
}
maps = NULL;
ast_mutex_unlock(&ast_cust_config_lock);
}
static int config_command(int fd, int argc, char **argv)
{
struct ast_config_reg *key;
int x;
struct ast_config_map *map;
ast_cli(fd,"\n\n");
ast_mutex_lock(&ast_cust_config_lock);
for (key=get_config_registrations();key;key=key->next) {
ast_cli(fd,"\nConfig Engine: %s\n",key->name);
for (x=0;x<key->keycount;x++)
ast_cli(fd,"===>%s\n",key->keywords[x]);
map = maps;
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_cli(fd,"\n\n");
@ -1074,29 +706,46 @@ int read_ast_cust_config(void)
char *cfg = config_conf_file;
struct ast_config *config;
struct ast_variable *v;
struct ast_config_reg *ptr;
struct ast_config_reg *test = NULL;
struct ast_config_map *map;
int length;
char *driver, *table, *database, *stringp;
clear_cust_keywords();
config = ast_load(cfg);
if (config) {
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 (ptr) {
if (ptr->keycount >= CONFIG_KEYWORD_ARRAYLEN) {
ast_log(LOG_WARNING,"Max Number of Bindings exceeded for %s->%s %d/%d\n",v->name,v->value,ptr->keycount,CONFIG_KEYWORD_ARRAYLEN);
} else {
if (strcmp(v->name,config_conf_file) && strcmp(v->name,"asterisk.conf")) {
if (!(test = get_ast_cust_config_keyword(v->name))) {
ast_log(LOG_NOTICE,"Binding: %s to %s\n",v->name,v->value);
strncpy(ptr->keywords[ptr->keycount],v->name,sizeof(ptr->keywords[ptr->keycount]) - 1);
ptr->keywords[ptr->keycount][sizeof(ptr->keywords[ptr->keycount])-1] = '\0';
ptr->keycount++;
}
} else {
ast_log(LOG_WARNING,"Cannot bind %s, Permission Denied\n",v->name);
}
if (!strcmp(v->name,config_conf_file) || !strcmp(v->name,"asterisk.conf")) {
ast_log(LOG_WARNING, "Cannot bind asterisk.conf or extconfig.conf!\n");
} else if (driver && database) {
length = sizeof(struct ast_config_map);
length += strlen(v->name) + 1;
length += strlen(driver) + 1;
length += strlen(database) + 1;
if (table)
length += strlen(table) + 1;
map = malloc(length);
if (map) {
memset(map, 0, length);
map->name = map->stuff;
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]
;
; 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 *sameline;
struct ast_variable *next;
char stuff[0];
};
//! 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 */
int ast_category_exist(struct ast_config *config, char *category_name);
/* These are only in the config engine at this point */
struct ast_variable *ast_variable_append_modify(struct ast_config *cfg, char *category, char *variable, char *newvalue, int newcat, int newvar, int move);
//! Retrieve realtime configuration
/*!
* \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);
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);
//! Update realtime configuration
/*!
* \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)
}

View File

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

View File

@ -45,7 +45,7 @@ odbc_status odbc_obj_connect(odbc_obj *obj);
odbc_status odbc_obj_disconnect(odbc_obj *obj);
void destroy_obdc_obj(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);
#endif

View File

@ -26,6 +26,8 @@ struct ast_hostent {
char buf[1024];
};
extern char *ast_strip(char *buf);
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_base64decode(unsigned char *dst, char *src, int max);

View File

@ -1,9 +1,9 @@
/*
* 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 >
* Copyright (C) 2004 Anthony Minessale II <anthmct@yahoo.com>
@ -17,10 +17,12 @@
#include <asterisk/config_pvt.h>
#include <asterisk/module.h>
#include <asterisk/lock.h>
#include <asterisk/options.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <asterisk/res_odbc.h>
#include <asterisk/utils.h>
static char *tdesc = "ODBC Configuration";
static struct ast_config_reg reg1;
@ -29,18 +31,200 @@ STANDARD_LOCAL_USER;
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
#ifdef PRESERVE_COMMENTS
, struct ast_comment_struct *acs
#endif
)
static struct ast_variable *realtime_odbc(const char *database, const char *table, const char *keyfield, const char *lookup)
{
struct ast_config *config, *new;
struct ast_variable *v, *cur_v, *new_v;
odbc_obj *obj;
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;
char table[128] = "";
char connection[128] = "";
int configured = 0, res = 0;
int res = 0;
odbc_obj *obj;
SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0;
SQLBIGINT id;
@ -51,40 +235,16 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
int cat_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"))
return NULL; // cant configure myself with myself !
config = ast_load ("res_config_odbc.conf");
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);
obj = fetch_odbc_obj(database);
if (!obj)
return NULL;
last[0] = '\0';
res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
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, 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);
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;
}
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) {
res = SQLFetch (stmt);
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) {
if (!strcmp (var_name, "#include") && recur < MAX_INCLUDE_LEVEL) {
config_odbc (var_val, new, &cur_cat, &cur_v, recur + 1
#ifdef PRESERVE_COMMENTS
, acs
#endif
);
config_odbc(database, table, var_val, new, &cur_cat, &cur_v, recur + 1);
} else {
if (strcmp (last, category) || last_cat_metric != cat_metric) {
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)
{
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;
return 0;
}
@ -185,9 +355,12 @@ int load_module (void)
{
memset (&reg1, 0, sizeof (struct ast_config_reg));
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_log (LOG_NOTICE, "res_config_odbc loaded.\n");
if (option_verbose)
ast_verbose("res_config_odbc loaded.\n");
return 0;
}

View File

@ -1,9 +1,9 @@
/*
* 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>
* 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;
for (x = 0; x < MAX_ODBC_HANDLES; x++) {
@ -124,7 +124,7 @@ static int load_odbc_config(void)
password = v->value;
}
if (enabled && dsn && username && password) {
if (enabled && dsn) {
obj = new_odbc_obj(cat, dsn, username, password);
if (obj) {
register_odbc_obj(cat, obj);
@ -212,7 +212,7 @@ int register_odbc_obj(char *name, odbc_obj * obj)
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);
}
@ -233,18 +233,22 @@ odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password)
if (new->dsn == NULL)
return NULL;
new->username = malloc(strlen(username) + 1);
if (new->username == NULL)
return NULL;
if (username) {
new->username = malloc(strlen(username) + 1);
if (new->username == NULL)
return NULL;
strcpy(new->username, username);
}
new->password = malloc(strlen(password) + 1);
if (new->password == NULL)
return NULL;
if (password) {
new->password = malloc(strlen(password) + 1);
if (new->password == NULL)
return NULL;
strcpy(new->password, password);
}
strcpy(new->name, name);
strcpy(new->dsn, dsn);
strcpy(new->username, username);
strcpy(new->password, password);
new->up = 0;
ast_mutex_init(&new->lock);
return new;
@ -261,8 +265,10 @@ void destroy_obdc_obj(odbc_obj ** obj)
free((*obj)->name);
free((*obj)->dsn);
free((*obj)->username);
free((*obj)->password);
if ((*obj)->username)
free((*obj)->username);
if ((*obj)->password)
free((*obj)->password);
ast_mutex_unlock(&(*obj)->lock);
free(*obj);
}
@ -332,6 +338,7 @@ odbc_status odbc_obj_connect(odbc_obj * obj)
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,
(SQLCHAR *) obj->dsn, SQL_NTS,
(SQLCHAR *) obj->username, SQL_NTS,
@ -340,13 +347,11 @@ odbc_status odbc_obj_connect(odbc_obj * obj)
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
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;
} 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;
}

13
utils.c
View File

@ -28,6 +28,19 @@
static char base64[64];
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__)
/* duh? ERANGE value copied from web... */