Advertisement
Ollie920049

qgui.cpp

May 3rd, 2012
449
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.77 KB | None | 0 0
  1. /*
  2.  * =====================================================================================
  3.  *       Filename:  qgui.cpp
  4.  *    Description:  Contains all the functions required by the GUI to connect to the
  5.  *                  KDB server, update the database, inspect files, change settings.
  6.  *
  7.  *        Version:  1.0
  8.  *        Created:  23/04/12 15:42:19
  9.  *       Compiler:  "make" from QScanner root. Requires qt make installed
  10.  *                   $ sudo apt-get install libqt4-dev
  11.  *
  12.  *         Author:  Oliver Fletcher, ttolf@lboro.ac.uk
  13.  *     University:  Loughborough University
  14.  * =====================================================================================
  15.  */
  16.  
  17. #include <iostream>
  18. #include <stdio.h>
  19. #include <QtGui>
  20. #include "qgui.h"
  21. #include "k.h"
  22. using namespace std;
  23.  
  24. /*
  25.  * ===  FUNCTION  ======================================================================
  26.  *         Name:  qguiApp
  27.  *  Description:  GUI constructor function. Connects buttons to relevant functions and
  28.  *                sets up thread watchers.
  29.  * =====================================================================================
  30.  */
  31. qguiApp::qguiApp(QWidget *parent)
  32. {
  33.   setupUi(this);
  34.  
  35.   scanning->setText("");                        /* Scan in progress label set as blank */
  36.  
  37.   watcher = new QFutureWatcher<void>;           /* Create thread watchers and futures */
  38.   future = new QFuture<QByteArray>;
  39.   updateWatcher = new QFutureWatcher<void>;
  40.   updateFuture = new QFuture<QByteArray>;
  41.   fileWatcher = new QFutureWatcher<void>;
  42.   fileFuture = new QFuture<QByteArray>;
  43.  
  44.   // Crete connections for file browser button, file input box and drop down menu
  45.   connect (pushButton_browse,SIGNAL( clicked() ),this,SLOT( getPathOrDir()));
  46.   connect (scanType,SIGNAL( currentIndexChanged(int) ),this,SLOT( scanTypeChanged() ));
  47.   connect (fileBrowse,SIGNAL( clicked() ),this,SLOT( getPath()));
  48.  
  49.   // Connects the scan button to run thread. Runs a function when it starts and finishes
  50.   connect (scanButton,SIGNAL( clicked() ),this,SLOT( run_thread() ));
  51.   connect (watcher,SIGNAL(started()),this,SLOT(scan()));
  52.   connect (watcher,SIGNAL(finished()),this,SLOT(display_logs()));
  53.  
  54.   connect (updateButton,SIGNAL( clicked() ),this,SLOT( update_thread() ) );
  55.   connect (updateWatcher,SIGNAL(started()),this,SLOT(update_start()));
  56.   connect (updateWatcher,SIGNAL(finished()),this,SLOT(update_logs()));
  57.  
  58.   connect (fileinfoButton,SIGNAL( clicked() ),this,SLOT( file_thread() ) );
  59.   connect (fileWatcher,SIGNAL(finished()),this,SLOT(file_logs()));
  60.  
  61.   // Clear consoles
  62.   connect (clearScanButton,SIGNAL( clicked() ),this,SLOT( clearScan() ) );
  63.   connect (clearFileButton,SIGNAL( clicked() ),this,SLOT( clearFile() ) );
  64.  
  65.   // Update Q server with settings
  66.   connect (updateSettingsButton,SIGNAL( clicked() ),this,SLOT( updateSettings() ) );
  67.  
  68.   // Load settings  
  69.   connect (tabWidget,SIGNAL ( currentChanged(int) ),this,SLOT( loadSettings()));
  70.  
  71.   // Show the "Save" button when settings change
  72.   connect (settingsMd5,SIGNAL (  clicked()),this,SLOT( showSave()));
  73.   connect (settingsVirus,SIGNAL (  clicked()),this,SLOT( showSave()));
  74.   connect (settingsVerbose,SIGNAL (  clicked()),this,SLOT( showSave()));
  75.   connect (settingsUpdates,SIGNAL ( clicked() ),this,SLOT( showSave()));
  76.  
  77.   // Show help manual
  78.   connect (help,SIGNAL( clicked() ),this,SLOT (showHelp()) );
  79. }
  80.  
  81. /*
  82.  * ===  FUNCTION  ======================================================================
  83.  *         Name:  update_thread()
  84.  *  Description:  Run the functions update_query() in a separate thread. Set up a
  85.  *                watcher.
  86.  * =====================================================================================
  87.  */
  88. void qguiApp::update_thread()
  89. {
  90.   *updateFuture = QtConcurrent::run( update_query );
  91.   updateWatcher->setFuture(*updateFuture);
  92. }
  93.  
  94. /*
  95.  * ===  FUNCTION  ======================================================================
  96.  *         Name:  update_query()
  97.  *  Description:  Checks for a valid connection to clamAV server. Connects to KDB
  98.  *                instance and sends the function "qupdate[]" which returns information
  99.  *                on the update.
  100.  *      Returns:  logs -> Contains signatures updated and time
  101.  * =====================================================================================
  102.  */
  103. QByteArray update_query()
  104. {
  105.   QByteArray logs;
  106.   K result,line;
  107.   unsigned char * str;
  108.   const char * str1;
  109.  
  110.   if ( system("ping -c1 -s1 db.local.clamav.net > /dev/null" )){ /* Test internet connection */
  111.     logs = "Error: No Internet Connection";
  112.     return logs;
  113.   }
  114.  
  115.   qconn *conn = new qconn;                      /* Create KDB connection */
  116.   if(conn->isConnected()){
  117.     result = conn->sync_query("qupdate[]");
  118.     delete conn;
  119.   }
  120.   else {
  121.     delete conn;
  122.     logs = "Error connecting to database";
  123.     return logs;
  124.   }
  125.  
  126.   for(int i=0;i<result->n;i++)                  /* Loop through query results */
  127.   {
  128.     line=kK(result)[i];                         /* Get first element */
  129.     int s = line->n;                            /* Get char array size */
  130.     str = (kC(line));                           /* Assign to unsigned char */
  131.     str[s] = '\0';                              /* End string */
  132.     str1 = reinterpret_cast<const char*>(str);  
  133.     logs.append(str1);                          /* Add to QByteArray logs */
  134.     logs.append('\n');
  135.   }
  136.  
  137.   return logs;
  138. }
  139.  
  140. /*
  141.  * ===  FUNCTION  ======================================================================
  142.  *         Name:  update_start
  143.  *  Description:  Called when the update thread begins. Sets a label and shows a gif.
  144.  * =====================================================================================
  145.  */
  146. void qguiApp::update_start()
  147. {
  148.   scanning->setText("Updating...");
  149.  
  150.   QMovie *movie = new QMovie("img/loading.gif");
  151.   gif_loader->setMovie(movie);
  152.   movie->start();
  153. }
  154.  
  155. /*
  156.  * ===  FUNCTION  ======================================================================
  157.  *         Name:  update_logs
  158.  *  Description:  Called when the update thread is finished.
  159.  *                Receives the logs from the future object.
  160.  *                Clears the scanning gif and label.
  161.  *                Shows the log in the console.
  162.  * =====================================================================================
  163.  */
  164. void qguiApp::update_logs()
  165. {
  166.   QByteArray ulogs = updateFuture->result();    /* Gets the return variable from update_query */
  167.  
  168.   scanConsole->setText(ulogs);
  169.  
  170.   scanning->setText("");
  171.   gif_loader->clear();
  172. }
  173.  
  174. /*
  175.  * ===  FUNCTION  ======================================================================
  176.  *         Name:  run_thread
  177.  *  Description:  Grabs the file or directory path selected.
  178.  *                Builds a Q query based on file/directory selected
  179.  *                Launches a thread to scan the file/directory
  180.  * =====================================================================================
  181.  */
  182. void qguiApp::run_thread()
  183. {
  184.   string path;
  185.   char * qinput;
  186.  
  187.   if(file->toPlainText().toStdString() == ""){  /* Check if a file has been selected */
  188.     scanConsole->setText("Select file or Directory");
  189.     return;
  190.   }
  191.  
  192.   if(scanType->currentText() == "File"){        /* Convert path to directory and path */
  193.     path=(file->toPlainText()).toStdString();
  194.     fname=path.substr(path.find_last_of("/") + 1);
  195.     dir=path.substr(0,path.find_last_of("/"));
  196.   }
  197.   else {                                        /* Convert path to directory */
  198.     path=(file->toPlainText()).toStdString();
  199.     fname="";
  200.     dir=path;
  201.   }
  202.  
  203.   // Build the query to be sent to Q
  204.   string input = "qscan[\"" + fname + "\";\"" + dir + "\"]";
  205.   qinput = new char[input.size() + 1];
  206.   copy(input.begin(),input.end(),qinput);
  207.   qinput[input.size()] = '\0';
  208.  
  209.   if(fname==""){isdir=true;}else {isdir=false;} /* isdir -> is directory? */
  210.  
  211.   updateButton->setEnabled(false);              /* Disable updates while scanning */
  212.  
  213.   *future = QtConcurrent::run( q_query, qinput, isdir ); /* Launch scan thread */
  214.   watcher->setFuture(*future);
  215. }
  216.  
  217. /*
  218.  * ===  FUNCTION  ======================================================================
  219.  *         Name:  scan
  220.  *  Description:  Launched when the scan begins. Alerts the user that a scan is in
  221.  *                progress and shows a loading animated gif.
  222.  * =====================================================================================
  223.  */
  224. void qguiApp::scan()
  225. {
  226.   string scanInProgress,directory;
  227.  
  228.   if(isdir){                                    /* Build scan in progress string */
  229.     scanInProgress = "Directory: ";
  230.   }
  231.   else {
  232.     scanInProgress = "File: ";
  233.   }
  234.   scanInProgress = "Scanning " + scanInProgress;
  235.   scanning->setText( scanInProgress.c_str() );  /* Set scan in progress label */
  236.  
  237.   directory = dir+fname;                    /* Build and set directory been scanned */
  238.   filename->setText( directory.c_str() );
  239.  
  240.   QMovie *movie = new QMovie( "img/loading.gif" ); /* Show the loading gif */
  241.   gif_loader->setMovie(movie);
  242.   movie->start();
  243. }
  244.  
  245. /*
  246.  * ===  FUNCTION  ======================================================================
  247.  *         Name:  display_logs
  248.  *  Description:  Gets the run_thread result for the scan query when its completed
  249.  *                Displays the result in the console window
  250.  * =====================================================================================
  251.  */
  252. void qguiApp::display_logs()
  253. {
  254.   QByteArray slogs = future->result();          /* Get the QScan results */
  255.  
  256.   string logs = slogs.data();                   /* Convert to string */
  257.  
  258.   // Inspect if malware was found or an error occurred
  259.   bool found=logs.find("Malware Detected: ")!=string::npos;
  260.   bool error=logs.find("Error connecting to database")!=string::npos;
  261.  
  262.   scanConsole->setText(slogs);                  /* Output results to console */
  263.  
  264.   if(!error){                                   /* Append virus warning */
  265.     if(!found){
  266.       scanConsole->append("**************************************************************\n\n                       NO VIRUSES FOUND                       \n\n**************************************************************\n\n");
  267.     }
  268.     else {
  269.       scanConsole->append("**************************************************************\n\n          VIRUSES FOUND (CHECK LOG ABOVE FOR DETAILS)         \n\n**************************************************************\n\n");
  270.     }
  271.   }
  272.  
  273.   // Scroll the console to the  bottom of the page
  274.   QScrollBar *vScrollBar = scanConsole->verticalScrollBar();
  275.   vScrollBar->triggerAction(QScrollBar::SliderToMaximum);
  276.  
  277.   updateButton->setEnabled(true);               /* Clear the display */
  278.   scanning->setText("");
  279.   filename->setText("");
  280.   gif_loader->clear();
  281. }
  282.  
  283. /*
  284.  * ===  FUNCTION  ======================================================================
  285.  *         Name:  q_query
  286.  *  Description:  Connects to KDB server, sends the scan command, returns the scan
  287.  *                results and converts to QByteArray  
  288.  *      Returns:  logs -> QByteArray
  289.  * =====================================================================================
  290.  */
  291. QByteArray q_query(char* qinput,bool isdir)
  292. {
  293.   K result,line,directory_result;
  294.   QByteArray logs;
  295.   unsigned char *str;
  296.   const char* str1;
  297.  
  298.   qconn *conn = new qconn;                      /* Create new Q connection */
  299.   if( conn->isConnected() ){                    /* If connected then query */
  300.     result = conn->sync_query(qinput);
  301.     delete conn;
  302.   }
  303.   else {                                        /* Else return error */
  304.     delete conn;
  305.     logs = "Error connecting to database\nCheck error logs for more details";
  306.     return logs;
  307.   }
  308.  
  309.   if(isdir){
  310.     for(int j=0;j<result->n;j++){       /* Iterate through K array of K objects */
  311.       directory_result=kK(result)[j];  
  312.       for(int i=0;i<directory_result->n;i++){ /* Grab object */
  313.         line=kK(directory_result)[i];
  314.         int s = line->n;                        /* Find length */
  315.         str = (kC(line));                       /* Accessor kC converts to char */
  316.         str[s] = '\0';
  317.         str1 = reinterpret_cast<const char*>(str); /* Convert to signed */
  318.         logs.append(str1);                      /* Append to log file */
  319.         logs.append('\n');
  320.       }
  321.       logs.append('\n');
  322.     }
  323.   }
  324.  // Same process as above but for a single K object (rather than an array of objects)
  325.   else{
  326.     for(int i=0;i<result->n;i++){
  327.       line=kK(result)[i];
  328.       int s = line->n;
  329.       str = (kC(line));
  330.       str[s] = '\0';
  331.       str1 = reinterpret_cast<const char*>(str);
  332.       logs.append(str1);
  333.       logs.append('\n');
  334.     }
  335.   }
  336.   return logs;
  337. }
  338.  
  339. /*
  340.  * ===  FUNCTION  ======================================================================
  341.  *         Name:  file_thread
  342.  *  Description:  Builds file directory and path strings
  343.  *                Builds Q function to be sent to KDB server
  344.  *                Launches query in a separate thread
  345.  * =====================================================================================
  346.  */
  347. void qguiApp::file_thread()
  348. {
  349.   string path,fname,dir,input;
  350.  
  351.   if(file_2->toPlainText().toStdString() == ""){ /* Check if a file has been selected */
  352.     fileConsole->setText("Select file");
  353.     return;
  354.   }
  355.  
  356.   path=(file_2->toPlainText()).toStdString();    /* Convert path to directory and path */
  357.   fname=path.substr(path.find_last_of("/") + 1);
  358.   dir=path.substr(0,path.find_last_of("/"));
  359.  
  360.   // Build the query to be sent to Q
  361.   input = "qscan[\"" + fname + "\";\"" + dir + "\"]";
  362.   char * qinput = new char[input.size() + 1];
  363.   copy(input.begin(),input.end(),qinput);
  364.   qinput[input.size()] = '\0';
  365.  
  366.   *fileFuture = QtConcurrent::run( file_query,qinput ); /* Launch scan thread */
  367.   fileWatcher->setFuture(*fileFuture);
  368. }
  369.  
  370. /*
  371.  * ===  FUNCTION  ======================================================================
  372.  *         Name:  file_logs
  373.  *  Description:  Gets file inspection query results
  374.  *                Displays results in console
  375.  * =====================================================================================
  376.  */
  377. void qguiApp::file_logs()
  378. {
  379.   QByteArray flogs = fileFuture->result();      /* Display file inspection results */
  380.   fileConsole->setText(flogs);
  381. }
  382.  
  383. /*
  384.  * ===  FUNCTION  ======================================================================
  385.  *         Name:  file_query
  386.  *  Description:  Connects to KDB database
  387.  *                Adjusts settings NOT to scan the file and just get file info
  388.  *                Convert results to QByteArray
  389.  *      Returns:  logs -> QByteArray, contains query results
  390.  * =====================================================================================
  391.  */
  392. QByteArray file_query(char* qinput)
  393. {
  394.   K result,line;
  395.   QByteArray logs;
  396.   unsigned char *str;
  397.   const char *str1;
  398.  
  399.   qconn *conn = new qconn;                      /* Make KDB connection */
  400.   if( conn->isConnected() ){
  401.     conn->async_query("t:settings[`verbose`md5`virus]"); /* Save settings state */
  402.     conn->async_query("settings[`verbose`md5`virus]:100b"); /* Turn scanning off */
  403.    
  404.     result=conn->sync_query(qinput);            /* Query file */
  405.    
  406.     conn->async_query("settings[`verbose`md5`virus]:t"); /* Restore save state */
  407.    
  408.     delete conn;                                /* Close connection */
  409.   }
  410.   else {                                        /* Deal with error connecting to KDB */
  411.     delete conn;
  412.     logs = "Error connecting to database\nCheck error logs for more details";
  413.     return logs;
  414.   }
  415.  
  416.   for(int i=0;i<5;i++){                         /* Convert results to QByteArray */
  417.     line=kK(result)[i];
  418.     int s = line->n;
  419.     str = (kC(line));
  420.     str[s] = '\0';
  421.     str1 = reinterpret_cast<const char*>(str);
  422.     logs.append(str1);
  423.     logs.append('\n');
  424.   }
  425.   return logs;
  426. }
  427.  
  428. /*
  429.  * ===  FUNCTION  ======================================================================
  430.  *         Name:  clearScan
  431.  *  Description:  Clears the console screen
  432.  * =====================================================================================
  433.  */
  434. void qguiApp::clearScan()
  435. {
  436.   scanConsole->clear();
  437. }
  438.  
  439. /*
  440.  * ===  FUNCTION  ======================================================================
  441.  *         Name:  clearFile
  442.  *  Description:  Clears the file inspectors console screen
  443.  * =====================================================================================
  444.  */
  445. void qguiApp::clearFile()
  446. {
  447.   fileConsole->clear();
  448. }
  449.  
  450. /*
  451.  * ===  FUNCTION  ======================================================================
  452.  *         Name:  updateSettings
  453.  *  Description:  Takes the values on the settings page and updates the KDB database
  454.  *                with the current settings.
  455.  * =====================================================================================
  456.  */
  457. void qguiApp::updateSettings()
  458. {
  459.   bool settings_verbose,settings_md5,settings_updates,settings_virus;
  460.   string sverbose,smd5,supdates,svirus,query;
  461.  
  462.   settings_md5 = settingsMd5->isChecked();      /* Get settings checked */
  463.   settings_virus= settingsVirus->isChecked();
  464.   settings_updates= settingsUpdates->isChecked();
  465.   settings_verbose = settingsVerbose->isChecked();
  466.  
  467.   if(settings_md5){smd5="1";}else {smd5="0";}   /* Used to build Q update query */
  468.   if(settings_virus){svirus="1";}else {svirus="0";}
  469.   if(settings_verbose){sverbose="1";}else {sverbose="0";}
  470.   if(settings_updates){supdates="1";}else {supdates="0";}
  471.  
  472.   // Build the Q query
  473.   query = "qsettings["+sverbose+ " " +svirus+ " " +smd5+ " " + supdates+"]";  
  474.   char * qinput = new char[query.size() + 1];
  475.   copy(query.begin(),query.end(),qinput);
  476.   qinput[query.size()] = '\0';
  477.  
  478.   qconn *conn = new qconn;                      /* Connect to KDB server */
  479.   if(conn->isConnected()){
  480.     conn->async_query( qinput );
  481.   }
  482.   delete conn;
  483.   updateSettingsButton->setEnabled(false);      /* After a save, disable the button */
  484. }
  485.  
  486. /*
  487.  * ===  FUNCTION  ======================================================================
  488.  *         Name:  loadSettings
  489.  *  Description:  When a tab is changed, the current settings saved in the KDB database
  490.  *                are updated.
  491.  * =====================================================================================
  492.  */
  493. void qguiApp::loadSettings()
  494. {
  495.   bool verbose,md5,virus,updates;
  496.   K result;
  497.  
  498.   qconn *conn = new qconn;                      /* Connect to Q */
  499.   if(conn->isConnected()){
  500.     result = conn->sync_query("settings[`verbose`virus`md5`updates]");
  501.                                                
  502.     verbose   =  kG(result)[0];                 /* Get the settings from the results */
  503.     virus     =  kG(result)[1];
  504.     md5       =  kG(result)[2];
  505.     updates   =  kG(result)[3];
  506.  
  507.     settingsMd5->setChecked(md5);               /* Configure the settings page */
  508.     settingsVirus->setChecked(virus);
  509.     settingsUpdates->setChecked(updates);
  510.     settingsVerbose->setChecked(verbose);
  511.   }
  512.   delete conn;
  513.   updateSettingsButton->setEnabled(false);
  514. }
  515.  
  516. /*
  517.  * ===  FUNCTION  ======================================================================
  518.  *         Name:  showSave
  519.  *  Description:  Shows the save button on the settings page when the settings in the
  520.  *                KDB database do not match the GUI selected settings
  521.  * =====================================================================================
  522.  */
  523. void qguiApp::showSave()
  524. {
  525.   bool verbose,md5,virus,updates,same;
  526.   K result;
  527.  
  528.   qconn *conn = new qconn;                      /* Connect to KDB server */
  529.   if(conn->isConnected()){
  530.     // Get the current settings
  531.     result = conn->sync_query("settings[`verbose`virus`md5`updates]");
  532.  
  533.     verbose   =  kG(result)[0];
  534.     virus     =  kG(result)[1];
  535.     md5       =  kG(result)[2];
  536.     updates   =  kG(result)[3];
  537.  
  538.     // When the checked values equal the KDB settings values same is true
  539.     same = (verbose!=settingsVerbose->isChecked()) && (virus!=settingsVirus->isChecked()) &&
  540.       (md5!=settingsMd5->isChecked()) && (updates!=settingsUpdates->isChecked());
  541.  
  542.     // Show the button if the KDB settings dont match GUI settings
  543.     if(!same){updateSettingsButton->setEnabled(true);}
  544.   }
  545.  
  546.   delete conn;
  547. }
  548.  
  549. /*
  550.  * ===  FUNCTION  ======================================================================
  551.  *         Name:  getPathOrDir
  552.  *  Description:  Get the selected scan type from the dropbox (file or directory)
  553.  *                Open a file explorer allowing the user to choose file or directory
  554.  *                Load the file or directory into the textbox
  555.  * =====================================================================================
  556.  */
  557. void qguiApp::getPathOrDir()
  558. {
  559.   QString path;
  560.   QString type;
  561.  
  562.   type = scanType->currentText();               /* Get drop menu selection */
  563.  
  564.   if(type == "File"){
  565.     path = QFileDialog::getOpenFileName(        /* Open file explorer */
  566.         this,
  567.         "Choose a file to scan",
  568.         QString::null,
  569.         QString::null);
  570.   }
  571.   else {
  572.     path = QFileDialog::getExistingDirectory(   /* Open directory explorer */
  573.         this,
  574.         "Choose a directory",
  575.         QString::null
  576.         );
  577.   }
  578.   file->setText( path );                        /* Set file path in text box */
  579. }
  580.  
  581. /*
  582.  * ===  FUNCTION  ======================================================================
  583.  *         Name:  getPath
  584.  *  Description:  Opens the file explorer and sets a text box with the path chosen
  585.  * =====================================================================================
  586.  */
  587. void qguiApp::getPath()
  588. {
  589.   QString path;
  590.  
  591.   path = QFileDialog::getOpenFileName(          /* Open explorer */
  592.       this,
  593.       "Choose a file to scan",
  594.       QString::null,
  595.       QString::null);
  596.  
  597.   file_2->setText( path );                      /* Set text */
  598. }
  599.  
  600. /*
  601.  * ===  FUNCTION  ======================================================================
  602.  *         Name:  scanTypeChanged
  603.  *  Description:  When the drop down menu to select a file or directory is changed this
  604.  *                function empties the text box
  605.  * =====================================================================================
  606.  */
  607. void qguiApp::scanTypeChanged()
  608. {
  609.   file->setText("");
  610. }
  611.  
  612. /*
  613.  * ===  FUNCTION  ======================================================================
  614.  *         Name:  showHelp
  615.  *  Description:  Dispalys a help file in the console window
  616.  * =====================================================================================
  617.  */
  618. void qguiApp::showHelp()
  619. {
  620.   QFile userGuide("doc/manual.txt");            /* Read in the file */
  621.   userGuide.open(QIODevice::ReadOnly);
  622.  
  623.   QByteArray userGuideText = userGuide.readAll(); /* and display... */
  624.   scanConsole->setText( userGuideText );
  625. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement