/*
 * Copyright (C) 2004 Robert Hogan <robert at roberthogan dot net>
 *
 *  ClamAV DB code:
 *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>

 */

#include "dbviewer.h"
#include "klamav.h"
#include <clamav.h>
#include "pageviewer.h"
#include "tabwidget.h"
#include "freshklam.h"
#include "version.h"
#include "../config.h"

#include <tqheader.h>
#include <tqlayout.h>
#include <tqpopupmenu.h>
#include <tqstringlist.h>

#include <tdetoolbarbutton.h> //ctor
#include <tdetempfile.h>
#include <ktempdir.h>
#include <tdelistviewsearchline.h>
#include <tdelistview.h>
#include <kprogress.h>

#include <dirent.h>
#include <unistd.h>
#include <zlib.h>

#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kiconloader.h>

#include <kurl.h>

#define TAR_BLOCKSIZE 512
#define FILEBUFF 8192

int cli_untgz(int fd, const char *destdir);
int cli_rmdirs(const char *dirname);
int cli_strbcasestr(const char *haystack, const char *needle);
int cli_chomp(char *string);
char *cli_strtok(const char *line, int field, const char *delim);

using namespace KlamAV;
/*
 *  Constructs a KlamDB as a child of 'parent', with the
 *  name 'name' and widget flags set to 'f'.
 *
 *  The dialog will by default be modeless, unless you set 'modal' to
 *  true to construct a modal dialog.
 */
KlamDB::KlamDB( TQWidget* parent, const char* name, bool modal, WFlags fl )
    : TQDialog( parent, name, modal, fl )
{
    if ( !name )
    setName( "KlamDB" );

        loadinprogress = false;
    TQVBoxLayout *vbox = new TQVBoxLayout(this, KDialog::marginHint(),
            KDialog::spacingHint(), "vbox");

    TQWidget* privateLayoutWidget = new TQWidget( this, "dblayout" );
    vbox->addWidget(privateLayoutWidget);

    dblayout = new TQGridLayout( privateLayoutWidget, 1, 1, 2, 2, "dblayout"); 
    dblayout->setColStretch(1, 1);

    tabBrowser = new TabWidget(privateLayoutWidget, "KlamDB", TQStringList("Home"));

    
    dblayout->addMultiCellWidget( tabBrowser, 0, 1, 1, 1 );
        
    TDEToolBarButton *button;
    TDEToolBar* searchToolBar = new TDEToolBar( privateLayoutWidget );
    searchToolBar->setMovingEnabled(false);
    searchToolBar->setFlat(true);
    searchToolBar->setIconSize( 16 );
    searchToolBar->setEnableContextMenu( false );

    button = new TDEToolBarButton( "locationbar_erase", 0, searchToolBar );

    VirusList = new TDEListView( privateLayoutWidget, "VirusList" );
    VirusList->addColumn( i18n( "All Known Viruses" ),150 );
    connect(VirusList, TQ_SIGNAL( doubleClicked( TQListViewItem * , const TQPoint &, int ) ),
                    this, TQ_SLOT(slotOpenTab(TQListViewItem * , const TQPoint &, int )) );

    menu = new TQPopupMenu( VirusList );

    TQPixmap gicon;
    TQPixmap ticon;

    TQString iconPath = locate("cache", KMimeType::favIconForURL("http://www.google.com")+".png");
    if ( iconPath.isEmpty() )
      gicon = SmallIcon("edit-find");
    else
      gicon = TQPixmap( iconPath );

    iconPath = locate("cache", KMimeType::favIconForURL("http://www.trendmicro.com")+".png");
    if ( iconPath.isEmpty() )
      ticon = SmallIcon("edit-find");
    else
      ticon = TQPixmap( iconPath );

    menu->insertItem(ticon, i18n("Search with Trend Micro"), this,TQ_SLOT(slotTrendMicro()) );
    menu->insertItem(gicon, i18n("Search with Google"), this,TQ_SLOT(slotGoogle()) );

    googlePrefix = TQString::fromAscii("http://www.google.com/search?ie=ISO-8859-1&q=");
    tMicroPrefix = TQString::fromAscii("https://www.trendmicro.com/vinfo/us/threat-encyclopedia/search/");

    connect(VirusList, TQ_SIGNAL( contextMenuRequested( TQListViewItem *, const TQPoint& , int ) ), 
    this, TQ_SLOT( slotRMB( TQListViewItem *, const TQPoint &, int ) ) );

    kLineEdit1 = new TDEListViewSearchLine( (TQWidget *)searchToolBar, VirusList,"klinedit1");
    TQValueList<int> columns;
        columns.append(0);
    kLineEdit1->setSearchColumns(columns);
    kLineEdit1->setMaxLength(2);
    connect(button, TQ_SIGNAL( clicked() ),
                    kLineEdit1, TQ_SLOT(clear()) );

    dblayout->addWidget( searchToolBar, 0, 0 );
    
    dblayout->addWidget( VirusList, 1, 0 );
    

    languageChange();
    clearWState( WState_Polished );
    
    slotOpenHome();
}

/*
 *  Destroys the object and frees any allocated resources
 */
KlamDB::~KlamDB()
{
    // no need to delete child widgets, TQt does it all for us
}

/*
 *  Sets the strings of the subwidgets using the current
 *  language.
 */
void KlamDB::languageChange()
{
    setCaption("Form1");
    tabBrowser->changeTab( tab, i18n( "Info" ) );
    VirusList->header()->setLabel( 0, i18n( "All Known Viruses" ) );
    VirusList->clear();
    /*TDEListViewItem * item =*/ new TDEListViewItem( VirusList, 0 );
    //item->setText( 0, tr( "New Item" ) );

}

int KlamDB::listdb(const char *filename)
{
    FILE *fd, *tmpd;
//    char *buffer, *pt, *start, *dir, *tmp;
    char *buffer, *pt, *start;
    int line = 0, bytes;
    const char *tmpdir;

    if(cli_strbcasestr(filename, ".inc")) { /* incremental directory */
	if(listdir(filename) == -1) {
	    printf("!listdb: Can't list incremental directory %s\n", filename);
	    return -1;
	}
	return 0;
    }

    if((fd = fopen(filename, "rb")) == NULL) {
    printf("!listdb(): Can't open file %s\n", filename);
    return -1;
    }

    if(!(buffer = (char *) malloc(FILEBUFF))) {
    printf("!listdb(): Can't allocate memory.\n");
    fclose(fd);
    return -1;
    }

    memset(buffer, 0, FILEBUFF);
    /* check for CVD file */
    fgets(buffer, 12, fd);
    rewind(fd);

    if(!strncmp(buffer, "ClamAV-VDB:", 11)) {

    fseek(fd, 512, SEEK_SET);

    tmpdir = getenv("TMPDIR");
    if(tmpdir == NULL)
#ifdef P_tmpdir
        tmpdir = P_tmpdir;
#else
        tmpdir = "/tmp";
#endif

    KTempDir* tf = new KTempDir();
    if ( tf->status() != 0 ) {
        delete tf;
        return -1;
    }

    /* FIXME: it seems there is some problem with current position indicator
    * after gzdopen() call in cli_untgz(). Temporarily we need this wrapper:
    */

    /* start */

    KTempFile* tn = new KTempFile(tf->name());
    
    if((tmpd = fopen(tn->name().ascii(), "wb+")) == NULL) {
        printf("!listdb(): Can't create temporary file \n");
        delete tf;
        delete tn;
        free(buffer);
        fclose(fd);
        return -1;
    }

    while((bytes = fread(buffer, 1, FILEBUFF, fd)) > 0)
        fwrite(buffer, 1, bytes, tmpd);

    free(buffer);
    fclose(fd);

    fflush(tmpd);
    fseek(tmpd, 0L, SEEK_SET);

    if(cli_untgz(fileno(tmpd), tf->name().ascii())) {
        printf("!listdb(): Can't unpack CVD file.\n");
        cli_rmdirs(tf->name().ascii());
        delete tf;
        delete tn;
        fclose(tmpd);
        free(buffer);
        return -1;
    }

    fclose(tmpd);
    delete tn;
    /* wrapper end */

    /* list extracted directory */
    listdir(tf->name().ascii());

    cli_rmdirs(tf->name().ascii());
    delete tf;
    
    return 0;
    }

    if(cli_strbcasestr(filename, ".db") || cli_strbcasestr(filename, ".db2")) {
    /* old style database */

    while(fgets(buffer, FILEBUFF, fd)) {
        line++;
        pt = strchr(buffer, '=');
        if(!pt) {
        printf("!listdb(): Malformed pattern line %d (file %s).\n", line, filename);
        fclose(fd);
        free(buffer);
        return -1;
        }

        start = buffer;
        *pt = 0;

        if((pt = strstr(start, " (Clam)")))
        *pt = 0;

        //printf("%s\n", start);
        addVirusName(start);

    }

    } else if(cli_strbcasestr(filename, ".hdb")) {

    while(fgets(buffer, FILEBUFF, fd)) {
        line++;
        cli_chomp(buffer);
        start = cli_strtok(buffer, 2, ":");

        if(!start) {
        printf("!listdb(): Malformed pattern line %d (file %s).\n", line, filename);
        fclose(fd);
        free(buffer);
        return -1;
        }

        if((pt = strstr(start, " (Clam)")))
        *pt = 0;

        //printf("%s\n", start);
        addVirusName(start);
        free(start);
    }

    } else if(cli_strbcasestr(filename, ".ndb")) {

    while(fgets(buffer, FILEBUFF, fd)) {
        line++;
        cli_chomp(buffer);
        start = cli_strtok(buffer, 0, ":");

        if(!start) {
        printf("!listdb(): Malformed pattern line %d (file %s).\n", line, filename);
        fclose(fd);
        free(buffer);
        return -1;
        }

        if((pt = strstr(start, " (Clam)")))
        *pt = 0;

        //printf("%s\n", start);
        addVirusName(start);

        free(start);
    }
    }

    fclose(fd);
    free(buffer);
    return 0;
}

int KlamDB::listdir(const char *dirname)
{
    DIR *dd;
    struct dirent *dent;
    char *dbfile;


    if((dd = opendir(dirname)) == NULL) {
        printf("!Can't open directory %s\n", dirname);
        return -1;
    }

    while((dent = readdir(dd))) {
#ifndef C_INTERIX
    if(dent->d_ino)
#endif
    {
        if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") &&
	    (cli_strbcasestr(dent->d_name, ".db")  ||
	     cli_strbcasestr(dent->d_name, ".hdb") ||
	     cli_strbcasestr(dent->d_name, ".mdb") ||
	     cli_strbcasestr(dent->d_name, ".ndb") ||
	     cli_strbcasestr(dent->d_name, ".sdb") ||
	     cli_strbcasestr(dent->d_name, ".zmd") ||
	     cli_strbcasestr(dent->d_name, ".rmd") ||
	     cli_strbcasestr(dent->d_name, ".inc") ||
	     cli_strbcasestr(dent->d_name, ".cvd"))) {

        dbfile = (char *) calloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));

        if(!dbfile) {
            printf("!listdir(): Can't allocate memory.\n");
            closedir(dd);
            return -1;
        }
        sprintf(dbfile, "%s/%s", dirname, dent->d_name);

        if(listdb(dbfile)) {
            printf("!listdb(): error listing database %s\n", dbfile);
            free(dbfile);
            closedir(dd);
            return -1;
        }
        free(dbfile);
        }
    }
    }

    closedir(dd);
    return 0;
}

int KlamDB::checkdir(const char *dirname)
{
    DIR *dd;
    struct dirent *dent;


    if((dd = opendir(dirname)) == NULL) {
        printf("!Can't open directory %s\n", dirname);
        return -1;
    }

    int found = 0;
    while((dent = readdir(dd))) {
#ifndef C_INTERIX
    if(dent->d_ino)
#endif
    {
        if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") &&
	    (cli_strbcasestr(dent->d_name, ".db")  ||
	     cli_strbcasestr(dent->d_name, ".hdb") ||
	     cli_strbcasestr(dent->d_name, ".mdb") ||
	     cli_strbcasestr(dent->d_name, ".ndb") ||
	     cli_strbcasestr(dent->d_name, ".sdb") ||
	     cli_strbcasestr(dent->d_name, ".zmd") ||
	     cli_strbcasestr(dent->d_name, ".rmd") ||
	     cli_strbcasestr(dent->d_name, ".inc") ||
	     cli_strbcasestr(dent->d_name, ".cvd"))) {
        found = 1;
        }
    }
    }

    closedir(dd);
    
    if (!(found))
        return -1;
    return 0;
}

int cli_untgz(int fd, const char *destdir)
{
    char *fullname, osize[13], name[101], type;
    char block[TAR_BLOCKSIZE];
    int nbytes, nread, nwritten, in_block = 0;
    unsigned int size;
    FILE *outfile = NULL;
    gzFile infile;

    printf("in cli_untgz()\n");

    if((infile = gzdopen(fd, "rb")) == NULL) {
    printf("Can't gzdopen() descriptor %d\n", fd);
    return -1;
    }


    fullname = (char *) calloc(sizeof(char), strlen(destdir) + 100 + 5);

    while(1) {

    nread = gzread(infile, block, TAR_BLOCKSIZE);

    if(!in_block && nread == 0)
        break;

    if(nread != TAR_BLOCKSIZE) {
        printf("Incomplete block read.\n");
        free(fullname);
        gzclose(infile);
        return -1;
    }

    if(!in_block) {
        if (block[0] == '\0')  /* We're done */
        break;

        strncpy(name, block, 100);
        name[100] = '\0';
        strcpy(fullname, destdir);
        strcat(fullname, "/");
        strcat(fullname, name);
        printf("Unpacking %s\n",fullname);
        type = block[156];

        switch(type) {
        case '0':
        case '\0':
            break;
        case '5':
            printf("Directories in CVD are not supported.\n");
            free(fullname);
                gzclose(infile);
            return -1;
        default:
            printf("Unknown type flag %c.\n",type);
            free(fullname);
                gzclose(infile);
            return -1;
        }

        in_block = 1;

        if(outfile) {
        if(fclose(outfile)) {
            printf("Cannot close file %s.\n", fullname);
            free(fullname);
                gzclose(infile);
            return -1;
        }
        outfile = NULL;
        }

        if(!(outfile = fopen(fullname, "wb"))) {
        printf("Cannot create file %s.\n", fullname);
        free(fullname);
            gzclose(infile);
        return -1;
        }

        strncpy(osize, block + 124, 12);
        osize[12] = '\0';

        if((sscanf(osize, "%o", &size)) == 0) {
        printf("Invalid size in header.\n");
        free(fullname);
            gzclose(infile);
        fclose(outfile);
        return -1;
        }

    } else { /* write or continue writing file contents */
        nbytes = size > TAR_BLOCKSIZE ? TAR_BLOCKSIZE : size;
        nwritten = fwrite(block, 1, nbytes, outfile);

        if(nwritten != nbytes) {
        printf("Wrote %d instead of %d (%s).\n", nwritten, nbytes, fullname);
        free(fullname);
            gzclose(infile);
        return -1;
        }

        size -= nbytes;
        if(size == 0)
        in_block = 0;
    }
    }

    if(outfile)
    fclose(outfile);

    gzclose(infile);
    free(fullname);
    return 0;
}

int cli_rmdirs(const char *dirname)
{
    DIR *dd;
    struct dirent *dent;
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
    union {
        struct dirent d;
        char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
    } result;
#endif
    struct stat maind, statbuf;
    char *fname;


    chmod(dirname, 0700);
    if((dd = opendir(dirname)) != NULL) {
    while(stat(dirname, &maind) != -1) {
        if(!rmdir(dirname)) break;

#ifdef HAVE_READDIR_R_3
        while(!readdir_r(dd, &result.d, &dent) && dent) {
#elif defined(HAVE_READDIR_R_2)
        while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
#else
        while((dent = readdir(dd))) {
#endif
#ifndef C_INTERIX
        if(dent->d_ino)
#endif
        {
            if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
            fname = (char *)calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
            sprintf(fname, "%s/%s", dirname, dent->d_name);

            /* stat the file */
            if(lstat(fname, &statbuf) != -1) {
                if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
                if(rmdir(fname) == -1) { /* can't be deleted */
                    if(errno == EACCES) {
                    printf("Can't remove some temporary directories due to access problem.\n");
                    closedir(dd);
                    free(fname);
                    return 0;
                    }
                    cli_rmdirs(fname);
                }
                } else
                unlink(fname);
            }

            free(fname);
            }
        }
        }

        rewinddir(dd);

    }

    } else { 
    return 53;
    }

    closedir(dd);
    return 0;
}

int cli_strbcasestr(const char *haystack, const char *needle)
{
    char *pt = (char *) haystack;
    int i, j;

    i = strlen(haystack);
    j = strlen(needle);

    if(i < j)
    return 0;

    pt += i - j;

    return !strcasecmp(pt, needle);
}

/*
 * Remove trailing NL and CR characters from the end of the given string.
 * Return the new length of the string (ala strlen)
 */
int
cli_chomp(char *string)
{
    int l;

    if(string == NULL)
        return -1;

    l  = strlen(string);

    if(l == 0)
        return 0;

    --l;

    while((l >= 0) && ((string[l] == '\n') || (string[l] == '\r')))
        string[l--] = '\0';

    return l + 1;
}

/*
 * char *cli_strok(const char *line, int fieldno, char *delim)
 * Return a copy of field <fieldno> from the string <line>, where
 * fields are delimited by any char from <delim>, or NULL if <line>
 * doesn't have <fieldno> fields or not enough memory is available.
 * The caller has to free() the result afterwards.
 */
char *cli_strtok(const char *line, int fieldno, const char *delim)
{
    int counter = 0, i, j;
    char *buffer = NULL;


    /* step to arg # <fieldno> */
    for (i=0; line[i] && counter != fieldno; i++) {
    if (strchr(delim, line[i])) {
        counter++;
        while(line[i+1] && strchr(delim, line[i+1])) {
        i++;
        }
    }
    }
    if (!line[i]) {
    /* end of buffer before field reached */
    return NULL;
    }

    for (j=i; line[j]; j++) {
    if (strchr(delim, line[j])) {
        break;
    }
    }
    if (i == j) {
    return NULL;
    }
    buffer = (char *)malloc(j-i+1);
    if(!buffer)
    return NULL;
    strncpy(buffer, line+i, j-i);
    buffer[j-i] = '\0';

    return buffer;
}

void KlamDB::shouldIShow(TQWidget * current)
{

    static struct cl_stat *dbstat=NULL;
    TQString location, res;

    if ((current == this) && (!(loadinprogress))){
        TQString db = tdemain->freshklam->getCurrentDBDir();
    
        if (checkdir(db.ascii()) == -1){
            kdDebug() << "returned -1" << endl;
            location = locate("data", "klamav/about/nodb.html");
            res = homepage->loadFile(location);

	    /* Stylesheets */
	    res = res.arg( locate( "data", "klamav/about/klamav.css" ) );
	    res = res.arg( locate( "data", "tdeui/about/kde_infopage.css" ) );
	    if ( kapp->reverseLayout() )
		res = res.arg( "@import \"%1\";" ).arg( locate( "data", "tdeui/about/kde_infopage_rtl.css" ) );
	    else
		res = res.arg( "" );


	    res = res.arg( i18n("Virus Browser") )
		.arg( i18n("Virus Browser") )
		.arg( i18n("Version ")+TQString(KLAMAV_VERSION) )
		.arg( i18n("The virus database could not be loaded.") )
		.arg( i18n("Please ensure that you have downloaded one (using the Updates section) and try again.") );

	    homepage->begin();
	    homepage->write(res);
	    homepage->end();
    
            return;
        }


        if ( ((cl_statchkdir(dbstat) == 1) || (dbstat == NULL))) {
            location = locate("data", "klamav/about/wait.html");
            res = homepage->loadFile(location);

	    /* Stylesheets */
	    res = res.arg( locate( "data", "klamav/about/klamav.css" ) );
	    res = res.arg( locate( "data", "tdeui/about/kde_infopage.css" ) );
	    if ( kapp->reverseLayout() )
		res = res.arg( "@import \"%1\";" ).arg( locate( "data", "tdeui/about/kde_infopage_rtl.css" ) );
	    else
		res = res.arg( "" );


	    res = res.arg( i18n("Virus Browser") )
		.arg( i18n("Virus Browser") )
		.arg( i18n("Version ")+TQString(KLAMAV_VERSION) )
		.arg( i18n("Please wait while the database loads...") );

	    homepage->begin();
	    homepage->write(res);
	    homepage->end();

            loadinprogress = true;

            sigs = ( int )getSigNos();
            progress = new KProgressDialog (this, "progress", i18n( "Loading .." ), i18n( "Loading..." ), true);
            progress->setAllowCancel(false);
            prog = progress->progressBar();
            progress->setLabel(i18n( "Loading lots and lots and lots of virus information" ));
            
            
            prog->setTotalSteps(sigs);
            
            //kdDebug() << prog->totalSteps() << endl;
            
            VirusList->hide();
            if (VirusList->childCount() > 0)
                VirusList->clear();
            count = 0;
            prog->setProgress (count);
            kapp->processEvents();

//             TQString db = tdemain->freshklam->getCurrentDBDir();

            listdir(db.ascii());

        
            prog->setProgress (sigs);
            
            VirusList->show();
            
            if(dbstat == NULL) {
                dbstat = (struct cl_stat *) malloc(sizeof(struct cl_stat));
            } else {
                cl_statfree(dbstat);
            }
            
            memset(dbstat, 0, sizeof(struct cl_stat));

            cl_statinidir(db.ascii(), dbstat);
            
          
            loadinprogress = false;

            location = locate("data", "klamav/about/main.html");
            res = homepage->loadFile(location);

	    /* Stylesheets */
	    res = res.arg( locate( "data", "klamav/about/klamav.css" ) );
	    res = res.arg( locate( "data", "tdeui/about/kde_infopage.css" ) );
	    if ( kapp->reverseLayout() )
		res = res.arg( "@import \"%1\";" ).arg( locate( "data", "tdeui/about/kde_infopage_rtl.css" ) );
	    else
		res = res.arg( "" );


	    res = res.arg( i18n("Virus Browser") )
		.arg( i18n("Virus Browser") )
		.arg( i18n("Version ")+TQString(KLAMAV_VERSION) )
		.arg( i18n("KlamAV's Virus Browser allows you to research the viruses detected by ClamAV.") )
		.arg( i18n("Usage is simple:") )
		.arg( i18n("Right-click on a virus-name to choose whether to research a virus using Google or TrendMicro.") )
		.arg( i18n("Right-click on a detected virus in the 'Scan' tab to research it in the virus browser.") )
		.arg( i18n("Right-click on a detected virus in the 'Quarantine' tab to research it in the virus browser.") );

	    homepage->begin();
	    homepage->write(res);
	    homepage->end();
        }
    }
}

void KlamDB::addVirusName(char *start)
{

    count++;
    
    kapp->processEvents();
    if ((count % 500) == 0){
        //progress->setLabel("Loading " + TQString(start));
        progress->setLabel( i18n( "Loading ClamAV's Database of Virus Signatures") );
        prog->setProgress (count);
        kapp->processEvents();
    }
    new TDEListViewItem( VirusList, TQString(start));
    kapp->processEvents();

}


unsigned int  KlamDB::getSigNos()
{
#   if defined(USE_CL_ERROR_T)
    cl_error_t ret  = CL_CLEAN;
#   else
    unsigned int ret= 0;
#   endif
    unsigned int no = 0;
    struct cl_engine *engine = NULL;
    TQStringList lastDownloadPaths;
    TQString dbdir;
    TQString db;

    TDEConfig* config = TDEGlobal::config();
    config->setGroup("Freshklam");
    lastDownloadPaths = config->readListEntry("lastDownloadPaths");
    dbdir = lastDownloadPaths.first();

      if((engine = cl_engine_new()) == NULL) {
          printf("Database initialization error: %s\n", cl_strerror(ret));;
          cl_engine_free(engine);
          return 0;
      }

    ret = cl_load(dbdir.ascii(), engine, &no, CL_DB_STDOPT);
    cl_engine_free(engine);

    kdDebug() << "no of sigs" << no << endl;
    return no;

}

void KlamDB::slotOpenTab(TQListViewItem * item, const TQPoint& , int )
{
    PageViewer* page = new PageViewer(this, "page");
    //connect( m_part, TQ_SIGNAL(signalSettingsChanged()), page, TQ_SLOT(slotPaletteOrFontChanged()));
    
    //connect( page, TQ_SIGNAL(setTabIcon(const TQPixmap&)),
    //        this, TQ_SLOT(setTabIcon(const TQPixmap&)));
    //connect( page, TQ_SIGNAL(setWindowCaption (const TQString &)),
    //        this, TQ_SLOT(slotTabCaption (const TQString &)) );
    connect( page, TQ_SIGNAL(urlClicked(const KURL &,bool)),
            this, TQ_SLOT(slotOpenTabPlain(const KURL &,bool)) );

    TQString url = item->text(0);
    
    Frame *frame=new Frame(this, page, page->widget(), "VirusList : "+item->text(0));
    //connectFrame(frame);
    tabBrowser->addFrame(frame);

//    if(!background)
        tabBrowser->showPage(page->widget());
//    else
        setFocus();
    
    //if (m_tabs->count() > 1 && m_tabs->currentPageIndex() != 0)
//        m_tabsClose->setEnabled(true);
    page->openURL("http://www.viruslist.com/en/find?search_mode=virus&words="+url);
}

void KlamDB::slotOpenTabPlain(const KURL& url, bool background)
{
    PageViewer* page = new PageViewer(this, "page");
    //connect( m_part, TQ_SIGNAL(signalSettingsChanged()), page, TQ_SLOT(slotPaletteOrFontChanged()));
    
/*    connect( page, TQ_SIGNAL(setTabIcon(const TQPixmap&)),
            this, TQ_SLOT(setTabIcon(const TQPixmap&)));*/
    connect( page, TQ_SIGNAL(setWindowCaption (const TQString &)),
            this, TQ_SLOT(slotTabCaption (const TQString &)) );
    connect( page, TQ_SIGNAL(urlClicked(const KURL &,bool)),
            this, TQ_SLOT(slotOpenTabPlain(const KURL &,bool)) );

    Frame *frame=new Frame(this, page, page->widget(), i18n("Untitled"));
    //connectFrame(frame);
    tabBrowser->addFrame(frame);

    if(!background)
        tabBrowser->showPage(page->widget());
    else
        setFocus();
    
    //if (m_tabs->count() > 1 && m_tabs->currentPageIndex() != 0)
//        m_tabsClose->setEnabled(true);

    //kdDebug() << url << endl;
    page->openURL(url);
}

void KlamDB::slotTabCaption(const TQString &caption)
{
    if (!caption.isEmpty())
    {
        PageViewer *pv=(PageViewer *)sender();
        tabBrowser->setTitle(caption, pv->widget());
        pv->slotSetCaption(caption);
    }
}

void KlamDB::slotOpenHome()
{
    homepage = new PageViewer(this, "page");
    
    Frame *frame=new Frame(this, homepage, homepage->widget(), "Home");
    //connectFrame(frame);
    tabBrowser->addFrame(frame);

//    if(!background)
        tabBrowser->showPage(homepage->widget());
//    else
        setFocus();
        
    TQString location = locate( "data", "klamav/about/wait-" + TDEGlobal::locale()->language() + ".html" );
    if( location != TQString::null )
       homepage->openURL( location );
    else
       homepage->openURL( locate("data", "klamav/about/wait.html") );
}

void KlamDB::slotRMB( TQListViewItem* Item, const TQPoint & point, int )
{
    if( Item )
        menu->popup( point );
}

void KlamDB::slotOpenPrefix(TQString prefix, TQString title,TQString url)
{

    PageViewer* page = new PageViewer(this, "page");


    Frame *frame=new Frame(this, page, page->widget(), title+" : "+url);
    tabBrowser->addFrame(frame);

        tabBrowser->showPage(page->widget());
        setFocus();

    page->openURL(prefix+url);
}

void KlamDB::slotGoogle()
{
    TQString url = KURL::encode_string( VirusList->selectedItem()->text(0) );
    slotOpenPrefix(googlePrefix,"Google",url);
}

void KlamDB::slotTrendMicro()
{

    TQString url = KURL::encode_string( VirusList->selectedItem()->text(0) );
    slotOpenPrefix(tMicroPrefix,"TrendMicro",url);
}

void KlamDB::slotExternal(TQString name,TQString service)
{
    tdemain->showVirusBrowser();
    shouldIShow(this);
    TQString prefix;
    if (service == "Google")
        prefix = googlePrefix;
    else
        prefix = tMicroPrefix;
    slotOpenPrefix(prefix,service,name);
}

#include "dbviewer.moc"
