/* * Asterisk -- A telephony toolkit for Linux. * * FreeTDS CDR logger * * This program is free software, distributed under the terms of * the GNU General Public License. * * * Table Structure for `cdr` * * Created on: 05/20/2004 16:16 * Last changed on: 06/07/2004 17:19 CREATE TABLE [dbo].[cdr] ( [accountcode] [varchar] (20) NULL , [src] [varchar] (80) NULL , [dst] [varchar] (80) NULL , [dcontext] [varchar] (80) NULL , [clid] [varchar] (80) NULL , [channel] [varchar] (80) NULL , [dstchannel] [varchar] (80) NULL , [lastapp] [varchar] (80) NULL , [lastdata] [varchar] (80) NULL , [start] [datetime] NULL , [answer] [datetime] NULL , [end] [datetime] NULL , [duration] [int] NULL , [billsec] [int] NULL , [disposition] [varchar] (20) NULL , [amaflags] [varchar] (16) NULL , [uniqueid] [varchar] (32) NULL ) ON [PRIMARY] */ #include #include #include #include #include #include #include #include "../asterisk.h" #include #include #include #include #include #include #include #include #define DATE_FORMAT "%Y/%m/%d %T" static char *desc = "MSSQL CDR Backend"; static char *name = "mssql"; static char *config = "cdr_tds.conf"; char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL; static int connected = 0; static ast_mutex_t tds_lock = AST_MUTEX_INITIALIZER; static TDSSOCKET *tds; static TDSLOGIN *login; static TDSCONTEXT *context; static int tds_log(struct ast_cdr *cdr) { struct tm tm; time_t t; char sqlcmd[2048], start[80], answer[80], end[80]; ast_mutex_lock(&tds_lock); if (!connected) { TDSCONNECTINFO *connection = tds_read_config_info(NULL, login, context->locale); if (!connection || tds_connect(tds, connection) == TDS_FAIL) { ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n"); } tds_free_connect(connection); } else { memset(sqlcmd, 0, 2048); if (strlen(cdr->accountcode) > 20) cdr->accountcode[20] = '\0'; if (strlen(cdr->src) > 80) cdr->src[80] = '\0'; if (strlen(cdr->dst) > 80) cdr->dst[80] = '\0'; if (strlen(cdr->dcontext) > 80) cdr->dcontext[80] = '\0'; if (strlen(cdr->clid) > 80) cdr->clid[80] = '\0'; if (strlen(cdr->channel) > 80) cdr->channel[80] = '\0'; if (strlen(cdr->dstchannel) > 80) cdr->dstchannel[80] = '\0'; if (strlen(cdr->lastapp) > 80) cdr->lastapp[80] = '\0'; if (strlen(cdr->lastdata) > 80) cdr->lastdata[80] = '\0'; if (strlen(cdr->uniqueid) > 32) cdr->uniqueid[32] = '\0'; t = cdr->start.tv_sec; localtime_r(&t, &tm); strftime(start, 80, DATE_FORMAT, &tm); t = cdr->answer.tv_sec; localtime_r(&t, &tm); strftime(answer, 80, DATE_FORMAT, &tm); t = cdr->end.tv_sec; localtime_r(&t, &tm); strftime(end, 80, DATE_FORMAT, &tm); sprintf(sqlcmd, "INSERT INTO cdr (accountcode, src, dst, dcontext, clid, channel, dstchannel, lastapp, lastdata, start, answer, [end], duration, billsec, disposition, amaflags, uniqueid) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, %i, '%s', '%s', '%s')", cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, start, answer, end, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid); if ((tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) { ast_log(LOG_ERROR, "Failed to insert record into database.\n"); ast_mutex_unlock(&tds_lock); connected = 0; return -1; } } ast_mutex_unlock(&tds_lock); return 0; } char *description(void) { return desc; } int unload_module(void) { tds_free_socket(tds); tds_free_login(login); tds_free_context(context); if (hostname) { free(hostname); hostname = NULL; } if (dbname) { free(dbname); dbname = NULL; } if (dbuser) { free(dbuser); dbuser = NULL; } if (password) { free(password); password = NULL; } if (charset) { free(charset); charset = NULL; } if (language) { free(language); language = NULL; } ast_cdr_unregister(name); return 0; } int load_module(void) { TDSCONNECTINFO *connection; int res = 0; struct ast_config *cfg; struct ast_variable *var; char query[1024], *ptr = NULL; cfg = ast_load(config); if (!cfg) { ast_log(LOG_WARNING, "Unable to load config for MSSQL CDR's: %s\n", config); return 0; } var = ast_variable_browse(cfg, "global"); if (!var) /* nothing configured */ return 0; ptr = ast_variable_retrieve(cfg, "global", "hostname"); if (ptr) hostname = strdup(ptr); else { ast_log(LOG_ERROR,"Database server hostname not specified.\n"); return -1; } ptr = ast_variable_retrieve(cfg, "global", "dbname"); if (ptr) dbname = strdup(ptr); else { ast_log(LOG_ERROR,"Database dbname not specified.\n"); return -1; } ptr = ast_variable_retrieve(cfg, "global", "user"); if (ptr) dbuser = strdup(ptr); else { ast_log(LOG_ERROR,"Database dbuser not specified.\n"); return -1; } ptr = ast_variable_retrieve(cfg, "global", "password"); if (ptr) password = strdup(ptr); else { ast_log(LOG_ERROR,"Database password not specified.\n"); return -1; } ptr = ast_variable_retrieve(cfg, "global", "charset"); if (ptr) charset = strdup(ptr); else charset = strdup("iso_1"); ptr = ast_variable_retrieve(cfg, "global", "language"); if (ptr) language = strdup(ptr); else language = strdup("us_english"); ast_destroy(cfg); // Connect to M$SQL Server if (!(login = tds_alloc_login())) { ast_log(LOG_ERROR, "tds_alloc_login() failed.\n"); return -1; } tds_set_server(login, hostname); tds_set_user(login, dbuser); tds_set_passwd(login, password); tds_set_app(login, "TSQL"); tds_set_library(login, "TDS-Library"); tds_set_client_charset(login, charset); tds_set_language(login, language); tds_set_packet(login, 512); tds_set_version(login, 7, 0); context = tds_alloc_context(); tds = tds_alloc_socket(context, 512); tds_set_parent(tds, NULL); connection = tds_read_config_info(NULL, login, context->locale); if (!connection || tds_connect(tds, connection) == TDS_FAIL) { ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n"); res = -1; } else connected = 1; tds_free_connect(connection); if (!res) { memset(query, 0, 1024); sprintf(query, "USE %s", dbname); if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) { ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname); res = -1; } else { // Register MSSQL CDR handler res = ast_cdr_register(name, desc, tds_log); if (res) { ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n"); } } } return res; } int reload(void) { unload_module(); return load_module(); } int usecount(void) { return 0; } char *key() { return ASTERISK_GPL_KEY; }