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 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 267670 $")
00037
00038 #include "asterisk/module.h"
00039 #include "asterisk/file.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/res_odbc.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/strings.h"
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 static char *config = "func_odbc.conf";
00101
00102 enum {
00103 OPT_ESCAPECOMMAS = (1 << 0),
00104 OPT_MULTIROW = (1 << 1),
00105 } odbc_option_flags;
00106
00107 struct acf_odbc_query {
00108 AST_RWLIST_ENTRY(acf_odbc_query) list;
00109 char readhandle[5][30];
00110 char writehandle[5][30];
00111 char sql_read[2048];
00112 char sql_write[2048];
00113 char sql_insert[2048];
00114 unsigned int flags;
00115 int rowlimit;
00116 struct ast_custom_function *acf;
00117 };
00118
00119 static void odbc_datastore_free(void *data);
00120
00121 struct ast_datastore_info odbc_info = {
00122 .type = "FUNC_ODBC",
00123 .destroy = odbc_datastore_free,
00124 };
00125
00126
00127 struct odbc_datastore_row {
00128 AST_LIST_ENTRY(odbc_datastore_row) list;
00129 char data[0];
00130 };
00131
00132
00133 struct odbc_datastore {
00134 AST_LIST_HEAD(, odbc_datastore_row);
00135 char names[0];
00136 };
00137
00138 AST_RWLIST_HEAD_STATIC(queries, acf_odbc_query);
00139
00140 static int resultcount = 0;
00141
00142 AST_THREADSTORAGE(sql_buf);
00143 AST_THREADSTORAGE(sql2_buf);
00144 AST_THREADSTORAGE(coldata_buf);
00145 AST_THREADSTORAGE(colnames_buf);
00146
00147 static void odbc_datastore_free(void *data)
00148 {
00149 struct odbc_datastore *result = data;
00150 struct odbc_datastore_row *row;
00151 AST_LIST_LOCK(result);
00152 while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
00153 ast_free(row);
00154 }
00155 AST_LIST_UNLOCK(result);
00156 AST_LIST_HEAD_DESTROY(result);
00157 ast_free(result);
00158 }
00159
00160 static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
00161 {
00162 int res;
00163 char *sql = data;
00164 SQLHSTMT stmt;
00165
00166 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00167 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00168 ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
00169 return NULL;
00170 }
00171
00172 res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
00173 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00174 if (res == SQL_ERROR) {
00175 int i;
00176 SQLINTEGER nativeerror=0, numfields=0;
00177 SQLSMALLINT diagbytes=0;
00178 unsigned char state[10], diagnostic[256];
00179
00180 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00181 for (i = 0; i < numfields; i++) {
00182 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00183 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00184 if (i > 10) {
00185 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
00186 break;
00187 }
00188 }
00189 }
00190
00191 ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
00192 SQLCloseCursor(stmt);
00193 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00194 return NULL;
00195 }
00196
00197 return stmt;
00198 }
00199
00200
00201
00202
00203 static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
00204 {
00205 struct odbc_obj *obj = NULL;
00206 struct acf_odbc_query *query;
00207 char *t, varname[15];
00208 int i, dsn, bogus_chan = 0;
00209 int transactional = 0;
00210 AST_DECLARE_APP_ARGS(values,
00211 AST_APP_ARG(field)[100];
00212 );
00213 AST_DECLARE_APP_ARGS(args,
00214 AST_APP_ARG(field)[100];
00215 );
00216 SQLHSTMT stmt = NULL;
00217 SQLLEN rows=0;
00218 struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
00219 struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
00220 const char *status = "FAILURE";
00221
00222 if (!buf || !insertbuf) {
00223 return -1;
00224 }
00225
00226 AST_RWLIST_RDLOCK(&queries);
00227 AST_RWLIST_TRAVERSE(&queries, query, list) {
00228 if (!strcmp(query->acf->name, cmd)) {
00229 break;
00230 }
00231 }
00232
00233 if (!query) {
00234 ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00235 AST_RWLIST_UNLOCK(&queries);
00236 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00237 return -1;
00238 }
00239
00240 if (!chan) {
00241 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc")))
00242 bogus_chan = 1;
00243 }
00244
00245 if (chan)
00246 ast_autoservice_start(chan);
00247
00248 ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
00249 ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
00250
00251
00252 t = value ? ast_strdupa(value) : "";
00253
00254 if (!s || !t) {
00255 ast_log(LOG_ERROR, "Out of memory\n");
00256 AST_RWLIST_UNLOCK(&queries);
00257 if (chan)
00258 ast_autoservice_stop(chan);
00259 if (bogus_chan) {
00260 ast_channel_free(chan);
00261 } else {
00262 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00263 }
00264 return -1;
00265 }
00266
00267 AST_STANDARD_APP_ARGS(args, s);
00268 for (i = 0; i < args.argc; i++) {
00269 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
00270 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
00271 }
00272
00273
00274 AST_STANDARD_APP_ARGS(values, t);
00275 for (i = 0; i < values.argc; i++) {
00276 snprintf(varname, sizeof(varname), "VAL%d", i + 1);
00277 pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
00278 }
00279
00280
00281 pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
00282
00283 ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
00284 ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
00285
00286
00287 for (i = 0; i < args.argc; i++) {
00288 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
00289 pbx_builtin_setvar_helper(chan, varname, NULL);
00290 }
00291
00292 for (i = 0; i < values.argc; i++) {
00293 snprintf(varname, sizeof(varname), "VAL%d", i + 1);
00294 pbx_builtin_setvar_helper(chan, varname, NULL);
00295 }
00296 pbx_builtin_setvar_helper(chan, "VALUE", NULL);
00297
00298
00299
00300
00301
00302
00303
00304 for (dsn = 0; dsn < 5; dsn++) {
00305 if (transactional) {
00306
00307 ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
00308 }
00309
00310 if (!ast_strlen_zero(query->writehandle[dsn])) {
00311 if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
00312 transactional = 1;
00313 } else {
00314 obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
00315 transactional = 0;
00316 }
00317 if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
00318 break;
00319 }
00320 }
00321
00322 if (obj && !transactional) {
00323 ast_odbc_release_obj(obj);
00324 obj = NULL;
00325 }
00326 }
00327
00328 if (stmt && rows == 0 && ast_str_strlen(insertbuf) != 0) {
00329 SQLCloseCursor(stmt);
00330 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00331 for (dsn = 0; dsn < 5; dsn++) {
00332 if (!ast_strlen_zero(query->writehandle[dsn])) {
00333 obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
00334 if (obj) {
00335 stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
00336 }
00337 }
00338 if (stmt) {
00339 status = "FAILOVER";
00340 SQLRowCount(stmt, &rows);
00341 break;
00342 }
00343 if (obj) {
00344 ast_odbc_release_obj(obj);
00345 obj = NULL;
00346 }
00347 }
00348 } else if (stmt) {
00349 status = "SUCCESS";
00350 SQLRowCount(stmt, &rows);
00351 }
00352
00353 AST_RWLIST_UNLOCK(&queries);
00354
00355
00356
00357
00358
00359 snprintf(varname, sizeof(varname), "%d", (int)rows);
00360 pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
00361 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00362
00363 if (stmt) {
00364 SQLCloseCursor(stmt);
00365 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00366 }
00367 if (obj && !transactional) {
00368 ast_odbc_release_obj(obj);
00369 obj = NULL;
00370 }
00371
00372 if (chan)
00373 ast_autoservice_stop(chan);
00374 if (bogus_chan)
00375 ast_channel_free(chan);
00376
00377 return 0;
00378 }
00379
00380 static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
00381 {
00382 struct odbc_obj *obj = NULL;
00383 struct acf_odbc_query *query;
00384 char varname[15], rowcount[12] = "-1";
00385 struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
00386 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0;
00387 AST_DECLARE_APP_ARGS(args,
00388 AST_APP_ARG(field)[100];
00389 );
00390 SQLHSTMT stmt = NULL;
00391 SQLSMALLINT colcount=0;
00392 SQLLEN indicator;
00393 SQLSMALLINT collength;
00394 struct odbc_datastore *resultset = NULL;
00395 struct odbc_datastore_row *row = NULL;
00396 struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
00397 const char *status = "FAILURE";
00398
00399 if (!sql || !colnames) {
00400 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00401 return -1;
00402 }
00403
00404 ast_str_reset(colnames);
00405
00406 AST_RWLIST_RDLOCK(&queries);
00407 AST_RWLIST_TRAVERSE(&queries, query, list) {
00408 if (!strcmp(query->acf->name, cmd)) {
00409 break;
00410 }
00411 }
00412
00413 if (!query) {
00414 ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00415 AST_RWLIST_UNLOCK(&queries);
00416 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00417 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00418 return -1;
00419 }
00420
00421 if (!chan) {
00422 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) {
00423 bogus_chan = 1;
00424 }
00425 }
00426
00427 if (chan) {
00428 ast_autoservice_start(chan);
00429 }
00430
00431 AST_STANDARD_APP_ARGS(args, s);
00432 for (x = 0; x < args.argc; x++) {
00433 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00434 pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
00435 }
00436
00437 ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
00438
00439
00440 for (x = 0; x < args.argc; x++) {
00441 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00442 pbx_builtin_setvar_helper(chan, varname, NULL);
00443 }
00444
00445
00446 escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
00447 if (ast_test_flag(query, OPT_MULTIROW)) {
00448 resultset = ast_calloc(1, sizeof(*resultset));
00449 AST_LIST_HEAD_INIT(resultset);
00450 if (query->rowlimit) {
00451 rowlimit = query->rowlimit;
00452 } else {
00453 rowlimit = INT_MAX;
00454 }
00455 }
00456 AST_RWLIST_UNLOCK(&queries);
00457
00458 for (dsn = 0; dsn < 5; dsn++) {
00459 if (!ast_strlen_zero(query->readhandle[dsn])) {
00460 obj = ast_odbc_request_obj(query->readhandle[dsn], 0);
00461 if (obj) {
00462 stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql));
00463 }
00464 }
00465 if (stmt) {
00466 break;
00467 }
00468 if (obj) {
00469 ast_odbc_release_obj(obj);
00470 obj = NULL;
00471 }
00472 }
00473
00474 if (!stmt) {
00475 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
00476 if (obj) {
00477 ast_odbc_release_obj(obj);
00478 obj = NULL;
00479 }
00480 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00481 if (chan) {
00482 ast_autoservice_stop(chan);
00483 }
00484 if (bogus_chan) {
00485 ast_channel_free(chan);
00486 }
00487 return -1;
00488 }
00489
00490 res = SQLNumResultCols(stmt, &colcount);
00491 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00492 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
00493 SQLCloseCursor(stmt);
00494 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00495 ast_odbc_release_obj(obj);
00496 obj = NULL;
00497 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00498 if (chan) {
00499 ast_autoservice_stop(chan);
00500 }
00501 if (bogus_chan) {
00502 ast_channel_free(chan);
00503 }
00504 return -1;
00505 }
00506
00507 res = SQLFetch(stmt);
00508 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00509 int res1 = -1;
00510 if (res == SQL_NO_DATA) {
00511 ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
00512 res1 = 0;
00513 buf[0] = '\0';
00514 ast_copy_string(rowcount, "0", sizeof(rowcount));
00515 status = "NODATA";
00516 } else {
00517 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
00518 status = "FETCHERROR";
00519 }
00520 SQLCloseCursor(stmt);
00521 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00522 ast_odbc_release_obj(obj);
00523 obj = NULL;
00524 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00525 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00526 if (chan)
00527 ast_autoservice_stop(chan);
00528 if (bogus_chan)
00529 ast_channel_free(chan);
00530 return res1;
00531 }
00532
00533 status = "SUCCESS";
00534
00535 for (y = 0; y < rowlimit; y++) {
00536 buf[0] = '\0';
00537 for (x = 0; x < colcount; x++) {
00538 int i;
00539 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
00540 char *ptrcoldata;
00541
00542 if (!coldata) {
00543 ast_free(resultset);
00544 SQLCloseCursor(stmt);
00545 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00546 ast_odbc_release_obj(obj);
00547 obj = NULL;
00548 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00549 if (chan)
00550 ast_autoservice_stop(chan);
00551 if (bogus_chan) {
00552 ast_channel_free(chan);
00553 }
00554 return -1;
00555 }
00556
00557 if (y == 0) {
00558 char colname[256];
00559 SQLULEN maxcol;
00560
00561 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
00562 ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x);
00563 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
00564 snprintf(colname, sizeof(colname), "field%d", x);
00565 }
00566
00567 ast_str_make_space(&coldata, maxcol + 1);
00568
00569 if (ast_str_strlen(colnames)) {
00570 ast_str_append(&colnames, 0, ",");
00571 }
00572 ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
00573
00574 if (resultset) {
00575 void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
00576 if (!tmp) {
00577 ast_log(LOG_ERROR, "No space for a new resultset?\n");
00578 ast_free(resultset);
00579 SQLCloseCursor(stmt);
00580 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00581 ast_odbc_release_obj(obj);
00582 obj = NULL;
00583 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00584 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00585 if (chan)
00586 ast_autoservice_stop(chan);
00587 if (bogus_chan)
00588 ast_channel_free(chan);
00589 return -1;
00590 }
00591 resultset = tmp;
00592 strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
00593 }
00594 }
00595
00596 buflen = strlen(buf);
00597 res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
00598 if (indicator == SQL_NULL_DATA) {
00599 ast_debug(3, "Got NULL data\n");
00600 ast_str_reset(coldata);
00601 res = SQL_SUCCESS;
00602 }
00603
00604 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00605 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
00606 y = -1;
00607 buf[0] = '\0';
00608 goto end_acf_read;
00609 }
00610
00611 ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
00612
00613 if (x) {
00614 buf[buflen++] = ',';
00615 }
00616
00617
00618 ptrcoldata = ast_str_buffer(coldata);
00619 for (i = 0; i < ast_str_strlen(coldata); i++) {
00620 if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
00621 buf[buflen++] = '\\';
00622 }
00623 buf[buflen++] = ptrcoldata[i];
00624
00625 if (buflen >= len - 2) {
00626 break;
00627 }
00628
00629 if (ptrcoldata[i] == '\0') {
00630 break;
00631 }
00632 }
00633
00634 buf[buflen] = '\0';
00635 ast_debug(2, "buf is now set to '%s'\n", buf);
00636 }
00637 ast_debug(2, "buf is now set to '%s'\n", buf);
00638
00639 if (resultset) {
00640 row = ast_calloc(1, sizeof(*row) + buflen + 1);
00641 if (!row) {
00642 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
00643 status = "MEMERROR";
00644 goto end_acf_read;
00645 }
00646 strcpy((char *)row + sizeof(*row), buf);
00647 AST_LIST_INSERT_TAIL(resultset, row, list);
00648
00649
00650 res = SQLFetch(stmt);
00651 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00652 if (res != SQL_NO_DATA) {
00653 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
00654 }
00655
00656 y++;
00657 break;
00658 }
00659 }
00660 }
00661
00662 end_acf_read:
00663 snprintf(rowcount, sizeof(rowcount), "%d", y);
00664 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00665 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00666 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
00667 if (resultset) {
00668 int uid;
00669 struct ast_datastore *odbc_store;
00670 uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
00671 snprintf(buf, len, "%d", uid);
00672 odbc_store = ast_datastore_alloc(&odbc_info, buf);
00673 if (!odbc_store) {
00674 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
00675 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00676 odbc_datastore_free(resultset);
00677 SQLCloseCursor(stmt);
00678 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00679 ast_odbc_release_obj(obj);
00680 obj = NULL;
00681 if (chan)
00682 ast_autoservice_stop(chan);
00683 if (bogus_chan)
00684 ast_channel_free(chan);
00685 return -1;
00686 }
00687 odbc_store->data = resultset;
00688 ast_channel_datastore_add(chan, odbc_store);
00689 }
00690 SQLCloseCursor(stmt);
00691 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00692 ast_odbc_release_obj(obj);
00693 obj = NULL;
00694 if (chan)
00695 ast_autoservice_stop(chan);
00696 if (bogus_chan)
00697 ast_channel_free(chan);
00698 return 0;
00699 }
00700
00701 static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00702 {
00703 char *out = buf;
00704
00705 for (; *data && out - buf < len; data++) {
00706 if (*data == '\'') {
00707 *out = '\'';
00708 out++;
00709 }
00710 *out++ = *data;
00711 }
00712 *out = '\0';
00713
00714 return 0;
00715 }
00716
00717 static struct ast_custom_function escape_function = {
00718 .name = "SQL_ESC",
00719 .read = acf_escape,
00720 .write = NULL,
00721 };
00722
00723 static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00724 {
00725 struct ast_datastore *store;
00726 struct odbc_datastore *resultset;
00727 struct odbc_datastore_row *row;
00728 store = ast_channel_datastore_find(chan, &odbc_info, data);
00729 if (!store) {
00730 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
00731 return -1;
00732 }
00733 resultset = store->data;
00734 AST_LIST_LOCK(resultset);
00735 row = AST_LIST_REMOVE_HEAD(resultset, list);
00736 AST_LIST_UNLOCK(resultset);
00737 if (!row) {
00738
00739 ast_channel_datastore_remove(chan, store);
00740 ast_datastore_free(store);
00741 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
00742 return -1;
00743 }
00744 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
00745 ast_copy_string(buf, row->data, len);
00746 ast_free(row);
00747 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
00748 return 0;
00749 }
00750
00751 static struct ast_custom_function fetch_function = {
00752 .name = "ODBC_FETCH",
00753 .read = acf_fetch,
00754 .write = NULL,
00755 };
00756
00757 static char *app_odbcfinish = "ODBCFinish";
00758
00759 static int exec_odbcfinish(struct ast_channel *chan, void *data)
00760 {
00761 struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data);
00762 if (!store)
00763 return 0;
00764 ast_channel_datastore_remove(chan, store);
00765 ast_datastore_free(store);
00766 return 0;
00767 }
00768
00769 static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
00770 {
00771 const char *tmp;
00772 int i;
00773
00774 if (!cfg || !catg) {
00775 return EINVAL;
00776 }
00777
00778 *query = ast_calloc(1, sizeof(struct acf_odbc_query));
00779 if (! (*query))
00780 return ENOMEM;
00781
00782 if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
00783 char *tmp2 = ast_strdupa(tmp);
00784 AST_DECLARE_APP_ARGS(writeconf,
00785 AST_APP_ARG(dsn)[5];
00786 );
00787 AST_STANDARD_APP_ARGS(writeconf, tmp2);
00788 for (i = 0; i < 5; i++) {
00789 if (!ast_strlen_zero(writeconf.dsn[i]))
00790 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
00791 }
00792 }
00793
00794 if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
00795 char *tmp2 = ast_strdupa(tmp);
00796 AST_DECLARE_APP_ARGS(readconf,
00797 AST_APP_ARG(dsn)[5];
00798 );
00799 AST_STANDARD_APP_ARGS(readconf, tmp2);
00800 for (i = 0; i < 5; i++) {
00801 if (!ast_strlen_zero(readconf.dsn[i]))
00802 ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
00803 }
00804 } else {
00805
00806 for (i = 0; i < 5; i++) {
00807 if (!ast_strlen_zero((*query)->writehandle[i]))
00808 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
00809 }
00810 }
00811
00812 if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")))
00813 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00814 else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) {
00815 ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg);
00816 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00817 }
00818
00819 if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) {
00820 ast_free(*query);
00821 *query = NULL;
00822 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
00823 return EINVAL;
00824 }
00825
00826 if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")))
00827 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00828 else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) {
00829 ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg);
00830 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00831 }
00832
00833 if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) {
00834 ast_free(*query);
00835 *query = NULL;
00836 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
00837 return EINVAL;
00838 }
00839
00840 if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
00841 ast_copy_string((*query)->sql_insert, tmp, sizeof((*query)->sql_insert));
00842 }
00843
00844
00845 ast_set_flag((*query), OPT_ESCAPECOMMAS);
00846 if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
00847 if (ast_false(tmp))
00848 ast_clear_flag((*query), OPT_ESCAPECOMMAS);
00849 }
00850
00851 if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
00852 if (strcasecmp(tmp, "multirow") == 0)
00853 ast_set_flag((*query), OPT_MULTIROW);
00854 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
00855 sscanf(tmp, "%30d", &((*query)->rowlimit));
00856 }
00857
00858 (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
00859 if (! (*query)->acf) {
00860 ast_free(*query);
00861 *query = NULL;
00862 return ENOMEM;
00863 }
00864 if (ast_string_field_init((*query)->acf, 128)) {
00865 ast_free((*query)->acf);
00866 ast_free(*query);
00867 *query = NULL;
00868 return ENOMEM;
00869 }
00870
00871 if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
00872 if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
00873 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00874 }
00875 } else {
00876 if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
00877 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00878 }
00879 }
00880
00881 if (!((*query)->acf->name)) {
00882 ast_string_field_free_memory((*query)->acf);
00883 ast_free((*query)->acf);
00884 ast_free(*query);
00885 *query = NULL;
00886 return ENOMEM;
00887 }
00888
00889 if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
00890 ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
00891 } else {
00892 ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
00893 }
00894
00895 if (ast_strlen_zero((*query)->acf->syntax)) {
00896 ast_free((char *)(*query)->acf->name);
00897 ast_string_field_free_memory((*query)->acf);
00898 ast_free((*query)->acf);
00899 ast_free(*query);
00900 *query = NULL;
00901 return ENOMEM;
00902 }
00903
00904 if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
00905 ast_string_field_set((*query)->acf, synopsis, tmp);
00906 } else {
00907 ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
00908 }
00909
00910 if (ast_strlen_zero((*query)->acf->synopsis)) {
00911 ast_free((char *)(*query)->acf->name);
00912 ast_string_field_free_memory((*query)->acf);
00913 ast_free((*query)->acf);
00914 ast_free(*query);
00915 *query = NULL;
00916 return ENOMEM;
00917 }
00918
00919 if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) {
00920 ast_string_field_build((*query)->acf, desc,
00921 "Runs the following query, as defined in func_odbc.conf, performing\n"
00922 "substitution of the arguments into the query as specified by ${ARG1},\n"
00923 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
00924 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
00925 "%s"
00926 "\nRead:\n%s\n\nWrite:\n%s\n%s%s%s",
00927 ast_strlen_zero((*query)->sql_insert) ? "" :
00928 "If the write query affects no rows, the insert query will be\n"
00929 "performed.\n",
00930 (*query)->sql_read,
00931 (*query)->sql_write,
00932 ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n",
00933 ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
00934 ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
00935 } else if (!ast_strlen_zero((*query)->sql_read)) {
00936 ast_string_field_build((*query)->acf, desc,
00937 "Runs the following query, as defined in func_odbc.conf, performing\n"
00938 "substitution of the arguments into the query as specified by ${ARG1},\n"
00939 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n",
00940 (*query)->sql_read);
00941 } else if (!ast_strlen_zero((*query)->sql_write)) {
00942 ast_string_field_build((*query)->acf, desc,
00943 "Runs the following query, as defined in func_odbc.conf, performing\n"
00944 "substitution of the arguments into the query as specified by ${ARG1},\n"
00945 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
00946 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
00947 "This function may only be set.\n%sSQL:\n%s\n%s%s%s",
00948 ast_strlen_zero((*query)->sql_insert) ? "" :
00949 "If the write query affects no rows, the insert query will be\n"
00950 "performed.\n",
00951 (*query)->sql_write,
00952 ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n",
00953 ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
00954 ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
00955 } else {
00956 ast_string_field_free_memory((*query)->acf);
00957 ast_free((char *)(*query)->acf->name);
00958 ast_free((*query)->acf);
00959 ast_free(*query);
00960 ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg);
00961 return EINVAL;
00962 }
00963
00964 if (ast_strlen_zero((*query)->acf->desc)) {
00965 ast_string_field_free_memory((*query)->acf);
00966 ast_free((char *)(*query)->acf->name);
00967 ast_free((*query)->acf);
00968 ast_free(*query);
00969 *query = NULL;
00970 return ENOMEM;
00971 }
00972
00973 if (ast_strlen_zero((*query)->sql_read)) {
00974 (*query)->acf->read = NULL;
00975 } else {
00976 (*query)->acf->read = acf_odbc_read;
00977 }
00978
00979 if (ast_strlen_zero((*query)->sql_write)) {
00980 (*query)->acf->write = NULL;
00981 } else {
00982 (*query)->acf->write = acf_odbc_write;
00983 }
00984
00985 return 0;
00986 }
00987
00988 static int free_acf_query(struct acf_odbc_query *query)
00989 {
00990 if (query) {
00991 if (query->acf) {
00992 if (query->acf->name)
00993 ast_free((char *)query->acf->name);
00994 ast_string_field_free_memory(query->acf);
00995 ast_free(query->acf);
00996 }
00997 ast_free(query);
00998 }
00999 return 0;
01000 }
01001
01002 static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01003 {
01004 AST_DECLARE_APP_ARGS(args,
01005 AST_APP_ARG(field)[100];
01006 );
01007 struct ast_str *sql;
01008 char *char_args, varname[10];
01009 struct acf_odbc_query *query;
01010 struct ast_channel *chan;
01011 int i;
01012
01013 switch (cmd) {
01014 case CLI_INIT:
01015 e->command = "odbc read";
01016 e->usage =
01017 "Usage: odbc read <name> <args> [exec]\n"
01018 " Evaluates the SQL provided in the ODBC function <name>, and\n"
01019 " optionally executes the function. This function is intended for\n"
01020 " testing purposes. Remember to quote arguments containing spaces.\n";
01021 return NULL;
01022 case CLI_GENERATE:
01023 if (a->pos == 2) {
01024 int wordlen = strlen(a->word), which = 0;
01025
01026 AST_RWLIST_RDLOCK(&queries);
01027 AST_RWLIST_TRAVERSE(&queries, query, list) {
01028 if (!strncasecmp(query->acf->name, a->word, wordlen)) {
01029 if (++which > a->n) {
01030 char *res = ast_strdup(query->acf->name);
01031 AST_RWLIST_UNLOCK(&queries);
01032 return res;
01033 }
01034 }
01035 }
01036 AST_RWLIST_UNLOCK(&queries);
01037 return NULL;
01038 } else if (a->pos == 4) {
01039 return a->n == 0 ? ast_strdup("exec") : NULL;
01040 } else {
01041 return NULL;
01042 }
01043 }
01044
01045 if (a->argc < 4 || a->argc > 5) {
01046 return CLI_SHOWUSAGE;
01047 }
01048
01049 sql = ast_str_thread_get(&sql_buf, 16);
01050 if (!sql) {
01051 return CLI_FAILURE;
01052 }
01053
01054 AST_RWLIST_RDLOCK(&queries);
01055 AST_RWLIST_TRAVERSE(&queries, query, list) {
01056 if (!strcmp(query->acf->name, a->argv[2])) {
01057 break;
01058 }
01059 }
01060
01061 if (!query) {
01062 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
01063 AST_RWLIST_UNLOCK(&queries);
01064 return CLI_SHOWUSAGE;
01065 }
01066
01067 if (ast_strlen_zero(query->sql_read)) {
01068 ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
01069 AST_RWLIST_UNLOCK(&queries);
01070 return CLI_SUCCESS;
01071 }
01072
01073 ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
01074
01075
01076 char_args = ast_strdupa(a->argv[3]);
01077
01078 chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc");
01079
01080 AST_STANDARD_APP_ARGS(args, char_args);
01081 for (i = 0; i < args.argc; i++) {
01082 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
01083 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
01084 }
01085
01086 ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
01087 ast_channel_free(chan);
01088
01089 if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
01090
01091 struct odbc_obj *obj = NULL;
01092 int dsn, executed = 0;
01093 SQLHSTMT stmt;
01094 int rows = 0, res, x;
01095 SQLSMALLINT colcount = 0, collength;
01096 SQLLEN indicator;
01097 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
01098 char colname[256];
01099 SQLULEN maxcol;
01100
01101 if (!coldata) {
01102 AST_RWLIST_UNLOCK(&queries);
01103 return CLI_SUCCESS;
01104 }
01105
01106 for (dsn = 0; dsn < 5; dsn++) {
01107 if (ast_strlen_zero(query->readhandle[dsn])) {
01108 continue;
01109 }
01110 ast_debug(1, "Found handle %s\n", query->readhandle[dsn]);
01111 if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) {
01112 continue;
01113 }
01114
01115 ast_debug(1, "Got obj\n");
01116 if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
01117 ast_odbc_release_obj(obj);
01118 obj = NULL;
01119 continue;
01120 }
01121
01122 executed = 1;
01123
01124 res = SQLNumResultCols(stmt, &colcount);
01125 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01126 ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
01127 SQLCloseCursor(stmt);
01128 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01129 ast_odbc_release_obj(obj);
01130 obj = NULL;
01131 AST_RWLIST_UNLOCK(&queries);
01132 return CLI_SUCCESS;
01133 }
01134
01135 res = SQLFetch(stmt);
01136 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01137 SQLCloseCursor(stmt);
01138 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01139 ast_odbc_release_obj(obj);
01140 obj = NULL;
01141 if (res == SQL_NO_DATA) {
01142 ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql));
01143 break;
01144 } else {
01145 ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
01146 }
01147 AST_RWLIST_UNLOCK(&queries);
01148 return CLI_SUCCESS;
01149 }
01150 for (;;) {
01151 for (x = 0; x < colcount; x++) {
01152 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
01153 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
01154 snprintf(colname, sizeof(colname), "field%d", x);
01155 }
01156
01157 res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator);
01158 if (indicator == SQL_NULL_DATA) {
01159 ast_str_set(&coldata, 0, "(nil)");
01160 res = SQL_SUCCESS;
01161 }
01162
01163 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01164 ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
01165 SQLCloseCursor(stmt);
01166 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01167 ast_odbc_release_obj(obj);
01168 obj = NULL;
01169 AST_RWLIST_UNLOCK(&queries);
01170 return CLI_SUCCESS;
01171 }
01172
01173 ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata));
01174 }
01175 rows++;
01176
01177
01178 res = SQLFetch(stmt);
01179 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01180 break;
01181 }
01182 ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------");
01183 }
01184 SQLCloseCursor(stmt);
01185 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01186 ast_odbc_release_obj(obj);
01187 obj = NULL;
01188 ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]);
01189 break;
01190 }
01191 if (obj) {
01192 ast_odbc_release_obj(obj);
01193 obj = NULL;
01194 }
01195
01196 if (!executed) {
01197 ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
01198 }
01199 } else {
01200 ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
01201 }
01202 AST_RWLIST_UNLOCK(&queries);
01203 return CLI_SUCCESS;
01204 }
01205
01206 static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01207 {
01208 AST_DECLARE_APP_ARGS(values,
01209 AST_APP_ARG(field)[100];
01210 );
01211 AST_DECLARE_APP_ARGS(args,
01212 AST_APP_ARG(field)[100];
01213 );
01214 struct ast_str *sql;
01215 char *char_args, *char_values, varname[10];
01216 struct acf_odbc_query *query;
01217 struct ast_channel *chan;
01218 int i;
01219
01220 switch (cmd) {
01221 case CLI_INIT:
01222 e->command = "odbc write";
01223 e->usage =
01224 "Usage: odbc write <name> <args> <value> [exec]\n"
01225 " Evaluates the SQL provided in the ODBC function <name>, and\n"
01226 " optionally executes the function. This function is intended for\n"
01227 " testing purposes. Remember to quote arguments containing spaces.\n";
01228 return NULL;
01229 case CLI_GENERATE:
01230 if (a->pos == 2) {
01231 int wordlen = strlen(a->word), which = 0;
01232
01233 AST_RWLIST_RDLOCK(&queries);
01234 AST_RWLIST_TRAVERSE(&queries, query, list) {
01235 if (!strncasecmp(query->acf->name, a->word, wordlen)) {
01236 if (++which > a->n) {
01237 char *res = ast_strdup(query->acf->name);
01238 AST_RWLIST_UNLOCK(&queries);
01239 return res;
01240 }
01241 }
01242 }
01243 AST_RWLIST_UNLOCK(&queries);
01244 return NULL;
01245 } else if (a->pos == 5) {
01246 return a->n == 0 ? ast_strdup("exec") : NULL;
01247 } else {
01248 return NULL;
01249 }
01250 }
01251
01252 if (a->argc < 5 || a->argc > 6) {
01253 return CLI_SHOWUSAGE;
01254 }
01255
01256 sql = ast_str_thread_get(&sql_buf, 16);
01257 if (!sql) {
01258 return CLI_FAILURE;
01259 }
01260
01261 AST_RWLIST_RDLOCK(&queries);
01262 AST_RWLIST_TRAVERSE(&queries, query, list) {
01263 if (!strcmp(query->acf->name, a->argv[2])) {
01264 break;
01265 }
01266 }
01267
01268 if (!query) {
01269 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
01270 AST_RWLIST_UNLOCK(&queries);
01271 return CLI_SHOWUSAGE;
01272 }
01273
01274 if (ast_strlen_zero(query->sql_write)) {
01275 ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
01276 AST_RWLIST_UNLOCK(&queries);
01277 return CLI_SUCCESS;
01278 }
01279
01280 ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
01281
01282
01283 char_args = ast_strdupa(a->argv[3]);
01284 char_values = ast_strdupa(a->argv[4]);
01285
01286 chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc");
01287
01288 AST_STANDARD_APP_ARGS(args, char_args);
01289 for (i = 0; i < args.argc; i++) {
01290 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
01291 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
01292 }
01293
01294
01295 AST_STANDARD_APP_ARGS(values, char_values);
01296 for (i = 0; i < values.argc; i++) {
01297 snprintf(varname, sizeof(varname), "VAL%d", i + 1);
01298 pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
01299 }
01300
01301
01302 pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
01303 ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
01304 ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
01305 ast_channel_free(chan);
01306
01307 if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
01308
01309 struct odbc_obj *obj = NULL;
01310 int dsn, executed = 0;
01311 SQLHSTMT stmt;
01312 SQLLEN rows = -1;
01313
01314 for (dsn = 0; dsn < 5; dsn++) {
01315 if (ast_strlen_zero(query->writehandle[dsn])) {
01316 continue;
01317 }
01318 if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) {
01319 continue;
01320 }
01321 if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
01322 ast_odbc_release_obj(obj);
01323 obj = NULL;
01324 continue;
01325 }
01326
01327 SQLRowCount(stmt, &rows);
01328 SQLCloseCursor(stmt);
01329 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01330 ast_odbc_release_obj(obj);
01331 obj = NULL;
01332 ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]);
01333 executed = 1;
01334 break;
01335 }
01336
01337 if (!executed) {
01338 ast_cli(a->fd, "Failed to execute query.\n");
01339 }
01340 } else {
01341 ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
01342 }
01343 AST_RWLIST_UNLOCK(&queries);
01344 return CLI_SUCCESS;
01345 }
01346
01347 static struct ast_cli_entry cli_func_odbc[] = {
01348 AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"),
01349 AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"),
01350 };
01351
01352 static int load_module(void)
01353 {
01354 int res = 0;
01355 struct ast_config *cfg;
01356 char *catg;
01357 struct ast_flags config_flags = { 0 };
01358
01359 res |= ast_custom_function_register(&fetch_function);
01360 res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish);
01361 AST_RWLIST_WRLOCK(&queries);
01362
01363 cfg = ast_config_load(config, config_flags);
01364 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
01365 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
01366 AST_RWLIST_UNLOCK(&queries);
01367 return AST_MODULE_LOAD_DECLINE;
01368 }
01369
01370 for (catg = ast_category_browse(cfg, NULL);
01371 catg;
01372 catg = ast_category_browse(cfg, catg)) {
01373 struct acf_odbc_query *query = NULL;
01374 int err;
01375
01376 if ((err = init_acf_query(cfg, catg, &query))) {
01377 if (err == ENOMEM)
01378 ast_log(LOG_ERROR, "Out of memory\n");
01379 else if (err == EINVAL)
01380 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
01381 else
01382 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
01383 } else {
01384 AST_RWLIST_INSERT_HEAD(&queries, query, list);
01385 ast_custom_function_register(query->acf);
01386 }
01387 }
01388
01389 ast_config_destroy(cfg);
01390 res |= ast_custom_function_register(&escape_function);
01391 ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
01392
01393 AST_RWLIST_UNLOCK(&queries);
01394 return res;
01395 }
01396
01397 static int unload_module(void)
01398 {
01399 struct acf_odbc_query *query;
01400 int res = 0;
01401
01402 AST_RWLIST_WRLOCK(&queries);
01403 while (!AST_RWLIST_EMPTY(&queries)) {
01404 query = AST_RWLIST_REMOVE_HEAD(&queries, list);
01405 ast_custom_function_unregister(query->acf);
01406 free_acf_query(query);
01407 }
01408
01409 res |= ast_custom_function_unregister(&escape_function);
01410 res |= ast_custom_function_unregister(&fetch_function);
01411 res |= ast_unregister_application(app_odbcfinish);
01412 ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
01413
01414
01415 AST_RWLIST_UNLOCK(&queries);
01416 usleep(1);
01417 AST_RWLIST_WRLOCK(&queries);
01418
01419 AST_RWLIST_UNLOCK(&queries);
01420 return 0;
01421 }
01422
01423 static int reload(void)
01424 {
01425 int res = 0;
01426 struct ast_config *cfg;
01427 struct acf_odbc_query *oldquery;
01428 char *catg;
01429 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
01430
01431 cfg = ast_config_load(config, config_flags);
01432 if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
01433 return 0;
01434
01435 AST_RWLIST_WRLOCK(&queries);
01436
01437 while (!AST_RWLIST_EMPTY(&queries)) {
01438 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
01439 ast_custom_function_unregister(oldquery->acf);
01440 free_acf_query(oldquery);
01441 }
01442
01443 if (!cfg) {
01444 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
01445 goto reload_out;
01446 }
01447
01448 for (catg = ast_category_browse(cfg, NULL);
01449 catg;
01450 catg = ast_category_browse(cfg, catg)) {
01451 struct acf_odbc_query *query = NULL;
01452
01453 if (init_acf_query(cfg, catg, &query)) {
01454 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
01455 } else {
01456 AST_RWLIST_INSERT_HEAD(&queries, query, list);
01457 ast_custom_function_register(query->acf);
01458 }
01459 }
01460
01461 ast_config_destroy(cfg);
01462 reload_out:
01463 AST_RWLIST_UNLOCK(&queries);
01464 return res;
01465 }
01466
01467
01468
01469 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC lookups",
01470 .load = load_module,
01471 .unload = unload_module,
01472 .reload = reload,
01473 );
01474