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:
parent
1a2ba48fa1
commit
ebb18daf22
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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", ®seconds) != 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", ®seconds) != 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)
|
static void realtime_update(const char *peername, struct sockaddr_in *sin)
|
||||||
free(p->contexts);
|
{
|
||||||
free(p);
|
char port[10];
|
||||||
p = NULL;
|
char ipaddr[20];
|
||||||
} else {
|
char regseconds[20];
|
||||||
strncpy(p->name, user, sizeof(p->name) - 1);
|
time_t nowtime;
|
||||||
p->temponly = 1;
|
|
||||||
p->capability = iax2_capability;
|
time(&nowtime);
|
||||||
p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
|
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);
|
||||||
}
|
}
|
||||||
return p;
|
|
||||||
}
|
|
||||||
#endif /* MYSQL_FRIENDS */
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
673
config.c
673
config.c
|
@ -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) {
|
|
||||||
/* Memset the header */
|
|
||||||
memset(c, 0, sizeof(struct ast_comment));
|
|
||||||
/* Copy the rest */
|
|
||||||
strcpy(c->cmt, cmt);
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel
|
ast_mutex_lock(&ast_cust_config_lock);
|
||||||
#ifdef PRESERVE_COMMENTS
|
map = maps;
|
||||||
, struct ast_comment_struct *acs
|
while(map) {
|
||||||
#endif
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, 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 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 *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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[settings]
|
|
||||||
table => ast_config
|
|
||||||
connection => mysql1
|
|
|
@ -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.
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 (®1);
|
ast_cust_config_deregister (®1);
|
||||||
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 (®1, 0, sizeof (struct ast_config_reg));
|
memset (®1, 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 (®1);
|
ast_cust_config_register (®1);
|
||||||
ast_log (LOG_NOTICE, "res_config_odbc loaded.\n");
|
if (option_verbose)
|
||||||
|
ast_verbose("res_config_odbc loaded.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
13
utils.c
|
@ -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... */
|
||||||
|
|
Loading…
Reference in New Issue