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