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