/* * Asterisk -- A telephony toolkit for Linux. * * ODBC exec function * * Robert Hanzlik * * This program is free software, distributed under the terms of * the GNU General Public License * * Copyright (c) Digium * * Based on work by Mark Spencer and Jefferson Noxon - app_db.c * and Brian K. West - app_dbodbc.c * */ #include #include #include #include #include #include #include #include #include #define AST_MODULE "app_odbcexec" static char *tdesc = "Database query functions for Asterisk extension logic"; static char *q_descrip = " ODBCquery(varname=query): Retrieves a value from the database query\n" "and stores it in the given variable. Always returns 0. If the\n" "query failes, jumps to priority n+101 if available.\n"; static char *e_descrip = " ODBCexec(query): Executes a database query. Always returns 0.\n" "If the query failes, jumps to priority n+101 if available.\n"; static char *q_app = "ODBCquery"; static char *e_app = "ODBCexec"; static char *q_synopsis = "Retrieve a value from a ODBC query"; static char *e_synopsis = "Execute a ODBC query"; AST_MUTEX_DEFINE_STATIC(odbc_lock); static SQLHENV HOdbcEnv; static int ODBC_res; /* global ODBC Result of Functions */ static SQLHDBC ODBC_con; /* global ODBC Connection Handle */ static SQLHSTMT ODBC_stmt; /* global ODBC Statement Handle */ static char *config = "odbcexec.conf"; static char *dsn = NULL, *username = NULL, *password = NULL; static int dsn_alloc = 0, username_alloc = 0, password_alloc = 0; static int connected = 0; static int ast_odbcexec(const char *query, char *out, int outlen); static int odbc_load_module(int); static int odbc_init(void); static int odbc_unload_module(void); static int odbc_do_query(char *sqlcmd); static void reconect(void); void LogErrMsg(char * source, long rc,SQLSMALLINT HandleType,SQLHANDLE Handle); void LogErrMsg(char * source, long rc,SQLSMALLINT HandleType,SQLHANDLE Handle) { SQLSMALLINT len; SQLCHAR msg[200],buffer[200]; SQLCHAR sqlstat[10]; ast_log(LOG_ERROR, "Error %s %d\n",source,rc); SQLGetDiagRec(HandleType,Handle,1, sqlstat, &rc,msg,100,&len); ast_log(LOG_ERROR, "%s (%d)\n",msg,rc); } static int odbcexec_exec(struct ast_channel *chan, void *data) { int arglen, res; char *argv; arglen = strlen (data); argv = alloca (arglen + 1); if (!argv) /* Why would this fail? */ { ast_log (LOG_DEBUG, "Memory allocation failed\n"); return 0; } memcpy (argv, data, arglen + 1); ast_verb (3, "odbcexec: query=%s\n", argv); ast_mutex_lock(&odbc_lock); res = odbc_do_query(argv); ast_mutex_unlock(&odbc_lock); if(res==-1) { ast_verb (3, "odbcexec: Query failed.\n"); /* Send the call to n+101 priority, where n is the current priority */ if (ast_exists_extension (chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) chan->priority += 100; } return 0; } static int odbcexec_query(struct ast_channel *chan, void *data) { int arglen; char *argv, *varname, *query; char dbresult[256]; arglen = strlen (data); argv = alloca (arglen + 1); if (!argv) /* Why would this fail? */ { ast_log (LOG_DEBUG, "Memory allocation failed\n"); return 0; } memcpy (argv, data, arglen + 1); if (strchr (argv, '=')) { varname = strsep (&argv, "="); query = strsep (&argv, "\0"); if (!varname || !query) { ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n"); return 0; } ast_verb (3, "odbcquery: varname=%s, query=%s\n", varname, query); if (!ast_odbcexec (query, dbresult, sizeof (dbresult) - 1)) { pbx_builtin_setvar_helper (chan, varname, dbresult); ast_verb (3, "odbcquery: set variable %s to %s\n", varname, dbresult); } else { ast_verb (3,"odbcquery: Value not found in database.\n"); /* Send the call to n+101 priority, where n is the current priority */ if (ast_exists_extension (chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) chan->priority += 100; } } else { ast_log (LOG_DEBUG, "Ignoring, no parameters\n"); } return 0; } static int odbc_init(void) { long int ODBC_err; short int ODBC_mlen; char ODBC_msg[200], ODBC_stat[10]; ast_verb(3, "odbc_init called\n"); if ( HOdbcEnv == SQL_NULL_HANDLE || !connected) { ODBC_res = SQLAllocEnv(&HOdbcEnv); if (!SQL_SUCCEEDED(ODBC_res)) { ast_log(LOG_ERROR, "SQLAllocEnv failed\n"); return -1; } ODBC_res = SQLAllocConnect(HOdbcEnv, &ODBC_con); if (!SQL_SUCCEEDED(ODBC_res)) { ast_log(LOG_ERROR, "SQLAllocConnect failed\n"); SQLFreeHandle(SQL_HANDLE_ENV, HOdbcEnv); HOdbcEnv=NULL; return -1; } } ODBC_res = SQLConnect(ODBC_con, (SQLCHAR*)dsn, SQL_NTS, (SQLCHAR*)username, SQL_NTS, (SQLCHAR*)password, SQL_NTS); if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb( 4, "app_odbcexec: Error SQLConnect %d\n", ODBC_res); LogErrMsg("SQLConnect", ODBC_res, SQL_HANDLE_DBC, ODBC_con); SQLFreeHandle(SQL_HANDLE_ENV, HOdbcEnv); connected = 0; return -1; } else { ast_verb( 4, "app_odbcexec: Connected to %s\n", dsn); connected = 1; } return 0; } static int odbc_load_module(int reload) { int retval; int res; struct ast_config *cfg; struct ast_variable *var; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; char *tmp; cfg = ast_config_load(config, config_flags); if (!cfg) { ast_log(LOG_WARNING, "app_odbcexec: Unable to load config for unixODBC: %s\n", config); return 0; } var = ast_variable_browse(cfg, "global"); if (!var) { /* nothing configured */ return 0; } tmp = ast_variable_retrieve(cfg,"global","dsn"); if (tmp) { dsn = malloc(strlen(tmp) + 1); if (dsn != NULL) { dsn_alloc = 1; strcpy(dsn,tmp); } else { ast_log(LOG_ERROR,"app_odbcexec: Out of memory error.\n"); return -1; } } else { ast_log(LOG_WARNING,"app_odbcexec: dsn not specified. Assuming asteriskdb\n"); dsn = "asteriskdb"; } tmp = ast_variable_retrieve(cfg,"global","username"); if (tmp) { username = malloc(strlen(tmp) + 1); if (username != NULL) { username_alloc = 1; strcpy(username,tmp); } else { ast_log(LOG_ERROR,"app_odbcexec: Out of memory error.\n"); return -1; } } else { ast_log(LOG_WARNING,"app_odbcexec: username not specified. Assuming root\n"); username = "root"; } tmp = ast_variable_retrieve(cfg,"global","password"); if (tmp) { password = malloc(strlen(tmp) + 1); if (password != NULL) { password_alloc = 1; strcpy(password,tmp); } else { ast_log(LOG_ERROR,"app_odbcexec: Out of memory error.\n"); return -1; } } else { ast_log(LOG_WARNING,"app_odbcexec: database password not specified. Assuming blank\n"); password = ""; } ast_config_destroy(cfg); ast_verb( 4, "app_odbcexec: dsn is %s\n",dsn); ast_verb( 4, "app_odbcexec: username is %s\n",username); ast_verb( 4, "app_odbcexec: password is [secret]\n"); res = odbc_init(); if(res < 0) { ast_log(LOG_ERROR, "app_odbcexec: Unable to connect to datasource: %s\n", dsn); ast_verb( 4, "app_odbcexec: Unable to connect to datasource: %s\n", dsn); } retval = ast_register_application (q_app, odbcexec_query, q_synopsis, q_descrip); if (!retval) retval = ast_register_application (e_app, odbcexec_exec, e_synopsis, e_descrip); return retval; } static int odbc_do_query(char *sqlcmd) { long int ODBC_err; short int ODBC_mlen; char ODBC_msg[200], ODBC_stat[10]; int res2; ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, ODBC_con, &ODBC_stmt); if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb( 4, "app_odbcexec: Failure in AllocStatement %d\n", ODBC_res); LogErrMsg("SQLAllocHandle",ODBC_res,SQL_HANDLE_STMT,ODBC_con); SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); connected = 0; reconect(); return -1; } ODBC_res = SQLPrepare(ODBC_stmt, sqlcmd, SQL_NTS); if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb( 4, "app_odbcexec: Error in PREPARE %d\n", ODBC_res); LogErrMsg("SQLPrepare", ODBC_res, SQL_HANDLE_DBC, ODBC_con); SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); reconect(); return -1; } ODBC_res = SQLExecute(ODBC_stmt); if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb( 4, "app_odbcexec: Error in Query %d\n", ODBC_res); LogErrMsg("SQLExecute",ODBC_res,SQL_HANDLE_STMT,ODBC_stmt); SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); connected = 0; return -1; } else { ast_verb( 4, "app_odbcexec: Query Successful!\n"); connected = 1; } return 0; } static void reconect(void) { int res; if (connected) { SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); SQLDisconnect(ODBC_con); SQLFreeHandle(SQL_HANDLE_DBC, ODBC_con); SQLFreeHandle(SQL_HANDLE_ENV, HOdbcEnv); connected = 0; } res = odbc_init(); if(res < 0) { ast_log(LOG_ERROR, "app_odbcexec: Unable to connect to datasource: %s\n", dsn); ast_verb( 4, "app_odbcexec: Unable to connect to datasource: %s\n", dsn); } } static int odbc_unload_module(void) { int retval; if (connected) { ast_verb( 4, "app_odbcexec: Disconnecting from %s\n", dsn); SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); SQLDisconnect(ODBC_con); SQLFreeHandle(SQL_HANDLE_DBC, ODBC_con); SQLFreeHandle(SQL_HANDLE_ENV, HOdbcEnv); connected = 0; } if (dsn && dsn_alloc) { ast_verb( 4, "app_odbcexec: free dsn\n"); free(dsn); dsn = NULL; dsn_alloc = 0; } if (username && username_alloc) { ast_verb( 4, "app_odbcexec: free username\n"); free(username); username = NULL; username_alloc = 0; } if (password && password_alloc) { ast_verb( 4, "app_odbcexec: free password\n"); free(password); password = NULL; password_alloc = 0; } retval = ast_unregister_application (q_app); retval |= ast_unregister_application (e_app); return retval; } static int ast_odbcexec(const char *query, char *value, int valuelen) { int res; long int ODBC_err; char sqlcmd[1024]; char tmp[256] = ""; memset(sqlcmd,0,1024); ast_mutex_lock(&odbc_lock); sprintf(sqlcmd, "%s", query); res = odbc_do_query(sqlcmd); SQLBindCol(ODBC_stmt, 1, SQL_C_CHAR, &tmp, 50, &ODBC_err); if((ODBC_res = SQLFetch(ODBC_stmt) != SQL_NO_DATA)) { strcpy(value, tmp); } else { res = -1; } SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); ast_mutex_unlock(&odbc_lock); return res; } int unload_module (void) { ast_module_user_hangup_all(); return odbc_unload_module(); } int reload(void) { connected = 0; odbc_unload_module(); return odbc_load_module(1); } int load_module (void) { return odbc_load_module(0); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ODBC exec Querys");