|
|
|
// (c) 2004 Mark Kretschmann <markey@web.de>
|
|
|
|
// (c) 2004 Christian Muehlhaeuser <chris@chris.de>
|
|
|
|
// (c) 2004 Sami Nieminen <sami.nieminen@iki.fi>
|
|
|
|
// (c) 2005 Ian Monroe <ian@monroe.nu>
|
|
|
|
// See COPYING file for licensing information.
|
|
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "klamavconfig.h"
|
|
|
|
#include "collectiondb.h"
|
|
|
|
#include "klamav.h"
|
|
|
|
#include "activityviewer.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "sqlite/sqlite3.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kinputdialog.h> //setupCoverFetcher()
|
|
|
|
#include <kio/job.h>
|
|
|
|
#include <klineedit.h> //setupCoverFetcher()
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmdcodec.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kurl.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kio/netaccess.h>
|
|
|
|
|
|
|
|
#include <cmath> //DbConnection::sqlite_power()
|
|
|
|
#include <ctime> //query()
|
|
|
|
#include <unistd.h> //usleep()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CLASS CollectionDB
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
CollectionDB* CollectionDB::instance()
|
|
|
|
{
|
|
|
|
static CollectionDB db;
|
|
|
|
return &db;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CollectionDB::CollectionDB( bool temporary )
|
|
|
|
: m_isTemporary( temporary )
|
|
|
|
{
|
|
|
|
|
|
|
|
//<OPEN DATABASE>
|
|
|
|
initialize();
|
|
|
|
//</OPEN DATABASE>
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CollectionDB::~CollectionDB()
|
|
|
|
{
|
|
|
|
|
|
|
|
destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// PUBLIC
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
DbConnection
|
|
|
|
*CollectionDB::getStaticDbConnection()
|
|
|
|
{
|
|
|
|
return m_dbConnPool->getDbConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::returnStaticDbConnection( DbConnection *conn )
|
|
|
|
{
|
|
|
|
m_dbConnPool->putDbConnection( conn );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Executes a SQL query on the already opened database
|
|
|
|
* @param statement SQL program to execute. Only one SQL statement is allowed.
|
|
|
|
* @return The queried data, or TQStringList() on error.
|
|
|
|
*/
|
|
|
|
TQStringList
|
|
|
|
CollectionDB::query( const TQString& statement, DbConnection *conn )
|
|
|
|
{
|
|
|
|
clock_t start;
|
|
|
|
if ( DEBUGSQL )
|
|
|
|
{
|
|
|
|
kdDebug() << "Query-start: " << statement << endl;
|
|
|
|
start = clock();
|
|
|
|
}
|
|
|
|
|
|
|
|
DbConnection *dbConn;
|
|
|
|
if ( conn != NULL )
|
|
|
|
{
|
|
|
|
dbConn = conn;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbConn = m_dbConnPool->getDbConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
//kdDebug() << statement << endl;
|
|
|
|
|
|
|
|
TQStringList values = dbConn->query( statement );
|
|
|
|
|
|
|
|
//kdDebug() << values << endl;
|
|
|
|
|
|
|
|
if ( conn == NULL )
|
|
|
|
{
|
|
|
|
m_dbConnPool->putDbConnection( dbConn );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( DEBUGSQL )
|
|
|
|
{
|
|
|
|
clock_t finish = clock();
|
|
|
|
const double duration = (double) (finish - start) / CLOCKS_PER_SEC;
|
|
|
|
kdDebug() << "SQL-query (" << duration << "s): " << statement << endl;
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Executes a SQL insert on the already opened database
|
|
|
|
* @param statement SQL statement to execute. Only one SQL statement is allowed.
|
|
|
|
* @return The rowid of the inserted item.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
CollectionDB::insert( const TQString& statement, const TQString& table, DbConnection *conn )
|
|
|
|
{
|
|
|
|
clock_t start;
|
|
|
|
if ( DEBUGSQL )
|
|
|
|
{
|
|
|
|
kdDebug() << "insert-start: " << statement << endl;
|
|
|
|
start = clock();
|
|
|
|
}
|
|
|
|
|
|
|
|
DbConnection *dbConn;
|
|
|
|
if ( conn != NULL )
|
|
|
|
{
|
|
|
|
dbConn = conn;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbConn = m_dbConnPool->getDbConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
//kdDebug() << statement << endl;
|
|
|
|
|
|
|
|
int id = dbConn->insert( statement, table );
|
|
|
|
|
|
|
|
//kdDebug() << id << endl;
|
|
|
|
|
|
|
|
if ( conn == NULL )
|
|
|
|
{
|
|
|
|
m_dbConnPool->putDbConnection( dbConn );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( DEBUGSQL )
|
|
|
|
{
|
|
|
|
clock_t finish = clock();
|
|
|
|
const double duration = (double) (finish - start) / CLOCKS_PER_SEC;
|
|
|
|
kdDebug() << "SQL-insert (" << duration << "s): " << statement << endl;
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
CollectionDB::isEmpty()
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
|
|
|
|
values = query( "SELECT COUNT( type ) FROM klamav_activity LIMIT 0, 1;" );
|
|
|
|
|
|
|
|
return values.isEmpty() ? true : values.first() == "0";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
CollectionDB::isValid(const TQString &column, const TQString &table)
|
|
|
|
{
|
|
|
|
TQStringList values1;
|
|
|
|
TQStringList values2;
|
|
|
|
|
|
|
|
values1 = query( TQString("SELECT COUNT( %1 ) FROM %2 LIMIT 0, 1;").arg(column).arg(table) );
|
|
|
|
|
|
|
|
//TODO? this returns true if value1 or value2 is not empty. Shouldn't this be and (&&)???
|
|
|
|
return !values1.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::createTables( DbConnection */*conn*/ )
|
|
|
|
{
|
|
|
|
|
|
|
|
//create tag table
|
|
|
|
createActivityTable();
|
|
|
|
//createMetaDBTable();
|
|
|
|
|
|
|
|
//create indexes
|
|
|
|
/* query( TQString( "CREATE INDEX date_idx%1 ON klamav_activity%2( date );" )
|
|
|
|
.arg( conn ? "_temp" : "" ).arg( conn ? "_temp" : "" ), conn );*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::createActivityTable( DbConnection *conn )
|
|
|
|
{
|
|
|
|
|
|
|
|
query( "CREATE TABLE klamav_activity ( date TEXT, type TEXT, event TEXT, file TEXT);", conn );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::createMetaDBTable( DbConnection *conn )
|
|
|
|
{
|
|
|
|
|
|
|
|
query( "CREATE TABLE klamav_metadb ( id INTEGER PRIMARY KEY, date TEXT, submission INTEGER, creator TEXT, virus TEXT, alias TEXT, sender TEXT);", conn );
|
|
|
|
loadMetaDBTable(conn);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::loadMetaDBTable( DbConnection */*conn*/ )
|
|
|
|
{
|
|
|
|
|
|
|
|
TQString location = locate("data", "klamav/about/metadb.txt");
|
|
|
|
|
|
|
|
/* query( TQString( ".import %1 klamav_activity;" ).arg(location), conn );
|
|
|
|
|
|
|
|
return;*/
|
|
|
|
TQFile file( location );
|
|
|
|
if ( file.open( IO_ReadOnly ) ) {
|
|
|
|
TQTextStream stream( &file );
|
|
|
|
TQString line;
|
|
|
|
while ( !stream.atEnd() ) {
|
|
|
|
line = stream.readLine(); // line of text excluding '\n'
|
|
|
|
TQStringList columns = TQStringList::split("\t",line.remove("\""));
|
|
|
|
if (columns.count() >= 5)
|
|
|
|
insertMetaDBEntry(columns[0],columns[1],columns[2],columns[3],columns[4],columns[5]);
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
void
|
|
|
|
CollectionDB::dropTables( DbConnection *conn )
|
|
|
|
{
|
|
|
|
|
|
|
|
query( TQString( "DROP TABLE klamav_activity%1;" ).arg( conn ? "_temp" : "" ), conn );
|
|
|
|
query( TQString( "DROP TABLE klamav_metadb%1;" ).arg( conn ? "_temp" : "" ), conn );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::clearTables( DbConnection *conn )
|
|
|
|
{
|
|
|
|
|
|
|
|
TQString clearCommand = "DELETE FROM";
|
|
|
|
|
|
|
|
query( TQString( "%1 klamav_activity%2;" ).arg( clearCommand ).arg( conn ? "_temp" : "" ), conn );
|
|
|
|
query( TQString( "%1 klamav_metadb%2;" ).arg( clearCommand ).arg( conn ? "_temp" : "" ), conn );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::moveTempTables( DbConnection *conn )
|
|
|
|
{
|
|
|
|
insert( "INSERT INTO klamav_activity SELECT * FROM klamav_activity_temp;", NULL, conn );
|
|
|
|
insert( "INSERT INTO klamav_metadb SELECT * FROM klamav_activity_temp;", NULL, conn );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint
|
|
|
|
CollectionDB::IDFromValue( TQString name, TQString value, bool autocreate, const bool temporary, const bool updateSpelling, DbConnection *conn )
|
|
|
|
{
|
|
|
|
if ( temporary )
|
|
|
|
name.append( "_temp" );
|
|
|
|
else
|
|
|
|
conn = NULL;
|
|
|
|
|
|
|
|
TQStringList values =
|
|
|
|
query( TQString(
|
|
|
|
"SELECT id, name FROM %1 WHERE name LIKE '%2';" )
|
|
|
|
.arg( name )
|
|
|
|
.arg( CollectionDB::instance()->escapeString( value ) ), conn );
|
|
|
|
|
|
|
|
if ( updateSpelling && !values.isEmpty() && ( values[1] != value ) )
|
|
|
|
{
|
|
|
|
query( TQString( "UPDATE %1 SET id = %2, name = '%3' WHERE id = %4;" )
|
|
|
|
.arg( name )
|
|
|
|
.arg( values.first() )
|
|
|
|
.arg( CollectionDB::instance()->escapeString( value ) )
|
|
|
|
.arg( values.first() ), conn );
|
|
|
|
}
|
|
|
|
|
|
|
|
//check if item exists. if not, should we autocreate it?
|
|
|
|
uint id;
|
|
|
|
if ( values.isEmpty() && autocreate )
|
|
|
|
{
|
|
|
|
id = insert( TQString( "INSERT INTO %1 ( name ) VALUES ( '%2' );" )
|
|
|
|
.arg( name )
|
|
|
|
.arg( CollectionDB::instance()->escapeString( value ) ), name, conn );
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
return values.isEmpty() ? 0 : values.first().toUInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString
|
|
|
|
CollectionDB::valueFromID( TQString table, uint id )
|
|
|
|
{
|
|
|
|
TQStringList values =
|
|
|
|
query( TQString(
|
|
|
|
"SELECT name FROM %1 WHERE id=%2;" )
|
|
|
|
.arg( table )
|
|
|
|
.arg( id ) );
|
|
|
|
|
|
|
|
|
|
|
|
return values.isEmpty() ? 0 : values.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString
|
|
|
|
CollectionDB::typeCount( const TQString &type_id )
|
|
|
|
{
|
|
|
|
TQStringList values =
|
|
|
|
query( TQString(
|
|
|
|
"SELECT COUNT( type ) FROM klamav_activity WHERE type = %1;" )
|
|
|
|
.arg( type_id ) );
|
|
|
|
return values.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQStringList
|
|
|
|
CollectionDB::messagesForType( const TQString &type_id, const bool isValue )
|
|
|
|
{
|
|
|
|
if ( isValue)
|
|
|
|
{
|
|
|
|
return query( TQString( "SELECT * FROM klamav_activity "
|
|
|
|
"WHERE (type = \"%1\" ) ;" )
|
|
|
|
.arg( type_id ) );
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// PRIVATE SLOTS
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// PRIVATE
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::initialize()
|
|
|
|
{
|
|
|
|
m_dbConnPool = new DbConnectionPool( m_isTemporary );
|
|
|
|
DbConnection *dbConn = m_dbConnPool->getDbConnection();
|
|
|
|
m_dbConnPool->putDbConnection( dbConn );
|
|
|
|
|
|
|
|
// KConfig* config = amaroK::config( "Collection Browser" );
|
|
|
|
if(!dbConn->isConnected())
|
|
|
|
kdDebug() << "db not connected" << endl;
|
|
|
|
//amaroK::MessageQueue::instance()->addMessage(dbConn->lastError());
|
|
|
|
if ( !dbConn->isInitialized() )
|
|
|
|
{
|
|
|
|
createTables();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if (!isValid("id","klamav_metadb"))
|
|
|
|
// createMetaDBTable();
|
|
|
|
|
|
|
|
if (!isValid("type","klamav_activity"))
|
|
|
|
createActivityTable();
|
|
|
|
|
|
|
|
|
|
|
|
m_dbConnPool->createDbConnections();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::destroy()
|
|
|
|
{
|
|
|
|
delete m_dbConnPool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CLASS DbConnection
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
DbConnection::DbConnection( DbConfig* config )
|
|
|
|
: m_config( config )
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
DbConnection::~DbConnection()
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CLASS SqliteConnection
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
SqliteConnection::SqliteConnection( SqliteConfig* config )
|
|
|
|
: DbConnection( config )
|
|
|
|
{
|
|
|
|
|
|
|
|
TQString homepath = getenv("HOME");
|
|
|
|
const TQCString path = (homepath+"/.klamav/activity.db").local8Bit();
|
|
|
|
|
|
|
|
|
|
|
|
// Open database file and check for correctness
|
|
|
|
m_initialized = false;
|
|
|
|
TQFile file( path );
|
|
|
|
if ( file.open( IO_ReadOnly ) )
|
|
|
|
{
|
|
|
|
TQString format;
|
|
|
|
file.readLine( format, 50 );
|
|
|
|
if ( !format.startsWith( "SQLite format 3" ) )
|
|
|
|
{
|
|
|
|
kdDebug() << "Database versions incompatible. Removing and rebuilding database.\n";
|
|
|
|
}
|
|
|
|
else if ( sqlite3_open( path, &m_db ) != SQLITE_OK )
|
|
|
|
{
|
|
|
|
kdDebug() << "Database file corrupt. Removing and rebuilding database.\n";
|
|
|
|
sqlite3_close( m_db );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_initialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !m_initialized )
|
|
|
|
{
|
|
|
|
// Remove old db file; create new
|
|
|
|
TQFile::remove( path );
|
|
|
|
if ( sqlite3_open( path, &m_db ) == SQLITE_OK )
|
|
|
|
{
|
|
|
|
m_initialized = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( m_initialized )
|
|
|
|
{
|
|
|
|
if( sqlite3_create_function(m_db, "rand", 0, SQLITE_UTF8, NULL, sqlite_rand, NULL, NULL) != SQLITE_OK )
|
|
|
|
m_initialized = false;
|
|
|
|
if( sqlite3_create_function(m_db, "power", 2, SQLITE_UTF8, NULL, sqlite_power, NULL, NULL) != SQLITE_OK )
|
|
|
|
m_initialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//optimization for speeding up SQLite
|
|
|
|
query( "PRAGMA default_synchronous = OFF;" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SqliteConnection::~SqliteConnection()
|
|
|
|
{
|
|
|
|
if ( m_db ) sqlite3_close( m_db );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQStringList SqliteConnection::query( const TQString& statement )
|
|
|
|
{
|
|
|
|
TQStringList values;
|
|
|
|
int error;
|
|
|
|
const char* tail;
|
|
|
|
sqlite3_stmt* stmt;
|
|
|
|
|
|
|
|
//compile SQL program to virtual machine
|
|
|
|
error = sqlite3_prepare( m_db, statement.utf8(), statement.length(), &stmt, &tail );
|
|
|
|
|
|
|
|
if ( error != SQLITE_OK )
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << " sqlite3_compile error:" << endl;
|
|
|
|
kdDebug() << sqlite3_errmsg( m_db ) << endl;
|
|
|
|
kdDebug() << "on query: " << statement << endl;
|
|
|
|
values = TQStringList();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int busyCnt = 0;
|
|
|
|
int number = sqlite3_column_count( stmt );
|
|
|
|
//execute virtual machine by iterating over rows
|
|
|
|
while ( true )
|
|
|
|
{
|
|
|
|
error = sqlite3_step( stmt );
|
|
|
|
|
|
|
|
if ( error == SQLITE_BUSY )
|
|
|
|
{
|
|
|
|
if ( busyCnt++ > 20 ) {
|
|
|
|
kdDebug() << "Busy-counter has reached maximum. Aborting this sql statement!\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
::usleep( 100000 ); // Sleep 100 msec
|
|
|
|
kdDebug() << "sqlite3_step: BUSY counter: " << busyCnt << endl;
|
|
|
|
}
|
|
|
|
if ( error == SQLITE_MISUSE )
|
|
|
|
kdDebug() << "sqlite3_step: MISUSE" << endl;
|
|
|
|
if ( error == SQLITE_DONE || error == SQLITE_ERROR )
|
|
|
|
break;
|
|
|
|
|
|
|
|
//iterate over columns
|
|
|
|
for ( int i = 0; i < number; i++ )
|
|
|
|
{
|
|
|
|
values << TQString::fromUtf8( (const char*) sqlite3_column_text( stmt, i ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//deallocate vm ressources
|
|
|
|
sqlite3_finalize( stmt );
|
|
|
|
|
|
|
|
if ( error != SQLITE_DONE )
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << "sqlite_step error.\n";
|
|
|
|
kdDebug() << sqlite3_errmsg( m_db ) << endl;
|
|
|
|
kdDebug() << "on query: " << statement << endl;
|
|
|
|
values = TQStringList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SqliteConnection::insert( const TQString& statement, const TQString& /* table */ )
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
const char* tail;
|
|
|
|
sqlite3_stmt* stmt;
|
|
|
|
|
|
|
|
//compile SQL program to virtual machine
|
|
|
|
error = sqlite3_prepare( m_db, statement.utf8(), statement.length(), &stmt, &tail );
|
|
|
|
|
|
|
|
if ( error != SQLITE_OK )
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << " sqlite3_compile error:" << endl;
|
|
|
|
kdDebug() << sqlite3_errmsg( m_db ) << endl;
|
|
|
|
kdDebug() << "on insert: " << statement << endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int busyCnt = 0;
|
|
|
|
//execute virtual machine by iterating over rows
|
|
|
|
while ( true )
|
|
|
|
{
|
|
|
|
error = sqlite3_step( stmt );
|
|
|
|
|
|
|
|
if ( error == SQLITE_BUSY )
|
|
|
|
{
|
|
|
|
if ( busyCnt++ > 20 ) {
|
|
|
|
kdDebug() << "Busy-counter has reached maximum. Aborting this sql statement!\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
::usleep( 100000 ); // Sleep 100 msec
|
|
|
|
kdDebug() << "sqlite3_step: BUSY counter: " << busyCnt << endl;
|
|
|
|
}
|
|
|
|
if ( error == SQLITE_MISUSE )
|
|
|
|
kdDebug() << "sqlite3_step: MISUSE" << endl;
|
|
|
|
if ( error == SQLITE_DONE || error == SQLITE_ERROR )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//deallocate vm ressources
|
|
|
|
sqlite3_finalize( stmt );
|
|
|
|
|
|
|
|
if ( error != SQLITE_DONE )
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << "sqlite_step error.\n";
|
|
|
|
kdDebug() << sqlite3_errmsg( m_db ) << endl;
|
|
|
|
kdDebug() << "on insert: " << statement << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sqlite3_last_insert_rowid( m_db );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this implements a RAND() function compatible with the MySQL RAND() (0-param-form without seed)
|
|
|
|
void SqliteConnection::sqlite_rand(sqlite3_context *context, int /*argc*/, sqlite3_value ** /*argv*/)
|
|
|
|
{
|
|
|
|
sqlite3_result_double( context, static_cast<double>(KApplication::random()) / (RAND_MAX+1.0) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// this implements a POWER() function compatible with the MySQL POWER()
|
|
|
|
void SqliteConnection::sqlite_power(sqlite3_context *context, int argc, sqlite3_value **argv)
|
|
|
|
{
|
|
|
|
Q_ASSERT( argc==2 );
|
|
|
|
if( sqlite3_value_type(argv[0])==SQLITE_NULL || sqlite3_value_type(argv[1])==SQLITE_NULL ) {
|
|
|
|
sqlite3_result_null(context);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
double a = sqlite3_value_double(argv[0]);
|
|
|
|
double b = sqlite3_value_double(argv[1]);
|
|
|
|
sqlite3_result_double( context, pow(a,b) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CLASS SqliteConfig
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
SqliteConfig::SqliteConfig( const TQString& dbfile )
|
|
|
|
: m_dbfile( dbfile )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CLASS DbConnectionPool
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
DbConnectionPool::DbConnectionPool( bool temporary )
|
|
|
|
: m_isTemporary( temporary )
|
|
|
|
, m_semaphore( POOL_SIZE )
|
|
|
|
{
|
|
|
|
m_dbConnType = DbConnection::sqlite;
|
|
|
|
|
|
|
|
m_semaphore += POOL_SIZE;
|
|
|
|
DbConnection *dbConn;
|
|
|
|
|
|
|
|
m_dbConfig = new SqliteConfig( "activity.db" );
|
|
|
|
dbConn = new SqliteConnection( static_cast<SqliteConfig*> ( m_dbConfig ) );
|
|
|
|
|
|
|
|
enqueue( dbConn );
|
|
|
|
m_semaphore--;
|
|
|
|
kdDebug() << "Available db connections: " << m_semaphore.available() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbConnectionPool::~DbConnectionPool()
|
|
|
|
{
|
|
|
|
m_semaphore += POOL_SIZE;
|
|
|
|
DbConnection *conn;
|
|
|
|
bool vacuum = !m_isTemporary;
|
|
|
|
|
|
|
|
while ( ( conn = dequeue() ) != 0 )
|
|
|
|
{
|
|
|
|
if ( m_dbConnType == DbConnection::sqlite && vacuum )
|
|
|
|
{
|
|
|
|
vacuum = false;
|
|
|
|
kdDebug() << "Running VACUUM" << endl;
|
|
|
|
conn->query( "VACUUM; ");
|
|
|
|
}
|
|
|
|
|
|
|
|
delete conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete m_dbConfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DbConnectionPool::createDbConnections()
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < POOL_SIZE - 1; i++ )
|
|
|
|
{
|
|
|
|
DbConnection *dbConn;
|
|
|
|
|
|
|
|
dbConn = new SqliteConnection( static_cast<SqliteConfig*> ( m_dbConfig ) );
|
|
|
|
enqueue( dbConn );
|
|
|
|
m_semaphore--;
|
|
|
|
}
|
|
|
|
kdDebug() << "Available db connections: " << m_semaphore.available() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbConnection *DbConnectionPool::getDbConnection()
|
|
|
|
{
|
|
|
|
m_semaphore++;
|
|
|
|
return dequeue();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DbConnectionPool::putDbConnection( const DbConnection *conn )
|
|
|
|
{
|
|
|
|
enqueue( conn );
|
|
|
|
m_semaphore--;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
CollectionDB::expireActivity(const TQString &days )
|
|
|
|
{
|
|
|
|
int intdays = days.toInt();
|
|
|
|
if (intdays > 0)
|
|
|
|
intdays--;
|
|
|
|
|
|
|
|
query( TQString( "DELETE FROM klamav_activity WHERE date < datetime('now','localtime','-%2 days', 'start of day');" ).arg(intdays) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQStringList
|
|
|
|
CollectionDB::allActivity( )
|
|
|
|
{
|
|
|
|
return query( TQString( "SELECT * FROM klamav_activity" ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList
|
|
|
|
CollectionDB::allActivityOfType(const TQString &type,const TQString &days )
|
|
|
|
{
|
|
|
|
int intdays = days.toInt();
|
|
|
|
|
|
|
|
intdays--;
|
|
|
|
|
|
|
|
if (type == "All Types")
|
|
|
|
return query( TQString( "SELECT * FROM klamav_activity WHERE date > datetime('now','localtime','-%2 days', 'start of day');" ).arg(intdays) );
|
|
|
|
|
|
|
|
return query( TQString( "SELECT * FROM klamav_activity where type = '%1'"
|
|
|
|
" and date > datetime('now','localtime','-%2 days', 'start of day');" ).arg(type).arg(intdays) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionDB::insertEvent(const TQString &type, const TQString &event, const TQString &file, DbConnection *conn)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (((!(KlamavConfig::launchShutdown())) && (type == "Launch")) ||
|
|
|
|
((!(KlamavConfig::softwareUpdates())) && (type == "Updates")) ||
|
|
|
|
((!(KlamavConfig::dBUpdates())) && (type == "Updates")) ||
|
|
|
|
((!(KlamavConfig::quarantined())) && (type == "Quarantine")) ||
|
|
|
|
((!(KlamavConfig::virusFound())) && (type == "Virus Found")) ||
|
|
|
|
((!(KlamavConfig::error())) && (type == "Error Found")) ||
|
|
|
|
((!(KlamavConfig::startedStoppedCancelled())) && (type == "Manual Scan")) ||
|
|
|
|
((!(KlamavConfig::startedStoppedCancelled())) && (type == "Auto-Scan")))
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQString date = query( TQString( "select datetime('now','localtime')" ) ).first();
|
|
|
|
insert( TQString( "INSERT INTO klamav_activity ( type, date, event, file )"
|
|
|
|
" VALUES ( '%1', '%2', '%3', '%4' );" )
|
|
|
|
.arg( type )
|
|
|
|
.arg( date )
|
|
|
|
.arg( event )
|
|
|
|
.arg( file )
|
|
|
|
, "klamav_activity", conn);
|
|
|
|
|
|
|
|
kmain->activityviewer->insertItem(date,type,event,file);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionDB::insertMetaDBEntry(const TQString &date, const TQString &submission, const TQString &creator,const TQString &virus,const TQString &alias, const TQString &sender,DbConnection *conn)
|
|
|
|
{
|
|
|
|
|
|
|
|
insert( TQString( "INSERT INTO klamav_metadb ( id, date, submission, creator, virus, alias, sender )"
|
|
|
|
" VALUES ( NULL, \"%1\", \"%2\", \"%3\", \"%4\", \"%5\", \"%6\");" )
|
|
|
|
.arg( date )
|
|
|
|
.arg( submission.toInt() )
|
|
|
|
.arg( creator )
|
|
|
|
.arg( virus )
|
|
|
|
.arg( alias )
|
|
|
|
.arg( sender )
|
|
|
|
, "klamav_metadb", conn);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString
|
|
|
|
CollectionDB::latestMetaDBDate( )
|
|
|
|
{
|
|
|
|
TQStringList highest = query( TQString( "SELECT MAX(date) FROM klamav_metadb;" ));
|
|
|
|
|
|
|
|
return highest.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "collectiondb.moc"
|