00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00038
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <unistd.h>
00042 #include <string.h>
00043
00044 #include "asterisk/file.h"
00045 #include "asterisk/logger.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/lock.h"
00051 #include "asterisk/options.h"
00052 #include "asterisk/res_odbc.h"
00053 #include "asterisk/utils.h"
00054
00055 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
00056 {
00057 struct odbc_obj *obj;
00058 SQLHSTMT stmt;
00059 char sql[1024];
00060 char coltitle[256];
00061 char rowdata[2048];
00062 char *op;
00063 const char *newparam, *newval;
00064 char *stringp;
00065 char *chunk;
00066 SQLSMALLINT collen;
00067 int res;
00068 int x;
00069 struct ast_variable *var=NULL, *prev=NULL;
00070 SQLULEN colsize;
00071 SQLSMALLINT colcount=0;
00072 SQLSMALLINT datatype;
00073 SQLSMALLINT decimaldigits;
00074 SQLSMALLINT nullable;
00075 SQLLEN indicator;
00076 va_list aq;
00077
00078 va_copy(aq, ap);
00079
00080
00081 if (!table)
00082 return NULL;
00083
00084 obj = ast_odbc_request_obj(database, 0);
00085 if (!obj)
00086 return NULL;
00087
00088 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00089 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00090 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00091 ast_odbc_release_obj(obj);
00092 return NULL;
00093 }
00094
00095 newparam = va_arg(aq, const char *);
00096 if (!newparam) {
00097 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00098 ast_odbc_release_obj(obj);
00099 return NULL;
00100 }
00101 newval = va_arg(aq, const char *);
00102 if (!strchr(newparam, ' ')) op = " ="; else op = "";
00103 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op);
00104 while((newparam = va_arg(aq, const char *))) {
00105 if (!strchr(newparam, ' ')) op = " ="; else op = "";
00106 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op);
00107 newval = va_arg(aq, const char *);
00108 }
00109 va_end(aq);
00110 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
00111 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00112 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
00113 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00114 ast_odbc_release_obj(obj);
00115 return NULL;
00116 }
00117
00118
00119 x = 1;
00120
00121 while((newparam = va_arg(ap, const char *))) {
00122 newval = va_arg(ap, const char *);
00123 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00124 }
00125
00126 res = ast_odbc_smart_execute(obj, stmt);
00127
00128 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00129 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
00130 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00131 ast_odbc_release_obj(obj);
00132 return NULL;
00133 }
00134
00135 res = SQLNumResultCols(stmt, &colcount);
00136 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00137 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00138 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00139 ast_odbc_release_obj(obj);
00140 return NULL;
00141 }
00142
00143 res = SQLFetch(stmt);
00144 if (res == SQL_NO_DATA) {
00145 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00146 ast_odbc_release_obj(obj);
00147 return NULL;
00148 }
00149 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00150 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00151 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00152 ast_odbc_release_obj(obj);
00153 return NULL;
00154 }
00155 for (x = 0; x < colcount; x++) {
00156 rowdata[0] = '\0';
00157 collen = sizeof(coltitle);
00158 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
00159 &datatype, &colsize, &decimaldigits, &nullable);
00160 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00161 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00162 if (var)
00163 ast_variables_destroy(var);
00164 ast_odbc_release_obj(obj);
00165 return NULL;
00166 }
00167
00168 indicator = 0;
00169 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00170 if (indicator == SQL_NULL_DATA)
00171 continue;
00172
00173 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00174 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00175 if (var)
00176 ast_variables_destroy(var);
00177 ast_odbc_release_obj(obj);
00178 return NULL;
00179 }
00180 stringp = rowdata;
00181 while(stringp) {
00182 chunk = strsep(&stringp, ";");
00183 if (!ast_strlen_zero(ast_strip(chunk))) {
00184 if (prev) {
00185 prev->next = ast_variable_new(coltitle, chunk);
00186 if (prev->next)
00187 prev = prev->next;
00188 } else
00189 prev = var = ast_variable_new(coltitle, chunk);
00190
00191 }
00192 }
00193 }
00194
00195
00196 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00197 ast_odbc_release_obj(obj);
00198 return var;
00199 }
00200
00201 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
00202 {
00203 struct odbc_obj *obj;
00204 SQLHSTMT stmt;
00205 char sql[1024];
00206 char coltitle[256];
00207 char rowdata[2048];
00208 const char *initfield=NULL;
00209 char *op;
00210 const char *newparam, *newval;
00211 char *stringp;
00212 char *chunk;
00213 SQLSMALLINT collen;
00214 int res;
00215 int x;
00216 struct ast_variable *var=NULL;
00217 struct ast_config *cfg=NULL;
00218 struct ast_category *cat=NULL;
00219 struct ast_realloca ra;
00220 SQLULEN colsize;
00221 SQLSMALLINT colcount=0;
00222 SQLSMALLINT datatype;
00223 SQLSMALLINT decimaldigits;
00224 SQLSMALLINT nullable;
00225 SQLLEN indicator;
00226
00227 va_list aq;
00228 va_copy(aq, ap);
00229
00230
00231 if (!table)
00232 return NULL;
00233 memset(&ra, 0, sizeof(ra));
00234
00235 obj = ast_odbc_request_obj(database, 0);
00236 if (!obj)
00237 return NULL;
00238
00239 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00240 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00241 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00242 ast_odbc_release_obj(obj);
00243 return NULL;
00244 }
00245
00246 newparam = va_arg(aq, const char *);
00247 if (!newparam) {
00248 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00249 ast_odbc_release_obj(obj);
00250 return NULL;
00251 }
00252 initfield = ast_strdupa(newparam);
00253 if ((op = strchr(initfield, ' ')))
00254 *op = '\0';
00255 newval = va_arg(aq, const char *);
00256 if (!strchr(newparam, ' ')) op = " ="; else op = "";
00257 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op);
00258 while((newparam = va_arg(aq, const char *))) {
00259 if (!strchr(newparam, ' ')) op = " ="; else op = "";
00260 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op);
00261 newval = va_arg(aq, const char *);
00262 }
00263 if (initfield)
00264 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00265 va_end(aq);
00266 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
00267 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00268 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
00269 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00270 ast_odbc_release_obj(obj);
00271 return NULL;
00272 }
00273
00274
00275 x = 1;
00276
00277 while((newparam = va_arg(ap, const char *))) {
00278 newval = va_arg(ap, const char *);
00279 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00280 }
00281
00282 res = ast_odbc_smart_execute(obj, stmt);
00283
00284 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00285 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
00286 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00287 ast_odbc_release_obj(obj);
00288 return NULL;
00289 }
00290
00291 res = SQLNumResultCols(stmt, &colcount);
00292 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00293 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00294 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00295 ast_odbc_release_obj(obj);
00296 return NULL;
00297 }
00298
00299 cfg = ast_config_new();
00300 if (!cfg) {
00301 ast_log(LOG_WARNING, "Out of memory!\n");
00302 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00303 ast_odbc_release_obj(obj);
00304 return NULL;
00305 }
00306
00307 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
00308 var = NULL;
00309 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00310 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00311 continue;
00312 }
00313 cat = ast_category_new("");
00314 if (!cat) {
00315 ast_log(LOG_WARNING, "Out of memory!\n");
00316 continue;
00317 }
00318 for (x=0;x<colcount;x++) {
00319 rowdata[0] = '\0';
00320 collen = sizeof(coltitle);
00321 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
00322 &datatype, &colsize, &decimaldigits, &nullable);
00323 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00324 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00325 ast_category_destroy(cat);
00326 continue;
00327 }
00328
00329 indicator = 0;
00330 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00331 if (indicator == SQL_NULL_DATA)
00332 continue;
00333
00334 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00335 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00336 ast_category_destroy(cat);
00337 continue;
00338 }
00339 stringp = rowdata;
00340 while(stringp) {
00341 chunk = strsep(&stringp, ";");
00342 if (!ast_strlen_zero(ast_strip(chunk))) {
00343 if (initfield && !strcmp(initfield, coltitle))
00344 ast_category_rename(cat, chunk);
00345 var = ast_variable_new(coltitle, chunk);
00346 ast_variable_append(cat, var);
00347 }
00348 }
00349 }
00350 ast_category_append(cfg, cat);
00351 }
00352
00353 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00354 ast_odbc_release_obj(obj);
00355 return cfg;
00356 }
00357
00358 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
00359 {
00360 struct odbc_obj *obj;
00361 SQLHSTMT stmt;
00362 char sql[256];
00363 SQLLEN rowcount=0;
00364 const char *newparam, *newval;
00365 int res;
00366 int x;
00367 va_list aq;
00368
00369 va_copy(aq, ap);
00370
00371 if (!table)
00372 return -1;
00373
00374 obj = ast_odbc_request_obj(database, 0);
00375 if (!obj)
00376 return -1;
00377
00378 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00379 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00380 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00381 ast_odbc_release_obj(obj);
00382 return -1;
00383 }
00384
00385 newparam = va_arg(aq, const char *);
00386 if (!newparam) {
00387 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00388 ast_odbc_release_obj(obj);
00389 return -1;
00390 }
00391 newval = va_arg(aq, const char *);
00392 snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
00393 while((newparam = va_arg(aq, const char *))) {
00394 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
00395 newval = va_arg(aq, const char *);
00396 }
00397 va_end(aq);
00398 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
00399
00400 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
00401 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00402 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
00403 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00404 ast_odbc_release_obj(obj);
00405 return -1;
00406 }
00407
00408
00409 x = 1;
00410
00411 while((newparam = va_arg(ap, const char *))) {
00412 newval = va_arg(ap, const char *);
00413 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00414 }
00415
00416 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
00417
00418 res = ast_odbc_smart_execute(obj, stmt);
00419
00420 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00421 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
00422 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00423 ast_odbc_release_obj(obj);
00424 return -1;
00425 }
00426
00427 res = SQLRowCount(stmt, &rowcount);
00428 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00429 ast_odbc_release_obj(obj);
00430
00431 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00432 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00433 return -1;
00434 }
00435
00436 if (rowcount >= 0)
00437 return (int)rowcount;
00438
00439 return -1;
00440 }
00441
00442 struct config_odbc_obj {
00443 char *sql;
00444 unsigned long cat_metric;
00445 char category[128];
00446 char var_name[128];
00447 char var_val[1024];
00448 SQLLEN err;
00449 };
00450
00451 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
00452 {
00453 struct config_odbc_obj *q = data;
00454 SQLHSTMT sth;
00455 int res;
00456
00457 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00458 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00459 if (option_verbose > 3)
00460 ast_verbose( VERBOSE_PREFIX_4 "Failure in AllocStatement %d\n", res);
00461 return NULL;
00462 }
00463
00464 res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00465 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00466 if (option_verbose > 3)
00467 ast_verbose( VERBOSE_PREFIX_4 "Error in PREPARE %d\n", res);
00468 SQLFreeHandle(SQL_HANDLE_STMT, sth);
00469 return NULL;
00470 }
00471
00472 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00473 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00474 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00475 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
00476
00477 return sth;
00478 }
00479
00480 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
00481 {
00482 struct ast_variable *new_v;
00483 struct ast_category *cur_cat;
00484 int res = 0;
00485 struct odbc_obj *obj;
00486 char sqlbuf[1024] = "";
00487 char *sql = sqlbuf;
00488 size_t sqlleft = sizeof(sqlbuf);
00489 unsigned int last_cat_metric = 0;
00490 SQLSMALLINT rowcount = 0;
00491 SQLHSTMT stmt;
00492 char last[128] = "";
00493 struct config_odbc_obj q;
00494
00495 memset(&q, 0, sizeof(q));
00496
00497 if (!file || !strcmp (file, "res_config_odbc.conf"))
00498 return NULL;
00499
00500 obj = ast_odbc_request_obj(database, 0);
00501 if (!obj)
00502 return NULL;
00503
00504 ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
00505 ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
00506 ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00507 q.sql = sqlbuf;
00508
00509 stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
00510
00511 if (!stmt) {
00512 ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00513 ast_odbc_release_obj(obj);
00514 return NULL;
00515 }
00516
00517 res = SQLNumResultCols(stmt, &rowcount);
00518
00519 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00520 ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
00521 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00522 ast_odbc_release_obj(obj);
00523 return NULL;
00524 }
00525
00526 if (!rowcount) {
00527 ast_log(LOG_NOTICE, "found nothing\n");
00528 ast_odbc_release_obj(obj);
00529 return cfg;
00530 }
00531
00532 cur_cat = ast_config_get_current_category(cfg);
00533
00534 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
00535 if (!strcmp (q.var_name, "#include")) {
00536 if (!ast_config_internal_load(q.var_val, cfg, 0)) {
00537 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00538 ast_odbc_release_obj(obj);
00539 return NULL;
00540 }
00541 continue;
00542 }
00543 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
00544 cur_cat = ast_category_new(q.category);
00545 if (!cur_cat) {
00546 ast_log(LOG_WARNING, "Out of memory!\n");
00547 break;
00548 }
00549 strcpy(last, q.category);
00550 last_cat_metric = q.cat_metric;
00551 ast_category_append(cfg, cur_cat);
00552 }
00553
00554 new_v = ast_variable_new(q.var_name, q.var_val);
00555 ast_variable_append(cur_cat, new_v);
00556 }
00557
00558 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00559 ast_odbc_release_obj(obj);
00560 return cfg;
00561 }
00562
00563 static struct ast_config_engine odbc_engine = {
00564 .name = "odbc",
00565 .load_func = config_odbc,
00566 .realtime_func = realtime_odbc,
00567 .realtime_multi_func = realtime_multi_odbc,
00568 .update_func = update_odbc
00569 };
00570
00571 static int unload_module (void)
00572 {
00573 ast_module_user_hangup_all();
00574 ast_config_engine_deregister(&odbc_engine);
00575 if (option_verbose)
00576 ast_verbose("res_config_odbc unloaded.\n");
00577 return 0;
00578 }
00579
00580 static int load_module (void)
00581 {
00582 ast_config_engine_register(&odbc_engine);
00583 if (option_verbose)
00584 ast_verbose("res_config_odbc loaded.\n");
00585 return 0;
00586 }
00587
00588 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC Configuration",
00589 .load = load_module,
00590 .unload = unload_module,
00591 );