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.
adept/adept/kubuntu_upgrader/upgradewizard.cpp

544 lines
18 KiB

/***************************************************************************
* Copyright (C) 2006 by Vladimir Stefan *
* vstefan85@gmail.com *
* *
* 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kurl.h>
#include <kio/netaccess.h>
#include <kio/job.h>
#include <kprocess.h>
#include <klocale.h>
#include <kglobal.h>
#include <kconfig.h>
#include <ktar.h>
#include <kdebug.h>
#include <qwizard.h>
#include <qwidget.h>
#include <qpushbutton.h>
#include <qtextstream.h>
#include <qfile.h>
#include <qtextbrowser.h>
#include <qmime.h>
#include <qstring.h>
#include <qdialog.h>
#include <qlabel.h>
#include <qdatetime.h>
#include <qtextstream.h>
#include <qptrlist.h>
#include <qdir.h>
#include <iostream>
#include <cstdlib>
#include "upgradewizard.h"
#include "errordialog.h"
DistroEntry::DistroEntry(QString *d_field)
{
dist_field = d_field;
supported_field = false;
name_field = NULL;
version_field = NULL;
date_field = NULL;
desc_field = NULL;
release_file_url = NULL;
release_notes_url = NULL;
upgrade_tool_url = NULL;
upgrade_tool_sig_url = NULL;
}
DistroEntry::~DistroEntry() {
free( dist_field );
free( name_field );
free( version_field );
free( date_field );
free( desc_field );
free( release_file_url );
free( release_notes_url );
free( upgrade_tool_url );
free( upgrade_tool_sig_url );
}
UpgradeWizard::UpgradeWizard(QWidget* parent, const char* name, bool modal, WFlags fl)
: UpgradeWizardDlg(parent,name, modal,fl)
{
err_dlg = NULL;
for(int i=0; i<pageCount(); i++) {
QWidget* p = page( i );
setHelpEnabled( p, false );
}
QWidget *p = page( pageCount()-1 );
setBackEnabled( p, false );
textLabel3->hide();
p = page( pageCount()-2 );
setNextEnabled( p, false );
QPushButton *fin = finishButton();
connect(fin, SIGNAL( clicked() ), this, SLOT( launchDistUpdater() ) );
}
UpgradeWizard::~UpgradeWizard()
{}
// ** FUNCTIONS ** //
void UpgradeWizard::removeDirectory(QString directoryName)
{
// recursively delete a directory structure
// Mar-22-2007 Billy Pollifrone
QDir dir(directoryName);
QStringList files(dir.entryList());
for (QStringList::Iterator i=files.begin(); i!=files.end(); i++) {
QString fileName(*(i));
if (fileName == QString(".") || fileName == QString("..")) continue;
QFileInfo fileInfo(directoryName, fileName);
if (fileInfo.isDir()) {
removeDirectory(fileInfo.absFilePath());
} else {
QFile file(fileInfo.absFilePath());
file.remove();
}
}
dir.rmdir(directoryName);
}
void UpgradeWizard::removeOldUpgradeTool()
{
// remove old files from dist-upgrade when we check if there is a knew one since
// adept kills us before we have a chance on the same run.
// Mar-22-2007 Billy Pollifrone
QString directoryName("/tmp/kde-root");
QString directoryFilter("adept_*.tmp*");
QDir dir(directoryName, directoryFilter);
QStringList files(dir.entryList());
for (QStringList::Iterator i=files.begin(); i!=files.end(); i++) {
QString fileName(*(i));
QFileInfo fileInfo(directoryName, fileName);
if (fileInfo.isDir()) {
removeDirectory(fileInfo.absFilePath());
} else {
QFile file(fileInfo.absFilePath());
file.remove();
}
}
}
bool UpgradeWizard::checkForDistUpgrade(QString url, bool developmentVersion) {
removeOldUpgradeTool();
std::cout << "UpgradeWizard::checkForDistUpgrade" << std::endl;
if (url == QString("")) {
url = QString("http://changelogs.ubuntu.com/meta-release");
}
bool upgrade_available = false;
KConfig* config = KGlobal::config();
config->setGroup("General Settings");
QString upgradeURL;
upgradeURL = config->readEntry(QString("upgradeURL"), url);
KURL metafile_url( upgradeURL );
QString temp_file_location;
if( KIO::NetAccess::download( metafile_url, temp_file_location, NULL ) ) {
QFile temp_file( temp_file_location );
temp_file.open( IO_ReadOnly );
QTextIStream *temp_file_stream = new QTextIStream( temp_file.readAll() );
// need to spawn a process to call lsb_release -c -s
// to find out which version of kubuntu we are using
KProcess *proc = new KProcess;
*proc << "lsb_release";
*proc << "-c" << "-s";
connect(proc, SIGNAL( receivedStdout( KProcess*, char *, int ) ),
this, SLOT( receiveDistroName( KProcess*, char *, int ) ) );
proc->start( KProcess::Block, KProcess::Stdout );
current_dist = 0;
QPtrList<DistroEntry> *entry_list = parseMetafile( temp_file_stream, distro_name );
upgrade_dist = entry_list->last();
DistroEntry* entry;
// if current_dist hasn't been set in parseMetafile then we can't upgrade, since we don't know what we are
if (current_dist == 0) {
return false;
}
// find the distro version one newer than our current one
for( entry = entry_list->first(); entry; entry = entry_list->next() ) {
//std::cout << "current date: " << (*current_dist->date_field).toString().latin1() << std::endl;
//std::cout << "entry date: " << (*entry->date_field).toString().latin1() << std::endl;
if( *entry->date_field > *current_dist->date_field /*&& entry->supported_field == true*/ ) {
upgrade_dist = entry;
upgrade_available = true;
//std::cout << "entry date: " << (*entry->name_field).latin1() << std::endl;
break;
}
}
// if there isn't one newer, find the current one
if (!upgrade_available) {
for( entry = entry_list->first(); entry; entry = entry_list->next() ) {
//std::cout << "current date: " << (*current_dist->date_field).toString().latin1() << std::endl;
//std::cout << "entry date: " << (*entry->date_field).toString().latin1() << std::endl;
if( *entry->date_field >= *current_dist->date_field && developmentVersion /*&& entry->supported_field == true*/ ) {
upgrade_dist = entry;
upgrade_available = true;
//std::cout << "entry date: " << (*entry->name_field).latin1() << std::endl;
break;
}
}
}
// DistroEntry *entry = NULL;
/*Debugging
for( entry = entry_list->first(); entry; entry = entry_list->next() ) {
std::cout << "current date: " << (*current_dist->date_field).toString().latin1() << std::endl;
std::cout << "entry date: " << (*entry->date_field).toString().latin1() << std::endl;
std::cout << "Dist: " << *entry->dist_field->latin1() << std::endl;
std::cout << "Name: " << *entry->name_field->latin1() << std::endl;
std::cout << "Version: " << *entry->version_field->latin1() << std::endl;
std::cout << "Date: " << entry->date_field->toString( QString( "ddd, dd MMM yyyy hh:mm:ss UTC" ) ).latin1() << std::endl;
//std::cout << "Supported: " << entry->supported_field.latin1() << std::endl;
std::cout << "Description: " << *entry->desc_field->latin1() << std::endl;
std::cout << "Release-File: " << entry->release_file_url->prettyURL().latin1() << std::endl;
if( entry->release_notes_url != NULL ) {
std::cout << "ReleaseNotes: " << entry->release_notes_url->prettyURL().latin1() << std::endl;
}
if( entry->upgrade_tool_url != NULL ) {
std::cout << "UpgradeTool: " << entry->upgrade_tool_url->prettyURL().latin1() << std::endl;
}
if( entry->upgrade_tool_sig_url != NULL ) {
std::cout << "UpgradeToolSignature: " << entry->upgrade_tool_sig_url->prettyURL().latin1() << std::endl;
}
std::cout << std::endl;
}
*/
temp_file.close();
KIO::NetAccess::removeTempFile( temp_file_location );
}
return upgrade_available;
}
QPtrList<DistroEntry> *UpgradeWizard::parseMetafile( QTextIStream *text_stream,
QString my_distro_name )
{
QPtrList<DistroEntry> *metafile_entries = new QPtrList<DistroEntry>();
DistroEntry *entry = NULL;
while( !text_stream->atEnd() ) {
QStringList line = QStringList::split( QChar(':'), text_stream->readLine() );
if( !line.isEmpty() ) {
QString first = line.first();
if( QString::compare( first, QString( "Dist" ) ) == 0 ) {
// we've encountered a new entry:
// first save the old one
if( entry != NULL ) {
// if this entry is for the current version we are running,
// then add it at the start of the list
if( QString::compare( *entry->dist_field, my_distro_name ) == 0) {
current_dist = entry;
metafile_entries->prepend( entry );
} else {
metafile_entries->append( entry );
}
}
// now create a new entry
line.pop_front();
entry = new DistroEntry( new QString( line.first().stripWhiteSpace() ) );
}
else if( QString::compare( first, QString( "Name" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
entry->name_field = new QString( line.first().stripWhiteSpace() );
}
}
else if( QString::compare( first, QString( "Version" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
entry->version_field = new QString( line.first().stripWhiteSpace() );
}
}
else if( QString::compare( first, QString( "Date" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
QString temp = line.join( QChar(' ') ).stripWhiteSpace();
// get the day(verbal)
line = QStringList::split( QChar(' '), temp );
QString day_verbal = line.first();
day_verbal.truncate(3);
// get the date
line.pop_front();
QString date = line.first();
// get the month(verbal)
line.pop_front();
QString month_verbal = line.first();
// get the year
line.pop_front();
QString year = line.first();
// get the time
line.pop_front();
QString time = line.first() + ":";
line.pop_front();
time += line.first() + ":";
line.pop_front();
time += line.first();
QDate the_date( QDate::fromString( day_verbal + " " + month_verbal + " " + date + " " + year) );
QTime the_time( QTime::fromString( time ) );
entry->date_field = new QDateTime( the_date, the_time );
}
}
else if( QString::compare( first, QString( "Supported" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
entry->supported_field = line.first().stripWhiteSpace().toInt();
}
}
else if( QString::compare( first, QString( "Description" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
entry->desc_field = new QString( line.first().stripWhiteSpace() );
}
}
else if( QString::compare( first, QString( "Release-File" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
QString http_part = line.first().stripWhiteSpace() + ":";
line.pop_front();
QString complete_url = http_part + line.first().stripWhiteSpace();
entry->release_file_url = new KURL( complete_url );
}
}
else if( QString::compare( first, QString( "ReleaseNotes" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
QString http_part = line.first().stripWhiteSpace() + ":";
line.pop_front();
QString complete_url = http_part + line.first().stripWhiteSpace();
entry->release_notes_url = new KURL( complete_url );
}
}
else if( QString::compare( first, QString( "UpgradeTool" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
QString http_part = line.first().stripWhiteSpace() + ":";
line.pop_front();
QString complete_url = http_part + line.first().stripWhiteSpace();
entry->upgrade_tool_url = new KURL( complete_url );
}
}
else if( QString::compare( first, QString( "UpgradeToolSignature" ) ) == 0 ) {
if( entry != NULL ) {
line.pop_front();
QString http_part = line.first().stripWhiteSpace() + ":";
line.pop_front();
QString complete_url = http_part + line.first().stripWhiteSpace();
entry->upgrade_tool_sig_url = new KURL( complete_url );
}
}
}
}
// add the last one
// if this entry is for the current version we are running,
// then add it at the start of the list
if( QString::compare( *entry->dist_field, my_distro_name ) == 0 ) {
current_dist = entry;
metafile_entries->prepend( entry );
} else {
metafile_entries->append( entry );
}
return metafile_entries;
}
// ** SLOTS ** //
void UpgradeWizard::receiveDistroName( KProcess*, char *buffer, int buflen ) {
distro_name = QString::fromAscii( buffer, buflen-1 );
}
void UpgradeWizard::launchDistUpdater() {
QDir dir;
dir.mkdir(upgrade_tool_location+"-extract");
KTar tarFile(upgrade_tool_location, QString("application/x-gzip"));
tarFile.open(IO_ReadOnly);
//KArchiveDirectory* tarDirectory = tarFile.directory();
//tarDirectory->copyTo(upgrade_tool_location+"-extract");
tarFile.directory()->copyTo(upgrade_tool_location+"-extract", true);
KProcess *proc = new KProcess;
proc->setWorkingDirectory(upgrade_tool_location+"-extract");
*proc << "python" << upgrade_tool_location+"-extract/dist-upgrade.py";
*proc << "--frontend" << "DistUpgradeViewKDE";
proc->start( KProcess::DontCare );
// don't kill adept, it stops the app from running
// parentWidget()->close();
}
void UpgradeWizard::fetchReleaseAnnounce() {
QString temp_file_location;
bool result = false;
if (upgrade_dist->release_notes_url == NULL) {
kdDebug() << "No release notes URL, so I'm skipping the fetch." << endl;
} else {
KURL my_url(*upgrade_dist->release_notes_url);
result = KIO::NetAccess::download(my_url, temp_file_location, NULL );
}
if( result ) {
emit killErrorDialog();
err_dlg = NULL;
textBrowser1->mimeSourceFactory()->setExtensionType( QString("tmp"), "text/plain" );
textBrowser1->setSource( temp_file_location );
QWidget *p = page( pageCount()-2 );
setNextEnabled( p, true );
} else {
if(err_dlg == NULL ) {
err_dlg = new ErrorDialog( this, i18n( "Could not download the release announcement. Please check that your Internet connection is active." ), 0, 1 );
connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( fetchReleaseAnnounce() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) );
connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) );
err_dlg->show();
}
}
}
void UpgradeWizard::fetchUpgradeTool() {
// download the upgrade tool
KURL my_url(*upgrade_dist->upgrade_tool_url);
bool result = KIO::NetAccess::download( my_url, upgrade_tool_location, NULL );
// uncomment this to use for testing if you don't want to d/l the file every time
//bool result = KIO::NetAccess::download( "/home/vladi/edgy.tar.gz", upgrade_tool_location, NULL );
if( result ) {
emit killErrorDialog();
err_dlg = NULL;
fetchUpgradeToolSig();
} else {
if(err_dlg == NULL ) {
err_dlg = new ErrorDialog( this, i18n( "Could not download the upgrade tool. Please check that your Internet connection is active." ), 0, 1 );
connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( fetchUpgradeTool() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) );
connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) );
err_dlg->show();
}
}
}
void UpgradeWizard::fetchUpgradeToolSig() {
bool result = KIO::NetAccess::download( *upgrade_dist->upgrade_tool_sig_url, upgrade_tool_sig_location, NULL );
if( result) {
emit killErrorDialog();
err_dlg = NULL;
verifyUpgradeTool();
} else {
if(err_dlg == NULL ) {
err_dlg = new ErrorDialog( this, i18n( "Could not download the upgrade tool's GPG signature. Please check that your Internet connection is active." ), 0, 1 );
connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( fetchUpgradeToolSig() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) );
connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) );
err_dlg->show();
}
}
}
void UpgradeWizard::verifyUpgradeTool() {
// spawn a process to call gpg and verify the signature
KProcess *proc = new KProcess;
*proc << "gpg";
*proc << "--keyring" << "/etc/apt/trusted.gpg" << "--verify" << upgrade_tool_sig_location << upgrade_tool_location;
proc->start( KProcess::Block, KProcess::Stdout );
// signature verification successful if gpg exist status = 0
if( proc->exitStatus() == 0 ) {
emit killErrorDialog();
err_dlg = NULL;
// remove the signature file
KIO::file_delete( KURL( upgrade_tool_sig_location ), false );
QWidget *p = page( pageCount()-1 );
setFinishEnabled( p, true );
textLabel3->show();
} else {
if(err_dlg == NULL ) {
err_dlg = new ErrorDialog( this, i18n( "Could not verify the integrity of the upgrader application. This program will now exit." ), 0, 1 );
//connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( verify_upgrade_tool() ) );
err_dlg->retryButton->setEnabled( false );
connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) );
connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) );
connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) );
err_dlg->show();
}
}
}
void UpgradeWizard::back()
{
QWizard::back();
}
void UpgradeWizard::next()
{
QWizard::next();
// page 1: d/l release announcement
// and display it on page1
if( indexOf( currentPage() ) == 1 ) {
fetchReleaseAnnounce();
}
else if( indexOf( currentPage() ) == 2 ) {
// remove the temp file used to store the release announcement
KIO::file_delete( KURL( textBrowser1->source() ), false );
// download the tool, its signature, and verify
fetchUpgradeTool();
}
}
#include "upgradewizard.moc"