00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 158135 $")
00039
00040 #include <time.h>
00041
00042 #include "asterisk/config.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/cdr.h"
00045 #include "asterisk/module.h"
00046 #include "asterisk/res_odbc.h"
00047
00048 #define DATE_FORMAT "%Y-%m-%d %T"
00049
00050 static char *name = "ODBC";
00051 static char *config_file = "cdr_odbc.conf";
00052 static char *dsn = NULL, *table = NULL;
00053
00054 enum {
00055 CONFIG_LOGUNIQUEID = 1 << 0,
00056 CONFIG_USEGMTIME = 1 << 1,
00057 CONFIG_DISPOSITIONSTRING = 1 << 2,
00058 };
00059
00060 static struct ast_flags config = { 0 };
00061
00062 static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
00063 {
00064 struct ast_cdr *cdr = data;
00065 SQLRETURN ODBC_res;
00066 char sqlcmd[2048] = "", timestr[128];
00067 struct ast_tm tm;
00068 SQLHSTMT stmt;
00069
00070 ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
00071 ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00072
00073 if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
00074 snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
00075 "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
00076 "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
00077 "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
00078 } else {
00079 snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
00080 "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
00081 "duration,billsec,disposition,amaflags,accountcode) "
00082 "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
00083 }
00084
00085 ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00086
00087 if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
00088 ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
00089 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00090 return NULL;
00091 }
00092
00093 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL);
00094 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL);
00095 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL);
00096 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL);
00097 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL);
00098 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL);
00099 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL);
00100 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL);
00101 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL);
00102 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
00103 if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING))
00104 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL);
00105 else
00106 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
00107 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
00108 SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);
00109
00110 if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
00111 SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
00112 SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
00113 }
00114
00115 ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);
00116
00117 if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
00118 ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res);
00119 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00120 return NULL;
00121 }
00122
00123 return stmt;
00124 }
00125
00126
00127 static int odbc_log(struct ast_cdr *cdr)
00128 {
00129 struct odbc_obj *obj = ast_odbc_request_obj(dsn, 0);
00130 SQLHSTMT stmt;
00131
00132 if (!obj) {
00133 ast_log(LOG_ERROR, "Unable to retrieve database handle. CDR failed.\n");
00134 return -1;
00135 }
00136
00137 stmt = ast_odbc_direct_execute(obj, execute_cb, cdr);
00138 if (stmt) {
00139 SQLLEN rows = 0;
00140
00141 SQLRowCount(stmt, &rows);
00142 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00143
00144 if (rows == 0)
00145 ast_log(LOG_WARNING, "CDR successfully ran, but inserted 0 rows?\n");
00146 } else
00147 ast_log(LOG_ERROR, "CDR direct execute failed\n");
00148 ast_odbc_release_obj(obj);
00149 return 0;
00150 }
00151
00152 static int odbc_load_module(int reload)
00153 {
00154 int res = 0;
00155 struct ast_config *cfg;
00156 struct ast_variable *var;
00157 const char *tmp;
00158 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00159
00160 do {
00161 cfg = ast_config_load(config_file, config_flags);
00162 if (!cfg) {
00163 ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config_file);
00164 res = AST_MODULE_LOAD_DECLINE;
00165 break;
00166 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00167 break;
00168
00169 var = ast_variable_browse(cfg, "global");
00170 if (!var) {
00171
00172 break;
00173 }
00174
00175 if ((tmp = ast_variable_retrieve(cfg, "global", "dsn")) == NULL) {
00176 ast_log(LOG_WARNING, "cdr_odbc: dsn not specified. Assuming asteriskdb\n");
00177 tmp = "asteriskdb";
00178 }
00179 if (dsn)
00180 ast_free(dsn);
00181 dsn = ast_strdup(tmp);
00182 if (dsn == NULL) {
00183 res = -1;
00184 break;
00185 }
00186
00187 if (((tmp = ast_variable_retrieve(cfg, "global", "dispositionstring"))) && ast_true(tmp))
00188 ast_set_flag(&config, CONFIG_DISPOSITIONSTRING);
00189 else
00190 ast_clear_flag(&config, CONFIG_DISPOSITIONSTRING);
00191
00192 if (((tmp = ast_variable_retrieve(cfg, "global", "loguniqueid"))) && ast_true(tmp)) {
00193 ast_set_flag(&config, CONFIG_LOGUNIQUEID);
00194 ast_debug(1, "cdr_odbc: Logging uniqueid\n");
00195 } else {
00196 ast_clear_flag(&config, CONFIG_LOGUNIQUEID);
00197 ast_debug(1, "cdr_odbc: Not logging uniqueid\n");
00198 }
00199
00200 if (((tmp = ast_variable_retrieve(cfg, "global", "usegmtime"))) && ast_true(tmp)) {
00201 ast_set_flag(&config, CONFIG_USEGMTIME);
00202 ast_debug(1, "cdr_odbc: Logging in GMT\n");
00203 } else {
00204 ast_clear_flag(&config, CONFIG_USEGMTIME);
00205 ast_debug(1, "cdr_odbc: Logging in local time\n");
00206 }
00207
00208 if ((tmp = ast_variable_retrieve(cfg, "global", "table")) == NULL) {
00209 ast_log(LOG_WARNING, "cdr_odbc: table not specified. Assuming cdr\n");
00210 tmp = "cdr";
00211 }
00212 if (table)
00213 ast_free(table);
00214 table = ast_strdup(tmp);
00215 if (table == NULL) {
00216 res = -1;
00217 break;
00218 }
00219
00220 ast_verb(3, "cdr_odbc: dsn is %s\n", dsn);
00221 ast_verb(3, "cdr_odbc: table is %s\n", table);
00222
00223 res = ast_cdr_register(name, ast_module_info->description, odbc_log);
00224 if (res) {
00225 ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n");
00226 }
00227 } while (0);
00228
00229 if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED)
00230 ast_config_destroy(cfg);
00231 return res;
00232 }
00233
00234 static int load_module(void)
00235 {
00236 return odbc_load_module(0);
00237 }
00238
00239 static int unload_module(void)
00240 {
00241 ast_cdr_unregister(name);
00242
00243 if (dsn) {
00244 ast_verb(11, "cdr_odbc: free dsn\n");
00245 ast_free(dsn);
00246 }
00247 if (table) {
00248 ast_verb(11, "cdr_odbc: free table\n");
00249 ast_free(table);
00250 }
00251
00252 return 0;
00253 }
00254
00255 static int reload(void)
00256 {
00257 return odbc_load_module(1);
00258 }
00259
00260 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC CDR Backend",
00261 .load = load_module,
00262 .unload = unload_module,
00263 .reload = reload,
00264 );