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 id;
00445 unsigned long cat_metric;
00446 unsigned long var_metric;
00447 unsigned long commented;
00448 char filename[128];
00449 char category[128];
00450 char var_name[128];
00451 char var_val[1024];
00452 SQLLEN err;
00453 };
00454
00455 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
00456 {
00457 struct config_odbc_obj *q = data;
00458 SQLHSTMT sth;
00459 int res;
00460
00461 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00462 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00463 if (option_verbose > 3)
00464 ast_verbose( VERBOSE_PREFIX_4 "Failure in AllocStatement %d\n", res);
00465 return NULL;
00466 }
00467
00468 res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00469 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00470 if (option_verbose > 3)
00471 ast_verbose( VERBOSE_PREFIX_4 "Error in PREPARE %d\n", res);
00472 SQLFreeHandle(SQL_HANDLE_STMT, sth);
00473 return NULL;
00474 }
00475
00476 SQLBindCol(sth, 1, SQL_C_ULONG, &q->id, sizeof(q->id), &q->err);
00477 SQLBindCol(sth, 2, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00478 SQLBindCol(sth, 3, SQL_C_ULONG, &q->var_metric, sizeof(q->var_metric), &q->err);
00479 SQLBindCol(sth, 4, SQL_C_ULONG, &q->commented, sizeof(q->commented), &q->err);
00480 SQLBindCol(sth, 5, SQL_C_CHAR, q->filename, sizeof(q->filename), &q->err);
00481 SQLBindCol(sth, 6, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00482 SQLBindCol(sth, 7, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00483 SQLBindCol(sth, 8, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
00484
00485 return sth;
00486 }
00487
00488 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
00489 {
00490 struct ast_variable *new_v;
00491 struct ast_category *cur_cat;
00492 int res = 0;
00493 struct odbc_obj *obj;
00494 char sql[255] = "";
00495 unsigned int last_cat_metric = 0;
00496 SQLSMALLINT rowcount=0;
00497 SQLHSTMT stmt;
00498 char last[128] = "";
00499 struct config_odbc_obj q;
00500
00501 memset(&q, 0, sizeof(q));
00502
00503 if (!file || !strcmp (file, "res_config_odbc.conf"))
00504 return NULL;
00505
00506 obj = ast_odbc_request_obj(database, 0);
00507 if (!obj)
00508 return NULL;
00509
00510 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);
00511 q.sql = sql;
00512
00513 stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
00514
00515 if (!stmt) {
00516 ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00517 ast_odbc_release_obj(obj);
00518 return NULL;
00519 }
00520
00521 res = SQLNumResultCols(stmt, &rowcount);
00522
00523 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00524 ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
00525 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00526 ast_odbc_release_obj(obj);
00527 return NULL;
00528 }
00529
00530 if (!rowcount) {
00531 ast_log(LOG_NOTICE, "found nothing\n");
00532 ast_odbc_release_obj(obj);
00533 return cfg;
00534 }
00535
00536 cur_cat = ast_config_get_current_category(cfg);
00537
00538 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
00539 if (!strcmp (q.var_name, "#include")) {
00540 if (!ast_config_internal_load(q.var_val, cfg, 0)) {
00541 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00542 ast_odbc_release_obj(obj);
00543 return NULL;
00544 }
00545 continue;
00546 }
00547 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
00548 cur_cat = ast_category_new(q.category);
00549 if (!cur_cat) {
00550 ast_log(LOG_WARNING, "Out of memory!\n");
00551 break;
00552 }
00553 strcpy(last, q.category);
00554 last_cat_metric = q.cat_metric;
00555 ast_category_append(cfg, cur_cat);
00556 }
00557
00558 new_v = ast_variable_new(q.var_name, q.var_val);
00559 ast_variable_append(cur_cat, new_v);
00560 }
00561
00562 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00563 ast_odbc_release_obj(obj);
00564 return cfg;
00565 }
00566
00567 static struct ast_config_engine odbc_engine = {
00568 .name = "odbc",
00569 .load_func = config_odbc,
00570 .realtime_func = realtime_odbc,
00571 .realtime_multi_func = realtime_multi_odbc,
00572 .update_func = update_odbc
00573 };
00574
00575 static int unload_module (void)
00576 {
00577 ast_module_user_hangup_all();
00578 ast_config_engine_deregister(&odbc_engine);
00579 if (option_verbose)
00580 ast_verbose("res_config_odbc unloaded.\n");
00581 return 0;
00582 }
00583
00584 static int load_module (void)
00585 {
00586 ast_config_engine_register(&odbc_engine);
00587 if (option_verbose)
00588 ast_verbose("res_config_odbc loaded.\n");
00589 return 0;
00590 }
00591
00592 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC Configuration",
00593 .load = load_module,
00594 .unload = unload_module,
00595 );