Example #1
0
static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
{

	buf[0] = '\0';
	/* Account code */
	append_string(buf, cdr->accountcode, bufsize);
	/* Source */
	append_string(buf, cdr->src, bufsize);
	/* Destination */
	append_string(buf, cdr->dst, bufsize);
	/* Destination context */
	append_string(buf, cdr->dcontext, bufsize);
	/* Caller*ID */
	append_string(buf, cdr->clid, bufsize);
	/* Channel */
	append_string(buf, cdr->channel, bufsize);
	/* Destination Channel */
	append_string(buf, cdr->dstchannel, bufsize);
	/* Last Application */
	append_string(buf, cdr->lastapp, bufsize);
	/* Last Data */
	append_string(buf, cdr->lastdata, bufsize);
	/* Start Time */
	append_date(buf, cdr->start, bufsize);
	/* Answer Time */
	append_date(buf, cdr->answer, bufsize);
	/* End Time */
	append_date(buf, cdr->end, bufsize);
	/* Duration */
	append_int(buf, cdr->duration, bufsize);
	/* Billable seconds */
	append_int(buf, cdr->billsec, bufsize);
	/* Disposition */
	append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
	/* AMA Flags */
	append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize);

#ifdef CSV_LOGUNIQUEID
	/* Unique ID */
	append_string(buf, cdr->uniqueid, bufsize);
#endif
#ifdef CSV_LOGUSERFIELD
	/* append the user field */
	append_string(buf, cdr->userfield,bufsize);	
#endif
	/* If we hit the end of our buffer, log an error */
	if (strlen(buf) < bufsize - 5) {
		/* Trim off trailing comma */
		buf[strlen(buf) - 1] = '\0';
		strncat(buf, "\n", bufsize - strlen(buf) - 1);
		return 0;
	}
	return -1;
}
Example #2
0
static int manager_log(struct ast_cdr *cdr)
{
	time_t t;
	struct tm timeresult;
	char strStartTime[80] = "";
	char strAnswerTime[80] = "";
	char strEndTime[80] = "";
	
	if (!enablecdr)
		return 0;

	t = cdr->start.tv_sec;
	localtime_r(&t, &timeresult);
	strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);
	
	if (cdr->answer.tv_sec)	{
    		t = cdr->answer.tv_sec;
    		localtime_r(&t, &timeresult);
		strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
	}

	t = cdr->end.tv_sec;
	localtime_r(&t, &timeresult);
	strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);

	manager_event(EVENT_FLAG_CALL, "Cdr",
	    "AccountCode: %s\r\n"
	    "Source: %s\r\n"
	    "Destination: %s\r\n"
	    "DestinationContext: %s\r\n"
	    "CallerID: %s\r\n"
	    "Channel: %s\r\n"
	    "DestinationChannel: %s\r\n"
	    "LastApplication: %s\r\n"
	    "LastData: %s\r\n"
	    "StartTime: %s\r\n"
	    "AnswerTime: %s\r\n"
	    "EndTime: %s\r\n"
	    "Duration: %d\r\n"
	    "BillableSeconds: %d\r\n"
	    "Disposition: %s\r\n"
	    "AMAFlags: %s\r\n"
	    "UniqueID: %s\r\n"
	    "UserField: %s\r\n",
	    cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
	    cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
	    cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), 
	    ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield);
	    	
	return 0;
}
Example #3
0
static int mongodb_log(struct ast_cdr *cdr)
{
	const char * ns;
	mongo conn[1];

	ast_debug(1, "mongodb: Starting mongodb_log.\n");

	mongo_init( &conn );
	if (mongo_connect( &conn , ast_str_buffer(hostname), dbport ) != MONGO_OK){
		mongo_destroy( &conn );
		ast_log(LOG_ERROR, "Method: mongodb_log, MongoDB failed to connect.\n");
		connected = 0;
		records = 0;
		return -1;
	}

	if (ast_str_strlen(dbuser) != 0 && (mongo_cmd_authenticate(&conn, ast_str_buffer(dbname), ast_str_buffer(dbuser), ast_str_buffer(password)) != MONGO_OK)) {
		mongo_destroy( &conn );
		ast_log(LOG_ERROR, "Method: mongodb_log, MongoDB failed to authenticate to do %s with username %s!\n", ast_str_buffer(dbname), ast_str_buffer(dbuser));
		connected = 0;
		records = 0;
		return -1;
	}

	ast_debug(1, "mongodb: Locking mongodb_lock.\n");
	ast_mutex_lock(&mongodb_lock);

	ast_debug(1, "mongodb: Got connection, Preparing record.\n");

	bson b[1];

	ast_debug(1, "mongodb: Init bson.\n");
	bson_init( &b );
	bson_append_new_oid( &b, "_id" );
	
	ast_debug(1, "mongodb: accountcode.\n");
	bson_append_string( &b , "accountcode",  cdr->accountcode);

	ast_debug(1, "mongodb: src.\n");
	bson_append_string( &b , "src",  cdr->src);

	ast_debug(1, "mongodb: dst.\n");
	bson_append_string( &b, "dst" , cdr->dst );

	ast_debug(1, "mongodb: dcontext.\n");
	bson_append_string( &b, "dcontext" , cdr->dcontext );

	ast_debug(1, "mongodb: clid.\n");
	bson_append_string( &b, "clid" , cdr->clid );

	ast_debug(1, "mongodb: channel.\n");
	bson_append_string( &b, "channel" , cdr->channel );

	ast_debug(1, "mongodb: dstchannel.\n");
	bson_append_string( &b, "dstchannel" , cdr->dstchannel );

	ast_debug(1, "mongodb: lastapp.\n");
	bson_append_string( &b, "lastapp" , cdr->lastapp );

	ast_debug(1, "mongodb: lastdata.\n");
	bson_append_string( &b, "lastdata" , cdr->lastdata );

	ast_debug(1, "mongodb: start.\n");
	bson_append_date( &b, "start", (bson_date_t)cdr->start.tv_sec*1000);

	ast_debug(1, "mongodb: answer.\n");
	bson_append_date( &b, "answer", (bson_date_t)cdr->answer.tv_sec*1000);

	ast_debug(1, "mongodb: end.\n");
	bson_append_date( &b, "end" , (bson_date_t)cdr->end.tv_sec*1000);

	ast_debug(1, "mongodb: duration.\n");
	bson_append_int( &b, "duration" , cdr->duration );

	ast_debug(1, "mongodb: billsec.\n");
	bson_append_int( &b, "billsec" , cdr->billsec );

	ast_debug(1, "mongodb: disposition.\n");
	bson_append_string( &b, "disposition" , ast_cdr_disp2str(cdr->disposition) );

	ast_debug(1, "mongodb: amaflags.\n");
	bson_append_string( &b, "amaflags" , ast_cdr_flags2str(cdr->amaflags) );

	ast_debug(1, "mongodb: uniqueid.\n");
	bson_append_string( &b, "uniqueid" , cdr->uniqueid );

	ast_debug(1, "mongodb: userfield.\n");
	bson_append_string( &b, "userfield" , cdr->userfield );

	bson_finish(&b);

	ast_debug(1, "mongodb: Inserting a CDR record.\n");
	mongo_insert( &conn , ast_str_buffer(dbnamespace) , &b );
	bson_destroy(&b);
	mongo_destroy( &conn );

	connected = 1;
	records++;
	totalrecords++;

	ast_debug(1, "Unlocking mongodb_lock.\n");
	ast_mutex_unlock(&mongodb_lock);
	return 0;
}
Example #4
0
static int csv_log(struct ast_cdr *cdr)
{
	FILE *mf = NULL;
	/* Make sure we have a big enough buf */
	char buf[1024];
	char csvmaster[PATH_MAX];
	snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
#if 0
	printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode);
#endif
	if (build_csv_record(buf, sizeof(buf), cdr)) {
		ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
		return 0;
	}

	/* because of the absolutely unconditional need for the
	   highest reliability possible in writing billing records,
	   we open write and close the log file each time */
	ast_mutex_lock(&mf_lock);
	if ((mf = fopen(csvmaster, "a"))) {
		fputs(buf, mf);
		fflush(mf); /* be particularly anal here */
		fclose(mf);
		mf = NULL;
		ast_mutex_unlock(&mf_lock);
	} else {
		ast_mutex_unlock(&mf_lock);
		ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
	}

	if (!ast_strlen_zero(cdr->accountcode)) {
		if (writefile(buf, cdr->accountcode))
			ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
	}

	return 0;
}
Example #5
0
static int tds_log(struct ast_cdr *cdr)
{
	char sqlcmd[2048], start[80], answer[80], end[80];
	char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
	int res = 0;
	int retried = 0;
#ifdef FREETDS_PRE_0_62
	TDS_INT result_type;
#endif

	ast_mutex_lock(&tds_lock);

	memset(sqlcmd, 0, 2048);

	accountcode = anti_injection(cdr->accountcode, 20);
	src = anti_injection(cdr->src, 80);
	dst = anti_injection(cdr->dst, 80);
	dcontext = anti_injection(cdr->dcontext, 80);
	clid = anti_injection(cdr->clid, 80);
	channel = anti_injection(cdr->channel, 80);
	dstchannel = anti_injection(cdr->dstchannel, 80);
	lastapp = anti_injection(cdr->lastapp, 80);
	lastdata = anti_injection(cdr->lastdata, 80);
	uniqueid = anti_injection(cdr->uniqueid, 32);

	get_date(start, cdr->start);
	get_date(answer, cdr->answer);
	get_date(end, cdr->end);

	sprintf(
		sqlcmd,
		"INSERT INTO cdr "
		"("
			"accountcode, "
			"src, "
			"dst, "
			"dcontext, "
			"clid, "
			"channel, "
			"dstchannel, "
			"lastapp, "
			"lastdata, "
			"start, "
			"answer, "
			"[end], "
			"duration, "
			"billsec, "
			"disposition, "
			"amaflags, "
			"uniqueid"
		") "
		"VALUES "
		"("
			"'%s', "	/* accountcode */
			"'%s', "	/* src */
			"'%s', "	/* dst */
			"'%s', "	/* dcontext */
			"'%s', "	/* clid */
			"'%s', "	/* channel */
			"'%s', "	/* dstchannel */
			"'%s', "	/* lastapp */
			"'%s', "	/* lastdata */
			"%s, "		/* start */
			"%s, "		/* answer */
			"%s, "		/* end */
			"%ld, "		/* duration */
			"%ld, "		/* billsec */
			"'%s', "	/* disposition */
			"'%s', "	/* amaflags */
			"'%s'"		/* uniqueid */
		")",
		accountcode,
		src,
		dst,
		dcontext,
		clid,
		channel,
		dstchannel,
		lastapp,
		lastdata,
		start,
		answer,
		end,
		cdr->duration,
		cdr->billsec,
		ast_cdr_disp2str(cdr->disposition),
		ast_cdr_flags2str(cdr->amaflags),
		uniqueid
	);

	do {
		if (!connected) {
			if (mssql_connect())
				ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n");
			else
				ast_log(LOG_WARNING, "Reconnected to SQL database.\n");

			retried = 1;	/* note that we have now tried */
		}

#ifdef FREETDS_PRE_0_62
		if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
#else
		if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
#endif
		{
			ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n");

			mssql_disconnect();	/* this is ok even if we are already disconnected */
		}
	} while (!connected && !retried);

	free(accountcode);
	free(src);
	free(dst);
	free(dcontext);
	free(clid);
	free(channel);
	free(dstchannel);
	free(lastapp);
	free(lastdata);
	free(uniqueid);

	ast_mutex_unlock(&tds_lock);

	return res;
}
Example #6
0
static int manager_log(struct ast_cdr *cdr)
{
	struct ast_tm timeresult;
	char strStartTime[80] = "";
	char strAnswerTime[80] = "";
	char strEndTime[80] = "";
	char buf[CUSTOM_FIELDS_BUF_SIZE];

	if (!enablecdr)
		return 0;

	ast_localtime(&cdr->start, &timeresult, NULL);
	ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);

	if (cdr->answer.tv_sec)	{
		ast_localtime(&cdr->answer, &timeresult, NULL);
		ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
	}

	ast_localtime(&cdr->end, &timeresult, NULL);
	ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);

	buf[0] = '\0';
	ast_rwlock_rdlock(&customfields_lock);
	if (customfields && ast_str_strlen(customfields)) {
		struct ast_channel *dummy = ast_dummy_channel_alloc();
		if (!dummy) {
			ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
			return 0;
		}
		dummy->cdr = ast_cdr_dup(cdr);
		pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
		ast_channel_unref(dummy);
	}
	ast_rwlock_unlock(&customfields_lock);

	manager_event(EVENT_FLAG_CDR, "Cdr",
	    "AccountCode: %s\r\n"
	    "Source: %s\r\n"
	    "Destination: %s\r\n"
	    "DestinationContext: %s\r\n"
	    "CallerID: %s\r\n"
	    "Channel: %s\r\n"
	    "DestinationChannel: %s\r\n"
	    "LastApplication: %s\r\n"
	    "LastData: %s\r\n"
	    "StartTime: %s\r\n"
	    "AnswerTime: %s\r\n"
	    "EndTime: %s\r\n"
	    "Duration: %ld\r\n"
	    "BillableSeconds: %ld\r\n"
	    "Disposition: %s\r\n"
	    "AMAFlags: %s\r\n"
	    "UniqueID: %s\r\n"
	    "UserField: %s\r\n"
	    "%s",
	    cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
	    cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
	    cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
	    ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf);

	return 0;
}
Example #7
0
static int odbc_log(struct ast_cdr *cdr)
{
	int ODBC_res;
	char sqlcmd[2048] = "", timestr[128];
	int res = 0;
	struct tm tm;

	if (usegmtime) 
		gmtime_r(&cdr->start.tv_sec,&tm);
	else
		ast_localtime(&cdr->start.tv_sec, &tm, NULL);

	ast_mutex_lock(&odbc_lock);
	strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
	memset(sqlcmd,0,2048);
	if (loguniqueid) {
		snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
		"(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
		"lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
		"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table);
	} else {
		snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
		"(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
		"duration,billsec,disposition,amaflags,accountcode) "
		"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table);
	}

	if (!connected) {
		res = odbc_init();
		if (res < 0) {
			odbc_disconnect();
			ast_mutex_unlock(&odbc_lock);
			return 0;
		}				
	}

	ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, ODBC_con, &ODBC_stmt);

	if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
		if (option_verbose > 10)
			ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
		SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
		odbc_disconnect();
		ast_mutex_unlock(&odbc_lock);
		return 0;
	}

	/* We really should only have to do this once.  But for some
	   strange reason if I don't it blows holes in memory like
	   like a shotgun.  So we just do this so its safe. */

	ODBC_res = SQLPrepare(ODBC_stmt, (unsigned char *)sqlcmd, SQL_NTS);
	
	if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
		if (option_verbose > 10)
			ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error in PREPARE %d\n", ODBC_res);
		SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
		odbc_disconnect();
		ast_mutex_unlock(&odbc_lock);
		return 0;
	}

	SQLBindParameter(ODBC_stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(timestr), 0, &timestr, 0, NULL);
	SQLBindParameter(ODBC_stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL);
	SQLBindParameter(ODBC_stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL);
	SQLBindParameter(ODBC_stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL);
	SQLBindParameter(ODBC_stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL);
	SQLBindParameter(ODBC_stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL);
	SQLBindParameter(ODBC_stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL);
	SQLBindParameter(ODBC_stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL);
	SQLBindParameter(ODBC_stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL);
	SQLBindParameter(ODBC_stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL);
	SQLBindParameter(ODBC_stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
	if (dispositionstring)
		SQLBindParameter(ODBC_stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL);
	else
		SQLBindParameter(ODBC_stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
	SQLBindParameter(ODBC_stmt, 13, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
	SQLBindParameter(ODBC_stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);

	if (loguniqueid) {
		SQLBindParameter(ODBC_stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
		SQLBindParameter(ODBC_stmt, 16, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
	}

	if (connected) {
		res = odbc_do_query();
		if (res < 0) {
			if (option_verbose > 10)		
				ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n");
			if (option_verbose > 10)
				ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Reconnecting to dsn %s\n", dsn);
			SQLDisconnect(ODBC_con);
			res = odbc_init();
			if (res < 0) {
				if (option_verbose > 10)
					ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: %s has gone away!\n", dsn);
				odbc_disconnect();
			} else {
				if (option_verbose > 10)
					ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Trying Query again!\n");
				res = odbc_do_query();
				if (res < 0) {
					if (option_verbose > 10)
						ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n");
				}
			}
		}
	} else {
		if (option_verbose > 10)
			ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n");
	}
	SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
	ast_mutex_unlock(&odbc_lock);
	return 0;
}
Example #8
0
static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
{
    struct ast_cdr *cdr = data;
    SQLRETURN ODBC_res;
    char sqlcmd[2048] = "", timestr[128];
    struct ast_tm tm;
    SQLHSTMT stmt;

    ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
    ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);

    if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
        snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
                 "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
                 "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
                 "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
    } else {
        snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
                 "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
                 "duration,billsec,disposition,amaflags,accountcode) "
                 "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
    }

    ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);

    if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
        ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
        return NULL;
    }

    SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL);
    SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL);
    SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL);
    SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL);
    SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL);
    SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL);
    SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL);
    SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL);

    if (ast_test_flag(&config, CONFIG_HRTIME)) {
        double hrbillsec = 0.0;
        double hrduration;

        if (!ast_tvzero(cdr->answer)) {
            hrbillsec = (double) ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0;
        }
        hrduration = (double) ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0;

        SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrduration, 0, NULL);
        SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrbillsec, 0, NULL);
    } else {
        SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL);
        SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
    }

    if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING))
        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);
    else
        SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
    SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
    SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);

    if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
        SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
        SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
    }

    ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);

    if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
        ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res);
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
        return NULL;
    }

    return stmt;
}
Example #9
0
static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr)
{
	int recordtype = PW_STATUS_STOP;
	struct ast_tm tm;
	char timestr[128];
	char *tmp;

	if (!rc_avpair_add(rh, tosend, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0))
		return -1;

	/* Account code */
	if (!rc_avpair_add(rh, tosend, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE))
		return -1;

 	/* Source */
	if (!rc_avpair_add(rh, tosend, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE))
		return -1;

 	/* Destination */
	if (!rc_avpair_add(rh, tosend, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE))
		return -1;

 	/* Destination context */
	if (!rc_avpair_add(rh, tosend, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE))
		return -1;

	/* Caller ID */
	if (!rc_avpair_add(rh, tosend, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE))
		return -1;

	/* Channel */
	if (!rc_avpair_add(rh, tosend, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE))
		return -1;

	/* Destination Channel */
	if (!rc_avpair_add(rh, tosend, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE))
		return -1;

	/* Last Application */
	if (!rc_avpair_add(rh, tosend, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE))
		return -1;

	/* Last Data */
	if (!rc_avpair_add(rh, tosend, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE))
		return -1;


	/* Start Time */
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT,
		ast_localtime(&cdr->start, &tm,
			ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL));
	if (!rc_avpair_add(rh, tosend, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE))
		return -1;

	/* Answer Time */
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT,
		ast_localtime(&cdr->answer, &tm,
			ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL));
	if (!rc_avpair_add(rh, tosend, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE))
		return -1;

	/* End Time */
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT,
		ast_localtime(&cdr->end, &tm,
			ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL));
	if (!rc_avpair_add(rh, tosend, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE))
		return -1;

 	/* Duration */
	if (!rc_avpair_add(rh, tosend, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE))
		return -1;

	/* Billable seconds */
	if (!rc_avpair_add(rh, tosend, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE))
		return -1;

	/* Disposition */
	tmp = ast_cdr_disp2str(cdr->disposition);
	if (!rc_avpair_add(rh, tosend, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE))
		return -1;

	/* AMA Flags */
	tmp = ast_cdr_flags2str(cdr->amaflags);
	if (!rc_avpair_add(rh, tosend, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE))
		return -1;

	if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
		/* Unique ID */
		if (!rc_avpair_add(rh, tosend, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE))
			return -1;
	}

	if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) {
		/* append the user field */
		if (!rc_avpair_add(rh, tosend, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE))
			return -1;
	}

	/* Setting Acct-Session-Id & User-Name attributes for proper generation
	   of Acct-Unique-Session-Id on server side */
	/* Channel */
	if (!rc_avpair_add(rh, tosend, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0))
		return -1;

	/* Unique ID */
	if (!rc_avpair_add(rh, tosend, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0))
		return -1;

	return 0;
}
Example #10
0
static int beanstalk_put(struct ast_cdr *cdr) {
	struct ast_tm timeresult;
	char strAnswerTime[80] = "";
	char strStartTime[80];
	char strEndTime[80];
	char *cdr_buffer;
	int bs_id;
	int bs_socket;
	struct ast_json *t_cdr_json;

	if (!enablecdr) {
		return 0;
	}

	ast_rwlock_rdlock(&config_lock);
	bs_socket = bs_connect(bs_host, bs_port);

	if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {
		ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);
		ast_rwlock_unlock(&config_lock);
		return 0;
	}

	ast_localtime(&cdr->start, &timeresult, NULL);
	ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);

	if (cdr->answer.tv_sec) {
		ast_localtime(&cdr->answer, &timeresult, NULL);
		ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
	}

	ast_localtime(&cdr->end, &timeresult, NULL);
	ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);

	ast_rwlock_unlock(&config_lock);

	t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:s}",
							   "AccountCode", S_OR(cdr->accountcode, ""),
							   "Source", S_OR(cdr->src, ""),
							   "Destination", S_OR(cdr->dst, ""),
							   "DestinationContext", S_OR(cdr->dcontext, ""),
							   "CallerID", S_OR(cdr->clid, ""),
							   "Channel", S_OR(cdr->channel, ""),
							   "DestinationChannel", S_OR(cdr->dstchannel, ""),
							   "LastApplication", S_OR(cdr->lastapp, ""),
							   "LastData", S_OR(cdr->lastdata, ""),
							   "StartTime", S_OR(strStartTime, ""),
							   "AnswerTime", S_OR(strAnswerTime, ""),
							   "EndTime", S_OR(strEndTime, ""),
							   "Duration", cdr->duration,
							   "Billsec", cdr->billsec,
							   "Disposition", S_OR(ast_cdr_disp2str(cdr->disposition), ""),
							   "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""),
							   "UniqueID", S_OR(cdr->uniqueid, ""),
							   "UserField", S_OR(cdr->userfield, ""));

	cdr_buffer = ast_json_dump_string(t_cdr_json);

	ast_json_unref(t_cdr_json);

	bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cdr_buffer, strlen(cdr_buffer));

	if (bs_id > 0) {
		ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cdr_buffer);
	} else {
		ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cdr_buffer);
	}

	bs_disconnect(bs_socket);
	ast_json_free(cdr_buffer);
	return 0;
}
Example #11
0
static int mongodb_log(struct ast_cdr *cdr)
{
	int ret = -1;
    bson_t *doc = NULL;
    mongoc_collection_t *collection = NULL;

	if(dbpool == NULL) {
		ast_log(LOG_ERROR, "unexpected error, no connection pool\n");
		return ret;
	}

	mongoc_client_t *dbclient = mongoc_client_pool_pop(dbpool);
	if(dbclient == NULL) {
		ast_log(LOG_ERROR, "unexpected error, no client allocated\n");
		return ret;
	}

	do {
	    bson_error_t error;

	    doc = bson_new();
		if(doc == NULL) {
			ast_log(LOG_ERROR, "cannot make a document\n");
			break;
		}
	    mongoc_collection_t *collection = mongoc_client_get_collection(dbclient, dbname, dbcollection);
		if(collection == NULL) {
			ast_log(LOG_ERROR, "cannot get such a collection, %s, %s\n", dbname, dbcollection);
			break;
		}
		BSON_APPEND_UTF8(doc, "clid", cdr->clid);
		BSON_APPEND_UTF8(doc, "src", cdr->src);
		BSON_APPEND_UTF8(doc, "dst", cdr->dst);
		BSON_APPEND_UTF8(doc, "dcontext", cdr->dcontext);
		BSON_APPEND_UTF8(doc, "channel", cdr->channel);
		BSON_APPEND_UTF8(doc, "dstchannel", cdr->dstchannel);
		BSON_APPEND_UTF8(doc, "lastapp", cdr->lastapp);
		BSON_APPEND_UTF8(doc, "lastdata", cdr->lastdata);
		BSON_APPEND_UTF8(doc, "disposition", ast_cdr_disp2str(cdr->disposition));
		BSON_APPEND_UTF8(doc, "amaflags", ast_channel_amaflags2string(cdr->amaflags));
		BSON_APPEND_UTF8(doc, "accountcode", cdr->accountcode);
		BSON_APPEND_UTF8(doc, "uniqueid", cdr->uniqueid);
		BSON_APPEND_UTF8(doc, "userfield", cdr->userfield);
		BSON_APPEND_UTF8(doc, "peeraccount", cdr->peeraccount);
		BSON_APPEND_UTF8(doc, "linkedid", cdr->linkedid);
		BSON_APPEND_INT32(doc, "duration", cdr->duration);
		BSON_APPEND_INT32(doc, "billsec", cdr->billsec);
		BSON_APPEND_INT32(doc, "sequence", cdr->sequence);
		BSON_APPEND_TIMEVAL(doc, "start", &cdr->start);
		BSON_APPEND_TIMEVAL(doc, "answer", &cdr->answer);
		BSON_APPEND_TIMEVAL(doc, "end", &cdr->end);
		if (serverid)
			BSON_APPEND_OID(doc, SERVERID, serverid);

		if(!mongoc_collection_insert(collection, MONGOC_INSERT_NONE, doc, NULL, &error))
			ast_log(LOG_ERROR, "insertion failed, %s\n", error.message);

		ret = 0; // success
	} while(0);

	if (collection)
	    mongoc_collection_destroy(collection);
	if (doc)
	    bson_destroy(doc);
	mongoc_client_pool_push(dbpool, dbclient);
	return ret;
}
Example #12
0
static int sqlite_log(struct ast_cdr *cdr)
{
	int res = 0;
	char *zErr = 0;
	struct tm tm;
	time_t t;
	char startstr[80];
	char answerstr[80];
	char endstr[80];
	char *dispositionstr = NULL;
	int count;

	ast_mutex_lock(&sqlite_lock);

	t = cdr->start.tv_sec;
	ast_localtime(&t, &tm, NULL);
	strftime(startstr, sizeof(startstr), DATE_FORMAT, &tm);

	t = cdr->answer.tv_sec;
	ast_localtime(&t, &tm, NULL);
	strftime(answerstr, sizeof(answerstr), DATE_FORMAT, &tm);

	t = cdr->end.tv_sec;
	ast_localtime(&t, &tm, NULL);
	strftime(endstr, sizeof(endstr), DATE_FORMAT, &tm);
	
	dispositionstr = ast_cdr_disp2str(cdr->disposition);

	for(count=0; count<5; count++) {
		res = sqlite_exec_printf(db,
			"INSERT INTO cdr ("
				"clid,"
				"src,"
				"dst,"
				"dcontext,"
				"channel,"
				"dstchannel,"
				"lastapp,"
				"lastdata,"
				"start,"
				"answer,"
				"end,"
				"duration,"
				"billsec,"
				"disposition,"
				"amaflags,"
				"accountcode,"
				"uniqueid,"
				"userfield"
			") VALUES ("
				"'%q', "	// clid
				"'%q', "	// src
				"'%q', "	// dst
				"'%q', "	// dcontext 
				"'%q', "	// channel
				"'%q', "	// dstchannel
				"'%q', "	// lastapp
				"'%q', "	// lastdata
				"'%q', "	// start
				"'%q', "	// answer
				"'%q', "	// end
				"%d, "		// duration
				"%d, "		// billsec
				"'%q', "		// disposition
				"%d, "		// amaflags
				"'%q', "	// accountcode
				"'%q', "	// uniqueiq
				"'%q' "		// userfield
			")", NULL, NULL, &zErr,
				cdr->clid, 
				cdr->src, 
				cdr->dst, 
				cdr->dcontext,
				cdr->channel, 
				cdr->dstchannel, 
				cdr->lastapp, 
				cdr->lastdata,
				startstr, 
				answerstr, 
				endstr,
				cdr->duration, 
				cdr->billsec, 
				dispositionstr,
				cdr->amaflags,
				cdr->accountcode,
				cdr->uniqueid,
				cdr->userfield
			);
		if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
			break;
		usleep(200);
	}
	
	if (zErr) {
		ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
		free(zErr);
	}

	ast_mutex_unlock(&sqlite_lock);
	return res;
}
Example #13
0
static int pgsql_log(struct ast_cdr *cdr)
{
	struct tm tm;
	time_t t = cdr->start.tv_sec;
	char sqlcmd[2048] = "", timestr[128];
	char *pgerror;
	PGresult *result;

	ast_mutex_lock(&pgsql_lock);

	ast_localtime(&t, &tm, NULL);
	strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);

	if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) {
		conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
		if (PQstatus(conn) != CONNECTION_BAD) {
			connected = 1;
		} else {
			pgerror = PQerrorMessage(conn);
			ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s.  Calls will not be logged!\n", pghostname);
			ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
			PQfinish(conn);
			conn = NULL;
		}
	}

	if (connected) {
		char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL;
		char *src=NULL, *dst=NULL, *uniqueid=NULL, *userfield=NULL;
		int pgerr;

		/* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */
		if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, clid, cdr->clid, strlen(cdr->clid), &pgerr);
		if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, dcontext, cdr->dcontext, strlen(cdr->dcontext), &pgerr);
		if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, channel, cdr->channel, strlen(cdr->channel), &pgerr);
		if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, dstchannel, cdr->dstchannel, strlen(cdr->dstchannel), &pgerr);
		if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, lastapp, cdr->lastapp, strlen(cdr->lastapp), &pgerr);
		if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, lastdata, cdr->lastdata, strlen(cdr->lastdata), &pgerr);
		if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, uniqueid, cdr->uniqueid, strlen(cdr->uniqueid), &pgerr);
		if ((userfield = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, userfield, cdr->userfield, strlen(cdr->userfield), &pgerr);
		if ((src = alloca(strlen(cdr->src) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, src, cdr->src, strlen(cdr->src), &pgerr);
		if ((dst = alloca(strlen(cdr->dst) * 2 + 1)) != NULL)
			PQescapeStringConn(conn, dst, cdr->dst, strlen(cdr->dst), &pgerr);

		/* Check for all alloca failures above at once */
		if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid) || (!userfield) || (!src) || (!dst)) {
			ast_log(LOG_ERROR, "cdr_pgsql:  Out of memory error (insert fails)\n");
			ast_mutex_unlock(&pgsql_lock);
			return -1;
		}

		if (option_debug > 1)
			ast_log(LOG_DEBUG, "cdr_pgsql: inserting a CDR record.\n");

		snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,"
				 "lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES"
				 " ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%ld,%ld,'%s',%ld,'%s','%s','%s')",
				 table, timestr, clid, src, dst, dcontext, channel, dstchannel, lastapp, lastdata,
				 cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfield);
		
		if (option_debug > 2)
			ast_log(LOG_DEBUG, "cdr_pgsql: SQL command executed:  %s\n",sqlcmd);
		
		/* Test to be sure we're still connected... */
		/* If we're connected, and connection is working, good. */
		/* Otherwise, attempt reconnect.  If it fails... sorry... */
		if (PQstatus(conn) == CONNECTION_OK) {
			connected = 1;
		} else {
			ast_log(LOG_ERROR, "cdr_pgsql: Connection was lost... attempting to reconnect.\n");
			PQreset(conn);
			if (PQstatus(conn) == CONNECTION_OK) {
				ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n");
				connected = 1;
			} else {
				pgerror = PQerrorMessage(conn);
				ast_log(LOG_ERROR, "cdr_pgsql: Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname);
				ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
				PQfinish(conn);
				conn = NULL;
				connected = 0;
				ast_mutex_unlock(&pgsql_lock);
				return -1;
			}
		}
		result = PQexec(conn, sqlcmd);
		if (PQresultStatus(result) != PGRES_COMMAND_OK) {
			pgerror = PQresultErrorMessage(result);
			ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n");
			ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror);
			ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n");
			PQreset(conn);
			if (PQstatus(conn) == CONNECTION_OK) {
				ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n");
				connected = 1;
				PQclear(result);
				result = PQexec(conn, sqlcmd);
				if (PQresultStatus(result) != PGRES_COMMAND_OK) {
					pgerror = PQresultErrorMessage(result);
					ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR!  Attempted reconnection failed.  DROPPING CALL RECORD!\n");
					ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror);
				}
			}
			ast_mutex_unlock(&pgsql_lock);
			PQclear(result);
			return -1;
		}
		PQclear(result);
	}
	ast_mutex_unlock(&pgsql_lock);
	return 0;
}