You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
klamav/src/update.cpp

563 lines
17 KiB

/***************************************************************************
* Copyright (C) 2004 by Robert Hogan *
* robert@roberthogan.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "klamav.h"
#include "update.h"
#include "klamavconfig.h"
#include <kstaticdeleter.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kaction.h>
#include <tqcheckbox.h>
#include <kbuttonbox.h>
#include <kurlrequester.h>
#include <kurlcompletion.h>
#include <kcombobox.h>
#include <tqlayout.h>
#include <kmessagebox.h>
#include <klineedit.h>
#include <ktempfile.h>
#include <ksystemtray.h>
#include <ktar.h>
#include <kprogress.h>
#include <kprocio.h>
#include <knotifyclient.h>
#include <dom/html_misc.h>
#include <kapplication.h>
#include <dcopclient.h>
#include <kuser.h>
#include <tqtimer.h>
#include "version.h"
#include <stdlib.h>
const char *mirrors[] = {
"heanet",
"internap",
"surfnet",
"umn",
"nchc",
"ufpr",
"unc",
"jaist",
"voxel",
"citkit",
"optusnet",
"ovh",
"mesh",
"easynews",
"switch",
"kent",
"puzzle",
0
};
KlamavUpdate::KlamavUpdate(TQWidget *parent, const char *name)
: TQWidget(parent, name),filelist(new KHTMLPart(this))
{
filelist->hide();
filelist->setJScriptEnabled(false);
filelist->setJavaEnabled(false);
filelist->setAutoloadImages(false);
filelist->setDNDEnabled(false);
filelist->setPluginsEnabled(false);
}
KlamavUpdate::~KlamavUpdate()
{
kdDebug() << "deleting" << endl;
//delete filelist;
}
void KlamavUpdate::downloadComponent(TQString component, TQString version, TQString extension)
{
upgradeinprogress = true;
TQString location = getenv("HOME");
location += "/.klamav";
TQDir klamavdir(location);
if (!klamavdir.exists() && !klamavdir.mkdir(location))
location = getenv("HOME");
TQString currentclamav = location + TQString("/%1-%2").arg(component).arg(version);
TQDir clamavdir(currentclamav);
TQString configure;
/* if (component == "klamav"){
configure = TQString("%1/%2-%3/%4-%5/configure").arg(location).arg(component).arg(version).arg(component).arg(version);
}else{*/
configure = TQString("%1/%2-%3/configure").arg(location).arg(component).arg(version);
// }
TQFile configurefile(configure);
bool download = true;
if (clamavdir.exists() && configurefile.exists()){
int result = KMessageBox::questionYesNo(this, i18n( "You seem to have downloaded %1-%2 already (in %3/%4-%5). Would you like to skip re-downloading it and just try to compile it?").arg(component).arg(version).arg(location).arg(component).arg(version),i18n( "Compile %1" ).arg(component));
switch (result) {
case 2 :
download = true;break;
case 3 :
download = false;
}
}
while (download){
startProgressDialog( i18n( "Downloading %1-%2..." ).arg(component).arg(version) );
TQString tmpFile;
if ( !KIO::NetAccess::download( TQString("http://%1.dl.sourceforge.net/sourceforge/%2/%3-%4.%5").arg(getMirror()).arg(component).arg(component).arg(version).arg(extension), tmpFile, 0L ) ){
KMessageBox::information (this,i18n("Couldn't download %1.").arg(component));
delete timer;
timer=0;
delete progressDialog;
progressDialog = 0;
upgradeinprogress = false;
return;
}
kdDebug() << "Theme is in temp file: " << tmpFile << endl;
if ((progressDialog) && (progressDialog->wasCancelled())){
updateCanceled();
return;
}
progressDialog->setLabel( i18n( "Unpacking %1-%2 to %3/%4-%5" ).arg(component).arg(version).arg(location).arg(component).arg(version));
// unpack the tarball
KTar tar( tmpFile );
if (!(tar.open( IO_ReadOnly ))){
int result = KMessageBox::questionYesNo(this, i18n( "The mirror I attempted to download from has not updated yet. Should I try another?"));
kdDebug() << result << endl;
switch (result) {
case KMessageBox::Yes :
download = true; break;
case KMessageBox::No :
download = false;
default:
download = false;
}
}else{
download = false;
}
tar.directory()->copyTo( location );
tar.close();
// remove the temp file
KIO::NetAccess::removeTempFile( tmpFile );
delete timer;
timer=0;
delete progressDialog;
progressDialog = 0;
}
if ((progressDialog) && (progressDialog->wasCancelled())){
updateCanceled();
delete progressDialog;
progressDialog = 0;
return;
}
//KTar does not honour executable permissions
if (clamavdir.exists() && configurefile.exists()){
chmod((const char *)configure,0700);
// if (component == "klamav"){
// TQString dazukoconfigure = i18n("%1/%2-%3/dazuko/configure").arg(location).arg(component).arg(version);
//
// chmod((const char *)dazukoconfigure,0700);
// }
int result = KMessageBox::warningContinueCancel(this, i18n( "%1-%2 is ready for compiling and installation. Would you like the wizard to ask you for the root password so it can compile and install it for you? (If not, you can compile it yourself later at %3/%4-%5)").arg(component).arg(version).arg(location).arg(component).arg(version),i18n( "Install %1-%2" ).arg(component).arg(version),i18n( "Use the Wizard" ));
switch (result) {
case 2 :
KMessageBox::information (this,i18n("Installation of %1 Cancelled.").arg(component));
upgradeinprogress = false;
break;
case 5 :
KProcess* arkollonproc = new KShellProcess();
//make sure we catch arkollon in the .klamav directory
// TQString curpath = (TQString) getenv("PATH");
// TQString homedir = (TQString) getenv("HOME");
// arkollonproc->setEnvironment("PATH",homedir+"/.klamav/bin:" + curpath);
KMessageBox::information (this,i18n( "<p><b>If this the first time you've compiled software then here are a few useful tips:</b><br>"
"1. Any error messages in the log file with the words 'KDE', 'TQt','curl' or 'X' in them mean that you need to install "
"the appropriate development libraries.<br>"
"2. Any package provided by your distribution with 'lib' or 'devel' in the name is a development library, e.g. qt-devel, libkde.<br>"
"3. If you encounter errors installing Dazuko, just deselect it at installation time and try the instructions at www.dazuko.org.<br>"
"4. Some distributions provide a dazuko package, see if yours does.</p>" ),"Compilation Tips","compiler");
TQString command = TQString("klamarkollon %1/%2-%3").arg(location).arg(component).arg(version);
*arkollonproc << command;
if (component == "klamav")
connect( arkollonproc, SIGNAL(processExited(KProcess *)), SLOT(klamavInstallationExited(KProcess *)) );
else
connect( arkollonproc, SIGNAL(processExited(KProcess *)), SLOT(clamavInstallationExited(KProcess *)) );
arkollonproc->start();
}
}
}
void KlamavUpdate::checkForNewKlamAV()
{
kdDebug() << "Checking for new KlamAV" << endl;
checkingDirectly = false;
highestsofarnumeric = 0;
klamav_url = "http://ftp.heanet.ie/mirrors/download.sourceforge.net/pub/sourceforge/k/kl/klamav/";
getLatestVersionFromSFHack(klamav_url);
}
void KlamavUpdate::checkForNewKlamAVDirectly()
{
kdDebug() << "Checking for new KlamAV" << endl;
checkingDirectly = true;
highestsofarnumeric = 0;
klamav_url = "http://ftp.heanet.ie/mirrors/download.sourceforge.net/pub/sourceforge/k/kl/klamav/";
startProgressDialog( i18n( "Checking for new version of KlamAV..." ) );
getLatestVersionFromSF(klamav_url);
}
void KlamavUpdate::checkForNewClamAVDirectly()
{
kdDebug() << "Checking for new ClamAV" << endl;
checkingDirectly = true;
highestsofarnumeric = 0;
clamav_url = "http://ftp.heanet.ie/mirrors/download.sourceforge.net/pub/sourceforge/c/cl/clamav/";
startProgressDialog( i18n( "Checking for new version of ClamAV..." ) );
getLatestVersionFromSF(clamav_url);
}
void KlamavUpdate::completedSearchForUpdates(const TQString &component, const TQString &extension)
{
double currentversion;
if (component == "KlamAV")
currentversion = VERSION_KLAMAV;
else{
TQString currentClamAVVersion = KlamavConfig::clamAVVersion();
currentversion = numericizeVersion(currentClamAVVersion);
}
kdDebug() << "in completed search for updates" << endl;
kdDebug() << currentversion << endl;
kdDebug() << highestsofarnumeric << endl;
if (highestsofarnumeric > currentversion){
int result = KMessageBox::warningContinueCancel(this, i18n( "It looks like your version of %1 is out of date! %2-%3 is the most recent version available. Would you like KlamAV to download and compile it for you?").arg(component).arg(component).arg(highestsofarraw),i18n( "Download and Install %1-%2" ).arg(component).arg(highestsofarraw),i18n( "Download and Install %1-%2" ).arg(component).arg(highestsofarraw));
switch (result) {
case 2 :
break;
case 5 :
downloadComponent(component.lower(), highestsofarraw, extension);
}
}else if (checkingDirectly){
KMessageBox::information (this,i18n("Your installation of %1 is already up-to-date!").arg(component));
}
checkingDirectly = false;
emit toggleUpgradeButtons(true);
// if (filelist)
// filelist->deleteLater();
}
void KlamavUpdate::startProgressDialog( const TQString & text )
{
//if ( progressDialog )
// delete progressDialog;
progressDialog = new KProgressDialog( this, "progress_dialog", TQString::null, text, false );
progressDialog->setAllowCancel( true );
progressDialog->showCancelButton( true );
progressDialog->setPlainCaption( i18n( "Please Wait" ) );
progressDialog->progressBar()->setTotalSteps( 0 );
progressDialog->progressBar()->setPercentageVisible( false );
progressDialog->setMinimumDuration( 500 );
progressDialog->show();
timer = new TQTimer( this );
connect( timer, SIGNAL( timeout() ), this, SLOT( slotProg() ) );
timer->start( 200, FALSE );
}
void KlamavUpdate::slotProg()
{
if (progressDialog)
progressDialog->progressBar()->setProgress(progressDialog->progressBar()->progress() + 4 );
}
void KlamavUpdate::clamavInstallationExited(KProcess* arkollonproc)
{
arkollonproc = 0;
delete arkollonproc;
upgradeinprogress = false;
emit getCurrentVersionOfClamAV( );
}
void KlamavUpdate::klamavInstallationExited(KProcess* arkollonproc)
{
arkollonproc = 0;
delete arkollonproc;
upgradeinprogress = false;
KMessageBox::information (this,i18n( "If the installation of KlamAV completed successfully you should restart KlamAV for the new version to take effect." ));
}
void KlamavUpdate::getLatestVersionFromSF(KURL url)
{
kdDebug() << "getting latest version" << endl;
kdDebug() << url << endl;
emit toggleUpgradeButtons(false);
connect( filelist, SIGNAL( completed() ), this,
SLOT( parseSFPage() ) );
filelist->openURL(url);
if (progressDialog)
connect( progressDialog, SIGNAL( cancelClicked() ), this,
SLOT( updateCanceled() ) );
}
void KlamavUpdate::getLatestVersionFromSFHack(KURL url)
{
kdDebug() << "getting latest version" << endl;
kdDebug() << url << endl;
emit toggleUpgradeButtons(false);
connect( filelist, SIGNAL( completed() ), this,
SLOT( parseSFPageHack() ) );
filelist->openURL(url);
}
void KlamavUpdate::updateCanceled()
{
kdDebug() << "cancelled" << endl;
filelist->closeURL();
emit toggleUpgradeButtons(true);
}
void KlamavUpdate::parseSFPage()
{
kdDebug() << "parsing sf page" << endl;
const DOM::HTMLCollection links = filelist->htmlDocument().links();
kdDebug() << links.length() << endl;
if (links.length() == 0){
KMessageBox::information (this,i18n( "Could not contact update server!" ));
updateCanceled();
delete progressDialog;
progressDialog = 0;
return;
}
disconnect( filelist, SIGNAL( completed() ), this,
SLOT( parseSFPage() ) );
for (unsigned int j=0; j != links.length(); j++ ){
const DOM::Node linkNode = links.item( j );
getVersionFromLink( linkNode );
}
delete progressDialog;
progressDialog = 0;
kdDebug() << highestsofarfilename << endl;
if (highestsofarfilename.contains("klamav"))
completedSearchForUpdates("KlamAV", "tar.bz2");
else if (highestsofarfilename.contains("clamav"))
completedSearchForUpdates("ClamAV", "tar.gz");
}
void KlamavUpdate::parseSFPageHack()
{
kdDebug() << "parsing sf page" << endl;
const DOM::HTMLCollection links = filelist->htmlDocument().links();
kdDebug() << links.length() << endl;
if (links.length() == 0){
return;
}
disconnect( filelist, SIGNAL( completed() ), this,
SLOT( parseSFPageHack() ) );
for (unsigned int j=0; j != links.length(); j++ ){
const DOM::Node linkNode = links.item( j );
getVersionFromLink( linkNode );
}
//delete progressDialog;
//progressDialog = 0;
kdDebug() << highestsofarfilename << endl;
if (highestsofarfilename.contains("klamav"))
completedSearchForUpdates("KlamAV", "tar.bz2");
else if (highestsofarfilename.contains("clamav"))
completedSearchForUpdates("ClamAV", "tar.gz");
}
void KlamavUpdate::getVersionFromLink( const DOM::Node &n )
{
double numericversion;
TQString tmpversion;
if ( n.isNull() || n.nodeType() != DOM::Node::ELEMENT_NODE )
return;
DOM::Element elem = static_cast<DOM::Element>( n );
KURL href ( elem.getAttribute( "href" ).string() );
kdDebug() << elem.getAttribute( "href" ).string() << endl;
TQString name = elem.getAttribute( "href" ).string();
TQString version = name.replace(".tar.bz2","").replace(".tar.gz","");
version = version.replace("clamav-","").replace("klamav-","");
TQString rawversion = version;
if (m_alpha)
version.remove("-alpha").remove("-beta").remove("-rc");
numericversion = numericizeVersion(version);
if (numericversion > highestsofarnumeric){
highestsofarnumeric = numericversion;
highestsofarraw = rawversion;
highestsofarfilename = elem.getAttribute( "href" ).string();
}
}
TQString KlamavUpdate::getMirror()
{
int r = 1+(int) (16.0*rand()/(RAND_MAX+1.0));
static int previousmirror = 0;
while (r == previousmirror)
r=1+(int) (16.0*rand()/(RAND_MAX+1.0));
previousmirror = r;
kdDebug() << r << endl;
return mirrors[r];
}
double KlamavUpdate::numericizeVersion(TQString &version)
{
TQString tmpversion = version;
TQStringList tokens = TQStringList::split(".",tmpversion);
for ( TQStringList::Iterator it = tokens.begin(); it != tokens.end(); it++ )
{
if ((*it).length() < 2)
(*it).prepend("0");
}
tmpversion = tokens.join(".");
unsigned int firstdot = tmpversion.find(".");
for (unsigned int j=tmpversion.length(); j != firstdot; j-- ){
if (tmpversion.mid(j,1) == "."){
tmpversion.remove(j,1);
j--;
}
}
return tmpversion.toDouble();
}
#include "update.moc"