diff --git a/apps/app_queue.c b/apps/app_queue.c index 24bea7492b..0febe56221 100755 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -730,6 +730,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser int numlines; int sentringing = 0; int numbusies = 0; + int numnochan = 0; int orig = *to; struct ast_frame *f; struct localuser *peer = NULL; @@ -754,7 +755,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser numlines++; } if (found < 0) { - if (numlines == numbusies) { + if (numlines == (numbusies + numnochan)) { ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); } else { ast_log(LOG_NOTICE, "No one is answering queue '%s'\n", queue); @@ -776,6 +777,77 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *allowdisconnect_out = o->allowdisconnect_out; } } else if (o->chan && (o->chan == winner)) { + if (!ast_strlen_zero(o->chan->call_forward)) { + char tmpchan[256]=""; + char *stuff; + char *tech; + strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1); + if ((stuff = strchr(tmpchan, '/'))) { + *stuff = '\0'; + stuff++; + tech = tmpchan; + } else { + snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); + stuff = tmpchan; + tech = "Local"; + } + /* Before processing channel, go ahead and check for forwarding */ + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); + /* Setup parameters */ + o->chan = ast_request(tech, in->nativeformats, stuff); + if (!o->chan) { + ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); + o->stillgoing = 0; + numnochan++; + } else { + if (o->chan->cid.cid_num) + free(o->chan->cid.cid_num); + o->chan->cid.cid_num = NULL; + if (o->chan->cid.cid_name) + free(o->chan->cid.cid_name); + o->chan->cid.cid_name = NULL; + + if (in->cid.cid_num) { + o->chan->cid.cid_num = strdup(in->cid.cid_num); + if (!o->chan->cid.cid_num) + ast_log(LOG_WARNING, "Out of memory\n"); + } + if (in->cid.cid_name) { + o->chan->cid.cid_name = strdup(in->cid.cid_name); + if (!o->chan->cid.cid_name) + ast_log(LOG_WARNING, "Out of memory\n"); + } + strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1); + o->chan->cdrflags = in->cdrflags; + + if (in->cid.cid_ani) { + if (o->chan->cid.cid_ani) + free(o->chan->cid.cid_ani); + o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1); + if (o->chan->cid.cid_ani) + strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1); + else + ast_log(LOG_WARNING, "Out of memory\n"); + } + if (o->chan->cid.cid_rdnis) + free(o->chan->cid.cid_rdnis); + if (!ast_strlen_zero(in->macroexten)) + o->chan->cid.cid_rdnis = strdup(in->macroexten); + else + o->chan->cid.cid_rdnis = strdup(in->exten); + if (ast_call(o->chan, tmpchan, 0)) { + ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); + o->stillgoing = 0; + ast_hangup(o->chan); + o->chan = NULL; + numnochan++; + } + } + /* Hangup the original channel now, in case we needed it */ + ast_hangup(winner); + continue; + } f = ast_read(winner); if (f) { if (f->frametype == AST_FRAME_CONTROL) { diff --git a/asterisk.c b/asterisk.c index cbf9ca0176..1a0a6dfe3a 100755 --- a/asterisk.c +++ b/asterisk.c @@ -1859,12 +1859,15 @@ int main(int argc, char *argv[]) printf(term_quit()); exit(1); } +#if 0 + /* This should no longer be necessary */ /* sync cust config and reload some internals in case a custom config handler binded to them */ read_ast_cust_config(); reload_logger(0); reload_manager(); ast_enum_reload(); ast_rtp_reload(); +#endif /* We might have the option of showing a console, but for now just diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index c495f53d9f..8024be534a 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -62,9 +62,6 @@ #include #endif /* __linux__ */ #endif -#ifdef MYSQL_FRIENDS -#include -#endif #include "iax2.h" #include "iax2-parser.h" #include "iax2-provision.h" @@ -99,14 +96,6 @@ /* Sample over last 100 units to determine historic jitter */ #define GAMMA (0.01) -#ifdef MYSQL_FRIENDS -AST_MUTEX_DEFINE_STATIC(mysqllock); -static MYSQL *mysql; -static char mydbuser[80]; -static char mydbpass[80]; -static char mydbhost[80]; -static char mydbname[80]; -#endif static char *desc = "Inter Asterisk eXchange (Ver 2)"; static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)"; static char *type = "IAX2"; @@ -1990,154 +1979,108 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha return 0; } -#ifdef MYSQL_FRIENDS +static struct iax2_peer *build_peer(const char *name, struct ast_variable *v); +static struct iax2_user *build_user(const char *name, struct ast_variable *v); -static void mysql_update_peer(char *peer, struct sockaddr_in *sin) -{ - if (mysql && (strlen(peer) < 128)) { - char query[512]; - char *name; - char iabuf[INET_ADDRSTRLEN]; - time_t nowtime; - name = alloca(strlen(peer) * 2 + 1); - time(&nowtime); - mysql_real_escape_string(mysql, name, peer, strlen(peer)); - snprintf(query, sizeof(query), "UPDATE iaxfriends SET ipaddr=\"%s\", port=\"%d\", regseconds=\"%ld\" WHERE name=\"%s\"", - ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), nowtime, name); - ast_mutex_lock(&mysqllock); - if (mysql_real_query(mysql, query, strlen(query))) - ast_log(LOG_WARNING, "Unable to update database\n"); - - ast_mutex_unlock(&mysqllock); - } -} +static void destroy_user(struct iax2_user *user); +static void destroy_peer(struct iax2_peer *peer); -static struct iax2_peer *mysql_peer(char *peer) +static struct iax2_peer *realtime_peer(const char *peername) { - struct iax2_peer *p; - int success = 0; - - p = malloc(sizeof(struct iax2_peer)); - memset(p, 0, sizeof(struct iax2_peer)); - if (mysql && (strlen(peer) < 128)) { - char query[512]; - char *name; - int numfields, x; - int port; - time_t regseconds, nowtime; - MYSQL_RES *result; - MYSQL_FIELD *fields; - MYSQL_ROW rowval; - name = alloca(strlen(peer) * 2 + 1); - mysql_real_escape_string(mysql, name, peer, strlen(peer)); - snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds FROM iaxfriends WHERE name=\"%s\"", name); - ast_mutex_lock(&mysqllock); - mysql_query(mysql, query); - if ((result = mysql_store_result(mysql))) { - if ((rowval = mysql_fetch_row(result))) { - numfields = mysql_num_fields(result); - fields = mysql_fetch_fields(result); - success = 1; - for (x=0;xsecret, rowval[x], sizeof(p->secret) - 1); - } else if (!strcasecmp(fields[x].name, "context")) { - strncpy(p->context, rowval[x], sizeof(p->context) - 1); - } else if (!strcasecmp(fields[x].name, "ipaddr")) { - inet_aton(rowval[x], &p->addr.sin_addr); - } else if (!strcasecmp(fields[x].name, "port")) { - if (sscanf(rowval[x], "%i", &port) != 1) - port = 0; - p->addr.sin_port = htons(port); - } else if (!strcasecmp(fields[x].name, "regseconds")) { - if (sscanf(rowval[x], "%li", ®seconds) != 1) - regseconds = 0; - } - } + struct ast_variable *var; + struct ast_variable *tmp; + struct iax2_peer *peer=NULL; + time_t regseconds, nowtime; + int dynamic=0; + var = ast_load_realtime("iaxfriends", "name", peername); + if (var) { + /* Make sure it's not a user only... */ + peer = build_peer(peername, var); + if (peer) { + /* Add some finishing touches, addresses, etc */ + peer->temponly = 1; + tmp = var; + while(tmp) { + if (!strcasecmp(tmp->name, "type")) { + if (strcasecmp(tmp->value, "friend") && + strcasecmp(tmp->value, "peer")) { + /* Whoops, we weren't supposed to exist! */ + destroy_peer(peer); + peer = NULL; + break; + } + } else if (!strcasecmp(tmp->name, "regseconds")) { + if (sscanf(tmp->value, "%li", ®seconds) != 1) + regseconds = 0; + } else if (!strcasecmp(tmp->name, "ipaddr")) { + inet_aton(tmp->value, &(peer->addr.sin_addr)); + } else if (!strcasecmp(tmp->name, "port")) { + peer->addr.sin_port = htons(atoi(tmp->value)); + } else if (!strcasecmp(tmp->name, "host")) { + if (!strcasecmp(tmp->value, "dynamic")) + dynamic = 1; } + tmp = tmp->next; + } + if (peer && dynamic) { time(&nowtime); - if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) - memset(&p->addr, 0, sizeof(p->addr)); - } - mysql_free_result(result); - result = NULL; - } - ast_mutex_unlock(&mysqllock); - } - if (!success) { - free(p); - p = NULL; - } else { - strncpy(p->name, peer, sizeof(p->name) - 1); - p->dynamic = 1; - p->temponly = 1; - p->expire = -1; - p->capability = iax2_capability; - p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT; - } - return p; -} -static struct iax2_user *mysql_user(char *user) -{ - struct iax2_user *p; - struct iax2_context *con; - int success = 0; - - p = malloc(sizeof(struct iax2_user)); - memset(p, 0, sizeof(struct iax2_user)); - con = malloc(sizeof(struct iax2_context)); - memset(con, 0, sizeof(struct iax2_context)); - strncpy(con->context, "default", sizeof(con->context) - 1); - p->contexts = con; - if (mysql && (strlen(user) < 128)) { - char query[512]; - char *name; - int numfields, x; - MYSQL_RES *result; - MYSQL_FIELD *fields; - MYSQL_ROW rowval; - name = alloca(strlen(user) * 2 + 1); - mysql_real_escape_string(mysql, name, user, strlen(user)); - snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds, accountcode FROM iaxfriends WHERE name=\"%s\"", name); - ast_mutex_lock(&mysqllock); - mysql_query(mysql, query); - if ((result = mysql_store_result(mysql))) { - if ((rowval = mysql_fetch_row(result))) { - numfields = mysql_num_fields(result); - fields = mysql_fetch_fields(result); - success = 1; - for (x=0;xsecret, rowval[x], sizeof(p->secret) - 1); - } else if (!strcasecmp(fields[x].name, "context")) { - strncpy(p->contexts->context, rowval[x], sizeof(p->contexts->context) - 1); - } else if (!strcasecmp(fields[x].name, "accountcode")) { - strncpy(p->accountcode, rowval[x], sizeof(p->accountcode) - 1); - } - } + if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) { + memset(&peer->addr, 0, sizeof(peer->addr)); + if (option_debug) + ast_log(LOG_DEBUG, "Bah, we're expired (%ld/%ld/%ld)!\n", nowtime - regseconds, regseconds, nowtime); } } - mysql_free_result(result); - result = NULL; } - ast_mutex_unlock(&mysqllock); + ast_destroy_realtime(var); } - if (!success) { - if (p->contexts) - free(p->contexts); - free(p); - p = NULL; - } else { - strncpy(p->name, user, sizeof(p->name) - 1); - p->temponly = 1; - p->capability = iax2_capability; - p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT; - } - return p; + return peer; } -#endif /* MYSQL_FRIENDS */ + +static struct iax2_user *realtime_user(const char *username) +{ + struct ast_variable *var; + struct ast_variable *tmp; + struct iax2_user *user=NULL; + var = ast_load_realtime("iaxfriends", "name", username); + if (var) { + /* Make sure it's not a user only... */ + user = build_user(username, var); + if (user) { + /* Add some finishing touches, addresses, etc */ + user->temponly = 1; + tmp = var; + while(tmp) { + if (!strcasecmp(tmp->name, "type")) { + if (strcasecmp(tmp->value, "friend") && + strcasecmp(tmp->value, "user")) { + /* Whoops, we weren't supposed to exist! */ + destroy_user(user); + user = NULL; + break; + } + } + tmp = tmp->next; + } + } + ast_destroy_realtime(var); + } + return user; +} + +static void realtime_update(const char *peername, struct sockaddr_in *sin) +{ + char port[10]; + char ipaddr[20]; + char regseconds[20]; + time_t nowtime; + + time(&nowtime); + snprintf(regseconds, sizeof(regseconds), "%ld", nowtime); + ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin->sin_addr); + snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port)); + ast_update_realtime("iaxfriends", "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, NULL); +} + static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk, int *notransfer, int *usejitterbuf, char *username, int usernlen, char *secret, int seclen, int *ofound, char *peercontext) { @@ -2160,10 +2103,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i p = p->next; } ast_mutex_unlock(&peerl.lock); -#ifdef MYSQL_FRIENDS if (!p) - p = mysql_peer(peer); -#endif + p = realtime_peer(peer); if (p) { found++; if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && @@ -2197,7 +2138,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i *usejitterbuf=p->usejitterbuf; } else { if (p->temponly) - free(p); + destroy_peer(p); p = NULL; } } @@ -2216,7 +2157,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i } else if (!p) return -1; if (p->temponly) - free(p); + destroy_peer(p); return 0; } @@ -3691,18 +3632,14 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies } ast_mutex_unlock(&userl.lock); user = best; -#ifdef MYSQL_FRIENDS - if (!user && mysql && !ast_strlen_zero(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) { - user = mysql_user(iaxs[callno]->username); + if (!user && !ast_strlen_zero(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) { + user = realtime_user(iaxs[callno]->username); if (user && !ast_strlen_zero(iaxs[callno]->context) && /* No context specified */ !apply_context(user->contexts, iaxs[callno]->context)) { /* Context is permitted */ - if (user->contexts) - free(user->contexts); - free(user); + destroy_user(user); user = NULL; } } -#endif if (user) { /* We found our match (use the first) */ @@ -3874,10 +3811,8 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (!strcasecmp(p->name, peer)) break; ast_mutex_unlock(&peerl.lock); -#ifdef MYSQL_FRIENDS if (!p) - p = mysql_peer(peer); -#endif + p = realtime_peer(peer); if (!p) { if (authdebug) @@ -3889,7 +3824,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (authdebug) ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr)); if (p->temponly) - free(p); + destroy_peer(p); return -1; } @@ -3897,7 +3832,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (authdebug) ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name); if (p->temponly) - free(p); + destroy_peer(p); return -1; } strncpy(iaxs[callno]->secret, p->secret, sizeof(iaxs[callno]->secret)-1); @@ -3923,14 +3858,14 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (authdebug) ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys); if (p->temponly) - free(p); + destroy_peer(p); return -1; } } else { if (authdebug) ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer); if (p->temponly) - free(p); + destroy_peer(p); return -1; } } else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) { @@ -3939,7 +3874,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (authdebug) ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name); if (p->temponly) - free(p); + destroy_peer(p); return -1; } else iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; @@ -3956,7 +3891,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (authdebug) ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name, requeststr, md5secret); if (p->temponly) - free(p); + destroy_peer(p); return -1; } else iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; @@ -3964,7 +3899,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (authdebug) ast_log(LOG_NOTICE, "Inappropriate authentication received\n"); if (p->temponly) - free(p); + destroy_peer(p); return -1; } strncpy(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer)-1); @@ -3972,7 +3907,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies * if (expire && (expire < iaxs[callno]->expirey)) iaxs[callno]->expirey = expire; if (p->temponly) - free(p); + destroy_peer(p); return 0; } @@ -4342,9 +4277,10 @@ static void register_peer_exten(struct iax2_peer *peer, int onoff) strncpy(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi) - 1); stringp = multi; while((ext = strsep(&stringp, "&"))) { - if (onoff) - ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, type); - else + if (onoff) { + if (!ast_exists_extension(NULL, regcontext, ext, 1, NULL)) + ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, type); + } else ast_context_remove_extension(regcontext, ext, 1, NULL); } } @@ -4422,15 +4358,11 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char break; } } -#ifdef MYSQL_FRIENDS if (!p) - p = mysql_peer(name); -#endif + p = realtime_peer(name); if (p) { -#ifdef MYSQL_FRIENDS if (p->temponly) - mysql_update_peer(name, sin); -#endif + realtime_update(name, sin); if (inaddrcmp(&p->addr, sin)) { if (iax2_regfunk) iax2_regfunk(p->name, 1); @@ -4490,7 +4422,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char if (version) iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version); if (p->temponly) - free(p); + destroy_peer(p); return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1); } ast_log(LOG_WARNING, "No such peer '%s'\n", name); @@ -4508,10 +4440,8 @@ static int registry_authrequest(char *name, int callno) } } ast_mutex_unlock(&peerl.lock); -#ifdef MYSQL_FRIENDS if (!p) - p = mysql_peer(name); -#endif + p = realtime_peer(name); if (p) { memset(&ied, 0, sizeof(ied)); iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods); @@ -4522,7 +4452,7 @@ static int registry_authrequest(char *name, int callno) } iax_ie_append_str(&ied, IAX_IE_USERNAME, name); if (p->temponly) - free(p); + destroy_peer(p); return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);; } ast_log(LOG_WARNING, "No such peer '%s'\n", name); @@ -6375,7 +6305,7 @@ static int get_auth_methods(char *value) return methods; } -static struct iax2_peer *build_peer(char *name, struct ast_variable *v) +static struct iax2_peer *build_peer(const char *name, struct ast_variable *v) { struct iax2_peer *peer; struct iax2_peer *prev; @@ -6540,7 +6470,7 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v) return peer; } -static struct iax2_user *build_user(char *name, struct ast_variable *v) +static struct iax2_user *build_user(const char *name, struct ast_variable *v) { struct iax2_user *prev, *user; struct iax2_context *con, *conl = NULL; @@ -6702,6 +6632,13 @@ static void delete_users(void) ast_mutex_unlock(&peerl.lock); } +static void destroy_user(struct iax2_user *user) +{ + ast_free_ha(user->ha); + free_context(user->contexts); + free(user); +} + static void prune_users(void) { struct iax2_user *user, *usernext, *userlast = NULL; @@ -6709,9 +6646,7 @@ static void prune_users(void) for (user=userl.users;user;) { usernext = user->next; if (user->delme) { - ast_free_ha(user->ha); - free_context(user->contexts); - free(user); + destroy_user(user); if (userlast) userlast->next = usernext; else @@ -6723,32 +6658,37 @@ static void prune_users(void) ast_mutex_unlock(&userl.lock); } +static void destroy_peer(struct iax2_peer *peer) +{ + int x; + ast_free_ha(peer->ha); + for (x=0;xpeerpoke == peer)) { + iax2_destroy(x); + } + ast_mutex_unlock(&iaxsl[x]); + } + /* Delete it, it needs to disappear */ + if (peer->expire > -1) + ast_sched_del(sched, peer->expire); + if (peer->pokeexpire > -1) + ast_sched_del(sched, peer->pokeexpire); + if (peer->callno > 0) + iax2_destroy(peer->callno); + register_peer_exten(peer, 0); + free(peer); +} + static void prune_peers(void){ /* Prune peers who still are supposed to be deleted */ struct iax2_peer *peer, *peerlast, *peernext; - int x; ast_mutex_lock(&peerl.lock); peerlast = NULL; for (peer=peerl.peers;peer;) { peernext = peer->next; if (peer->delme) { - ast_free_ha(peer->ha); - for (x=0;xpeerpoke == peer)) { - iax2_destroy(x); - } - ast_mutex_unlock(&iaxsl[x]); - } - /* Delete it, it needs to disappear */ - if (peer->expire > -1) - ast_sched_del(sched, peer->expire); - if (peer->pokeexpire > -1) - ast_sched_del(sched, peer->pokeexpire); - if (peer->callno > 0) - iax2_destroy(peer->callno); - register_peer_exten(peer, 0); - free(peer); + destroy_peer(peer); if (peerlast) peerlast->next = peernext; else @@ -6894,16 +6834,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin){ } else { amaflags = format; } -#ifdef MYSQL_FRIENDS - } else if (!strcasecmp(v->name, "dbuser")) { - strncpy(mydbuser, v->value, sizeof(mydbuser) - 1); - } else if (!strcasecmp(v->name, "dbpass")) { - strncpy(mydbpass, v->value, sizeof(mydbpass) - 1); - } else if (!strcasecmp(v->name, "dbhost")) { - strncpy(mydbhost, v->value, sizeof(mydbhost) - 1); - } else if (!strcasecmp(v->name, "dbname")) { - strncpy(mydbname, v->value, sizeof(mydbname) - 1); -#endif } else if (!strcasecmp(v->name, "language")) { strncpy(language, v->value, sizeof(language) - 1); } //else if (strcasecmp(v->name,"type")) @@ -6943,21 +6873,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin){ } ast_destroy(cfg); set_timing(); -#ifdef MYSQL_FRIENDS - /* Connect to db if appropriate */ - if (!mysql && !ast_strlen_zero(mydbname)) { - mysql = mysql_init(NULL); - if (!mysql_real_connect(mysql, mydbhost[0] ? mydbhost : NULL, mydbuser, mydbpass, mydbname, 0, NULL, 0)) { - memset(mydbpass, '*', strlen(mydbpass)); - ast_log(LOG_WARNING, "Database connection failed (db=%s, host=%s, user=%s, pass=%s)!\n", - mydbname, mydbhost, mydbuser, mydbpass); - free(mysql); - mysql = NULL; - } else - ast_verbose(VERBOSE_PREFIX_1 "Connected to database '%s' on '%s' as '%s'\n", - mydbname, mydbhost, mydbuser); - } -#endif return capability; } diff --git a/config.c b/config.c index bc9de3018a..5c972298a2 100755 --- a/config.c +++ b/config.c @@ -29,74 +29,45 @@ static int ast_cust_config=0; -struct ast_config *(*global_load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int -#ifdef PRESERVE_COMMENTS -,struct ast_comment_struct * -#endif -); +struct ast_config *(*global_load_func)(const char *dbname, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int); + +static struct ast_config_map { + struct ast_config_map *next; + char *name; + char *driver; + char *database; + char *table; + char stuff[0]; +} *maps = NULL; AST_MUTEX_DEFINE_STATIC(ast_cust_config_lock); static struct ast_config_reg *ast_cust_config_list; static char *config_conf_file = "extconfig.conf"; -static char *strip(char *buf) +void ast_destroy_realtime(struct ast_variable *v) { - char *start; - /* Strip off trailing whitespace, returns, etc */ - while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33)) - buf[strlen(buf)-1] = '\0'; - start = buf; - /* Strip off leading whitespace, returns, etc */ - while (*start && (*start < 33)) - *start++ = '\0'; - return start; -} - -#ifdef PRESERVE_COMMENTS -static void free_comments(struct ast_comment *com) -{ - struct ast_comment *l; - while (com) { - l = com; - com = com->next; - free(l); + struct ast_variable *vn; + while(v) { + vn = v; + v = v->next; + free(vn); } } -#endif void ast_destroy(struct ast_config *ast) { struct ast_category *cat, *catn; - struct ast_variable *v, *vn; if (!ast) return; cat = ast->root; while(cat) { - v = cat->root; - while(v) { - vn = v; - free(v->name); - free(v->value); -#ifdef PRESERVE_COMMENTS - free_comments(v->precomments); - free_comments(v->sameline); -#endif - v = v->next; - free(vn); - } + ast_destroy_realtime(cat->root); catn = cat; -#ifdef PRESERVE_COMMENTS - free_comments(cat->precomments); - free_comments(cat->sameline); -#endif cat = cat->next; free(catn); } -#ifdef PRESERVE_COMMENTS - free_comments(ast->trailingcomments); -#endif free(ast); } @@ -180,222 +151,6 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val return NULL; } -#ifdef PRESERVE_COMMENTS -int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value) -{ - struct ast_variable *v, *pv, *bv, *bpv; - struct ast_category *cat; - cat = cfg->root; - while(cat) { - if (cat->name == category) { - break; - } - cat = cat->next; - } - if (!cat) { - cat = cfg->root; - while(cat) { - if (!strcasecmp(cat->name, category)) { - break; - } - cat = cat->next; - } - } - if (!cat) - return -1; - v = cat->root; - pv = NULL; - while (v) { - if ((variable == v->name) && (!value || !strcmp(v->value, value))) - break; - pv = v; - v=v->next; - } - if (!v) { - /* Get the last one that looks like it */ - bv = NULL; - bpv = NULL; - v = cat->root; - pv = NULL; - while (v) { - if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) { - bv = v; - bpv = pv; - } - pv = v; - v=v->next; - } - v = bv; - } - - if (v) { - /* Unlink from original position */ - if (pv) - pv->next = v->next; - else - cat->root = v->next; - v->next = NULL; - free(v->name); - if (v->value) - free(v->value); - free_comments(v->sameline); - free_comments(v->precomments); - return 0; - } - return -1; -} - -int ast_category_delete(struct ast_config *cfg, char *category) -{ - struct ast_variable *v, *pv; - struct ast_category *cat, *cprev; - cat = cfg->root; - cprev = NULL; - while(cat) { - if (cat->name == category) { - break; - } - cprev = cat; - cat = cat->next; - } - if (!cat) { - cat = cfg->root; - cprev = NULL; - while(cat) { - if (!strcasecmp(cat->name, category)) { - break; - } - cprev = cat; - cat = cat->next; - } - } - if (!cat) - return -1; - /* Unlink it */ - if (cprev) - cprev->next = cat->next; - else - cfg->root = cat->next; - v = cat->root; - while (v) { - pv = v; - v=v->next; - if (pv->value) - free(pv->value); - if (pv->name) - free(pv->name); - free_comments(pv->sameline); - free_comments(pv->precomments); - free(pv); - } - free_comments(cat->sameline); - free_comments(cat->precomments); - free(cat); - return 0; -} - -struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move) -{ - struct ast_variable *v, *pv=NULL, *bv, *bpv; - struct ast_category *cat, *pcat; - cat = config->root; - if (!newcat) { - while(cat) { - if (cat->name == category) { - break; - } - cat = cat->next; - } - if (!cat) { - cat = config->root; - while(cat) { - if (!strcasecmp(cat->name, category)) { - break; - } - cat = cat->next; - } - } - } - if (!cat) { - cat = malloc(sizeof(struct ast_category)); - if (!cat) - return NULL; - memset(cat, 0, sizeof(struct ast_category)); - strncpy(cat->name, category, sizeof(cat->name) - 1); - if (config->root) { - /* Put us at the end */ - pcat = config->root; - while(pcat->next) - pcat = pcat->next; - pcat->next = cat; - } else { - /* We're the first one */ - config->root = cat; - } - - } - if (!newvar) { - v = cat->root; - pv = NULL; - while (v) { - if (variable == v->name) - break; - pv = v; - v=v->next; - } - if (!v) { - /* Get the last one that looks like it */ - bv = NULL; - bpv = NULL; - v = cat->root; - pv = NULL; - while (v) { - if (!strcasecmp(variable, v->name)) { - bv = v; - bpv = pv; - } - pv = v; - v=v->next; - } - v = bv; - } - } else v = NULL; - if (v && move) { - /* Unlink from original position */ - if (pv) - pv->next = v->next; - else - cat->root = v->next; - v->next = NULL; - } - if (!v) { - v = malloc(sizeof(struct ast_variable)); - if (!v) - return NULL; - memset(v, 0, sizeof(struct ast_variable)); - v->name = strdup(variable); - move = 1; - } - if (v->value) - free(v->value); - if (value) - v->value = strdup(value); - else - v->value = strdup(""); - if (move) { - if (cat->root) { - pv = cat->root; - while (pv->next) - pv = pv->next; - pv->next = v; - } else { - cat->root = v; - } - } - return v; -} -#endif - int ast_category_exist(struct ast_config *config, char *category_name) { struct ast_category *category = NULL; @@ -411,65 +166,73 @@ int ast_category_exist(struct ast_config *config, char *category_name) return 0; } -#ifdef PRESERVE_COMMENTS -static struct ast_comment *build_comment(char *cmt) + +static struct ast_config_reg *get_ast_cust_config_keyword(const char *name, char *database, int dbsiz, char *table, int tabsiz) { - struct ast_comment *c; - int len = strlen(cmt) + 1; - c = malloc(sizeof(struct ast_comment) + len); - if (c) { - /* Memset the header */ - memset(c, 0, sizeof(struct ast_comment)); - /* Copy the rest */ - strcpy(c->cmt, cmt); + struct ast_config_reg *reg,*ret=NULL; + struct ast_config_map *map; + + ast_mutex_lock(&ast_cust_config_lock); + map = maps; + while(map) { + if (!strcasecmp(name, map->name)) { + strncpy(database, map->database, dbsiz - 1); + if (map->table) + strncpy(table, map->table, tabsiz - 1); + else + strncpy(table, name, tabsiz - 1); + break; + } + map = map->next; } - return c; + if (map) { + for (reg=ast_cust_config_list;reg && !ret;reg=reg->next) { + if (!strcmp(reg->name,map->driver)) + ret=reg; + } + } + ast_mutex_unlock(&ast_cust_config_lock); + return ret; } -#endif -static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel -#ifdef PRESERVE_COMMENTS -, struct ast_comment_struct *acs -#endif -); +void ast_config_destroy_all(void) +{ + struct ast_config_reg *key; + ast_mutex_lock(&ast_cust_config_lock); + for (key=ast_cust_config_list;key;key=key->next) { + ast_config_deregister(key); + } + ast_cust_config_list = NULL; + ast_mutex_unlock(&ast_cust_config_lock); +} -static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel -#ifdef PRESERVE_COMMENTS -,struct ast_comment_struct *acs -#endif -) +static struct ast_config_reg *get_config_registrations(void) +{ + return ast_cust_config_list; +} + + +static struct ast_config *__ast_load(const char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel); + +static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, const char *configfile, int includelevel ) { char *c; char *cur; char *arg=NULL; - struct ast_config_reg *reg=NULL; - struct ast_config *(*load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int -#ifdef PRESERVE_COMMENTS -,struct ast_comment_struct * -#endif - ); struct ast_variable *v; -#ifdef PRESERVE_COMMENTS - struct ast_comment *com = NULL; -#endif int object; /* Strip off lines using ; as comment */ c = strchr(buf, ';'); while (c) { if ((c == buf) || (*(c-1) != '\\')) { *c = '\0'; -#ifdef PRESERVE_COMMENTS - c++; - if (*c != '!') - com = build_comment(c); -#endif } else { *(c-1) = ';'; memmove(c, c + 1, strlen(c + 1)); } c = strchr(c + 1, ';'); } - cur = strip(buf); + cur = ast_strip(buf); if (!ast_strlen_zero(cur)) { /* Actually parse the entry */ if (cur[0] == '[') { @@ -487,20 +250,12 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru memset(*_tmpc, 0, sizeof(struct ast_category)); strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1); (*_tmpc)->root = NULL; -#ifdef PRESERVE_COMMENTS - (*_tmpc)->precomments = acs->root; - (*_tmpc)->sameline = com; -#endif if (!tmp->prev) tmp->root = *_tmpc; else tmp->prev->next = *_tmpc; tmp->prev = *_tmpc; -#ifdef PRESERVE_COMMENTS - acs->root = NULL; - acs->prev = NULL; -#endif *_last = NULL; } else { ast_log(LOG_WARNING, @@ -542,28 +297,9 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru if (includelevel < MAX_INCLUDE_LEVEL) { if(arg && cur) { - load_func = NULL; - if(ast_cust_config_list) - reg = get_ast_cust_config(cur); - if(reg && reg->func) - load_func = reg->func; - if(load_func) { - ast_log(LOG_NOTICE,"External Include '%s' via '%s' config engine\n",arg,cur); - load_func(arg,tmp, _tmpc, _last, includelevel -#ifdef PRESERVE_COMMENTS - ,&acs -#endif - ); - } - else - ast_log(LOG_WARNING,"Cant Find Registered Config Engine [%s] for [%s]\n",cur,arg); - } - else { - __ast_load(cur, tmp, _tmpc, _last, includelevel + 1 -#ifdef PRESERVE_COMMENTS - ,acs -#endif - ); + ast_log(LOG_WARNING, "Including files with explicit config engine no longer permitted. Please use extconfig.conf to specify all mappings\n"); + } else { + __ast_load(cur, tmp, _tmpc, _last, includelevel + 1); } } else ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel); @@ -591,21 +327,12 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru c++; } else object = 0; - v = malloc(sizeof(struct ast_variable)); + v = ast_new_variable(ast_strip(cur), ast_strip(c)); if (v) { - memset(v, 0, sizeof(struct ast_variable)); v->next = NULL; - v->name = strdup(strip(cur)); - v->value = strdup(strip(c)); v->lineno = lineno; v->object = object; /* Put and reset comments */ -#ifdef PRESERVE_COMMENTS - v->precomments = acs->root; - v->sameline = com; - acs->prev = NULL; - acs->root = NULL; -#endif v->blanklines = 0; if (*_last) (*_last)->next = v; @@ -622,34 +349,10 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru } } - } else { - /* store any comments if there are any */ -#ifdef PRESERVE_COMMENTS - if (com) { - if (acs->prev) - acs->prev->next = com; - else - acs->root = com; - acs->prev = com; - } else { - if (*_last) - (*_last)->blanklines++; - } -#endif } return 0; } -#ifdef PRESERVE_COMMENTS -static void dump_comments(FILE *f, struct ast_comment *comment) -{ - while (comment) { - fprintf(f, ";%s", comment->cmt); - comment = comment->next; - } -} -#endif - int ast_save(char *configfile, struct ast_config *cfg, char *generator) { FILE *f; @@ -677,22 +380,10 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator) fprintf(f, ";!\n"); cat = cfg->root; while(cat) { -#ifdef PRESERVE_COMMENTS - /* Dump any precomments */ - dump_comments(f, cat->precomments); -#endif /* Dump section with any appropriate comment */ -#ifdef PRESERVE_COMMENTS - if (cat->sameline) - fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->cmt); - else -#endif - fprintf(f, "[%s]\n", cat->name); + fprintf(f, "[%s]\n", cat->name); var = cat->root; while(var) { -#ifdef PRESERVE_COMMENTS - dump_comments(f, var->precomments); -#endif if (var->sameline) fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt); else @@ -713,9 +404,6 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator) #endif cat = cat->next; } -#ifdef PRESERVE_COMMENTS - dump_comments(f, cfg->trailingcomments); -#endif } else { if (option_debug) printf("Unable to open for writing: %s\n", fn); @@ -727,46 +415,63 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator) return 0; } -static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel -#ifdef PRESERVE_COMMENTS -, struct ast_comment_struct *acs -#endif -) + +struct ast_variable *ast_load_realtime(const char *family, const char *keyfield, const char *lookup) +{ + struct ast_config_reg *reg; + char db[256]=""; + char table[256]=""; + reg = get_ast_cust_config_keyword(family, db, sizeof(db), table, sizeof(table)); + if (reg && reg->realtime_func) + return reg->realtime_func(db, table, keyfield, lookup); + return NULL; +} + +int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...) +{ + struct ast_config_reg *reg; + int res = -1; + char db[256]=""; + char table[256]=""; + va_list ap; + va_start(ap, lookup); + reg = get_ast_cust_config_keyword(family, db, sizeof(db), table, sizeof(table)); + if (reg && reg->update_func) + res = reg->update_func(db, table, keyfield, lookup, ap); + va_end(ap); + return res; +} + +static struct ast_config *__ast_load(const char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel) { char fn[256]; char buf[8192]; + char db[256]; + char table[256]; FILE *f; int lineno=0; int master=0; struct ast_config_reg *reg=NULL; - struct ast_config *(*load_func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int -#ifdef PRESERVE_COMMENTS -,struct ast_comment_struct * -#endif -); + struct ast_config *(*load_func)(const char *database, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int); load_func=NULL; if (strcmp(configfile,config_conf_file) && strcmp(configfile,"asterisk.conf") && ast_cust_config_list) { if (global_load_func) { load_func = global_load_func; } else { - reg = get_ast_cust_config_keyword(configfile); - if (reg && reg->func) { - load_func = reg->func; + reg = get_ast_cust_config_keyword(configfile, db, sizeof(db), table, sizeof(table)); + if (reg && reg->static_func) { + load_func = reg->static_func; } else { - reg = get_ast_cust_config_keyword("global"); - if (reg && reg->func) - global_load_func = load_func = reg->func; + reg = get_ast_cust_config_keyword(configfile, db, sizeof(db), table, sizeof(table)); + if (reg && reg->static_func) + global_load_func = load_func = reg->static_func; } } if (load_func) { ast_log(LOG_NOTICE,"Loading Config %s via %s engine\n",configfile,reg && reg->name ? reg->name : "global"); - tmp = load_func(configfile,tmp, _tmpc, _last, includelevel -#ifdef PRESERVE_COMMENTS -,&acs -#endif -); + tmp = load_func(db, table, configfile,tmp, _tmpc, _last, includelevel); if (tmp) return tmp; @@ -802,11 +507,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s while(!feof(f)) { lineno++; if (fgets(buf, sizeof(buf), f)) { - if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel -#ifdef PRESERVE_COMMENTS - , acs -#endif - )) { + if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel)) { fclose(f); return NULL; } @@ -819,65 +520,13 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s else if (option_verbose > 1) ast_verbose( "Not found (%s)\n", strerror(errno)); } -#ifdef PRESERVE_COMMENTS - if (master) { - /* Keep trailing comments */ - tmp->trailingcomments = acs->root; - acs->root = NULL; - acs->prev = NULL; - } -#endif return tmp; } -struct ast_config_reg *get_ast_cust_config_keyword(char *name) -{ - struct ast_config_reg *reg,*ret=NULL; - int x=0; - ast_mutex_lock(&ast_cust_config_lock); - for (reg=ast_cust_config_list;reg && !ret;reg=reg->next) { - for (x=0;xkeycount && !ret ;x++) { - if (!strcmp(reg->keywords[x],name)) - ret=reg; - } - } - ast_mutex_unlock(&ast_cust_config_lock); - return ret; -} - -struct ast_config_reg *get_ast_cust_config(char *name) -{ - struct ast_config_reg *ptr=NULL; - ast_mutex_lock(&ast_cust_config_lock); - for (ptr=ast_cust_config_list;ptr;ptr=ptr->next) { - if (!strcmp(name,ptr->name)) - break; - } - ast_mutex_unlock(&ast_cust_config_lock); - return ptr; -} - -void ast_config_destroy_all(void) -{ - struct ast_config_reg *key; - ast_mutex_lock(&ast_cust_config_lock); - for (key=ast_cust_config_list;key;key=key->next) { - ast_config_deregister(key); - } - ast_cust_config_list = NULL; - ast_mutex_unlock(&ast_cust_config_lock); -} - -struct ast_config_reg *get_config_registrations(void) -{ - return ast_cust_config_list; -} - int ast_config_register(struct ast_config_reg *new) { struct ast_config_reg *ptr; ast_mutex_lock(&ast_cust_config_lock); - new->keycount = 0; if (!ast_cust_config_list) { ast_cust_config_list = new; } else { @@ -920,17 +569,7 @@ struct ast_config *ast_load(char *configfile) struct ast_category *tmpc=NULL; struct ast_variable *last = NULL; - -#ifdef PRESERVE_COMMENTS - struct ast_comment_struct acs = { NULL, NULL }; -#endif - - - return __ast_load(configfile, NULL, &tmpc, &last, 0 -#ifdef PRESERVE_COMMENTS - ,&acs -#endif - ); + return __ast_load(configfile, NULL, &tmpc, &last, 0); } char *ast_category_browse(struct ast_config *config, char *prev) @@ -991,27 +630,16 @@ struct ast_category *ast_new_category(char *name) struct ast_variable *ast_new_variable(char *name, char *value) { struct ast_variable *variable; - variable = malloc(sizeof(struct ast_variable)); + int length = strlen(name) + strlen(value) + 2 + sizeof(struct ast_variable); + variable = malloc(length); if (variable) { - memset(variable,0,sizeof(struct ast_variable)); + memset(variable, 0, length); + variable->name = variable->stuff; + variable->value = variable->stuff + strlen(name) + 1; variable->object=0; - variable->name = malloc(strlen(name)+1); - if (variable->name) { - strcpy(variable->name,name); - variable->value = malloc(strlen(value)+1); - if (variable->value) { - strcpy(variable->value,value); - } else { - free(variable->name); - variable->name = NULL; - } - } + strcpy(variable->name,name); + strcpy(variable->value,value); } - if (!variable->value) { - free(variable); - variable = NULL; - } - return variable; } @@ -1030,29 +658,33 @@ int ast_cust_config_deregister(struct ast_config_reg *new) static void clear_cust_keywords(void) { - struct ast_config_reg *key; - int x; + struct ast_config_map *map, *prev; ast_mutex_lock(&ast_cust_config_lock); - for (key=get_config_registrations();key;key=key->next) { - for (x=0;xkeycount;x++) { - key->keywords[x][0] = '\0'; - } - key->keycount=0; + map = maps; + while(map) { + prev = map; + map = map->next; + free(prev); } + maps = NULL; ast_mutex_unlock(&ast_cust_config_lock); } static int config_command(int fd, int argc, char **argv) { struct ast_config_reg *key; - int x; + struct ast_config_map *map; ast_cli(fd,"\n\n"); ast_mutex_lock(&ast_cust_config_lock); for (key=get_config_registrations();key;key=key->next) { ast_cli(fd,"\nConfig Engine: %s\n",key->name); - for (x=0;xkeycount;x++) - ast_cli(fd,"===>%s\n",key->keywords[x]); + map = maps; + while(map) { + if (!strcasecmp(map->driver, key->name)) + ast_cli(fd,"===> %s (db=%s, table=%s)\n",map->name, map->database, map->table ? map->table : map->name); + map = map->next; + } } ast_mutex_unlock(&ast_cust_config_lock); ast_cli(fd,"\n\n"); @@ -1074,29 +706,46 @@ int read_ast_cust_config(void) char *cfg = config_conf_file; struct ast_config *config; struct ast_variable *v; - struct ast_config_reg *ptr; - struct ast_config_reg *test = NULL; + struct ast_config_map *map; + int length; + char *driver, *table, *database, *stringp; clear_cust_keywords(); config = ast_load(cfg); if (config) { for (v = ast_variable_browse(config,"settings");v;v=v->next) { + stringp = v->value; + driver = strsep(&stringp, ","); + database = strsep(&stringp, ","); + table = strsep(&stringp, ","); - ptr = get_ast_cust_config(v->value); - if (ptr) { - if (ptr->keycount >= CONFIG_KEYWORD_ARRAYLEN) { - ast_log(LOG_WARNING,"Max Number of Bindings exceeded for %s->%s %d/%d\n",v->name,v->value,ptr->keycount,CONFIG_KEYWORD_ARRAYLEN); - } else { - if (strcmp(v->name,config_conf_file) && strcmp(v->name,"asterisk.conf")) { - if (!(test = get_ast_cust_config_keyword(v->name))) { - ast_log(LOG_NOTICE,"Binding: %s to %s\n",v->name,v->value); - strncpy(ptr->keywords[ptr->keycount],v->name,sizeof(ptr->keywords[ptr->keycount]) - 1); - ptr->keywords[ptr->keycount][sizeof(ptr->keywords[ptr->keycount])-1] = '\0'; - ptr->keycount++; - } - } else { - ast_log(LOG_WARNING,"Cannot bind %s, Permission Denied\n",v->name); - } + if (!strcmp(v->name,config_conf_file) || !strcmp(v->name,"asterisk.conf")) { + ast_log(LOG_WARNING, "Cannot bind asterisk.conf or extconfig.conf!\n"); + } else if (driver && database) { + length = sizeof(struct ast_config_map); + length += strlen(v->name) + 1; + length += strlen(driver) + 1; + length += strlen(database) + 1; + if (table) + length += strlen(table) + 1; + map = malloc(length); + if (map) { + memset(map, 0, length); + map->name = map->stuff; + strcpy(map->name, v->name); + map->driver = map->name + strlen(map->name) + 1; + strcpy(map->driver, driver); + map->database = map->driver + strlen(map->driver) + 1; + strcpy(map->database, database); + if (table) { + map->table = map->database + strlen(map->database) + 1; + strcpy(map->table, table); + } else + map->table = NULL; + map->next = maps; + if (option_verbose > 1) + ast_verbose(VERBOSE_PREFIX_2 "Binding %s to %s/%s/%s\n",map->name,map->driver, map->database, map->table ? map->table : map->name); + maps = map; } } } diff --git a/configs/extconfig.conf.sample b/configs/extconfig.conf.sample index 50776fbdb1..957ff3702d 100755 --- a/configs/extconfig.conf.sample +++ b/configs/extconfig.conf.sample @@ -1,6 +1,28 @@ +; +; Static and realtime external configuration +; engine configuration +; [settings] +; +; Static configuration files: +; +; file.conf => driver,database[,table] +; +; maps a particular configuration file to the given +; database driver, database and table (or uses the +; name of the file as the table if not specified) +; +;uncomment to load queues.conf via the odbc engine. +; +;queues.conf => odbc,asterisk,ast_config -;uncomment to load queues.conf via the db engine. -;queues.conf => odbc - +; +; Realtime configuration engine +; +; maps a particular family of realtime +; configuration to a given database driver, +; database and table (or uses the name of +; the family if the table is not specified +; +;iaxfriends => odbc,asterisk diff --git a/configs/res_config_odbc.conf.sample b/configs/res_config_odbc.conf.sample deleted file mode 100755 index f11cf94814..0000000000 --- a/configs/res_config_odbc.conf.sample +++ /dev/null @@ -1,3 +0,0 @@ -[settings] -table => ast_config -connection => mysql1 diff --git a/doc/README.extconfig b/doc/README.extconfig new file mode 100755 index 0000000000..2602632086 --- /dev/null +++ b/doc/README.extconfig @@ -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. diff --git a/include/asterisk/config.h b/include/asterisk/config.h index e98df700f4..89e66437bb 100755 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -34,6 +34,7 @@ struct ast_variable { struct ast_comment *precomments; struct ast_comment *sameline; struct ast_variable *next; + char stuff[0]; }; //! Load a config file @@ -103,12 +104,37 @@ int ast_false(char *val); * Browse config structure and check for category duplicity Return non-zero if found */ int ast_category_exist(struct ast_config *config, char *category_name); -/* These are only in the config engine at this point */ -struct ast_variable *ast_variable_append_modify(struct ast_config *cfg, char *category, char *variable, char *newvalue, int newcat, int newvar, int move); +//! Retrieve realtime configuration +/*! + * \param family which family/config to lookup + * \param keyfield which field to use as the key + * \param lookup which value to look for in the key field to match the entry. + * This will use builtin configuration backends to look up a particular + * entity in realtime and return a variable list of its parameters. Note + * that unlike the variables in ast_config, the resulting list of variables + * MUST be fred with ast_free_runtime() as there is no container. + */ +struct ast_variable *ast_load_realtime(const char *family, const char *keyfield, const char *lookup); -int ast_category_delete(struct ast_config *cfg, char *category); -int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value); -int ast_save(char *filename, struct ast_config *cfg, char *generator); +//! Update realtime configuration +/*! + * \param family which family/config to be updated + * \param keyfield which field to use as the key + * \param lookup which value to look for in the key field to match the entry. + * \param variable which variable should be updated in the config, NULL to end list + * \param value the value to be assigned to that variable in the given entity. + * This function is used to update a parameter in realtime configuration space. + * + */ +int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...); + +//! Free realtime configuration +/*! + * \param var the linked list of variables to free + * This command free's a list of variables and should ONLY be used + * in conjunction with ast_load_realtime and not with the regular ast_load. + */ +void ast_destroy_realtime(struct ast_variable *var); #if defined(__cplusplus) || defined(c_plusplus) } diff --git a/include/asterisk/config_pvt.h b/include/asterisk/config_pvt.h index f87189d316..e33d92de9f 100755 --- a/include/asterisk/config_pvt.h +++ b/include/asterisk/config_pvt.h @@ -4,6 +4,7 @@ extern "C" { #endif +#include #define CONFIG_KEYWORD_STRLEN 128 #define CONFIG_KEYWORD_ARRAYLEN 512 #include @@ -14,10 +15,6 @@ struct ast_category { char name[80]; struct ast_variable *root; struct ast_category *next; -#ifdef PRESERVE_COMMENTS - struct ast_comment *precomments; - struct ast_comment *sameline; -#endif }; struct ast_config { @@ -25,43 +22,25 @@ struct ast_config { for now */ struct ast_category *root; struct ast_category *prev; -#ifdef PRESERVE_COMMENTS - struct ast_comment *trailingcomments; -#endif }; -#ifdef PRESERVE_COMMENTS -struct ast_comment_struct -{ - struct ast_comment *root; - struct ast_comment *prev; -}; -#endif struct ast_category; struct ast_config_reg { char name[CONFIG_KEYWORD_STRLEN]; - struct ast_config *(*func)(char *, struct ast_config *,struct ast_category **,struct ast_variable **,int -#ifdef PRESERVE_COMMENTS -,struct ast_comment_struct * -#endif -); - char keywords[CONFIG_KEYWORD_STRLEN][CONFIG_KEYWORD_ARRAYLEN]; - int keycount; + struct ast_config *(*static_func)(const char *database, const char *table, const char *, struct ast_config *,struct ast_category **,struct ast_variable **,int); + struct ast_variable *(*realtime_func)(const char *database, const char *table, const char *keyfield, const char *entity); + int (*update_func)(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap); struct ast_config_reg *next; }; - int ast_config_register(struct ast_config_reg *new); int ast_config_deregister(struct ast_config_reg *del); void ast_cust_config_on(void); void ast_cust_config_off(void); int ast_cust_config_active(void); -struct ast_config_reg *get_config_registrations(void); -struct ast_config_reg *get_ast_cust_config(char *name); -struct ast_config_reg *get_ast_cust_config_keyword(char *name); void ast_config_destroy_all(void); diff --git a/include/asterisk/res_odbc.h b/include/asterisk/res_odbc.h index 1a68acb983..9b0f71abea 100755 --- a/include/asterisk/res_odbc.h +++ b/include/asterisk/res_odbc.h @@ -45,7 +45,7 @@ odbc_status odbc_obj_connect(odbc_obj *obj); odbc_status odbc_obj_disconnect(odbc_obj *obj); void destroy_obdc_obj(odbc_obj **obj); int register_odbc_obj(char *name,odbc_obj *obj); -odbc_obj *fetch_odbc_obj(char *name); +odbc_obj *fetch_odbc_obj(const char *name); int odbc_dump_fd(int fd,odbc_obj *obj); #endif diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index bfbdd951c8..4543cd498b 100755 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -26,6 +26,8 @@ struct ast_hostent { char buf[1024]; }; + +extern char *ast_strip(char *buf); extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp); extern int ast_base64encode(char *dst, unsigned char *src, int srclen, int max); extern int ast_base64decode(unsigned char *dst, char *src, int max); diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 3f8490530c..2c16e5135a 100755 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -1,9 +1,9 @@ /* * Asterisk -- A telephony toolkit for Linux. * - * Copyright (C) 1999, Mark Spencer + * Copyright (C) 1999-2004, Digium, Inc. * - * Mark Spencer + * Mark Spencer * * res_config_odbc.c * Copyright (C) 2004 Anthony Minessale II @@ -17,10 +17,12 @@ #include #include #include +#include #include #include #include #include +#include static char *tdesc = "ODBC Configuration"; static struct ast_config_reg reg1; @@ -29,18 +31,200 @@ STANDARD_LOCAL_USER; LOCAL_USER_DECL; -static struct ast_config *config_odbc (char *file, struct ast_config *new_config_s, struct ast_category **new_cat_p, struct ast_variable **new_v_p, int recur -#ifdef PRESERVE_COMMENTS - , struct ast_comment_struct *acs -#endif -) +static struct ast_variable *realtime_odbc(const char *database, const char *table, const char *keyfield, const char *lookup) { - struct ast_config *config, *new; - struct ast_variable *v, *cur_v, *new_v; + odbc_obj *obj; + SQLHSTMT stmt; + char sql[256]; + char coltitle[256]; + char rowdata[2048]; + char *stringp; + char *chunk; + SQLSMALLINT collen; + int res; + int x; + struct ast_variable *var=NULL, *prev=NULL; + SQLLEN rowcount=0; + SQLULEN colsize; + SQLSMALLINT colcount=0; + SQLSMALLINT datatype; + SQLSMALLINT decimaldigits; + SQLSMALLINT nullable; + + if (!table) + return NULL; + + obj = fetch_odbc_obj(database); + if (!obj) + return NULL; + + res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); + return NULL; + } + + snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s=?", table, keyfield); + + res = SQLPrepare(stmt, sql, SQL_NTS); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL); + + res = SQLExecute(stmt); + + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + + res = SQLRowCount(stmt, &rowcount); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + + res = SQLNumResultCols(stmt, &colcount); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + + if (rowcount) { + res = SQLFetch(stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + for (x=0;xnext = ast_new_variable(coltitle, chunk); + if (prev->next) + prev = prev->next; + } else + prev = var = ast_new_variable(coltitle, chunk); + + } + } + } + } + + + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return var; +} + +static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) +{ + odbc_obj *obj; + SQLHSTMT stmt; + char sql[256]; + SQLLEN rowcount=0; + const char *newparam, *newval; + int res; + int x; + va_list aq; + + va_copy(aq, ap); + + if (!table) + return -1; + + obj = fetch_odbc_obj (database); + if (!obj) + return -1; + + res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); + return -1; + } + + newparam = va_arg(aq, const char *); + if (!newparam) { + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return -1; + } + newval = va_arg(aq, const char *); + snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam); + while((newparam = va_arg(aq, const char *))) { + snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam); + newval = va_arg(aq, const char *); + } + va_end(aq); + snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield); + + res = SQLPrepare(stmt, sql, SQL_NTS); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return -1; + } + + /* Now bind the parameters */ + x = 1; + + while((newparam = va_arg(ap, const char *))) { + newval = va_arg(ap, const char *); + SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); + } + + SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL); + + res = SQLExecute(stmt); + + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return -1; + } + + res = SQLRowCount(stmt, &rowcount); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + return -1; + } + + if (rowcount) + return 0; + return -1; +} + +static struct ast_config *config_odbc (const char *database, const char *table, const char *file, struct ast_config *new_config_s, struct ast_category **new_cat_p, struct ast_variable **new_v_p, int recur) +{ + struct ast_config *new; + struct ast_variable *cur_v, *new_v; struct ast_category *cur_cat, *new_cat; - char table[128] = ""; - char connection[128] = ""; - int configured = 0, res = 0; + int res = 0; odbc_obj *obj; SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0; SQLBIGINT id; @@ -51,40 +235,16 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config int cat_started = 0; int var_started = 0; - if (new_config_s) { - new = new_config_s; - cat_started++; - } else { - new = ast_new_config (); - } - - last[0] = '\0'; if (!file || !strcmp (file, "res_config_odbc.conf")) return NULL; // cant configure myself with myself ! - config = ast_load ("res_config_odbc.conf"); - - if (config) { - for (v = ast_variable_browse (config, "settings"); v; v = v->next) { - if (!strcmp (v->name, "table")) { - strncpy(table, v->value, sizeof(table) - 1); - configured++; - } else if (!strcmp (v->name, "connection")) { - strncpy(connection, v->value, sizeof(connection) - 1); - configured++; - } - } - ast_destroy (config); - } - - if (configured < 2) - return NULL; - - obj = fetch_odbc_obj (connection); + obj = fetch_odbc_obj(database); if (!obj) return NULL; + last[0] = '\0'; + res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); SQLBindCol (stmt, 1, SQL_C_ULONG, &id, sizeof (id), &err); @@ -96,7 +256,7 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config SQLBindCol (stmt, 7, SQL_C_CHAR, &var_name, sizeof (var_name), &err); SQLBindCol (stmt, 8, SQL_C_CHAR, &var_val, sizeof (var_val), &err); - snprintf(sql, sizeof(sql), "select * from %s where filename='%s' and commented=0 order by filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file); + snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE filename='%s' and commented=0 ORDER BY filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file); res = SQLExecDirect (stmt, sql, SQL_NTS); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { @@ -111,6 +271,19 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config return NULL; } + if (new_config_s) { + new = new_config_s; + cat_started++; + } else { + new = ast_new_config (); + } + + if (!new) { + ast_log(LOG_WARNING, "Out of memory!\n"); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + if (rowcount) { res = SQLFetch (stmt); cat_started = 0; @@ -126,11 +299,7 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config while (res != SQL_NO_DATA) { if (!strcmp (var_name, "#include") && recur < MAX_INCLUDE_LEVEL) { - config_odbc (var_val, new, &cur_cat, &cur_v, recur + 1 -#ifdef PRESERVE_COMMENTS - , acs -#endif - ); + config_odbc(database, table, var_val, new, &cur_cat, &cur_v, recur + 1); } else { if (strcmp (last, category) || last_cat_metric != cat_metric) { strncpy(last, category, sizeof(last) - 1); @@ -176,7 +345,8 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config int unload_module (void) { ast_cust_config_deregister (®1); - ast_log (LOG_NOTICE, "res_config_odbc unloaded.\n"); + if (option_verbose) + ast_verbose("res_config_odbc unloaded.\n"); STANDARD_HANGUP_LOCALUSERS; return 0; } @@ -185,9 +355,12 @@ int load_module (void) { memset (®1, 0, sizeof (struct ast_config_reg)); strncpy(reg1.name, "odbc", sizeof(reg1.name) - 1); - reg1.func = config_odbc; + reg1.static_func = config_odbc; + reg1.realtime_func = realtime_odbc; + reg1.update_func = update_odbc; ast_cust_config_register (®1); - ast_log (LOG_NOTICE, "res_config_odbc loaded.\n"); + if (option_verbose) + ast_verbose("res_config_odbc loaded.\n"); return 0; } diff --git a/res/res_odbc.c b/res/res_odbc.c index c8efb06201..c6f432ada0 100755 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -1,9 +1,9 @@ /* * Asterisk -- A telephony toolkit for Linux. * - * Copyright (C) 1999, Mark Spencer + * Copyright (C) 1999-2004, Digium, Inc. * - * Mark Spencer + * Mark Spencer * * res_odbc.c * Copyright (C) 2004 Anthony Minessale II @@ -45,7 +45,7 @@ static void odbc_destroy(void) } } -static odbc_obj *odbc_read(struct odbc_list *registry, char *name) +static odbc_obj *odbc_read(struct odbc_list *registry, const char *name) { int x = 0; for (x = 0; x < MAX_ODBC_HANDLES; x++) { @@ -124,7 +124,7 @@ static int load_odbc_config(void) password = v->value; } - if (enabled && dsn && username && password) { + if (enabled && dsn) { obj = new_odbc_obj(cat, dsn, username, password); if (obj) { register_odbc_obj(cat, obj); @@ -212,7 +212,7 @@ int register_odbc_obj(char *name, odbc_obj * obj) return 0; } -odbc_obj *fetch_odbc_obj(char *name) +odbc_obj *fetch_odbc_obj(const char *name) { return (odbc_obj *) odbc_read(ODBC_REGISTRY, name); } @@ -233,18 +233,22 @@ odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password) if (new->dsn == NULL) return NULL; - new->username = malloc(strlen(username) + 1); - if (new->username == NULL) - return NULL; + if (username) { + new->username = malloc(strlen(username) + 1); + if (new->username == NULL) + return NULL; + strcpy(new->username, username); + } - new->password = malloc(strlen(password) + 1); - if (new->password == NULL) - return NULL; + if (password) { + new->password = malloc(strlen(password) + 1); + if (new->password == NULL) + return NULL; + strcpy(new->password, password); + } strcpy(new->name, name); strcpy(new->dsn, dsn); - strcpy(new->username, username); - strcpy(new->password, password); new->up = 0; ast_mutex_init(&new->lock); return new; @@ -261,8 +265,10 @@ void destroy_obdc_obj(odbc_obj ** obj) free((*obj)->name); free((*obj)->dsn); - free((*obj)->username); - free((*obj)->password); + if ((*obj)->username) + free((*obj)->username); + if ((*obj)->password) + free((*obj)->password); ast_mutex_unlock(&(*obj)->lock); free(*obj); } @@ -332,6 +338,7 @@ odbc_status odbc_obj_connect(odbc_obj * obj) SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); } + ast_log(LOG_NOTICE, "Calling %p/%p\n", obj->username, obj->password); res = SQLConnect(obj->con, (SQLCHAR *) obj->dsn, SQL_NTS, (SQLCHAR *) obj->username, SQL_NTS, @@ -340,13 +347,11 @@ odbc_status odbc_obj_connect(odbc_obj * obj) if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - if (option_verbose > 3) - ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%ld %s\n", res, err, msg); + ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%ld %s\n", res, err, msg); return ODBC_FAIL; } else { - if (option_verbose > 3) - ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->name, obj->dsn); + ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->name, obj->dsn); obj->up = 1; } diff --git a/utils.c b/utils.c index 2557c3180e..a454ea4bf9 100755 --- a/utils.c +++ b/utils.c @@ -28,6 +28,19 @@ static char base64[64]; static char b2a[256]; +char *ast_strip(char *buf) +{ + char *start; + /* Strip off trailing whitespace, returns, etc */ + while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33)) + buf[strlen(buf)-1] = '\0'; + start = buf; + /* Strip off leading whitespace, returns, etc */ + while (*start && (*start < 33)) + *start++ = '\0'; + return start; +} + #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) /* duh? ERANGE value copied from web... */