Mon May 14 04:42:57 2007

Asterisk developer's documentation


res_config_odbc.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com>
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief odbc+odbc plugin for portable configuration engine
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  * \author Anthony Minessale II <anthmct@yahoo.com>
00027  *
00028  * \arg http://www.unixodbc.org
00029  */
00030 
00031 /*** MODULEINFO
00032    <depend>unixodbc</depend>
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    /* Now bind the parameters */
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    /* Now bind the parameters */
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    /* Now bind the parameters */
00409    x = 1;
00410 
00411    while((newparam = va_arg(ap, const char *))) {
00412       newval = va_arg(ap, const char *);
00413       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00414    }
00415       
00416    SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
00417 
00418    res = ast_odbc_smart_execute(obj, stmt);
00419 
00420    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00421       ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
00422       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00423       ast_odbc_release_obj(obj);
00424       return -1;
00425    }
00426 
00427    res = SQLRowCount(stmt, &rowcount);
00428    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00429    ast_odbc_release_obj(obj);
00430 
00431    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00432       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00433       return -1;
00434    }
00435 
00436    if (rowcount >= 0)
00437       return (int)rowcount;
00438 
00439    return -1;
00440 }
00441 
00442 struct config_odbc_obj {
00443    char *sql;
00444    unsigned long cat_metric;
00445    char category[128];
00446    char var_name[128];
00447    char var_val[1024]; /* changed from 128 to 1024 via bug 8251 */
00448    SQLLEN err;
00449 };
00450 
00451 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
00452 {
00453    struct config_odbc_obj *q = data;
00454    SQLHSTMT sth;
00455    int res;
00456 
00457    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00458    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00459       if (option_verbose > 3)
00460          ast_verbose( VERBOSE_PREFIX_4 "Failure in AllocStatement %d\n", res);
00461       return NULL;
00462    }
00463 
00464    res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00465    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00466       if (option_verbose > 3)
00467          ast_verbose( VERBOSE_PREFIX_4 "Error in PREPARE %d\n", res);
00468       SQLFreeHandle(SQL_HANDLE_STMT, sth);
00469       return NULL;
00470    }
00471 
00472    SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00473    SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00474    SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00475    SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
00476 
00477    return sth;
00478 }
00479 
00480 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
00481 {
00482    struct ast_variable *new_v;
00483    struct ast_category *cur_cat;
00484    int res = 0;
00485    struct odbc_obj *obj;
00486    char sqlbuf[1024] = "";
00487    char *sql = sqlbuf;
00488    size_t sqlleft = sizeof(sqlbuf);
00489    unsigned int last_cat_metric = 0;
00490    SQLSMALLINT rowcount = 0;
00491    SQLHSTMT stmt;
00492    char last[128] = "";
00493    struct config_odbc_obj q;
00494 
00495    memset(&q, 0, sizeof(q));
00496 
00497    if (!file || !strcmp (file, "res_config_odbc.conf"))
00498       return NULL;      /* cant configure myself with myself ! */
00499 
00500    obj = ast_odbc_request_obj(database, 0);
00501    if (!obj)
00502       return NULL;
00503 
00504    ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
00505    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
00506    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00507    q.sql = sqlbuf;
00508 
00509    stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
00510 
00511    if (!stmt) {
00512       ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00513       ast_odbc_release_obj(obj);
00514       return NULL;
00515    }
00516 
00517    res = SQLNumResultCols(stmt, &rowcount);
00518 
00519    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00520       ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
00521       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00522       ast_odbc_release_obj(obj);
00523       return NULL;
00524    }
00525 
00526    if (!rowcount) {
00527       ast_log(LOG_NOTICE, "found nothing\n");
00528       ast_odbc_release_obj(obj);
00529       return cfg;
00530    }
00531 
00532    cur_cat = ast_config_get_current_category(cfg);
00533 
00534    while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
00535       if (!strcmp (q.var_name, "#include")) {
00536          if (!ast_config_internal_load(q.var_val, cfg, 0)) {
00537             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00538             ast_odbc_release_obj(obj);
00539             return NULL;
00540          }
00541          continue;
00542       } 
00543       if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
00544          cur_cat = ast_category_new(q.category);
00545          if (!cur_cat) {
00546             ast_log(LOG_WARNING, "Out of memory!\n");
00547             break;
00548          }
00549          strcpy(last, q.category);
00550          last_cat_metric   = q.cat_metric;
00551          ast_category_append(cfg, cur_cat);
00552       }
00553 
00554       new_v = ast_variable_new(q.var_name, q.var_val);
00555       ast_variable_append(cur_cat, new_v);
00556    }
00557 
00558    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00559    ast_odbc_release_obj(obj);
00560    return cfg;
00561 }
00562 
00563 static struct ast_config_engine odbc_engine = {
00564    .name = "odbc",
00565    .load_func = config_odbc,
00566    .realtime_func = realtime_odbc,
00567    .realtime_multi_func = realtime_multi_odbc,
00568    .update_func = update_odbc
00569 };
00570 
00571 static int unload_module (void)
00572 {
00573    ast_module_user_hangup_all();
00574    ast_config_engine_deregister(&odbc_engine);
00575    if (option_verbose)
00576       ast_verbose("res_config_odbc unloaded.\n");
00577    return 0;
00578 }
00579 
00580 static int load_module (void)
00581 {
00582    ast_config_engine_register(&odbc_engine);
00583    if (option_verbose)
00584       ast_verbose("res_config_odbc loaded.\n");
00585    return 0;
00586 }
00587 
00588 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC Configuration",
00589       .load = load_module,
00590       .unload = unload_module,
00591       );

Generated on Mon May 14 04:42:57 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1