diff options
author | Tim Jenssen <tim.jenssen@nokia.com> | 2011-02-21 16:30:31 +0100 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@nokia.com> | 2011-02-21 16:41:32 +0100 |
commit | 8457830abdca9d5769e2ec1bdbfb793a05e6c5dd (patch) | |
tree | 4c9e87efd34104ec59ae31efd0394e998a2434f7 /installerbuilder/libinstaller/kdtools |
init commit
Diffstat (limited to 'installerbuilder/libinstaller/kdtools')
112 files changed, 17298 insertions, 0 deletions
diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDAutoPointer b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDAutoPointer new file mode 100644 index 000000000..5203ea2db --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDAutoPointer @@ -0,0 +1 @@ +#include "kdautopointer.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDByteSize b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDByteSize new file mode 100644 index 000000000..e0ee65f30 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDByteSize @@ -0,0 +1 @@ +#include "kdbytesize.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDGenericFactory b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDGenericFactory new file mode 100644 index 000000000..42f06640a --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDGenericFactory @@ -0,0 +1 @@ +#include "kdgenericfactory.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDJob b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDJob new file mode 100644 index 000000000..79fd1dde9 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDJob @@ -0,0 +1 @@ +#include "kdjob.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDLockfile b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDLockfile new file mode 100644 index 000000000..afd9f7ad1 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDLockfile @@ -0,0 +1 @@ +#include "kdlockfile.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDMetaMethodIterator b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDMetaMethodIterator new file mode 100644 index 000000000..cfb58d054 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDMetaMethodIterator @@ -0,0 +1 @@ +#include "kdmetamethoditerator.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDRunOnceChecker b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDRunOnceChecker new file mode 100644 index 000000000..d5ccad881 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDRunOnceChecker @@ -0,0 +1 @@ +#include "kdrunoncechecker.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSaveFile b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSaveFile new file mode 100644 index 000000000..f7df3f1b5 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSaveFile @@ -0,0 +1 @@ +#include "kdsavefile.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSelfRestarter b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSelfRestarter new file mode 100644 index 000000000..7de1c2779 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSelfRestarter @@ -0,0 +1 @@ +#include "kdselfrestarter.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSysInfo b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSysInfo new file mode 100644 index 000000000..7d5cec1e4 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDSysInfo @@ -0,0 +1 @@ +#include "kdsysinfo.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDToolsCore.pri b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDToolsCore.pri new file mode 100644 index 000000000..213c8343d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDToolsCore.pri @@ -0,0 +1,42 @@ +DEPENDPATH += $$PWD +INCLUDEPATH += $$PWD + +CONFIG( shared, static|shared) { + DEFINES += BUILD_SHARED_KDTOOLSCORE +} + +HEADERS += $$PWD/pimpl_ptr.h \ + $$PWD/kdtoolsglobal.h \ + $$PWD/kdbytesize.h \ + $$PWD/kdjob.h \ + $$PWD/kdwatchdog.h \ + $$PWD/kdgenericfactory.h \ + $$PWD/kdautopointer.h \ + $$PWD/kdselfrestarter.h \ + $$PWD/kdsavefile.h \ + $$PWD/kdmetamethoditerator.h \ + $$PWD/kdrunoncechecker.h \ + $$PWD/kdlockfile.h \ + $$PWD/kdsysinfo.h \ + $$PWD/kdversion.h + +SOURCES += $$PWD/pimpl_ptr.cpp \ + $$PWD/kdtoolsglobal.cpp \ + $$PWD/kdbytesize.cpp \ + $$PWD/kdjob.cpp \ + $$PWD/kdwatchdog.cpp \ + $$PWD/kdgenericfactory.cpp \ + $$PWD/kdautopointer.cpp \ + $$PWD/kdselfrestarter.cpp \ + $$PWD/kdsavefile.cpp \ + $$PWD/kdmetamethoditerator.cpp \ + $$PWD/kdrunoncechecker.cpp \ + $$PWD/kdlockfile.cpp \ + $$PWD/kdsysinfo.cpp \ + $$PWD/kdversion.cpp + +unix:SOURCES += $$PWD/kdlockfile_unix.cpp +win32:SOURCES += $$PWD/kdlockfile_win.cpp +win32:SOURCES += $$PWD/kdsysinfo_win.cpp +macx:SOURCES += $$PWD/kdsysinfo_mac.cpp +unix:!macx:SOURCES += $$PWD/kdsysinfo_x11.cpp diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/KDWatchdog b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDWatchdog new file mode 100644 index 000000000..3032c2a37 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/KDWatchdog @@ -0,0 +1 @@ +#include "kdwatchdog.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdautopointer.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdautopointer.cpp new file mode 100644 index 000000000..3398ac8b8 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdautopointer.cpp @@ -0,0 +1,577 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdautopointer.h" + +/*! + \class KDAutoPointer + \ingroup core smartptr + \brief Owning version of QPointer + \since_c 2.1 + + (The exception safety of this class has not been evaluated yet.) + + KDAutoPointer is a fusion of std::auto_ptr and QPointer, ie. it owns the + contained object, but if that object is otherwise deleted, it sets + itself to null, just like QPointer does. + + Like std::auto_ptr, ownership is never shared between instances of + KDAutoPointer. Copying and copy assignment \em transfer ownership, + ie. in the following code + + \code + KDAutoPointer<MyDialog> myDialog( new MyDialog ); + KDAutoPointer<QObject> monitor( myDialog ); // Probably WRONG! + \endcode + + \c monitor will end up owning the \c MyDialog instance, and \c + myDialog will be NULL, which is probably not what the programmer + intended. + + Like QPointer, KDAutoPointer can only hold objects of a class derived + from QObject. If you need this functionality for arbitrary types, + consider using std::tr1::shared_ptr together with + std::tr1::weak_ptr. + + \section overview Overview + + You construct a KDAutoPointer by passing a pointer to the object to be + owned in \link KDAutoPointer(T*) the constructor\endlink, or, after the + fact, by calling reset(). Neither of these operations happen + implicitly, since they entail a change of ownership that should be + visible in code. + + For the same reason, if you need to get a pointer to the contained + (owned) object, the conversion is not implicit, either. You have to + explicitly call get() (if you want to leave ownership to the + KDAutoPointer) or release() (if you want to transfer ownership out of + KDAutoPointer). + + Use \link swap(KDAutoPointer&,KDAutoPointer&) swap()\endlink to quickly + exchange the contents of two \link KDAutoPointer KDAutoPointers\endlink, and + operator unspecified_bool_type() to test whether KDAutoPointer (still) + contains an object: + + \code + KDAutoPointer w1( new QWidget ), w2(); + assert( w1 ); assert( !w2 ); + swap( w1, s2 ); + assert( !w1 ); assert( w2 ); + \endcode + + \section general-use General Use + + The general use case of KDAutoPointer is that of holding objects that + have unclear ownership semantics. E.g. classes that implement the + Command Pattern are sometimes implemented as deleting themselves + after the command finished. By holding instances of such classes in + KDAutoPointers, you do not have to care about whether or now the object + deletes itself. If it deletes itself, then KDAutoPointer will set itself + to NULL, if not, KDAutoPointer will delete the object when it goes out + of scope. + + \section child-creation Esp.: Child Creation + + You can also use KDAutoPointer for temporarily storing \link QObject + QObjects\endlink for exception safety. This is esp. useful when + following the Trolltech-recommended style of dialog creation (create + parent-less children up-front, add to layouts later): + + \code + QLabel * lb = new QLabel( tr("Name:" ); + QLineEdit * le = new QLineEdit; + + QHBoxLayout * hbox = new QHBoxLayout; + hbox->addWidget( lb ); + hbox->addWidget( le ); + // if somethings throws an exception here, + // all of the above will be leaked + setLayout( hbox ); + \endcode + + Rewriting this as (granted, cumbersome): + \code + KDAutoPointer<QLabel> lb( new QLabel( tr("Name:" ); + KDAutoPointer<QLineEdit> le( new QLineEdit ); + + KDAutoPointer<QHBoxLayout> hbox( new QHBoxLayout ); + hbox->addWidget( lb.get() ); + hbox->addWidget( le.get() ); + // if somethings throws an exception here, + // all of the above will be properly cleaned up + setLayout( hbox.release() ); + lb.release(); + le.release(); + \endcode + takes care of the leak. + + Since this is so cumbersome, you should instead always pass parents + to children as part of construction. + + \section model-dialogs Esp.: Modal Dialogs + + A more specific use case is (modal) dialogs. + + Traditionally, most programmers allocate these on the stack: + + \code + MyDialog dialog( parent ); + // set up 'dialog'... + if ( !dialog.exec() ) + return; + // extract information from 'dialog'... + return; + \endcode + + This is usually ok. Even though \c dialog has a parent, the parent + will usually live longer than the dialog. The dialog is modal, after + all, so the user is not supposed to be able to quit the application + while that dialog is on screen. + + There are some applications, however, that have other ways to + terminate than explicit user request. Whether the application exits + timer-driven, or by an IPC call, what will happen is that \c dialog + is deleted as a child of \c parent \em and \em then \em again by the + compiler as part of cleaning up the stack once \c exec() returns. + + This is where KDAutoPointer comes in. Instead of allocating modal + dialogs on the stack, allocate them into a KDAutoPointer: + + \code + const KDAutoPointer<MyDialog> dialog( new MyDialog( parent ) ); + // set up 'dialog'... + if ( !dialog->exec() || !dialog ) + return; + // extract information from 'dialog'... + return; + \endcode + + Note the use of \c const to prevent accidental copying of \c dialog, + and the additional check for \c dialog to catch the case where after + exec() returns, the dialog has been deleted. +*/ + +/*! + \typedef KDAutoPointer::element_type + + A typedef for \c T. For STL compatibility. +*/ + +/*! + \typedef KDAutoPointer::value_type + + A typedef for \c T. For STL compatibility. +*/ + +/*! + \typedef KDAutoPointer<T>::pointer + + A typedef for \c T*. For STL compatibility. +*/ + +/*! + \fn KDAutoPointer::KDAutoPointer() + + Default constructor. Constructs a NULL KDAutoPointer. + + \post get() == 0 +*/ + +/*! + \fn KDAutoPointer::KDAutoPointer( T * obj ) + + Constructor. Constructs a KDAutoPointer that contains (owns) \a obj. + + \post get() == obj +*/ + +/*! + \fn KDAutoPointer::KDAutoPointer( KDAutoPointer & other ) + + Move constructor. Constructs a KDAutoPointer that takes over ownership + of the object contained (owned) by \a other. + + \post this->get() == (the object previously owned by 'other') + \post other.get() == 0 +*/ + +/*! + \fn KDAutoPointer::KDAutoPointer( KDAutoPointer<U> & other ) + + \overload +*/ + +/*! + \fn KDAutoPointer & KDAutoPointer::operator=( KDAutoPointer & other ) + + Copy assignment operator. Equivalent to + \code + reset( other.release() ); + \endcode + + \post this->get() == (the object previously owned by 'other') + \post other.get() == 0 + \post The object previously owned by \c *this has been deleted. +*/ + +/*! + \fn KDAutoPointer & KDAutoPointer::operator=( KDAutoPointer<U> & other ) + + \overload +*/ + +/*! + \fn KDAutoPointer::~KDAutoPointer() + + Destructor. + + \post The object previously owned by \c *this has been deleted. +*/ + +/*! + \fn void KDAutoPointer::swap( KDAutoPointer & other ) + + Swaps the contents of \a *this and \a other. You probably want to + use the free function swap(KDAutoPointer&,KDAutoPointer&) instead. Also + qSwap() has been specialized to use this function internally. + + \post get() == (previous value of other.get()) + \post other.get() == (previous value of this->get()) +*/ + +/*! + \fn T * KDAutoPointer::get() const + + \returns a pointer to the contained (owned) object. +*/ + +/*! + \fn T * KDAutoPointer::release() + + Yields ownership of the contained object and returns a pointer to it. + + \post get() == 0 + \post The object previously owned by \c *this had \em not been deleted. +*/ + +/*! + \fn T * KDAutoPointer::data() const + + Equivalent to get(). Provided for consistency with Qt naming + conventions. +*/ + +/*! + \fn T * KDAutoPointer::take() + + Equivalent to release(). Provided for consistency with Qt naming + conventions. +*/ + +/*! + \fn void KDAutoPointer::reset( T * other ) + + Yields ownership of the contained object (if any) and and takes over + ownership of \a other. + + \post get() == other + \post The object previously owned by \c *this has been deleted. +*/ + +/*! + \fn T & KDAutoPointer::operator*() const + + Dereference operator. Returns \link get() *get()\endlink. +*/ + +/*! + \fn T * KDAutoPointer::operator->() const + + Member-by-pointer operator. Returns get(). +*/ + +/*! + \fn bool KDAutoPointer::operator==( const KDAutoPointer<S> & other ) const + + Equal-to operator. Returns get() == other.get(). + + \note Due to the fact that two \link KDAutoPointer KDAutoPointers\endlink + cannot contain the same object, the relational operators are not + very useful. +*/ + +/*! + \fn bool KDAutoPointer::operator!=( const KDAutoPointer<S> & other ) const + + Not-Equal-to operator. Returns get() != other.get(). + + \note Due to the fact that two \link KDAutoPointer KDAutoPointers\endlink + cannot contain the same object, the relational operators are not + very useful. +*/ + +/*! + \fn KDAutoPointer::operator unspecified_bool_type() const + + \returns \c true if \c *this contains an object, otherwise \c false. +*/ + +/*! + \fn void swap( KDAutoPointer<T> & lhs, KDAutoPointer<T> & rhs ) + \relates KDAutoPointer + + Equivalent to + \code + lhs.swap( rhs ); + \endcode + + Provided for generic code that uses the standard swap idiom: + \code + using std::swap; + swap( a, b ); + \endcode + to find through <a href="http://en.wikipedia.org/wiki/Argument_dependent_name_lookup">ADL</a>, + enabling such code to automatically use the more efficient + \link KDAutoPointer::swap() member swap\endlink instead of the default + implementation (which uses a temporary). +*/ + +/*! + \fn void qSwap( KDAutoPointer<T> & lhs, KDAutoPointer<S> & rhs ) + \relates KDAutoPointer + + Equivalent to + \code + swap( lhs, rhs ); + \endcode + except for code using %qSwap() instead of (std::)swap. +*/ + +/*! + \fn bool operator==( const KDAutoPointer<S> & lhs, const T * rhs ) + \relates KDAutoPointer + + Equal-to operator. Equivalent to + \code + lhs.get() == rhs + \endcode +*/ + +/*! + \fn bool operator==( const S * lhs, const KDAutoPointer<T> & rhs ) + \relates KDAutoPointer + \overload +*/ + +/*! + \fn bool operator==( const KDAutoPointer<S> & lhs, const QPointer<T> & rhs ) + \relates KDAutoPointer + \overload +*/ + +/*! + \fn bool operator==( const QPointer<S> & lhs, const KDAutoPointer<T> & rhs ) + \relates KDAutoPointer + \overload +*/ + + +/*! + \fn bool operator!=( const KDAutoPointer<S> & lhs, const T * rhs ) + \relates KDAutoPointer + + Not-equal-to operator. Equivalent to + \code + lhs.get() != rhs + \endcode +*/ + +/*! + \fn bool operator!=( const S * lhs, const KDAutoPointer<T> & rhs ) + \relates KDAutoPointer + \overload +*/ + +/*! + \fn bool operator!=( const KDAutoPointer<S> & lhs, const QPointer<T> & rhs ) + \relates KDAutoPointer + \overload +*/ + +/*! + \fn bool operator!=( const QPointer<S> & lhs, const KDAutoPointer<T> & rhs ) + \relates KDAutoPointer + \overload +*/ + +#ifdef KDTOOLSCORE_UNITTESTS + +#include <KDUnitTest/Test> + +namespace { + + struct A : QObject {}; + struct B : QObject {}; + +} + +KDAB_UNITTEST_SIMPLE( KDAutoPointer, "kdcoretools" ) { + + { + QPointer<QObject> o; + { + const KDAutoPointer<QObject> qobject( new QObject ); + o = qobject.get(); + } + assertNull( o ); + } + + { + // check that conversion to bool works + KDAutoPointer<A> a( new A ); + const bool b1 = a; + assertTrue( b1 ); + const bool b2 = !a; + assertFalse( b2 ); + a.reset(); + const bool b3 = a; + assertFalse( b3 ); + const bool b4 = !a; + assertTrue( b4 ); + } + + { + KDAutoPointer<QObject> o; + assertNull( o.get() ); + assertFalse( o ); + QObject * obj; + o.reset( obj = new QObject ); + assertNotNull( o.get() ); + assertTrue( o ); + assertEqual( o.get(), obj ); + + KDAutoPointer<QObject> o2 = o; + assertNull( o.get() ); + assertNotNull( o2.get() ); + assertEqual( o2.get(), obj ); + + delete obj; + assertNull( o2.get() ); + } + + { + QPointer<QObject> obj = new QObject; + KDAutoPointer<QObject> o( obj ); + o = o; // self-assignment + assertNotNull( obj ); + o.reset( o.get() ); // self-assignment-ish + assertNotNull( obj ); + + o.reset( new QObject ); + assertNull( obj ); + assertNotNull( o.get() ); + } + + { + QPointer<A> ap; + { + KDAutoPointer<A> a( new A ); + ap = a.get(); + KDAutoPointer<QObject> o1( a ); + assertNull( a.get() ); + assertNotNull( o1.get() ); + KDAutoPointer<QObject> o2; + o2 = a; + // doesn't compile (but doesn't compile for std::auto_ptr, + // either, so it's ok, I think + //KDAutoPointer<QObject> o3 = a + } + assertNull( ap ); + } + + { + // test swapping + KDAutoPointer<A> a1( new A ), a2( new A ); + + A * A1 = a1.get(); + A * A2 = a2.get(); + + using std::swap; + swap( a1, a2 ); + + assertNotNull( a1.get() ); + assertNotNull( a2.get() ); + + assertEqual( a1.get(), A2 ); + assertEqual( a2.get(), A1 ); + + qSwap( a1, a2 ); + assertEqual( a1.get(), A1 ); + assertEqual( a2.get(), A2 ); + + } + + { + KDAutoPointer<A> apa( new A ); + QPointer<A> qpa( apa.get() ); + A * pa = apa.get(); + const A * cpa = pa; + + assertEqual( apa.get(), apa.get() ); + assertEqual( apa.get(), qpa ); + assertEqual( apa.get(), pa ); + assertEqual( apa.get(), cpa ); + assertEqual( qpa, apa.get() ); + assertEqual( pa, apa.get() ); + assertEqual( cpa, apa.get() ); + + KDAutoPointer<QObject> apq; cpa = pa = qpa = 0; + + assertNotEqual( apa.get(), qpa ); + assertNotEqual( apa.get(), pa ); + assertNotEqual( apa.get(), cpa ); + assertNotEqual( qpa, apa.get() ); + assertNotEqual( pa, apa.get() ); + assertNotEqual( cpa, apa.get() ); + + assertNotEqual( apq.get(), apa.get() ); + assertNotEqual( apa.get(), apq.get() ); + + assertNotNull( apa.get() ); + + apq.reset( new QObject ); + + assertNotEqual( apa.get(), qpa ); + assertNotEqual( apa.get(), pa ); + assertNotEqual( apa.get(), cpa ); + assertNotEqual( qpa, apa.get() ); + assertNotEqual( pa, apa.get() ); + assertNotEqual( cpa, apa.get() ); + + assertNotEqual( apq.get(), apa.get() ); + assertNotEqual( apa.get(), apq.get() ); + + assertNotNull( apa.get() ); + } +} + +#endif // KDTOOLSCORE_UNITTESTS diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdautopointer.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdautopointer.h new file mode 100644 index 000000000..7a0558db0 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdautopointer.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_CORE_KDAUTOPOINTER_H__ +#define __KDTOOLS_CORE_KDAUTOPOINTER_H__ + +#include <KDToolsCore/kdtoolsglobal.h> + +#include <QtCore/QPointer> +#include <QtCore/QObject> + +class KDAutoPointerBase { +protected: + QPointer<QObject> o; + + KDAutoPointerBase() : o() {} + explicit KDAutoPointerBase( QObject * obj ) : o( obj ) {} + KDAutoPointerBase( KDAutoPointerBase & other ) : o( other.release() ) {} + ~KDAutoPointerBase() { delete o; } + + void swap( KDAutoPointerBase & other ) { + const QPointer<QObject> copy( o ); + o = other.o; + other.o = copy; + } + + QObject * release() { QObject * copy = o; o = 0 ; return copy; } + void reset( QObject * other ) { if ( o != other ) { delete o; o = other; } } + + KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( o ); +}; + +template <typename T> +class MAKEINCLUDES_EXPORT KDAutoPointer : KDAutoPointerBase { +public: + friend inline void swap( KDAutoPointer & lhs, KDAutoPointer & rhs ) { lhs.swap( rhs ); } + + typedef T element_type; + typedef T value_type; + typedef T * pointer; + + KDAutoPointer() : KDAutoPointerBase() {} + explicit KDAutoPointer( T * obj ) : KDAutoPointerBase( obj ) {} + KDAutoPointer( KDAutoPointer & other ) : KDAutoPointerBase( other.release() ) {} + template <typename U> + KDAutoPointer( KDAutoPointer<U> & other ) : KDAutoPointerBase( other.release() ) { T * t = other.get(); ( void )t; } + + KDAutoPointer & operator=( KDAutoPointer & other ) { + this->reset( other.release() ); + return *this; + } + + template <typename U> + KDAutoPointer & operator=( KDAutoPointer<U> & other ) { + this->reset( other.release() ); + return *this; + } + + ~KDAutoPointer() {} + + void swap( KDAutoPointer & other ) { + KDAutoPointerBase::swap( other ); + } + + T * get() const { QObject * obj = o; return static_cast<T*>( obj ); } + T * release() { return static_cast<T*>( KDAutoPointerBase::release() ); } + + T * data() const { return get(); } + T * take() { return release(); } + + void reset( T * other=0 ) { KDAutoPointerBase::reset( other ); } + + T & operator*() const { return *get(); } + T * operator->() const { return get(); } + + template <typename S> + bool operator==( const KDAutoPointer<S> & other ) const { + return get() == other.get(); + } + template <typename S> + bool operator!=( const KDAutoPointer<S> & other ) const { + return get() != other.get(); + } + + KDAB_USING_SAFE_BOOL_OPERATOR( KDAutoPointerBase ) +}; + +template <typename T> +inline void swap( KDAutoPointer<T> & lhs, KDAutoPointer<T> & rhs ) { lhs.swap( rhs ); } +template <typename T> +inline void qSwap( KDAutoPointer<T> & lhs, KDAutoPointer<T> & rhs ) { lhs.swap( rhs ); } + +template <typename S, typename T> +inline bool operator==( const KDAutoPointer<S> & lhs, const T * rhs ) { + return lhs.get() == rhs; +} +template <typename S, typename T> +inline bool operator==( const S * lhs, const KDAutoPointer<T> & rhs ) { + return lhs == rhs.get(); +} +template <typename S, typename T> +inline bool operator==( const KDAutoPointer<S> & lhs, const QPointer<T> & rhs ) { + return lhs.get() == rhs; +} +template <typename S, typename T> +inline bool operator==( const QPointer<S> & lhs, const KDAutoPointer<T> & rhs ) { + return lhs == rhs.get(); +} + +template <typename S, typename T> +inline bool operator!=( const KDAutoPointer<S> & lhs, const T * rhs ) { + return !operator==( lhs, rhs ); +} +template <typename S, typename T> +inline bool operator!=( const S * lhs, const KDAutoPointer<T> & rhs ) { + return !operator==( lhs, rhs ); +} +template <typename S, typename T> +inline bool operator!=( const KDAutoPointer<S> & lhs, const QPointer<T> & rhs ) { + return !operator==( lhs, rhs ); +} +template <typename S, typename T> +inline bool operator!=( const QPointer<S> & lhs, const KDAutoPointer<T> & rhs ) { + return !operator==( lhs, rhs ); +} + + +#endif /* __KDTOOLS_CORE_KDAUTOPOINTER_H__ */ diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.cpp new file mode 100644 index 000000000..0cf06f233 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ +#include "kdbytesize.h" + +#include <QStringList> +#include <QTextStream> + +KDByteSize::KDByteSize( quint64 size ) + : m_size( size ) +{ +} + +KDByteSize::~KDByteSize() +{ +} + +KDByteSize::operator quint64() const +{ + return m_size; +} + +quint64 KDByteSize::size() const +{ + return m_size; +} + +QString KDByteSize::toString() const +{ + static const QStringList units = QStringList() << QObject::tr( "B" ) + << QObject::tr( "kB" ) + << QObject::tr( "MB" ) + << QObject::tr( "GB" ) + << QObject::tr( "TB" ); + + double s = m_size; + quint64 factor = 1; + int unit = 0; + while( s >= 1024.0 && unit + 1 < units.count() ) + { + ++unit; + factor *= 1024; + s = 1.0 * m_size / factor; + } + + // only one digit after the decimal point is wanted + s = qRound( s * 10 ) / 10.0; + + return QString::fromLatin1( "%L1 %2" ).arg( s, 0, 'g', 4 ).arg( units[ unit ] ); +} + +bool operator==( const KDByteSize& lhs, const KDByteSize& rhs ) +{ + return lhs.size() == rhs.size(); +} + +bool operator<( const KDByteSize& lhs, const KDByteSize& rhs ) +{ + return lhs.size() < rhs.size(); +} + +KDByteSize operator*( const KDByteSize& lhs, int rhs ) +{ + return KDByteSize( lhs.size() * rhs ); +} + +#include <QDebug> + +QDebug operator<<( QDebug dbg, const KDByteSize& size ) +{ + return dbg << "KDByteSize(" << size.size() << ")"; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h new file mode 100644 index 000000000..cc8f5a770 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ +#ifndef KDBYTESIZE_H +#define KDBYTESIZE_H + +#include <KDToolsCore/kdtoolsglobal.h> + +class KDTOOLSCORE_EXPORT KDByteSize +{ +public: + explicit KDByteSize( quint64 size = 0 ); + virtual ~KDByteSize(); + + operator quint64() const; + quint64 size() const; + + QString toString() const; + +private: + quint64 m_size; +}; + +KDTOOLSCORE_EXPORT bool operator==( const KDByteSize& lhs, const KDByteSize& rhs ); +KDTOOLSCORE_EXPORT bool operator<( const KDByteSize& lhs, const KDByteSize& rhs ); +KDTOOLSCORE_EXPORT KDByteSize operator*( const KDByteSize& lhs, int rhs ); + +KDTOOLS_MAKE_RELATION_OPERATORS( KDByteSize, static inline ) + +class QDebug; +KDTOOLSCORE_EXPORT QDebug operator<<( QDebug dbg, const KDByteSize& size ); + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdgenericfactory.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdgenericfactory.cpp new file mode 100644 index 000000000..9352f83cd --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdgenericfactory.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdgenericfactory.h" + +/*! + \class KDGenericFactory + \ingroup core + \brief Template based generic factory implementation + \since_c 2.1 + + (The exception safety of this class has not been evaluated yet.) + + KDGenericFactory is an implemention of of the factory pattern. It can be used to + "produce" instances of different classes having a common superclass + T_Product. The user of the + factory registers those producable classes in the factory by using an identifier + (T_Identifier, defaulting to QString). That identifer can then be used to + produce as many instances of the registered product as he wants. + + The advanced user can even choose the type of the map the factory is using to store its + FactoryFunctions by passing a T_Map template parameter. It defaults to QHash. KDGenericFactory + expects it to be a template class accepting T_Identifier and FactoryFunction as parameters. + Additionally it needs to provide: + + \li\link QHash::const_iterator a nested %const_iterator \endlink typedef for an iterator type that when dereferenced has type ((const) reference to) FactoryFunction (Qt convention), + \li\link QHash::insert %insert( T_Identifier, FactoryFunction ) \endlink, which must overwrite any existing entries with the same identifier. + \li\link QHash::find %find( T_Identifier ) \endlink, + \li\link QHash::end %end() \endlink, + \li\link QHash::size %size() \endlink, + \li\link QHash::remove %remove( T_Identifier ) \endlink, and + \li\link QHash::keys %keys ) \endlink, returning a QList<T_Identifier>. + + The only two class templates that currently match this concept are + QHash and QMap. QMultiHash and QMulitMap do not work, since they + violate the requirement on insert() above, and std::map and + std::unordered_map do not match because they don't have keys() and + because a dereferenced iterator has type + std::pair<const T_Identifier,FactoryFunction> + instead of just FactoryFunction. + + \section general-use General Use + + The following example shows how the general use case of KDGenericFactory looks like: + + \code + + class Fruit + { + }; + + class Apple : public Fruit + { + }; + + class Pear : public Fruit + { + }; + + int main() + { + // creates a common fruit "factory" + KDGenericFactory< Fruit > fruitPlantation; + // registers the product "Apple" + fruitPlantation.registerProduct< Apple >( "Apple" ); + // registers the product "Pear" + fruitPlantation.registerProduct< Pear >( "Pear" ); + + // lets create some stuff - here comes our tasty apple: + Fruit* myApple = fruitPlantation.create( "Apple" ); + + // and a pear, please: + Fruit* myPear = fruitPlantation.create( "Pear" ); + + // ohh - that doesn't work, returns a null pointer: + Fruit* myCherry = fruitPlantation.create( "Cherry" ); + } + + \endcode +*/ + +/*! + \fn KDGenericFactory::~KDGenericFactory + + Destructor. +*/ + +/*! + \typedef KDGenericFactory::FactoryFunction + + This typedef defines a factory function producing an object of type T_Product. +*/ + +/*! + \fn KDGenericFactory::registerProduct( const T_Identifier& name ) + + Registers a product of type T, identified by \a name in the factory. + Any type with the same name gets unregistered. + + If a product was registered via this method, it will be created using its + default constructor. +*/ + +/*! + \fn KDGenericFactory::unregisterProduct( const T_Identifier& name ) + + Unregisters the previously registered product identified by \a name from the factory. + If no such product is known, nothing is done. +*/ + +/*! + \fn KDGenericFactory::productCount() const + + Returns the number of different products known to the factory. +*/ + +/*! + \fn KDGenericFactory::availableProducts() const + + Returns the list of products known to the factory. +*/ + +/*! + \fn KDGenericFactory::create( const T_Identifier& name ) const + + Creates and returns a product of the type identified by \a name. + Ownership of the product is transferred to the caller. +*/ + +/*! + \fn KDGenericFactory::registerProductionFunction( const T_Identifier& name, FactoryFunction create ) + + Subclasses can use this method to register their own FactoryFunction \a create to create products of + type T, identified by \a name. When a product is registered via this method, it will be created + by calling create(). +*/ + +#ifdef KDTOOLSCORE_UNITTESTS + +#include <KDUnitTest/test.h> + +#include <QStringList> +#include <QMap> + +class Fruit +{ +public: + virtual ~Fruit() {} +}; + +class Apple : public Fruit +{ +}; + +class Pear : public Fruit +{ +}; + +std::ostream& operator<<( std::ostream& stream, const QStringList& list ) +{ + stream << "QStringList("; + for( QStringList::const_iterator it = list.begin(); it != list.end(); ++it ) + { + stream << " " << it->toLocal8Bit().data(); + if( it + 1 != list.end() ) + stream << ","; + } + stream << " )"; + return stream; +} + +class KDGenericFactoryTest : public KDUnitTest::Test { +public: + KDGenericFactoryTest() : Test( "KDGenericFactory" ) {} + void run() { + doRun<QHash>(); + doRun<QMap>(); + } + + template <template <typename U, typename V> class T_Map> + void doRun(); +}; + +KDAB_EXPORT_UNITTEST( KDGenericFactoryTest, "kdcoretools" ) + +template <template <typename U, typename V> class T_Map> +void KDGenericFactoryTest::doRun() { + + { + KDGenericFactory< Fruit, QString, T_Map > fruitPlantation; + assertEqual( fruitPlantation.productCount(), 0U ); + assertEqual( fruitPlantation.availableProducts(), QStringList() ); + + fruitPlantation.template registerProduct< Apple >( QLatin1String( "Apple" ) ); + assertEqual( fruitPlantation.productCount(), 1U ); + assertEqual( fruitPlantation.availableProducts(), QStringList( QLatin1String( "Apple" ) ) ); + + fruitPlantation.template registerProduct< Pear >( QLatin1String( "Pear" ) ); + assertEqual( fruitPlantation.productCount(), 2U ); + + Fruit* fruit = 0; + fruit = fruitPlantation.create( QLatin1String( "Apple" ) ); + assertNotNull( fruit ); + assertNotNull( dynamic_cast< Apple* >( fruit ) ); + + fruit = fruitPlantation.create( QLatin1String( "Pear" ) ); + assertNotNull( fruit ); + assertNotNull( dynamic_cast< Pear* >( fruit ) ); + + fruit = fruitPlantation.create( QLatin1String( "Cherry" ) ); + assertNull( fruit ); + + fruitPlantation.unregisterProduct( QLatin1String( "Apple" ) ); + assertEqual( fruitPlantation.productCount(), 1U ); + assertEqual( fruitPlantation.availableProducts(), QStringList( QLatin1String( "Pear" ) ) ); + fruit = fruitPlantation.create( QLatin1String( "Apple" ) ); + assertNull( fruit ); + + fruit = fruitPlantation.create( QLatin1String( "Pear" ) ); + assertNotNull( fruit ); + assertNotNull( dynamic_cast< Pear* >( fruit ) ); + + + fruitPlantation.unregisterProduct( QLatin1String( "Pear" ) ); + assertEqual( fruitPlantation.productCount(), 0U ); + fruit = fruitPlantation.create( QLatin1String( "Pear" ) ); + assertNull( fruit ); + } + +} +#endif // KDTOOLSCORE_UNITTESTS diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdgenericfactory.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdgenericfactory.h new file mode 100644 index 000000000..1a0d7f854 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdgenericfactory.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE__KDGENERICFACTORY_H__ +#define __KDTOOLSCORE__KDGENERICFACTORY_H__ + +#include <KDToolsCore/kdtoolsglobal.h> + +#include <QtCore/QHash> + +template< typename T_Product, typename T_Identifier = QString, template< typename U, typename V > class T_Map = QHash > +class MAKEINCLUDES_EXPORT KDGenericFactory +{ +public: + virtual ~KDGenericFactory() + { + } + + typedef T_Product* (*FactoryFunction)(); + + template< typename T > + void registerProduct( const T_Identifier& name ) + { +#ifdef Q_CC_MSVC + FactoryFunction function = &KDGenericFactory::create<T>; + registerProductionFunction( name, function ); +#else + registerProductionFunction( name, &create<T> ); +#endif + } + + void unregisterProduct( const T_Identifier& name ) + { + map.remove( name ); + } + + unsigned int productCount() const + { + return map.size(); + } + + QList< T_Identifier > availableProducts() const + { + return map.keys(); + } + + T_Product* create( const T_Identifier& name ) const + { + const typename T_Map< T_Identifier, FactoryFunction >::const_iterator it = map.find( name ); + if( it == map.end() ) + return 0; + return (*it)(); + } + +protected: + void registerProductionFunction( const T_Identifier& name, FactoryFunction create ) + { + map.insert( name, create ); + } + +private: + template< typename T > + static T_Product* create() + { + return new T; + } + + T_Map< T_Identifier, FactoryFunction > map; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdjob.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdjob.cpp new file mode 100644 index 000000000..d88380ffb --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdjob.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdjob.h" + +#include <QEventLoop> + +class KDJob::Private { + KDJob* const q; +public: + explicit Private( KDJob* qq ) : q( qq ), error( KDJob::NoError ), errorString(), caps( KDJob::NoCapabilities ), autoDelete( true ), totalAmount( 100 ), processedAmount( 0 ) {} + + void delayedStart() { + q->doStart(); + emit q->started( q ); + } + + void waitForSignal( const char* sig ) { + QEventLoop loop; + q->connect( q, sig, &loop, SLOT(quit()) ); + loop.exec(); + } + + int error; + QString errorString; + KDJob::Capabilities caps; + bool autoDelete : 1; + quint64 totalAmount; + quint64 processedAmount; +}; + +KDJob::KDJob( QObject* parent ) : QObject( parent ), d( new Private( this ) ) { +} + +KDJob::~KDJob() { + //delete d; +} + +bool KDJob::autoDelete() const { + return d->autoDelete; +} + +void KDJob::setAutoDelete( bool autoDelete ) { + d->autoDelete = autoDelete; +} + +int KDJob::error() const { + return d->error; +} + +QString KDJob::errorString() const { + return d->errorString; +} + +void KDJob::emitFinished() { + emit finished( this ); + if ( d->autoDelete ) + deleteLater(); +} + +void KDJob::emitFinishedWithError( int error, const QString& errorString ) { + d->error = error; + d->errorString = errorString; + emitFinished(); +} + +void KDJob::setError( int error ) { + d->error = error; +} + +void KDJob::setErrorString( const QString& errorString ) { + d->errorString = errorString; +} + +void KDJob::waitForStarted() { + d->waitForSignal( SIGNAL(started(KDJob*)) ); +} + +void KDJob::waitForFinished() { + d->waitForSignal( SIGNAL(finished(KDJob*)) ); +} + +KDJob::Capabilities KDJob::capabilities() const { + return d->caps; +} + +bool KDJob::hasCapability( Capability c ) const { + return d->caps.testFlag( c ); +} + +void KDJob::setCapabilities( Capabilities c ) { + d->caps = c; +} + +void KDJob::start() { + QMetaObject::invokeMethod( this, "delayedStart", Qt::QueuedConnection ); +} + +void KDJob::doCancel() { +} + +void KDJob::cancel() { + doCancel(); + setError( Canceled ); +} + +quint64 KDJob::totalAmount() const { + return d->totalAmount; +} + +quint64 KDJob::processedAmount() const { + return d->processedAmount; +} + +void KDJob::setTotalAmount( quint64 amount ) { + if ( d->totalAmount == amount ) + return; + d->totalAmount = amount; + emit progress( this, d->processedAmount, d->totalAmount ); +} + +void KDJob::setProcessedAmount( quint64 amount ) { + if ( d->processedAmount == amount ) + return; + d->processedAmount = amount; + emit progress( this, d->processedAmount, d->totalAmount ); +} + +#include "moc_kdjob.cpp" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdjob.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdjob.h new file mode 100644 index 000000000..10cdd6899 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdjob.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_CORE_KDJOB_H__ +#define __KDTOOLS_CORE_KDJOB_H__ + +#include <QObject> + +#include <KDToolsCore/pimpl_ptr.h> + +class KDTOOLSCORE_EXPORT KDJob : public QObject { + Q_OBJECT + Q_PROPERTY( bool autoDelete READ autoDelete WRITE setAutoDelete ) + +public: + explicit KDJob( QObject* parent=0 ); + ~KDJob(); + + enum Error { + NoError=0, + Canceled=1, + UserDefinedError=128 + }; + + enum Capability { + NoCapabilities=0x0, + Cancelable=0x1 + }; + + Q_DECLARE_FLAGS(Capabilities, Capability) + + int error() const; + QString errorString() const; + + bool autoDelete() const; + void setAutoDelete( bool autoDelete ); + + Capabilities capabilities() const; + bool hasCapability( Capability c ) const; + + void waitForStarted(); + void waitForFinished(); + + quint64 totalAmount() const; + quint64 processedAmount() const; + +public Q_SLOTS: + void start(); + void cancel(); + +Q_SIGNALS: + void infoMessage( KDJob*, const QString& ); + +Q_SIGNALS: +#ifndef Q_MOC_RUN +private: // make signals private unless moc runs +#endif + void started( KDJob* ); + void finished( KDJob* ); + void progress( KDJob* job, quint64 processed, quint64 total ); + +protected: + virtual void doStart() = 0; + virtual void doCancel(); + + void setCapabilities( Capabilities c ); + void setTotalAmount( quint64 amount ); + void setProcessedAmount( quint64 amount ); + + void setError( int error ); + void setErrorString( const QString& errorString ); + + void emitFinished(); + void emitFinishedWithError( int error, const QString& errorString ); + +private: + class Private; + friend class ::KDJob::Private; + kdtools::pimpl_ptr<Private> d; + Q_PRIVATE_SLOT( d, void delayedStart() ) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(KDJob::Capabilities) + +#endif // __KDTOOLS_CORE_KDJOB_H__ diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.cpp new file mode 100644 index 000000000..234bc448e --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdlockfile.h" + +#include "kdlockfile_p.h" + +KDLockFile::Private::Private( const QString& filename_ ) + : filename( filename_ ) + , handle( 0 ) + , locked( false ) +{ +} + +KDLockFile::KDLockFile( const QString& name ) + : d( new Private( name ) ) +{ +} + +KDLockFile::~KDLockFile() +{ +} + +bool KDLockFile::lock() +{ + return d->lock(); +} + +QString KDLockFile::errorString() const +{ + return d->errorString; +} + +bool KDLockFile::unlock() +{ + return d->unlock(); +} + + +#ifdef KDTOOLSCORE_UNITTESTS + +#include <KDUnitTest/Test> +#include <QDebug> +#include <QDir> + +KDAB_UNITTEST_SIMPLE( KDLockFile, "kdcoretools" ) { + { + KDLockFile f( QLatin1String("/jlksdfdsfjkldsf-doesnotexist/file") ); + const bool locked = f.lock(); + assertFalse( locked ); + qDebug() << f.errorString(); + assertTrue( !f.errorString().isEmpty() ); + if ( !locked ) + assertTrue( f.unlock() ); + } + { + KDLockFile f( QDir::currentPath() + QLatin1String("/kdlockfile-test") ); + const bool locked = f.lock(); + assertTrue( locked ); + if ( !locked ) + qDebug() << f.errorString(); + assertEqual( locked, f.errorString().isEmpty() ); + const bool unlocked = f.unlock(); + assertTrue( unlocked ); + if ( !unlocked ) + qDebug() << f.errorString(); + assertEqual( unlocked, f.errorString().isEmpty() ); + } +} + +#endif // KDTOOLSCORE_UNITTESTS diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h new file mode 100644 index 000000000..cecbc5cbd --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE_KDLOCKFILE_H__ +#define __KDTOOLSCORE_KDLOCKFILE_H__ + +#include <pimpl_ptr.h> + +class QString; + +class KDTOOLSCORE_EXPORT KDLockFile +{ +public: + explicit KDLockFile( const QString & name ); + ~KDLockFile(); + + QString errorString() const; + + bool lock(); + bool unlock(); + +private: + Q_DISABLE_COPY(KDLockFile) + class Private; + kdtools::pimpl_ptr< Private > d; +}; + +#endif // __KDTOOLSCORE_KDLOCKFILE_H__ diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_p.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_p.h new file mode 100644 index 000000000..da4c4dc4c --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE_KDLOCKFILE_P_H__ +#define __KDTOOLSCORE_KDLOCKFILE_P_H__ + +#include "kdlockfile.h" +#include <QtCore/QString> +#ifdef Q_OS_WIN +#include <windows.h> +#endif + +class KDLockFile::Private +{ +public: + explicit Private( const QString& filename ); + ~Private(); + bool lock(); + bool unlock(); + + QString errorString; + +private: + QString filename; +#ifdef Q_OS_WIN + HANDLE handle; +#else + int handle; +#endif + bool locked; +}; + +#endif // LOCKFILE_P_H diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_unix.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_unix.cpp new file mode 100644 index 000000000..e3d187cbf --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_unix.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdlockfile_p.h" + +#include <QtCore/QCoreApplication> + +#include <cerrno> + +#include <sys/file.h> + +KDLockFile::Private::~Private() +{ + unlock(); +} + +bool KDLockFile::Private::lock() +{ + if ( locked ) + return true; + + errorString.clear(); + errno = 0; + handle = open( filename.toLatin1().constData(), O_CREAT | O_RDWR | O_NONBLOCK ); + if ( handle == -1 ) { + errorString = QObject::tr("Could not create lock file %1: %2").arg( filename, QLatin1String( strerror( errno ) ) ); + return false; + } + const QString pid = QString::number( qApp->applicationPid() ); + const QByteArray data = pid.toLatin1(); + errno = 0; + qint64 written = 0; + while ( written < data.size() ) { + const qint64 n = write( handle, data.constData() + written, data.size() - written ); + if ( n < 0 ) { + errorString = QObject::tr("Could not write PID to lock file %1: %2").arg( filename, QLatin1String( strerror( errno ) ) ); + return false; + } + written += n; + } + errno = 0; + locked = flock( handle, LOCK_NB | LOCK_EX ) != -1; + if ( !locked ) + errorString = QObject::tr("Could not lock lock file %1: %2").arg( filename, QLatin1String( strerror( errno ) ) ); + return locked; +} + +bool KDLockFile::Private::unlock() +{ + errorString.clear(); + if ( !locked ) + return true; + errno = 0; + locked = flock( handle, LOCK_UN | LOCK_NB ) == -1; + if ( locked ) + errorString = QObject::tr("Could not unlock lock file %1: %2").arg( filename, QLatin1String( strerror( errno ) ) ); + return !locked; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_win.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_win.cpp new file mode 100644 index 000000000..f7fed60ab --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile_win.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdlockfile.h" +#include "kdlockfile_p.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QFileInfo> + +KDLockFile::Private::~Private() +{ + unlock(); +} + +bool KDLockFile::Private::lock() +{ + const QFileInfo fi( filename ); + handle = CreateFile( filename.toStdWString().data(), + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, + NULL, fi.exists() ? OPEN_EXISTING : CREATE_NEW, + FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL ); + + if ( !handle ) + return false; + QString pid = QString::number( qApp->applicationPid() ); + QByteArray data = pid.toLatin1(); + DWORD bytesWritten; + const bool wrotePid = WriteFile( handle, data.data(), data.size(), &bytesWritten, NULL ); + if ( !wrotePid ) + return false; + FlushFileBuffers( handle ); + + const bool locked = LockFile( handle, 0, 0, fi.size(), 0 ); + + this->locked = locked; + return locked; +} + +bool KDLockFile::Private::unlock() +{ + const QFileInfo fi( filename ); + if ( locked ) + { + const bool success = UnlockFile( handle, 0, 0, 0, fi.size() ); + this->locked = !success; + CloseHandle( handle ); + return success; + } + return true; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdmetamethoditerator.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdmetamethoditerator.cpp new file mode 100644 index 000000000..1a0b863c7 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdmetamethoditerator.cpp @@ -0,0 +1,493 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdmetamethoditerator.h" + +/*! + \class KDMetaMethodIterator + \ingroup core + \brief Iterator over methods of QObjects + \since_c 2.3 + + KDMetaMethodIterator provides a way over all methods of a QObject which can be accessed via Qt's meta + object system. It is possible to filter on types of methods (Q_INVOKABLE methods, signals, slots, + constructors) and on access types (public, protected, private). Furthermore, KDMetaMethodIterator can + be configured to filter methods of the given object's base class or all methods provided by QObject. + + \section general-use General Use + + The following example shows a general use case of KDMetaMethodIterator: + + \code + + class QIODeviceWrapper : public QIODevice + { + Q_OBJECT + public: + QIODeviceWrapper( QIODevice* nestedDevice ) + : nested( nestedDevice ) + { + // make sure all signals of the nested QIODevice are forwarded, + // but make sure not to connect QObject's own destroyed() signal, + // therefore use KDMetaMethodIterator::IgnoreQObjectMethods + KDMetaMethodIterator it( QIODevice::staticMetaObject, KDMetaMethodIterator::Signal, KDMetaMethodIterator::IgnoreQObjectMethods ); + while( it.hasNext() ) + { + it.next(); + connect( nested, it.connectableSignature(), this, it.connectableSignature() ); + } + } + + protected: + // virtual methods needed to access the contents... + + private: + QIODevice* const nested; + }; + + \endcode +*/ + +/*! + \enum KDMetaMethodIterator::AccessType + This enum describes the access type of methods to iterate: +*/ + +/*! + \var KDMetaMethodIterator::Private + Iterate over private methods. +*/ + +/*! + \var KDMetaMethodIterator::Protected + Iterate over protected methods. +*/ + +/*! + \var KDMetaMethodIterator::Public + Iterate over public methods. +*/ + +/*! + \var KDMetaMethodIterator::AllAccessTypes + Iterate over methods of all access types. +*/ + +/*! + \enum KDMetaMethodIterator::MethodType + This enum describes the type of methods to iterate: +*/ + +/*! + \var KDMetaMethodIterator::Method + Iterate over methods marked with Q_INVOKABLE +*/ + +/*! + \var KDMetaMethodIterator::Signal + Iterate over signals. +*/ + +/*! + \var KDMetaMethodIterator::Slot + Iterate over slots. +*/ + +/*! + \var KDMetaMethodIterator::Constructor + Iterate over constructors marked with Q_INVOKABLE. +*/ + +/*! + \var KDMetaMethodIterator::AllMethodTypes + Iterate over all supported method types. +*/ + +/*! + \enum KDMetaMethodIterator::IteratorFlag + This enum describes flags which can be passed to KDMetaMethodIterator: +*/ + +/*! + \var KDMetaMethodIterator::NoFlags + No flags set, only type filtering takes place. +*/ + +/*! + \var KDMetaMethodIterator::IgnoreQObjectMethods + KDMetaMethodIterator will not iterate over methods provided by QObject itself. +*/ + +/*! + \var KDMetaMethodIterator::IgnoreSuperClassMethods + KDMetaMethodIterator will only iterate over methods provided by the passed class instance itself, ignoring any base classes. +*/ + +/*! + \internal + */ +class KDMetaMethodIterator::Priv +{ +public: + Priv( const QMetaObject* object, MethodTypes types, AccessTypes access, IteratorFlags flags ) + : index( -1 ), + m( types ), + a( access ), + f( flags ), + metaObject( object ) + { + } + + Priv( const QMetaObject* object, MethodTypes types, IteratorFlags flags ) + : index( -1 ), + m( types ), + a( ( types & Signal ) ? ( Protected | Public ) : Public ), + f( flags ), + metaObject( object ) + { + } + + bool filterMatches( const QMetaMethod& method, int index ) const; + + int index; + const MethodTypes m; + const AccessTypes a; + const IteratorFlags f; + const QMetaObject* const metaObject; + + mutable QByteArray connectableSignature; +}; + +/*! + Creates a new KDMetaMethodIterator iterating over \a metaObject. The iterator will only return methods of the given \a types. + By default, only public methods will be returned. If \a types contains Signal, the access type filter will automatically set + to return protected and public. + + By default, \a flags is NoFlags, which lists all methods. + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QMetaObject& metaObject, MethodTypes types, IteratorFlags flags ) + : d( new Priv( &metaObject, types, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a metaObject. The iterator will only return methods of the given \a types, + matching the \a access mode. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QMetaObject& metaObject, MethodTypes types, AccessType access, IteratorFlags flags ) + : d( new Priv( &metaObject, types, access, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a metaObject. The iterator will only return methods matching the \a access mode. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QMetaObject& metaObject, AccessType access, IteratorFlags flags ) + : d( new Priv( &metaObject, AllMethodTypes, access, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a metaObject. The iterator will only return methods of the given \a types. + By default, only public methods will be returned. If \a types contains Signal, the access type filter will automatically set + to return protected and public. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QMetaObject* metaObject, MethodTypes types, IteratorFlags flags ) + : d( new Priv( metaObject, types, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a metaObject. The iterator will only return methods of the given \a types, + matching the \a access mode. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QMetaObject* metaObject, MethodTypes types, AccessType access, IteratorFlags flags ) + : d( new Priv( metaObject, types, access, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a metaObject. The iterator will only return methods matching the \a access mode. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QMetaObject* metaObject, AccessType access, IteratorFlags flags ) + : d( new Priv( metaObject, AllMethodTypes, access, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a object. The iterator will only return methods of the given \a types. + By default, only public methods will be returned. If \a types contains Signal, the access type filter will automatically set + to return protected and public. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QObject* object, MethodTypes types, IteratorFlags flags ) + : d( new Priv( object->metaObject(), types, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a object. The iterator will only return methods of the given \a types, + matching the \a access mode. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QObject* object, MethodTypes types, AccessType access, IteratorFlags flags ) + : d( new Priv( object->metaObject(), types, access, flags ) ) +{ +} + +/*! + Creates a new KDMetaMethodIterator iterating over \a object. The iterator will only return methods matching the \a access mode. + + By default, \a flags is NoFlags, which lists all methods. + + \overload + */ +KDMetaMethodIterator::KDMetaMethodIterator( const QObject* object, AccessType access, IteratorFlags flags ) + : d( new Priv( object->metaObject(), AllMethodTypes, access, flags ) ) +{ +} + +/*! + Destroys the KDMetaMethodIterator. + */ +KDMetaMethodIterator::~KDMetaMethodIterator() +{ +} + +/*! + Returns true if there is at least one item ahead of the iterator, i.e. the iterator is not at the back of the method list; otherwise returns false. + */ +bool KDMetaMethodIterator::hasNext() const +{ + for( int i = d->index + 1; i < d->metaObject->methodCount(); ++i ) + { + const QMetaMethod method = d->metaObject->method( i ); + if( d->filterMatches( method, i ) ) + return true; + } + return false; +} + +/*! + Returns the next method and advances the iterator by one position. + */ +QMetaMethod KDMetaMethodIterator::next() +{ + Q_ASSERT( hasNext() ); + d->connectableSignature.clear(); + for( ++d->index; d->index < d->metaObject->methodCount(); ++d->index ) + { + const QMetaMethod method = d->metaObject->method( d->index ); + if( d->filterMatches( method, d->index ) ) + return method; + } + return QMetaMethod(); +} + +/*! + Returns the current method's signature ready to be passed to QObject::connect, i.e. already passed through the SIGNAL or SLOT macro. + The return value stays valid up to the following next() call. This is only valid for signals and slots. + */ +const char* KDMetaMethodIterator::connectableSignature() const +{ + if( d->connectableSignature.isEmpty() ) + { + const QMetaMethod method = d->metaObject->method( d->index ); + d->connectableSignature = method.signature(); + d->connectableSignature.push_front( QString::number( ( static_cast< int >( method.methodType() ) - 3 ) * -1 ).toLocal8Bit() ); + } + return d->connectableSignature.constData(); +} + +/*! + Returns true if \a method matches the filters set on the iterator, currently pointing to \a index. + \internal + */ +bool KDMetaMethodIterator::Priv::filterMatches( const QMetaMethod& method, int index ) const +{ + // filter QObject's own methods + if( ( f & IgnoreQObjectMethods ) && index < QObject::staticMetaObject.methodCount() ) + return false; + + // filter any super classes methods + if( ( f & IgnoreSuperClassMethods ) && index < metaObject->methodOffset() ) + return false; + + // filter any methods with unwanted access types + if( ( ( 1 << method.access() ) & a ) == 0 ) + return false; + + // filter any methods with unwanted method types + return ( ( 1 << method.methodType() ) & m ) != 0; +} + +#ifdef KDTOOLSCORE_UNITTESTS + +#include <KDUnitTest/Test> + +class TestClass : public QObject +{ + Q_OBJECT +public: + TestClass(){} + +public Q_SLOTS: + void publicSlot( int ) {} + +protected Q_SLOTS: + void protectedSlot( int ) {} + +private Q_SLOTS: + void privateSlot( int ) {} + +private: + Q_PRIVATE_SLOT( d, void veryPrivateSlot() ) + + class Private; + kdtools::pimpl_ptr< Private > d; +}; + +class TestClassDerived : public TestClass +{ + Q_OBJECT +public: + TestClassDerived(){} +}; + +class TestClass::Private +{ +public: + void veryPrivateSlot() {} +}; + +KDAB_UNITTEST_SIMPLE( KDMetaMethodIterator, "kdcoretools" ) { + + QObject o; + { + KDMetaMethodIterator it( &o, KDMetaMethodIterator::Signal ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "destroyed(QObject*)" ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "destroyed()" ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( QObject::staticMetaObject, KDMetaMethodIterator::Signal ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "destroyed(QObject*)" ); + } + { + KDMetaMethodIterator it( o.metaObject(), KDMetaMethodIterator::Signal ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "destroyed(QObject*)" ); + } + + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Signal ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "destroyed(QObject*)" ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "destroyed()" ); + assertEqual( std::string( it.connectableSignature() ), "2destroyed()" ); + assertFalse( it.hasNext() ); + } + + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Signal, KDMetaMethodIterator::IgnoreQObjectMethods ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Signal, KDMetaMethodIterator::IgnoreSuperClassMethods ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Slot ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "deleteLater()" ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "publicSlot(int)" ); + assertEqual( std::string( it.connectableSignature() ), "1publicSlot(int)" ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Slot, KDMetaMethodIterator::IgnoreQObjectMethods ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "publicSlot(int)" ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Slot, KDMetaMethodIterator::Protected, KDMetaMethodIterator::IgnoreQObjectMethods ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "protectedSlot(int)" ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( TestClass::staticMetaObject, KDMetaMethodIterator::Slot, KDMetaMethodIterator::Private, KDMetaMethodIterator::IgnoreQObjectMethods ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "privateSlot(int)" ); + assertEqual( std::string( it.next().signature() ), "veryPrivateSlot()" ); + assertFalse( it.hasNext() ); + } + + { + KDMetaMethodIterator it( TestClassDerived::staticMetaObject, KDMetaMethodIterator::Slot, KDMetaMethodIterator::Private, KDMetaMethodIterator::IgnoreQObjectMethods ); + assertTrue( it.hasNext() ); + assertEqual( std::string( it.next().signature() ), "privateSlot(int)" ); + assertEqual( std::string( it.next().signature() ), "veryPrivateSlot()" ); + assertFalse( it.hasNext() ); + } + { + KDMetaMethodIterator it( TestClassDerived::staticMetaObject, KDMetaMethodIterator::Slot, KDMetaMethodIterator::Private, KDMetaMethodIterator::IgnoreSuperClassMethods ); + assertFalse( it.hasNext() ); + } + +} + +#include "kdmetamethoditerator.moc" + +#endif // KDTOOLSCORE_UNITTESTS diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdmetamethoditerator.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdmetamethoditerator.h new file mode 100644 index 000000000..94bb8f707 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdmetamethoditerator.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE_KDMETAMETHODITERATOR_H__ +#define __KDTOOLSCORE_KDMETAMETHODITERATOR_H__ + +#include <KDToolsCore/pimpl_ptr.h> + +#include <QtCore/QMetaMethod> + +class KDTOOLSCORE_EXPORT KDMetaMethodIterator +{ +public: + enum AccessType + { + Private = 1 << QMetaMethod::Private, + Protected = 1 << QMetaMethod::Protected, + Public = 1 << QMetaMethod::Public, + AllAccessTypes = Private | Protected | Public + }; + Q_DECLARE_FLAGS( AccessTypes, AccessType ) + + enum MethodType + { + Method = 0x1, + Signal = 0x2, + Slot = 0x4, + Constructor = 0x8, + AllMethodTypes = Method | Signal | Slot | Constructor + }; + Q_DECLARE_FLAGS( MethodTypes, MethodType ) + + enum IteratorFlag + { + NoFlags = 0x00, + IgnoreQObjectMethods = 0x01, + IgnoreSuperClassMethods = 0x02 + }; + Q_DECLARE_FLAGS( IteratorFlags, IteratorFlag ) + + explicit KDMetaMethodIterator( const QMetaObject& metaObject, MethodTypes types = AllMethodTypes, IteratorFlags flags = NoFlags ); + KDMetaMethodIterator( const QMetaObject& metaObject, MethodTypes types, AccessType access, IteratorFlags flags = NoFlags ); + KDMetaMethodIterator( const QMetaObject& metaObject, AccessType access, IteratorFlags flags = NoFlags ); + + explicit KDMetaMethodIterator( const QMetaObject* metaObject, MethodTypes types = AllMethodTypes, IteratorFlags flags = NoFlags ); + KDMetaMethodIterator( const QMetaObject* metaObject, MethodTypes types, AccessType access, IteratorFlags flags = NoFlags ); + KDMetaMethodIterator( const QMetaObject* metaObject, AccessType access, IteratorFlags flags = NoFlags ); + + explicit KDMetaMethodIterator( const QObject* object, MethodTypes types = AllMethodTypes, IteratorFlags flags = NoFlags ); + KDMetaMethodIterator( const QObject* object, MethodTypes types, AccessType access, IteratorFlags flags = NoFlags ); + KDMetaMethodIterator( const QObject* object, AccessType access, IteratorFlags flags = NoFlags ); + + ~KDMetaMethodIterator(); + + bool hasNext() const; + QMetaMethod next(); + + const char* connectableSignature() const; + +private: + class Priv; + kdtools::pimpl_ptr< Priv > d; +}; + + +#endif // __KDTOOLSCORE_KDMETAMETHODITERATOR_H__ diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdrunoncechecker.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdrunoncechecker.cpp new file mode 100644 index 000000000..457a6215a --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdrunoncechecker.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdrunoncechecker.h" +#include "kdlockfile.h" +#include "kdsysinfo.h" + +#include <QtCore/QList> +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> + +#include <algorithm> + +class KDRunOnceChecker::Private +{ +public: + Private( const QString& filename ); + ~Private(); + KDLockFile m_lockfile; + bool m_hasLock; +}; + +KDRunOnceChecker::Private::Private( const QString& filename ) + : m_lockfile( filename ) + , m_hasLock( false ) +{ + +} + +KDRunOnceChecker::Private::~Private() +{ + +} + +KDRunOnceChecker::KDRunOnceChecker( const QString& filename ) + :d( new Private( filename ) ) +{ + +} + +KDRunOnceChecker::~KDRunOnceChecker() +{ + +} + +class ProcessnameEquals +{ +public: + ProcessnameEquals( const QString& name ): m_name( name ){} + bool operator()( const KDSysInfo::ProcessInfo& info ) + { +#ifndef Q_WS_WIN + if( info.name == m_name ) + return true; + const QFileInfo fi( info.name ); + if( fi.fileName() == m_name || fi.baseName() == m_name ) + return true; + return false; +#else + if( info.name.toLower() == m_name.toLower() ) + return true; + if( info.name.toLower() == QDir::toNativeSeparators(m_name.toLower()) ) + return true; + const QFileInfo fi( info.name ); + if( fi.fileName().toLower() == m_name.toLower() || fi.baseName().toLower() == m_name.toLower() ) + return true; + return info.name == m_name; +#endif + } + +private: + QString m_name; +}; + +bool KDRunOnceChecker::isRunning( Dependencies depends ) +{ + bool running = false; + switch ( depends ) + { + case( Lockfile ): + { + const bool locked = d->m_hasLock || d->m_lockfile.lock(); + if ( locked ) + d->m_hasLock = true; + running = running || ! locked; + } + break; + case( ProcessList ): + { + const QList< KDSysInfo::ProcessInfo > allProcesses = KDSysInfo::runningProcesses(); + const QString appName = qApp->applicationFilePath(); + //QList< KDSysInfo::ProcessInfo >::const_iterator it = std::find_if( allProcesses.constBegin(), allProcesses.constEnd(), ProcessnameEquals( appName ) ); + const int count = std::count_if( allProcesses.constBegin(), allProcesses.constEnd(), ProcessnameEquals( appName ) ); + running = running || /*it != allProcesses.constEnd()*/count > 1; + } + break; + case( BOTH ): + { + const QList< KDSysInfo::ProcessInfo > allProcesses = KDSysInfo::runningProcesses(); + const QString appName = qApp->applicationFilePath(); + //QList< KDSysInfo::ProcessInfo >::const_iterator it = std::find_if( allProcesses.constBegin(), allProcesses.constEnd(), ProcessnameEquals( appName ) ); + const int count = std::count_if( allProcesses.constBegin(), allProcesses.constEnd(), ProcessnameEquals( appName ) ); + const bool locked = d->m_hasLock || d->m_lockfile.lock(); + if ( locked ) + d->m_hasLock = true; + running = running || ( /*it != allProcesses.constEnd()*/count > 1 && !locked ); + + } + break; + } + + return running; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdrunoncechecker.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdrunoncechecker.h new file mode 100644 index 000000000..9e562d3cf --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdrunoncechecker.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_RUNONCECHECKER_H__ +#define __KDTOOLS_RUNONCECHECKER_H__ + +#include <KDToolsCore/pimpl_ptr> + +#include <QtCore/QString> + +class KDTOOLSCORE_EXPORT KDRunOnceChecker +{ + +public: + enum Dependencies{ ProcessList, Lockfile, BOTH }; + explicit KDRunOnceChecker( const QString& filename = QString() ); + ~KDRunOnceChecker(); + bool isRunning( Dependencies depends ); + +private: + Q_DISABLE_COPY(KDRunOnceChecker) + class Private; + kdtools::pimpl_ptr< Private > d; + +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsavefile.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsavefile.cpp new file mode 100644 index 000000000..38a4b87bf --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsavefile.cpp @@ -0,0 +1,476 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdsavefile.h" + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QPointer> +#include <QtCore/QTemporaryFile> + +#ifdef Q_OS_WIN +# include <io.h> +#endif +#include <memory> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> + +static int permissionsToMode( QFile::Permissions p, bool* ok ) { + Q_ASSERT( ok ); + int m = 0; +#ifdef Q_OS_WIN + //following qfsfileengine_win.cpp: QFSFileEngine::setPermissions() + if ( p & QFile::ReadOwner || p & QFile::ReadUser || p & QFile::ReadGroup || p & QFile::ReadOther ) + m |= _S_IREAD; + if ( p & QFile::WriteOwner || p & QFile::WriteUser || p & QFile::WriteGroup || p & QFile::WriteOther ) + m |= _S_IWRITE; + *ok = m != 0; +#else + if ( p & QFile::ReadUser ) + m |= S_IRUSR; + if ( p & QFile::WriteUser ) + m |= S_IWUSR; + if ( p & QFile::ExeUser) + m |= S_IXUSR; + if ( p & QFile::ReadGroup ) + m |= S_IRGRP; + if ( p & QFile::WriteGroup ) + m |= S_IWGRP; + if ( p & QFile::ExeGroup ) + m |= S_IXGRP; + if ( p & QFile::ReadOther ) + m |= S_IROTH; + if ( p & QFile::WriteOther ) + m |= S_IWOTH; + if ( p & QFile::ExeOther ) + m |= S_IXOTH; + *ok = true; +#endif + return m; +} + +static bool sync( int fd ) { +#ifdef Q_OS_WIN + return _commit( fd ) == 0; +#else + return fsync( fd ) == 0; +#endif +} + +static QString makeAbsolute( const QString& path ) { + if ( QDir::isAbsolutePath( path ) ) + return path; + return QDir::currentPath() + QLatin1String("/") + path; +} + +static int myOpen( const QString& path, int flags, int mode ) { +#ifdef Q_OS_WIN + int fd; + _wsopen_s( &fd, reinterpret_cast<const wchar_t*>( path.utf16() ), flags, _SH_DENYRW, mode ); + return fd; +#else + return open( QFile::encodeName( path ).constData(), flags, mode ); +#endif +} + +static void myClose( int fd ) { +#ifdef Q_OS_WIN + _close( fd ); +#else + close( fd ); +#endif +} + +static bool touchFile( const QString& path, QFile::Permissions p ) { + bool ok; + const int mode = permissionsToMode( p, &ok ); + if ( !ok ) + return false; + const int fd = myOpen( QDir::toNativeSeparators( path ), O_WRONLY|O_CREAT, mode ); + if ( fd < 0 ) + { + QFile file( path ); + if( !file.open( QIODevice::WriteOnly ) ) + return false; + if( !file.setPermissions( p ) ) { + QFile::remove( path ); + return false; + } + return true; + } + sync( fd ); + myClose( fd ); + return true; +} + +static QFile* createFile( const QString& path, QIODevice::OpenMode m, QFile::Permissions p, bool* openOk ) { + Q_ASSERT( openOk ); + if ( !touchFile( path, p ) ) + return 0; + std::auto_ptr<QFile> file( new QFile( path ) ); + *openOk = file->open( m | QIODevice::Append ); + if ( !*openOk ) + QFile::remove( path ); // try to remove empty file + return file.release(); +} + +/*! + Generates a temporary file name based on template \a path + \internal + */ +static QString generateTempFileName( const QString& path ) +{ + const QString tmp = path + QLatin1String( "tmp.dsfdf.%1" ); //TODO: use random suffix + int count = 1; + while ( QFile::exists( tmp.arg( count ) ) ) + ++count; + return tmp.arg( count ); +} + +/*! + \class KDSaveFile KDSaveFile + \ingroup core + \brief Secure and robust writing to a file + +*/ + +class KDSaveFile::Private { + KDSaveFile* const q; +public: + explicit Private( const QString& fname, KDSaveFile* qq ) : q( qq ), +#ifdef Q_OS_WIN + backupExtension( QLatin1String(".bak") ), +#else + backupExtension( QLatin1String("~") ), +#endif + permissions( QFile::ReadUser|QFile::WriteUser), filename( fname ), tmpFile() { + //TODO respect umask instead of hardcoded default permissions + } + + ~Private() { + deleteTempFile(); + } + + bool deleteTempFile() { + if ( !tmpFile ) + return true; + const QString name = tmpFile->fileName(); + delete tmpFile; + //force a real close by deleting the object, before deleting the actual file. Needed on Windows + QFile tmp( name ); + return tmp.remove(); + } + + bool recreateTemporaryFile( QIODevice::OpenMode mode ) { + deleteTempFile(); + bool ok; + tmpFile = createFile( generateTempFileName( filename ), mode, permissions, &ok ); + QObject::connect( tmpFile, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()) ); + QObject::connect( tmpFile, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)) ); + QObject::connect( tmpFile, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()) ); + QObject::connect( tmpFile, SIGNAL(readyRead()), q, SIGNAL(readyRead()) ); + return ok; + } + + QString generateBackupName() const { + const QString bf = filename + backupExtension; + if ( !QFile::exists( bf ) ) + return bf; + int count = 1; + while ( QFile::exists( bf + QString::number( count ) ) ) + ++count; + return bf + QString::number( count ); + } + + void propagateErrors() { + if ( !tmpFile ) + return; + q->setErrorString( tmpFile->errorString() ); + } + QString backupExtension; + QFile::Permissions permissions; + QString filename; + QPointer<QFile> tmpFile; +}; + +KDSaveFile::KDSaveFile( const QString& filename, QObject* parent ) : QIODevice( parent ), d( new Private( makeAbsolute( filename ), this ) ) { +} + +KDSaveFile::~KDSaveFile() { +} + +void KDSaveFile::close() { + d->deleteTempFile(); + QIODevice::close(); +} + +bool KDSaveFile::open( OpenMode mode ) { + setOpenMode( QIODevice::NotOpen ); + if ( mode & QIODevice::Append ) { + setErrorString( tr("Append mode not supported.") ); + return false; + } + + if ( ( mode & QIODevice::WriteOnly ) == 0 ) { + setErrorString( tr("Read-only access not supported.") ); + return false; + } + + // for some reason this seems to be problematic... let's remove it for now, will break in commit anyhow, if it's serious + //if ( QFile::exists( d->filename ) && !QFileInfo( d->filename ).isWritable() ) { + // setErrorString( tr("The target file %1 exists and is not writable").arg( d->filename ) ); + // return false; + //} + const bool opened = d->recreateTemporaryFile( mode ); + if ( opened ) { + setOpenMode( mode ); + } + + //if target file already exists, apply permissions of existing file to temp file + return opened; +} + +bool KDSaveFile::atEnd() { + return d->tmpFile ? d->tmpFile->atEnd() : QIODevice::atEnd(); +} + +qint64 KDSaveFile::bytesAvailable() const { + return d->tmpFile ? d->tmpFile->bytesAvailable() : QIODevice::bytesAvailable(); +} + +qint64 KDSaveFile::bytesToWrite() const { + return d->tmpFile ? d->tmpFile->bytesToWrite() : QIODevice::bytesToWrite(); +} + +bool KDSaveFile::canReadLine() const { + return d->tmpFile ? d->tmpFile->canReadLine() : QIODevice::canReadLine(); +} + +bool KDSaveFile::isSequential() const { + return d->tmpFile ? d->tmpFile->isSequential() : QIODevice::isSequential(); +} + +qint64 KDSaveFile::pos() const { + return d->tmpFile ? d->tmpFile->pos() : QIODevice::pos(); +} + +bool KDSaveFile::reset() { + return d->tmpFile ? d->tmpFile->reset() : QIODevice::reset(); +} + +bool KDSaveFile::seek( qint64 pos ) { + const bool ret = d->tmpFile ? d->tmpFile->seek( pos ) : QIODevice::seek( pos ); + if ( !ret ) + d->propagateErrors(); + return ret; +} + +qint64 KDSaveFile::size() const { + return d->tmpFile ? d->tmpFile->size() : QIODevice::size(); +} + +bool KDSaveFile::waitForBytesWritten( int msecs ) { + return d->tmpFile ? d->tmpFile->waitForBytesWritten( msecs ) : QIODevice::waitForBytesWritten( msecs ); +} + +bool KDSaveFile::waitForReadyRead( int msecs ) { + return d->tmpFile ? d->tmpFile->waitForReadyRead( msecs ) : QIODevice::waitForReadyRead( msecs ); +} + +bool KDSaveFile::commit( KDSaveFile::CommitMode mode ) { + if ( !d->tmpFile ) + return false; + const QString tmpfname = d->tmpFile->fileName(); + d->tmpFile->flush(); + delete d->tmpFile; + QFile orig( d->filename ); + QString backup; + if ( orig.exists() ) { + backup = d->generateBackupName(); + if ( !orig.rename( backup ) ) { + setErrorString( tr("Could not backup existing file %1: %2").arg( d->filename, orig.errorString() ) ); + QFile tmp( tmpfname ); + if ( !tmp.remove() ) // TODO how to report this error? + qWarning() << "Could not remove temp file" << tmpfname << tmp.errorString(); + if ( mode != OverwriteExistingFile ) + return false; + } + } + QFile target( tmpfname ); + if ( !target.rename( d->filename ) ) { + setErrorString( target.errorString() ); + return false; + } + if ( mode == OverwriteExistingFile ) { + QFile tmp( backup ); + const bool removed = !tmp.exists() || tmp.remove( backup ); + if ( !removed ) + qWarning() << "Could not remove the backup: " << tmp.errorString(); + } + + return true; +} + +QString KDSaveFile::fileName() const { + return d->filename; +} + +void KDSaveFile::setFileName( const QString& filename ) { + const QString fn = makeAbsolute( filename ); + if ( fn == d->filename ) + return; + close(); + delete d->tmpFile; + d->filename = fn; +} + +qint64 KDSaveFile::readData( char* data, qint64 maxSize ) { + if ( !d->tmpFile ) { + setErrorString( tr("TODO") ); + return -1; + } + const qint64 ret = d->tmpFile->read( data, maxSize ); + d->propagateErrors(); + return ret; +} + +qint64 KDSaveFile::readLineData( char* data, qint64 maxSize ) { + if ( !d->tmpFile ) { + setErrorString( tr("TODO") ); + return -1; + } + const qint64 ret = d->tmpFile->readLine( data, maxSize ); + d->propagateErrors(); + return ret; +} + +qint64 KDSaveFile::writeData( const char* data, qint64 maxSize ) { + if ( !d->tmpFile ) { + setErrorString( tr("TODO") ); + return -1; + } + const qint64 ret = d->tmpFile->write( data, maxSize ); + d->propagateErrors(); + return ret; +} + +bool KDSaveFile::flush() { + return d->tmpFile ? d->tmpFile->flush() : false; +} + +bool KDSaveFile::resize( qint64 sz ) { + return d->tmpFile ? d->tmpFile->resize( sz ) : false; +} + +int KDSaveFile::handle() const { + return d->tmpFile ? d->tmpFile->handle() : -1; +} + +QFile::Permissions KDSaveFile::permissions() const { + return d->tmpFile ? d->tmpFile->permissions() : d->permissions; +} + +bool KDSaveFile::setPermissions( QFile::Permissions p ) { + d->permissions = p; + if ( d->tmpFile ) + return d->tmpFile->setPermissions( p ); + return false; +} + +void KDSaveFile::setBackupExtension( const QString& ext ) { + d->backupExtension = ext; +} + +QString KDSaveFile::backupExtension() const { + return d->backupExtension; +} + +/** + * TODO + * + * + */ + +#ifdef KDTOOLSCORE_UNITTESTS + +#include <KDUnitTest/Test> + +KDAB_UNITTEST_SIMPLE( KDSaveFile, "kdcoretools" ) { + //TODO test contents (needs blocking and checked write() ) + { + const QString testfile1 = QLatin1String("kdsavefile-test1"); + QByteArray testData("lalalala"); + KDSaveFile saveFile( testfile1 ); + assertTrue( saveFile.open( QIODevice::WriteOnly ) ); + saveFile.write( testData.constData(), testData.size() ); + assertTrue( saveFile.commit() ); + assertTrue( QFile::exists( testfile1 ) ); + assertTrue( QFile::remove( testfile1 ) ); + } + { + const QString testfile1 = QLatin1String("kdsavefile-test1"); + QByteArray testData("lalalala"); + KDSaveFile saveFile( testfile1 ); + assertTrue( saveFile.open( QIODevice::WriteOnly ) ); + saveFile.write( testData.constData(), testData.size() ); + saveFile.close(); + assertFalse( QFile::exists( testfile1 ) ); + } + { + const QString testfile1 = QLatin1String("kdsavefile-test1"); + QByteArray testData("lalalala"); + KDSaveFile saveFile( testfile1 ); + assertTrue( saveFile.open( QIODevice::WriteOnly ) ); + saveFile.write( testData.constData(), testData.size() ); + assertTrue( saveFile.commit() ); + assertTrue( QFile::exists( testfile1 ) ); + + KDSaveFile sf2( testfile1 ); + sf2.setBackupExtension( QLatin1String(".bak") ); + assertTrue( sf2.open( QIODevice::WriteOnly ) ); + sf2.write( testData.constData(), testData.size() ); + sf2.commit(); //commit in backup mode (default) + const QString backup = testfile1 + sf2.backupExtension(); + assertTrue( QFile::exists( backup ) ); + assertTrue( QFile::remove( backup ) ); + + KDSaveFile sf3( testfile1 ); + sf3.setBackupExtension( QLatin1String(".bak") ); + assertTrue( sf3.open( QIODevice::WriteOnly ) ); + sf3.write( testData.constData(), testData.size() ); + sf3.commit( KDSaveFile::OverwriteExistingFile ); + const QString backup2 = testfile1 + sf3.backupExtension(); + assertFalse( QFile::exists( backup2 ) ); + + assertTrue( QFile::remove( testfile1 ) ); + } + { + const QString testfile1 = QLatin1String("kdsavefile-test1"); + KDSaveFile sf( testfile1 ); + assertFalse( sf.open( QIODevice::ReadOnly ) ); + assertFalse( sf.open( QIODevice::WriteOnly|QIODevice::Append ) ); + assertTrue( sf.open( QIODevice::ReadWrite ) ); + } +} + +#endif // KDTOOLSCORE_UNITTESTS diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsavefile.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsavefile.h new file mode 100644 index 000000000..94170608c --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsavefile.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE_KDSAVEFILE_H__ +#define __KDTOOLSCORE_KDSAVEFILE_H__ + +#include <KDToolsCore/kdtoolsglobal.h> +#include <KDToolsCore/pimpl_ptr.h> + +#include <QtCore/QIODevice> +#include <QtCore/QFile> +#include <QtCore/QString> + +class KDTOOLSCORE_EXPORT KDSaveFile : public QIODevice { + Q_OBJECT +public: + explicit KDSaveFile( const QString& filename=QString(), QObject* parent=0 ); + ~KDSaveFile(); + + enum CommitMode { + BackupExistingFile=0x1, + OverwriteExistingFile=0x2 + }; + + bool commit( CommitMode=BackupExistingFile ); + + QString fileName() const; + void setFileName( const QString& filename ); + + QFile::Permissions permissions() const; + bool setPermissions( QFile::Permissions ); + + QString backupExtension() const; + void setBackupExtension( const QString& extension ); + + bool flush(); + bool resize( qint64 sz ); + int handle() const; + + /* reimp */ bool atEnd(); + /* reimp */ qint64 bytesAvailable() const; + /* reimp */ qint64 bytesToWrite() const; + /* reimp */ bool canReadLine() const; + /* reimp */ void close(); + /* reimp */ bool isSequential() const; + /* reimp */ bool open( OpenMode mode=QIODevice::ReadWrite ); //only valid: WriteOnly, ReadWrite + /* reimp */ qint64 pos() const; + /* reimp */ bool reset(); + /* reimp */ bool seek( qint64 pos ); + /* reimp */ qint64 size() const; + /* reimp */ bool waitForBytesWritten( int msecs ); + /* reimp */ bool waitForReadyRead( int msecs ); + +private: + /* reimp */ qint64 readData( char* data, qint64 maxSize ); + /* reimp */ qint64 readLineData( char* data, qint64 maxSize ); + /* reimp */ qint64 writeData( const char* data, qint64 maxSize ); + +private: + class Private; + kdtools::pimpl_ptr<Private> d; +}; + +#endif // __KDTOOLSCORE_KDSAVEFILE_H__ diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdselfrestarter.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdselfrestarter.cpp new file mode 100644 index 000000000..fcd66f238 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdselfrestarter.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdselfrestarter.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QProcess> + +class KDSelfRestarter::Private { +public: + Private( int argc, char** argv ) : restartOnQuit( false ) { + executable = QString::fromLocal8Bit( argv[0] ); + workingPath = QDir::currentPath(); + for ( int i = 1; i < argc; ++i ) + args << QString::fromLocal8Bit( argv[i] ); + } + + Private() + { + executable = qApp->applicationFilePath(); + workingPath = QDir::currentPath(); + args = qApp->arguments().mid( 1 ); + } + + ~Private() { + if ( restartOnQuit ) + QProcess::startDetached( executable, args, workingPath ); + } + + QString executable; + QStringList args; + bool restartOnQuit; + QString workingPath; + static KDSelfRestarter* instance; +}; + +KDSelfRestarter* KDSelfRestarter::Private::instance = 0; + +KDSelfRestarter::KDSelfRestarter( int argc, char** argv ) : d( new Private( argc, argv ) ) { + Q_ASSERT_X( !Private::instance, Q_FUNC_INFO, "Cannot create more than one KDSelfRestarter instance" ); + Private::instance = this; +} + +KDSelfRestarter::~KDSelfRestarter() +{ + Q_ASSERT_X( Private::instance == this, Q_FUNC_INFO, "Cannot create more than one KDSelfRestarter instance" ); + Private::instance = 0; +} + +void KDSelfRestarter::setRestartOnQuit( bool restart ) { + Q_ASSERT_X( Private::instance, Q_FUNC_INFO, "KDSelfRestarter instance must be created in main()" ); + if ( Private::instance ) + Private::instance->d->restartOnQuit = restart; +} + +bool KDSelfRestarter::restartOnQuit() { + return Private::instance ? Private::instance->d->restartOnQuit : false; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdselfrestarter.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdselfrestarter.h new file mode 100644 index 000000000..0582c778d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdselfrestarter.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE_KDSELFRESTARTER_H__ +#define __KDTOOLSCORE_KDSELFRESTARTER_H__ + +#include <KDToolsCore/pimpl_ptr.h> + +class KDTOOLSCORE_EXPORT KDSelfRestarter { +public: + KDSelfRestarter( int argc, char** argv ); + ~KDSelfRestarter(); + + static bool restartOnQuit(); + static void setRestartOnQuit( bool restart ); + +private: + Q_DISABLE_COPY(KDSelfRestarter); + class Private; + kdtools::pimpl_ptr<Private> d; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.cpp new file mode 100644 index 000000000..e694d79fa --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdsysinfo.h" + +#include <algorithm> + +KDSysInfo::KDSysInfo() +{ +} + +KDSysInfo::~KDSysInfo() +{ +} + +#include <QDir> +#include <QDebug> + +QDebug operator<<( QDebug dbg, KDSysInfo::OperatingSystemType type ) +{ + switch( type ) + { + case KDSysInfo::Linux: + return dbg << "Linux"; + case KDSysInfo::MacOSX: + return dbg << "Mac OS X"; + case KDSysInfo::Windows: + return dbg << "Windows"; + default: + return dbg << "<unknown>"; + } +} + +QDebug operator<<( QDebug dbg, KDSysInfo::ArchitectureType type ) +{ + switch( type ) + { + case KDSysInfo::ARM: + return dbg << "ARM"; + case KDSysInfo::Intel: + return dbg << "Intel"; + case KDSysInfo::AMD64: + return dbg << "AMD64"; + case KDSysInfo::IA64: + return dbg << "IA64"; + case KDSysInfo::PowerPC: + return dbg << "Power PC"; + case KDSysInfo::Motorola68k: + return dbg << "Motorola 68k"; + default: + return dbg << "<unknown>"; + } +} + +QDebug operator<<( QDebug dbg, KDSysInfo::Volume volume ) +{ + return dbg << "KDSysInfo::Volume(" << volume.path() << ")"; +} + +QPair< KDByteSize, KDByteSize > volumeSpace( const QString& volume ); +QString volumeName( const QString& volume ); + +class KDSysInfo::Volume::Private : public QSharedData +{ +public: + QString p; + QString name; + KDByteSize size; + KDByteSize availableSpace; +}; + + +KDSysInfo::Volume::Volume() + : d( new Private ) +{ +} + +KDSysInfo::Volume::Volume( const Volume& other ) + : d( other.d ) +{ +} + +KDSysInfo::Volume::~Volume() +{ +} + +void KDSysInfo::Volume::swap( KDSysInfo::Volume& other ) +{ + std::swap( d, other.d ); +} + +KDSysInfo::Volume& KDSysInfo::Volume::operator=( const KDSysInfo::Volume& other ) +{ + KDSysInfo::Volume tmp( other ); + swap( tmp ); + return *this; +} + +void KDSysInfo::Volume::setPath( const QString& path ) +{ + d->p = path; +} + +bool KDSysInfo::Volume::operator == ( const Volume& other ) const +{ + return d->name == other.d->name && d->p == other.d->p; +} + +void KDSysInfo::Volume::setName( const QString& name ) +{ + d->name = name; +} + +QString KDSysInfo::Volume::name() const +{ + return d->name; +} + +QString KDSysInfo::Volume::path() const +{ + return d->p; +} + +KDByteSize KDSysInfo::Volume::size() const +{ + return d->size; +} + +void KDSysInfo::Volume::setSize( const KDByteSize& size ) +{ + d->size = size; +} + +KDByteSize KDSysInfo::Volume::availableSpace() const +{ + return d->availableSpace; +} + +void KDSysInfo::Volume::setAvailableSpace( const KDByteSize& available ) +{ + d->availableSpace = available; +} + +struct PathLongerThan +{ + bool operator()( const KDSysInfo::Volume& lhs, const KDSysInfo::Volume& rhs ) const + { + return lhs.path().length() > rhs.path().length(); + } +}; + +KDSysInfo::Volume KDSysInfo::Volume::fromPath( const QString& path ) +{ + QList< KDSysInfo::Volume > volumes = mountedVolumes(); + // sort by length to get the longest mount point (not just "/") first + std::sort( volumes.begin(), volumes.end(), PathLongerThan() ); + for( QList< KDSysInfo::Volume >::const_iterator it = volumes.constBegin(); it != volumes.constEnd(); ++it ) + { +#ifdef Q_WS_WIN + if( QDir::toNativeSeparators( path ).toLower().startsWith( it->path().toLower() ) ) +#else + if( path.startsWith( it->path() ) ) +#endif + return *it; + } + return KDSysInfo::Volume(); +} + +QDebug operator<<( QDebug dbg, KDSysInfo::ProcessInfo process ) +{ + return dbg << "KDSysInfo::ProcessInfo(" << process.id << ", " << process.name << ")"; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h new file mode 100644 index 000000000..2324ccfc8 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KDSYSINFO_H +#define KDSYSINFO_H + +#include <KDToolsCore/kdtoolsglobal.h> + +#include <QtCore/QString> +#include <QtCore/QSysInfo> +#include <QtCore/QSharedDataPointer> + +#include "kdbytesize.h" + +class KDVersion; + +class KDTOOLSCORE_EXPORT KDSysInfo : public QSysInfo +{ +private: + KDSysInfo(); + +public: + ~KDSysInfo(); + + enum OperatingSystemType + { + UnknownOperatingSystem = -1, + Linux, + MacOSX, + Windows + }; + + enum ArchitectureType + { + UnknownArchitecture = -1, + ARM, + Intel, + AMD64, + IA64, + PowerPC, + Motorola68k + }; + + class KDTOOLSCORE_EXPORT Volume + { + friend class ::KDSysInfo; + public: + static Volume fromPath( const QString& path ); + + Volume(); + Volume( const Volume& other ); + ~Volume(); + + QString name() const; + QString path() const; + KDByteSize size() const; + KDByteSize availableSpace() const; + + void swap( Volume& other ); + Volume& operator=( const Volume& other ); + bool operator == ( const Volume& other ) const; + + private: + void setPath( const QString& path ); + void setName( const QString& name ); + void setSize( const KDByteSize& size ); + void setAvailableSpace( const KDByteSize& available ); + + private: + class Private; + QSharedDataPointer<Private> d; + }; + + struct ProcessInfo + { + quint32 id; + QString name; + }; + + static OperatingSystemType osType(); + static KDVersion osVersion(); + static QString osDescription(); + static ArchitectureType architecture(); + + static KDByteSize installedMemory(); + static QList< Volume > mountedVolumes(); + static QList< ProcessInfo > runningProcesses(); +}; + +class QDebug; + +QDebug operator<<( QDebug dbg, KDSysInfo::OperatingSystemType type ); +QDebug operator<<( QDebug dbg, KDSysInfo::ArchitectureType type ); +QDebug operator<<( QDebug dbg, KDSysInfo::Volume volume ); +QDebug operator<<( QDebug dbg, KDSysInfo::ProcessInfo process ); + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_mac.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_mac.cpp new file mode 100644 index 000000000..024d1dd4d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_mac.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdsysinfo.h" + +#include "kdbytesize.h" +#include "kdversion.h" + +#include <Carbon/Carbon.h> + +static QString qt_mac_hfsunistr_to_qstring( const HFSUniStr255* hfs ) +{ + const QChar* const charPointer = reinterpret_cast< const QChar* >( hfs->unicode ); + return QString( charPointer, hfs->length ); +} + +KDSysInfo::OperatingSystemType KDSysInfo::osType() +{ + return MacOSX; +} + +KDVersion KDSysInfo::osVersion() +{ + SInt32 major = 0; + SInt32 minor = 0; + SInt32 bugfix = 0; + Gestalt( gestaltSystemVersionMajor, &major ); + Gestalt( gestaltSystemVersionMinor, &minor ); + Gestalt( gestaltSystemVersionBugFix, &bugfix ); + + QStringList result; + result << QString::number( major ); + result << QString::number( minor ); + result << QString::number( bugfix ); + + return KDVersion::fromString( result.join( QChar::fromLatin1( '.' ) ) ); +} + +QString KDSysInfo::osDescription() +{ + return QObject::tr( "Mac OS X Version %1" ).arg( osVersion().toString() ); +} + +KDByteSize KDSysInfo::installedMemory() +{ + SInt32 mb = 0; + Gestalt( gestaltPhysicalRAMSizeInMegabytes, &mb ); + return KDByteSize( static_cast< quint64 >( mb ) * 1024LL * 1024LL ); +} + +KDSysInfo::ArchitectureType KDSysInfo::architecture() +{ + SInt32 arch = 0; + Gestalt( gestaltSysArchitecture, &arch ); + switch( arch ) + { + case gestalt68k: + return Motorola68k; + case gestaltPowerPC: + return PowerPC; + case gestaltIntel: + return Intel; + default: + return UnknownArchitecture; + } +} + +QList< KDSysInfo::Volume > KDSysInfo::mountedVolumes() +{ + QList< KDSysInfo::Volume > result; + FSVolumeRefNum volume; + FSVolumeInfo info; + HFSUniStr255 volName; + FSRef ref; + int i = 0; + + while( FSGetVolumeInfo( kFSInvalidVolumeRefNum, ++i, &volume, kFSVolInfoFSInfo, &info, &volName, &ref ) == 0 ) + { + UInt8 path[ PATH_MAX + 1 ]; + if( FSRefMakePath( &ref, path, PATH_MAX ) == 0 ) + { + const QString name = qt_mac_hfsunistr_to_qstring( &volName ); + const QString mount = QString::fromLocal8Bit( reinterpret_cast< char* >( path ) ); + FSGetVolumeInfo( volume, 0, 0, kFSVolInfoSizes, &info, 0, 0 ); + Volume v; + v.setName( name ); + v.setPath( mount ); + v.setSize( KDByteSize( info.totalBytes ) ); + v.setAvailableSpace( KDByteSize( info.freeBytes ) ); + result.push_back( v ); + } + } + + return result; +} + +QList< KDSysInfo::ProcessInfo > KDSysInfo::runningProcesses() +{ + return QList< KDSysInfo::ProcessInfo >(); +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_win.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_win.cpp new file mode 100644 index 000000000..3456b89cb --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_win.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdsysinfo.h" + +#include "kdbytesize.h" +#include "kdversion.h" + +#include <windows.h> +#include <Tlhelp32.h> +#include <Psapi.h> + +#include <QDir> +#include <QPair> + +#include <QtCore/QLibrary> + +#define KDSYSINFO_PROCESS_QUERY_LIMITED_INFORMATION (0x1000) + +KDSysInfo::OperatingSystemType KDSysInfo::osType() +{ + return Windows; +} + +KDVersion KDSysInfo::osVersion() +{ + OSVERSIONINFO info; + memset( &info, 0, sizeof( info ) ); + info.dwOSVersionInfoSize = sizeof( info ); + GetVersionEx( &info ); + return KDVersion::fromString( QString::fromLatin1( "%1.%2" ).arg( info.dwMajorVersion ).arg( info.dwMinorVersion ) ); +} + +QString KDSysInfo::osDescription() +{ + switch( QSysInfo::windowsVersion() ) + { + case QSysInfo::WV_32s: + return QObject::tr( "Windows 3.1" ); + case QSysInfo::WV_95: + return QObject::tr( "Windows 95" ); + case QSysInfo::WV_98: + return QObject::tr( "Windows 98" ); + case QSysInfo::WV_Me: + return QObject::tr( "Windows ME" ); + case QSysInfo::WV_NT: + return QObject::tr( "Windows NT" ); + case QSysInfo::WV_2000: + return QObject::tr( "Windows 2000" ); + case QSysInfo::WV_XP: + return QObject::tr( "Windows XP" ); + case QSysInfo::WV_2003: + return QObject::tr( "Windows 2003" ); + case QSysInfo::WV_VISTA: + return QObject::tr( "Windows Vista" ); + case QSysInfo::WV_WINDOWS7: + return QObject::tr( "Windows 7" ); + case QSysInfo::WV_CE: + return QObject::tr( "Windows CE" ); + case QSysInfo::WV_CENET: + return QObject::tr( "Windows CE .NET" ); + case QSysInfo::WV_CE_5: + return QObject::tr( "Windows CE 5" ); + case QSysInfo::WV_CE_6: + return QObject::tr( "Windows CE 6" ); + default: + return QObject::tr( "Windows" ); + } +} + +KDByteSize KDSysInfo::installedMemory() +{ + MEMORYSTATUSEX status; + status.dwLength = sizeof( status ); + GlobalMemoryStatusEx( &status ); + return KDByteSize( status.ullTotalPhys ); +} + +KDSysInfo::ArchitectureType KDSysInfo::architecture() +{ +#if defined( _M_X64 ) + return AMD64; +#elif defined( _M_IX86 ) + return Intel; +#elif defined( _M_IA64 ) + return IA64; +#elif defined( _M_PPC ) + return PowerPC; +#elif defined( _M_ARM ) + return ARM; +#else + return UnknownArchitecture; +#endif +} + +QPair< KDByteSize, KDByteSize > volumeSpace( const QString& volume ) +{ + QPair< KDByteSize, KDByteSize > result; + ULARGE_INTEGER bytes; + ULARGE_INTEGER freebytes; + if( GetDiskFreeSpaceExA( qPrintable( volume ), 0, &bytes, &freebytes ) != 0 ) + { + result.first = KDByteSize( bytes.QuadPart ); + result.second = KDByteSize( freebytes.QuadPart ); + } + return result; +} + +QString volumeName( const QString& volume ) +{ + char name[ MAX_PATH + 1 ] = ""; + DWORD dummy; + char dummy2[ MAX_PATH + 1 ] = ""; + GetVolumeInformationA( qPrintable( volume ), name, MAX_PATH + 1, &dummy, &dummy, &dummy, dummy2, MAX_PATH + 1 ); + QString vName = QString::fromLatin1( name ); + if( vName.isEmpty() ) + { + const uint driveType = GetDriveTypeA( qPrintable( volume ) ); + switch( driveType ) + { + case DRIVE_REMOVABLE: + vName = QObject::tr( "Removable Disk" ); + break; + case DRIVE_CDROM: + vName = QObject::tr( "CD Drive" ); + break; + case DRIVE_FIXED: + vName = QObject::tr( "Local Disk" ); + break; + default: + return volume.left( 2 ); + } + } + return QString::fromLatin1( "%2 (%1)" ).arg( volume.left( 2 ), vName ); +} + +QList< KDSysInfo::Volume > KDSysInfo::mountedVolumes() +{ + QList< Volume > result; + const QFileInfoList drives = QDir::drives(); + for( QFileInfoList::const_iterator it = drives.constBegin(); it != drives.constEnd(); ++it ) + { + Volume volume; + const QString path = QDir::toNativeSeparators( it->path() ); + volume.setPath( path ); + volume.setName( volumeName( path ) ); + const QPair< KDByteSize, KDByteSize > sizes = volumeSpace( path ); + volume.setSize( sizes.first ); + volume.setAvailableSpace( sizes.second ); + result.push_back( volume ); + } + return result; +} + +struct EnumWindowsProcParam +{ + QList< KDSysInfo::ProcessInfo > processes; + QList< quint32 > seenIDs; +}; + +//BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam ) +//{ +// EnumWindowsProcParam* const list = reinterpret_cast< EnumWindowsProcParam* >( lParam ); + +// KDSysInfo::ProcessInfo info; + +// // process id +// DWORD procID = 0; +// GetWindowThreadProcessId( hWnd, &procID ); +// info.id = procID; + +// if( list->seenIDs.contains( info.id ) ) +// return TRUE; +// list->seenIDs.push_back( info.id ); + +// HINSTANCE inst = (HINSTANCE)GetWindowLongA( hWnd, GWL_HINSTANCE ); +// // process name +// HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, procID ); + +// static char buffer[ 1024 ]; +// if( GetModuleFileNameExA( process, inst, buffer, sizeof( buffer ) ) ) +// info.name = QString::fromLocal8Bit( buffer ); +// CloseHandle( process ); + +// list->processes.push_back( info ); +// return TRUE; +//} + +//QList< KDSysInfo::ProcessInfo > KDSysInfo::runningProcesses() +//{ +// EnumWindowsProcParam param; +// HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); +// if ( !snapshot ) +// return param.processes; +// PROCESSENTRY32 processStruct; +// processStruct.dwSize = sizeof( PROCESSENTRY32 ); +// bool foundProcess = Process32First( snapshot, &processStruct ); +// while ( foundProcess ) +// { +// //const QString executableName = QString::fromWCharArray( processStruct.szExeFile ); +// KDSysInfo::ProcessInfo info; +// HANDLE procHandle = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, false, processStruct.th32ProcessID ); +// char buffer[ 1024 ]; +// DWORD bufferSize = 1024; +// const bool succ = QueryFullProcessImageNameA( procHandle, 0, buffer, &bufferSize ); +// if ( succ ) +// { +// const QString executablepath = QString::fromLatin1( buffer ); +// const quint32 pid = processStruct.th32ProcessID; +// param.seenIDs.append( pid ); + +// info.id = pid; +// info.name = executablepath; +// param.processes.append( info ); +// } +// CloseHandle( procHandle ); + +// foundProcess = Process32Next( snapshot, &processStruct ); +// } +// if ( snapshot ) +// CloseHandle( snapshot ); +//// EnumDesktopWindows( 0, &EnumWindowsProc, reinterpret_cast< LPARAM >( ¶m ) ); +// return param.processes; +//} +typedef BOOL ( WINAPI *QueryFullProcessImageNamePtr )( HANDLE, DWORD, char*, PDWORD ); +typedef DWORD ( WINAPI *GetProcessImageFileNamePtr )( HANDLE, char*, DWORD ); +QList< KDSysInfo::ProcessInfo > KDSysInfo::runningProcesses() +{ + EnumWindowsProcParam param; + HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); + if ( !snapshot ) + return param.processes; + PROCESSENTRY32 processStruct; + processStruct.dwSize = sizeof( PROCESSENTRY32 ); + bool foundProcess = Process32First( snapshot, &processStruct ); + const DWORD bufferSize = 1024; + char driveBuffer[ bufferSize ]; + QStringList deviceList; + if ( QSysInfo::windowsVersion() <= QSysInfo::WV_5_2 ) + { + DWORD size = GetLogicalDriveStringsA( bufferSize, driveBuffer ); + deviceList = QString::fromLatin1( driveBuffer, size ).split( QLatin1Char( (char)0 ), QString::SkipEmptyParts ); + } + + QLibrary kernel32( QLatin1String( "Kernel32.dll" ) ); + kernel32.load(); + void* pQueryFullProcessImageNameA = kernel32.resolve( "QueryFullProcessImageNameA" ); + + QLibrary psapi( QLatin1String ( "Psapi.dll" ) ); + psapi.load(); + void* pGetProcessImageFileNamePtr = psapi.resolve( "GetProcessImageFileNameA" ); + QueryFullProcessImageNamePtr callPtr = ( QueryFullProcessImageNamePtr ) pQueryFullProcessImageNameA; + GetProcessImageFileNamePtr callPtrXp = ( GetProcessImageFileNamePtr ) pGetProcessImageFileNamePtr; + while ( foundProcess ) + { + HANDLE procHandle = OpenProcess( QSysInfo::windowsVersion() > QSysInfo::WV_5_2 ? + KDSYSINFO_PROCESS_QUERY_LIMITED_INFORMATION : + PROCESS_QUERY_INFORMATION + , false, + processStruct.th32ProcessID ); + + char buffer[ 1024 ]; + DWORD bufferSize = 1024; + bool succ = false; + QString whichFailed; + QString executablePath; + KDSysInfo::ProcessInfo info; + if ( QSysInfo::windowsVersion() > QSysInfo::WV_5_2 ) + { + succ = callPtr( procHandle, 0, buffer, &bufferSize ); + executablePath = QString::fromLatin1( buffer ); + } + else + { + if (pGetProcessImageFileNamePtr) { + succ = callPtrXp( procHandle, buffer, bufferSize ); + executablePath = QString::fromLatin1( buffer ); + for ( int i = 0; i < deviceList.count(); ++i ) + { + executablePath.replace( QString::fromLatin1( "\\Device\\HarddiskVolume%1\\" ).arg( i + 1 ), deviceList.at( i ) ); + } + } + + } + if ( succ ) + { + const quint32 pid = processStruct.th32ProcessID; + param.seenIDs.append( pid ); + + info.id = pid; + info.name = executablePath; + param.processes.append( info ); + } + + CloseHandle( procHandle ); + foundProcess = Process32Next( snapshot, &processStruct ); + + } + if ( snapshot ) + CloseHandle( snapshot ); + + kernel32.unload(); + return param.processes; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_x11.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_x11.cpp new file mode 100644 index 000000000..a9d609d4d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo_x11.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdsysinfo.h" + +#include "kdbytesize.h" +#include "kdversion.h" + +#include <sys/utsname.h> +#include <sys/statvfs.h> + +#include <QtCore/QFile> +#include <QtCore/QTextStream> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> + +KDSysInfo::OperatingSystemType KDSysInfo::osType() +{ +#if defined( Q_OS_LINUX ) + return Linux; +#else + UnknownOperatingSystem; +#endif +} + +KDVersion KDSysInfo::osVersion() +{ +#if defined( Q_OS_LINUX ) + struct utsname info; + uname( &info ); + QString v = QString::fromLatin1( info.release ); + if( v.contains( QString::fromLatin1( "-" ) ) ) + v = v.mid( 0, v.indexOf( QString::fromLatin1( "-" ) ) ); + + return KDVersion::fromString( v ); +#else + return KDVersion(); +#endif +} + +QString KDSysInfo::osDescription() +{ +#if defined( Q_OS_LINUX ) + return QObject::tr( "Linux %1" ).arg( osVersion().toString() ); +#else + return QString(); +#endif +} + +KDByteSize KDSysInfo::installedMemory() +{ +#ifdef Q_OS_LINUX + QFile f( QLatin1String( "/proc/meminfo" ) ); + f.open( QIODevice::ReadOnly ); + QTextStream stream( &f ); + while( true ) + { + const QString s = stream.readLine(); + if( !s.startsWith( QLatin1String( "MemTotal:" ) ) ) + continue; + else if( s.isEmpty() ) + return KDByteSize(); + + const QStringList parts = s.split( QLatin1Char( ' ' ), QString::SkipEmptyParts ); + return KDByteSize( parts.at(1).toInt() * 1024LL ); + } +#else + quint64 physmem; + size_t len = sizeof physmem; + static int mib[2] = { CTL_HW, HW_MEMSIZE }; + sysctl( mib, 2, &physmem, &len, 0, 0 ); + return KDByteSize( physmem ); +#endif + return KDByteSize(); +} + +KDSysInfo::ArchitectureType KDSysInfo::architecture() +{ + return UnknownArchitecture; +} + +QList< KDSysInfo::Volume > KDSysInfo::mountedVolumes() +{ + QList< Volume > result; + + QFile f( QLatin1String( "/etc/mtab" ) ); + if ( !f.open( QIODevice::ReadOnly ) ) { + qCritical( "%s: Could not open %s: %s", Q_FUNC_INFO, qPrintable(f.fileName()), qPrintable(f.errorString()) ); + return QList<KDSysInfo::Volume>(); //better error-handling? + } + + QTextStream stream( &f ); + while( true ) + { + const QString s = stream.readLine(); + if ( s.isNull() ) + return result; + + if( !s.startsWith( QLatin1Char( '/' ) ) ) + continue; + + const QStringList parts = s.split( QLatin1Char( ' ' ), QString::SkipEmptyParts ); + + Volume v; + v.setName( parts.at( 1 ) ); + v.setPath( parts.at( 1 ) ); + + struct statvfs data; + if( statvfs( qPrintable( v.name() ), &data ) == 0 ) + { + v.setSize( KDByteSize( static_cast< quint64 >( data.f_blocks ) * data.f_bsize ) ); + v.setAvailableSpace( KDByteSize( static_cast< quint64> ( data.f_bfree ) * data.f_bsize ) ); + } + + result.push_back( v ); + } + + return result; +} + +QList< KDSysInfo::ProcessInfo > KDSysInfo::runningProcesses() +{ + QList< KDSysInfo::ProcessInfo > processes; + QDir procDir( QLatin1String( "/proc" ) ); + const QFileInfoList procCont = procDir.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable ); + QRegExp validator( QLatin1String( "[0-9]+" ) ); + Q_FOREACH( const QFileInfo& info, procCont ) + { + if ( validator.exactMatch( info.fileName() ) ) + { + const QString linkPath = QDir( info.absoluteFilePath() ).absoluteFilePath( QLatin1String( "exe" ) ); + const QFileInfo linkInfo( linkPath ); + if ( linkInfo.exists() ) + { + KDSysInfo::ProcessInfo processInfo; + processInfo.name = linkInfo.symLinkTarget(); + processInfo.id = info.fileName().toInt(); + processes.append( processInfo ); + } + } + } + return processes; +} + diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdtoolsglobal.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdtoolsglobal.cpp new file mode 100644 index 000000000..f41d7974e --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdtoolsglobal.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdtoolsglobal.h" + +#include <QByteArray> + +#include <algorithm> + +namespace { + struct Version { + unsigned char v[3]; + }; + + static inline bool operator<( const Version & lhs, const Version & rhs ) { + return std::lexicographical_compare( lhs.v, lhs.v + 3, rhs.v, rhs.v + 3 ); + } + static inline bool operator==( const Version & lhs, const Version & rhs ) { + return std::equal( lhs.v, lhs.v + 3, rhs.v ); + } + KDTOOLS_MAKE_RELATION_OPERATORS( Version, static inline ) +} + +static Version kdParseQtVersion( const char * const version ) { + if ( !version || qstrlen( version ) < 5 || version[1] != '.' || version[3] != '.' || ( version[5] != 0 && version[5] != '.' && version[5] != '-' ) ) + return Version(); // parse error + const Version result = { { version[0] - '0', version[2] - '0', version[4] - '0' } }; + return result; +} + +bool _kdCheckQtVersion_impl( int major, int minor, int patchlevel ) { + static const Version actual = kdParseQtVersion( qVersion() ); // do this only once each run... + const Version requested = { { major, minor, patchlevel } }; + return actual >= requested; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdtoolsglobal.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdtoolsglobal.h new file mode 100644 index 000000000..3d687da39 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdtoolsglobal.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_KDTOOLSGLOBAL_H__ +#define __KDTOOLS_KDTOOLSGLOBAL_H__ + +#include <QtCore/QtGlobal> + +#define KDAB_DISABLE_COPY( x ) private: x( const x & ); x & operator=( const x & ) + +#ifdef KDTOOLS_SHARED +# ifdef BUILD_SHARED_KDTOOLSCORE +# define KDTOOLSCORE_EXPORT Q_DECL_EXPORT +# else +# define KDTOOLSCORE_EXPORT Q_DECL_IMPORT +# endif +# ifdef BUILD_SHARED_KDTOOLSGUI +# define KDTOOLSGUI_EXPORT Q_DECL_EXPORT +# else +# define KDTOOLSGUI_EXPORT Q_DECL_IMPORT +# endif +# ifdef BUILD_SHARED_KDTOOLSXML +# define KDTOOLSXML_EXPORT Q_DECL_EXPORT +# else +# define KDTOOLSXML_EXPORT Q_DECL_IMPORT +# endif +# ifdef BUILD_SHARED_KDUPDATER +# define KDTOOLS_UPDATER_EXPORT Q_DECL_EXPORT +# else +# define KDTOOLS_UPDATER_EXPORT Q_DECL_IMPORT +# endif +#else // KDTOOLS_SHARED +# define KDTOOLSCORE_EXPORT +# define KDTOOLSGUI_EXPORT +# define KDTOOLSXML_EXPORT +# define KDTOOLS_UPDATER_EXPORT +#endif // KDTOOLS_SHARED + +#define MAKEINCLUDES_EXPORT + +#define DOXYGEN_PROPERTY( x ) +#ifdef DOXYGEN_RUN +# define KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( func ) operator unspecified_bool_type() const { return func; } +# define KDAB_USING_SAFE_BOOL_OPERATOR( Class ) operator unspecified_bool_type() const; +#else +# define KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( func ) \ + private: struct __safe_bool_dummy__ { void nonnull() {} }; \ + typedef void ( __safe_bool_dummy__::*unspecified_bool_type )(); \ + public: \ + operator unspecified_bool_type() const { \ + return ( func ) ? &__safe_bool_dummy__::nonnull : 0 ; \ + } +#define KDAB_USING_SAFE_BOOL_OPERATOR( Class ) \ + using Class::operator Class::unspecified_bool_type; +#endif + +#define KDTOOLS_MAKE_RELATION_OPERATORS( Class, linkage ) \ + linkage bool operator>( const Class & lhs, const Class & rhs ) { \ + return operator<( rhs, lhs ); \ + } \ + linkage bool operator!=( const Class & lhs, const Class & rhs ) { \ + return !operator==( lhs, rhs ); \ + } \ + linkage bool operator<=( const Class & lhs, const Class & rhs ) { \ + return !operator>( lhs, rhs ); \ + } \ + linkage bool operator>=( const Class & lhs, const Class & rhs ) { \ + return !operator<( lhs, rhs ); \ + } + +template <typename T> +inline T & __kdtools__dereference_for_methodcall( T & o ) { + return o; +} + +template <typename T> +inline T & __kdtools__dereference_for_methodcall( T * o ) { + return *o; +} + +#define KDAB_SET_OBJECT_NAME( x ) __kdtools__dereference_for_methodcall( x ).setObjectName( QLatin1String( #x ) ) + +KDTOOLSCORE_EXPORT bool _kdCheckQtVersion_impl( int major, int minor=0, int patchlevel=0 ); +static inline bool kdCheckQtVersion( unsigned int major, unsigned int minor=0, unsigned int patchlevel=0 ) { + return (major<<16|minor<<8|patchlevel) <= static_cast<unsigned int>(QT_VERSION) + || _kdCheckQtVersion_impl( major, minor, patchlevel ); +} + +#define KDTOOLS_DECLARE_PRIVATE_BASE( Class ) \ +protected: \ + class Private; \ + Private * d_func() { return _d; } \ + const Private * d_func() const { return _d; } \ + Class( Private * _d_, bool b ) : _d( _d_ ) { init(b); } \ +private: \ + void init(bool); \ +private: \ + Private * _d + +#define KDTOOLS_DECLARE_PRIVATE_DERIVED( Class, Base ) \ +protected: \ + class Private; \ + Private * d_func() { \ + return reinterpret_cast<Private*>( Base::d_func() ); \ + } \ + const Private * d_func() const { \ + return reinterpret_cast<const Private*>( Base::d_func() ); \ + } \ + Class( Private * _d_, bool b ) \ + : Base( reinterpret_cast<Base::Private*>(_d_), b ) { init(b); } \ +private: \ + void init(bool) + + +#endif /* __KDTOOLS_KDTOOLSGLOBAL_H__ */ + diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdversion.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdversion.cpp new file mode 100644 index 000000000..53f91412f --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdversion.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdversion.h" + +#include <QDebug> + +KDVersion::KDVersion() +{ +} + +KDVersion::~KDVersion() +{ +} + +bool KDVersion::isNull() const +{ + return parts.isEmpty(); +} + +QString KDVersion::toString() const +{ + return parts.join( QChar::fromLatin1( '.' ) ); +} + +KDVersion KDVersion::fromString( const QString& string ) +{ + KDVersion result; + result.parts = string.split( QChar::fromLatin1( '.' ) ); + return result; +} + +bool operator<( const KDVersion& lhs, const KDVersion& rhs ) +{ + for( int i = 0; i < lhs.parts.count(); ++i ) + { + if( i == rhs.parts.count() ) + return false; + + const QString& l = lhs.parts[ i ]; + const QString& r = lhs.parts[ i ]; + + bool okl = false; + bool okr = false; + const int li = l.toInt( &okl ); + const int ri = r.toInt( &okr ); + + if( okl && okr ) + { + if( li < ri ) + return true; + } + else if( QString::localeAwareCompare( l, r ) < 0 ) + { + return true; + } + } + return true; +} + +bool operator==( const KDVersion& lhs, const KDVersion& rhs ) +{ + return lhs.parts == rhs.parts; +} + +QDebug operator<<( QDebug debug, const KDVersion& version ) +{ + return debug << "KDVersion(" << version.toString().toLatin1().data() << ")"; + return debug; +} diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdversion.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdversion.h new file mode 100644 index 000000000..b71cb1933 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdversion.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KDVERSION_H +#define KDVERSION_H + +#include <KDToolsCore/kdtoolsglobal.h> + +#include <QtCore/QStringList> + +class KDTOOLSCORE_EXPORT KDVersion +{ + friend bool operator<( const KDVersion& lhs, const KDVersion& rhs ); + friend bool operator==( const KDVersion& lhs, const KDVersion& rhs ); +public: + KDVersion(); + virtual ~KDVersion(); + + bool isNull() const; + + QString toString() const; + static KDVersion fromString( const QString& string ); + +private: + QStringList parts; +}; + +bool operator<( const KDVersion& lhs, const KDVersion& rhs ); +bool operator==( const KDVersion& lhs, const KDVersion& rhs ); + +QDebug operator<<( QDebug debug, const KDVersion& version ); + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdwatchdog.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdwatchdog.cpp new file mode 100644 index 000000000..7c0abd486 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdwatchdog.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdwatchdog.h" + +#include <QTimer> + +/*! + \internal + */ +class KDWatchdog::Private +{ +public: + Private() + : active( true ) + { + } + + bool active; + QTimer timer; +}; + +/*! + Creates a new KDWatchdog with \a parent. + */ +KDWatchdog::KDWatchdog( QObject* parent ) + : QObject( parent ) +{ + d->timer.setSingleShot( true ); + connect( &d->timer, SIGNAL( timeout() ), this, SIGNAL( timeout() ) ); + setTimeoutInterval( 30000 ); + activate(); +} + +/*! + Destroys the KDWatchdog. + */ +KDWatchdog::~KDWatchdog() +{ +} + +bool KDWatchdog::isActive() const +{ + return d->active; +} + +int KDWatchdog::timeoutInterval() const +{ + return d->timer.interval(); +} + +void KDWatchdog::setTimeoutInterval( int interval ) +{ + d->timer.setInterval( interval ); + resetTimeoutTimer(); +} + +void KDWatchdog::setActive( bool active ) +{ + if( d->active == active ) + return; + d->active = active; + if( d->active ) + d->timer.start(); + else + d->timer.stop(); +} + +/*! + Activates the watchdog. + */ +void KDWatchdog::activate() +{ + setActive( true ); +} + +/*! + Deactivates the watchdog. + */ +void KDWatchdog::deactivate() +{ + setActive( false ); +} + +/*! + Resets the watchdog timer. This slot should be called whenever + the watched event occures. + If the watchdog has been stop()'ed, nothing happens. + */ +void KDWatchdog::resetTimeoutTimer() +{ + if( d->active ) + d->timer.start(); +} + +#include "moc_kdwatchdog.cpp" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdwatchdog.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdwatchdog.h new file mode 100644 index 000000000..4319b0e8b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdwatchdog.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS__CORE__KDWATCHDOG_H__ +#define __KDTOOLS__CORE__KDWATCHDOG_H__ + +#include <QtCore/QObject> + +#include <KDToolsCore/pimpl_ptr.h> + +class KDTOOLSCORE_EXPORT KDWatchdog : public QObject +{ + Q_OBJECT + Q_PROPERTY( bool active READ isActive WRITE setActive ) + Q_PROPERTY( int timeoutInterval READ timeoutInterval WRITE setTimeoutInterval ) + +public: + explicit KDWatchdog( QObject* parent = 0 ); + ~KDWatchdog(); + + bool isActive() const; + int timeoutInterval() const; + +public Q_SLOTS: + void setTimeoutInterval( int interval ); + + void setActive( bool active ); + void activate(); + void deactivate(); + + void resetTimeoutTimer(); + +Q_SIGNALS: + void timeout(); + +private: + class Private; + kdtools::pimpl_ptr< Private > d; +}; + +#endif /* __KDTOOLS__CORE__KDWATCHDOG_H__ */ diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr b/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr new file mode 100644 index 000000000..aa2f3984a --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr @@ -0,0 +1 @@ +#include "pimpl_ptr.h" diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr.cpp b/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr.cpp new file mode 100644 index 000000000..1a7f017a1 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "pimpl_ptr.h" + +/*! + \class pimpl_ptr: + \ingroup core smartptr + \brief Owning pointer for private implementations + \since_c 2.1 + + (The exception safety of this class has not been evaluated yet.) + + pimpl_ptr is a smart immutable pointer, which owns the contained object. Unlike other smart pointers, + it creates a standard constructed object when instanciated via the + \link pimpl_ptr() standard constructor\endlink. + Additionally, pimpl_ptr respects constness of the pointer object and returns \c const \c T* for + a const pimpl_ptr object. + + The content of a pimpl_ptr cannot be changed during it's lifetime. + + \section general-use General Use + + The general use case of pimpl_ptr is the "Pimpl Idiom", i.e. hiding the private implementation of a class + from the user's compiler which see \c MyClass as + + \code + class MyClass + { + public: + MyClass(); + ~MyClass(); + + // public class API + int value() const; + + private: + class Private; // defined later + kdtools::pimpl_ptr< Private > d; + }; + \endcode + + but not the private parts of it. These can only be seen (and accessed) by the code knowing \c MyClass::Private: + + \code + class MyClass::Private + { + public: + int value; + }; + + MyClass::MyClass() + { + // d was automatically filled with new Private + d->value = 42; + } + + MyClass::~MyClass() + { + // the content of d gets deleted automatically + } + + int MyClass::value() const + { + // access the private part: + // since MyClass::value() is const, the returned pointee is const, too + return d->value; + } + \endcode + +*/ + +/*! + \fn pimpl_ptr::pimpl_ptr() + + Default constructor. Constructs a pimpl_tr that contains (owns) a standard constructed + instance of \c T. + + \post \c *this owns a new object. +*/ + +/*! + \fn pimpl_ptr::pimpl_ptr( T * t ) + + Constructor. Constructs a pimpl_ptr that contains (owns) \a t. + + \post get() == obj +*/ + +/*! + \fn pimpl_ptr::~pimpl_ptr() + + Destructor. + + \post The object previously owned by \c *this has been deleted. +*/ + +/*! + \fn const T * pimpl_ptr::get() const + + \returns a const pointer to the contained (owned) object. + \overload +*/ + +/*! + \fn T * pimpl_ptr::get() + + \returns a pointer to the contained (owned) object. +*/ + +/*! + \fn const T & pimpl_ptr::operator*() const + + Dereference operator. Returns \link get() *get()\endlink. + \overload +*/ + +/*! + \fn T & pimpl_ptr::operator*() + + Dereference operator. Returns \link get() *get()\endlink. +*/ + +/*! + \fn const T * pimpl_ptr::operator->() const + + Member-by-pointer operator. Returns get(). + \overload +*/ + +/*! + \fn T * pimpl_ptr::operator->() + + Member-by-pointer operator. Returns get(). +*/ + +#ifdef KDTOOLSCORE_UNITTESTS + +#include <KDUnitTest/test.h> + +#include <QObject> +#include <QPointer> + +namespace +{ + struct ConstTester + { + bool isConst() + { + return false; + } + + bool isConst() const + { + return true; + } + }; +} + +KDAB_UNITTEST_SIMPLE( pimpl_ptr, "kdcoretools" ) { + + { + kdtools::pimpl_ptr< QObject > p; + assertNotNull( p.get() ); + assertNull( p->parent() ); + } + + + { + QPointer< QObject > o; + { + kdtools::pimpl_ptr< QObject > qobject( new QObject ); + o = qobject.get(); + assertEqual( o, qobject.operator->() ); + assertEqual( o, &(qobject.operator*()) ); + } + assertNull( o ); + } + + { + const kdtools::pimpl_ptr< QObject > qobject( new QObject ); + const QObject* o = qobject.get(); + assertEqual( o, qobject.operator->() ); + assertEqual( o, &(qobject.operator*()) ); + } + + { + kdtools::pimpl_ptr< QObject > o1; + assertTrue( o1 ); + kdtools::pimpl_ptr< QObject > o2( 0 ); + assertFalse( o2 ); + } + + { + const kdtools::pimpl_ptr< ConstTester > o1; + kdtools::pimpl_ptr< ConstTester > o2; + assertTrue( o1->isConst() ); + assertFalse( o2->isConst() ); + assertTrue( (*o1).isConst() ); + assertFalse( (*o2).isConst() ); + assertTrue( o1.get()->isConst() ); + assertFalse( o2.get()->isConst() ); + } +} + +#endif // KDTOOLSCORE_UNITTESTS diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr.h new file mode 100644 index 000000000..195b967d1 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/pimpl_ptr.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLSCORE__PIMPL_PTR_H__ +#define __KDTOOLSCORE__PIMPL_PTR_H__ + +#include <KDToolsCore/kdtoolsglobal.h> + +#ifndef DOXYGEN_RUN +namespace kdtools { +#endif + + template <typename T> + class MAKEINCLUDES_EXPORT pimpl_ptr { + KDAB_DISABLE_COPY( pimpl_ptr ); + T * d; + public: + pimpl_ptr() : d( new T ) {} + explicit pimpl_ptr( T * t ) : d( t ) {} + ~pimpl_ptr() { delete d; d = 0; } + + T * get() { return d; } + const T * get() const { return d; } + + T * operator->() { return get(); } + const T * operator->() const { return get(); } + + T & operator*() { return *get(); } + const T & operator*() const { return *get(); } + + KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( get() ) + }; + + // these are not implemented, so's we can catch their use at + // link-time. Leaving them undeclared would open up a comparison + // via operator unspecified-bool-type(). + template <typename T, typename S> + void operator==( const pimpl_ptr<T> &, const pimpl_ptr<S> & ); + template <typename T, typename S> + void operator!=( const pimpl_ptr<T> &, const pimpl_ptr<S> & ); + +#ifndef DOXYGEN_RUN +} // namespace kdtools +#endif + +#endif /* __KDTOOLSCORE__PIMPL_PTR_H__ */ + diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/Application b/installerbuilder/libinstaller/kdtools/KDUpdater/Application new file mode 100644 index 000000000..7545e9447 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/Application @@ -0,0 +1 @@ +#include "kdupdaterapplication.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/FileDownloader b/installerbuilder/libinstaller/kdtools/KDUpdater/FileDownloader new file mode 100644 index 000000000..beca4f9c1 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/FileDownloader @@ -0,0 +1 @@ +#include "kdupdaterfiledownloader.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/FileDownloaderFactory b/installerbuilder/libinstaller/kdtools/KDUpdater/FileDownloaderFactory new file mode 100644 index 000000000..65dbb7a4e --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/FileDownloaderFactory @@ -0,0 +1 @@ +#include "kdupdaterfiledownloaderfactory.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/KDUpdater b/installerbuilder/libinstaller/kdtools/KDUpdater/KDUpdater new file mode 100644 index 000000000..a327ece5b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/KDUpdater @@ -0,0 +1,20 @@ +#include "kdupdater.h" +#include "kdupdaterapplication.h" +#include "kdupdatercrypto.h" +#include "kdupdaterfiledownloader.h" +#include "kdupdaterfiledownloaderfactory.h" +#include "kdupdaterpackagesinfo.h" +#include "kdupdaterpackagesview.h" +#include "kdupdatersignatureverificationresult.h" +#include "kdupdatersignatureverificationrunnable.h" +#include "kdupdatersignatureverifier.h" +#include "kdupdatertask.h" +#include "kdupdaterupdate.h" +#include "kdupdaterupdatefinder.h" +#include "kdupdaterupdateinstaller.h" +#include "kdupdaterupdateoperation.h" +#include "kdupdaterupdateoperationfactory.h" +#include "kdupdaterupdateoperations.h" +#include "kdupdaterupdatesdialog.h" +#include "kdupdaterupdatesourcesinfo.h" +#include "kdupdaterupdatesourcesview.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/KDUpdater.pri b/installerbuilder/libinstaller/kdtools/KDUpdater/KDUpdater.pri new file mode 100644 index 000000000..d97399040 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/KDUpdater.pri @@ -0,0 +1,73 @@ +DEPENDPATH += $$PWD +INCLUDEPATH += $$PWD + +CONFIG( shared, static|shared) { + DEFINES += BUILD_SHARED_KDUPDATER +} + +HEADERS += $$PWD/kdupdater.h \ + $$PWD/kdupdaterapplication.h \ + $$PWD/kdupdatercrypto.h \ + $$PWD/kdupdaterfiledownloader.h \ + $$PWD/kdupdaterfiledownloader_p.h \ + $$PWD/kdupdaterfiledownloaderfactory.h \ + $$PWD/kdupdaterpackagesinfo.h \ + $$PWD/kdupdaterpackagesview.h \ + $$PWD/kdupdatersignatureverificationresult.h \ + $$PWD/kdupdatersignatureverifier.h \ + $$PWD/kdupdaterupdate.h \ + $$PWD/kdupdaterupdateoperation.h \ + $$PWD/kdupdaterupdateoperationfactory.h \ + $$PWD/kdupdaterupdateoperations.h \ + $$PWD/kdupdaterupdatesourcesinfo.h \ + $$PWD/kdupdatertask.h \ + $$PWD/kdupdatersignatureverificationrunnable.h \ + $$PWD/kdupdaterupdatefinder.h \ + $$PWD/kdupdaterupdatesinfo_p.h \ + $$PWD/kdupdaterupdateinstaller.h \ + $$PWD/kdupdaterufuncompressor_p.h \ + $$PWD/kdupdaterupdatesdialog.h \ + $$PWD/kdupdaterupdatesourcesview.h \ + $$PWD/kdupdaterufcompresscommon_p.h \ + $$PWD/environment.h + +SOURCES += $$PWD/kdupdaterapplication.cpp \ + $$PWD/kdupdatercrypto.cpp \ + $$PWD/kdupdaterfiledownloader.cpp \ + $$PWD/kdupdaterfiledownloaderfactory.cpp \ + $$PWD/kdupdaterpackagesinfo.cpp \ + $$PWD/kdupdaterpackagesview.cpp \ + $$PWD/kdupdatersignatureverificationresult.cpp \ + $$PWD/kdupdatersignatureverifier.cpp \ + $$PWD/kdupdaterupdate.cpp \ + $$PWD/kdupdaterupdateoperation.cpp \ + $$PWD/kdupdaterupdateoperationfactory.cpp \ + $$PWD/kdupdaterupdateoperations.cpp \ + $$PWD/kdupdaterupdatesourcesinfo.cpp \ + $$PWD/kdupdatertask.cpp \ + $$PWD/kdupdatersignatureverificationrunnable.cpp \ + $$PWD/kdupdaterupdatefinder.cpp \ + $$PWD/kdupdaterupdatesinfo.cpp \ + $$PWD/kdupdaterupdateinstaller.cpp \ + $$PWD/kdupdaterufuncompressor.cpp \ + $$PWD/kdupdaterupdatesdialog.cpp \ + $$PWD/kdupdaterupdatesourcesview.cpp \ + $$PWD/kdupdaterufcompresscommon.cpp \ + $$PWD/environment.cpp + + + +FORMS += $$PWD/updatesdialog.ui \ + $$PWD/addupdatesourcedialog.ui + +DEFINES += KDUPDATERGUITEXTBROWSER \ + KDUPDATERVIEW=QTextBrowser +QT += gui + +TRY_INCLUDEPATHS = /include /usr/include /usr/local/include $$QMAKE_INCDIR $$INCLUDEPATH +win32:TRY_INCLUDEPATHS += $$PWD/../../3rdparty/openssl-0.9.8k/src/include +linux-lsb-g++:TRY_INCLUDEPATHS = $$QMAKE_INCDIR $$INCLUDEPATH +for(p, TRY_INCLUDEPATHS) { + pp = $$join(p, "", "", "/openssl") + exists($$pp):INCLUDEPATH *= $$p +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/PackagesInfo b/installerbuilder/libinstaller/kdtools/KDUpdater/PackagesInfo new file mode 100644 index 000000000..8e709882d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/PackagesInfo @@ -0,0 +1 @@ +#include "kdupdaterpackagesinfo.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/SignatureVerificationResult b/installerbuilder/libinstaller/kdtools/KDUpdater/SignatureVerificationResult new file mode 100644 index 000000000..5a71cdfde --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/SignatureVerificationResult @@ -0,0 +1 @@ +#include "kdupdatersignatureverificationresult.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/SignatureVerifier b/installerbuilder/libinstaller/kdtools/KDUpdater/SignatureVerifier new file mode 100644 index 000000000..3d9d7f946 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/SignatureVerifier @@ -0,0 +1 @@ +#include "kdupdatersignatureverifier.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/Update b/installerbuilder/libinstaller/kdtools/KDUpdater/Update new file mode 100644 index 000000000..8328b020b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/Update @@ -0,0 +1 @@ +#include "kdupdaterupdate.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateFinder b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateFinder new file mode 100644 index 000000000..71666b90d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateFinder @@ -0,0 +1 @@ +#include "kdupdaterupdatefinder.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateOperation b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateOperation new file mode 100644 index 000000000..fd82bafdb --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateOperation @@ -0,0 +1 @@ +#include "kdupdaterupdateoperation.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateOperationFactory b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateOperationFactory new file mode 100644 index 000000000..bd13c19c5 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateOperationFactory @@ -0,0 +1 @@ +#include "kdupdaterupdateoperationfactory.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateSourcesInfo b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateSourcesInfo new file mode 100644 index 000000000..b422ec594 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdateSourcesInfo @@ -0,0 +1 @@ +#include "kdupdaterupdatesourcesinfo.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/UpdatesDialog b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdatesDialog new file mode 100644 index 000000000..b1fbb7803 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/UpdatesDialog @@ -0,0 +1 @@ +#include "kdupdaterupdatesdialog.h" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/addupdatesourcedialog.ui b/installerbuilder/libinstaller/kdtools/KDUpdater/addupdatesourcedialog.ui new file mode 100644 index 000000000..c0de05109 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/addupdatesourcedialog.ui @@ -0,0 +1,193 @@ +<ui version="4.0" > + <class>AddUpdateSourceDialog</class> + <widget class="QDialog" name="AddUpdateSourceDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>239</height> + </rect> + </property> + <property name="windowTitle" > + <string>Add Update Source</string> + </property> + <layout class="QVBoxLayout" > + <item> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>&Name</string> + </property> + <property name="buddy" > + <cstring>txtName</cstring> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="txtName" > + <property name="font" > + <font> + <pointsize>10</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>&Title</string> + </property> + <property name="buddy" > + <cstring>txtTitle</cstring> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="txtTitle" > + <property name="font" > + <font> + <pointsize>9</pointsize> + <italic>false</italic> + </font> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>&Description</string> + </property> + <property name="alignment" > + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="buddy" > + <cstring>txtDescription</cstring> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QTextEdit" name="txtDescription" /> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_4" > + <property name="text" > + <string>&URL</string> + </property> + <property name="buddy" > + <cstring>txtUrl</cstring> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLineEdit" name="txtUrl" > + <property name="palette" > + <palette> + <active> + <colorrole role="Text" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>0</red> + <green>45</green> + <blue>195</blue> + </color> + </brush> + </colorrole> + </active> + <inactive> + <colorrole role="Text" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>0</red> + <green>45</green> + <blue>195</blue> + </color> + </brush> + </colorrole> + </inactive> + <disabled> + <colorrole role="Text" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>106</red> + <green>104</green> + <blue>100</blue> + </color> + </brush> + </colorrole> + </disabled> + </palette> + </property> + <property name="font" > + <font> + <underline>true</underline> + </font> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AddUpdateSourceDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>257</x> + <y>229</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AddUpdateSourceDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>325</x> + <y>229</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/environment.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/environment.cpp new file mode 100644 index 000000000..c1ddc11f1 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/environment.cpp @@ -0,0 +1,55 @@ +#include "environment.h" + +#include <QHash> +#include <QProcess> +#include <QProcessEnvironment> + +using namespace KDUpdater; + +class Environment::Private { +public: + static Environment* s_instance; + QHash<QString, QString> tempValues; +}; + +Environment* Environment::Private::s_instance = 0; + +Environment::Environment() + : d( new Private ) +{ +} + +Environment::~Environment() { + delete d; +} + +Environment* Environment::instance() { + if ( !Private::s_instance ) + Private::s_instance = new Environment; + return Private::s_instance; +} + +QString Environment::value( const QString& key, const QString& defvalue ) const { + const QHash<QString,QString>::ConstIterator it = d->tempValues.constFind( key ); + if ( it != d->tempValues.constEnd() ) + return *it; + else + return QProcessEnvironment::systemEnvironment().value( key, defvalue ); +} + +void Environment::setTemporaryValue( const QString& key, const QString& value ) { + d->tempValues.insert( key, value ); +} + +QProcessEnvironment Environment::applyTo( const QProcessEnvironment& qpe_ ) const { + QProcessEnvironment qpe( qpe_ ); + QHash<QString, QString>::ConstIterator it = d->tempValues.constBegin(); + const QHash<QString, QString>::ConstIterator end = d->tempValues.constEnd(); + for ( ; it != end; ++it ) + qpe.insert( it.key(), it.value() ); + return qpe; +} + +void Environment::applyTo( QProcess* proc ) { + proc->setProcessEnvironment( applyTo( proc->processEnvironment() ) ); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h b/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h new file mode 100644 index 000000000..001afbbc2 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h @@ -0,0 +1,36 @@ +#ifndef LIBINSTALLER_ENVIRONMENT_H +#define LIBINSTALLER_ENVIRONMENT_H + +#include "kdupdaterupdateoperation.h" + +#include <QString> + +class QProcess; +class QProcessEnvironment; + +namespace KDUpdater { + +class KDTOOLS_UPDATER_EXPORT Environment { + public: + static Environment* instance(); + + ~Environment(); + + QString value( const QString& key, const QString& defaultValue=QString() ) const; + void setTemporaryValue( const QString& key, const QString& value ); + + QProcessEnvironment applyTo( const QProcessEnvironment& qpe ) const; + void applyTo( QProcess* process ); + + private: + Environment(); + + private: + Q_DISABLE_COPY(Environment) + class Private; + Private* const d; +}; + +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdater.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdater.h new file mode 100644 index 000000000..9e0007155 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdater.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_H +#define KD_UPDATER_H + +#include <QtGlobal> + +#ifdef KDTOOLS_SHARED + #if defined(BUILD_SHARED_KDUPDATER) + #define KDTOOLS_UPDATER_EXPORT Q_DECL_EXPORT + #else + #define KDTOOLS_UPDATER_EXPORT Q_DECL_IMPORT + #endif +#else + #define KDTOOLS_UPDATER_EXPORT +#endif + +namespace KDUpdater +{ + enum Error + { + ENoError = 0, + ECannotStartTask, + ECannotPauseTask, + ECannotResumeTask, + ECannotStopTask, + EUnknown + }; + + enum UpdateType { + PackageUpdate = 0x1, + CompatUpdate = 0x2, + NewPackage = 0x4, + AllUpdate = PackageUpdate | CompatUpdate + }; + Q_DECLARE_FLAGS( UpdateTypes, UpdateType ) + Q_DECLARE_OPERATORS_FOR_FLAGS( UpdateTypes ) + + KDTOOLS_UPDATER_EXPORT int compareVersion(const QString& v1, const QString& v2); +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.cpp new file mode 100644 index 000000000..cf4379c90 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterapplication.h" +#include "kdupdaterpackagesinfo.h" +#include "kdupdatersignatureverifier.h" +#include "kdupdaterupdatesourcesinfo.h" + +#include <QCoreApplication> +#include <QDebug> +#include <QDir> +#include <QSettings> + +using namespace KDUpdater; + +/*! + \defgroup kdupdater KD Updater + \since_l 2.1 + + "KD Updater" is a library from KDAB that helps in enabling automatic updates for your applications. + All classes belonging to the "KD Updater" library are defined in the \ref KDUpdater namespace. + + TODO: this comes from the former mainpage: +KD Updater is a tool to automatically detect, retrieve, install and activate updates to software +applications and libraries. It is intended to be used with Qt based applications, and developed +against the Qt 4 series. It is a library that users link to their application. It uses only accepted +standard protocols, and does not require any other 3rd party libraries that are not shipped with +Qt. + +KD Updater is generic in that it is not developed for one specific application. The first version is +experimental. If it proves successful and useful, it will be integrated into KDAB's KD Tools +package. It is part of KDAB's strategy to provide functionality missing in Qt that is required for +medium-to-large scale software systems. +*/ + +/*! + \namespace KDUpdater +*/ + +ConfigurationInterface::~ConfigurationInterface() +{ +} + +namespace { + class DefaultConfigImpl : public ConfigurationInterface + { + public: + QVariant value( const QString& key ) const + { + QSettings settings; + settings.beginGroup( QLatin1String("KDUpdater") ); + return settings.value( key ); + } + + void setValue( const QString& key, const QVariant& value ) + { + QSettings settings; + settings.beginGroup( QLatin1String("KDUpdater") ); + settings.setValue( key, value ); + } + }; +} + +/*! + \class KDUpdater::Application kdupdaterapplication.h KDUpdaterApplication + \ingroup kdupdater + \brief This class represents an application that can be updated. + + A KDUpdater application is an application that needs to interact with one or more update servers and + downloads/installs updates This class helps in describing an application in terms of: + \li application Directory + \li packages XML file name and its corresponding KDUpdater::PackagesInfo object + \li update Sources XML file name and its corresponding KDUpdater::UpdateSourcesInfo object + + User can also retrieve some informations from this class: + \li application name + \li application version + \li compat level +*/ + +struct Application::ApplicationData +{ + explicit ApplicationData( ConfigurationInterface* config ) : + packagesInfo(0), + updateSourcesInfo(0), + configurationInterface( config ? config : new DefaultConfigImpl ) + { + const QStringList oldFiles = configurationInterface->value( QLatin1String("FilesForDelayedDeletion") ).toStringList(); + Q_FOREACH( const QString& i, oldFiles ) { //TODO this should happen asnyc and report errors, I guess + QFile f( i ); + if ( f.exists() && !f.remove() ) { + qWarning( "Could not delete file %s: %s", qPrintable(i), qPrintable(f.errorString()) ); + filesForDelayedDeletion << i; // try again next time + } + } + configurationInterface->setValue( QLatin1String("FilesForDelayedDeletion"), filesForDelayedDeletion ); + } + + ~ApplicationData() + { + delete packagesInfo; + delete updateSourcesInfo; + qDeleteAll( verifiers ); + delete configurationInterface; + } + + static Application* instance; + + QString applicationDirectory; + PackagesInfo* packagesInfo; + UpdateSourcesInfo* updateSourcesInfo; + QMap<Application::SignatureTarget, const SignatureVerifier*> verifiers; + QStringList filesForDelayedDeletion; + ConfigurationInterface* configurationInterface; +}; + +Application* Application::ApplicationData::instance = 0; + +/*! + Constructor of the Application class. The class will be constructed and configured to + assume the application directory to be the directory in which the application exists. The + application name is assumed to be QCoreApplication::applicationName() +*/ +Application::Application(ConfigurationInterface* config, QObject* p) : QObject(p) +{ + d = new Application::ApplicationData( config ); + d->packagesInfo = new PackagesInfo(this); + d->updateSourcesInfo = new UpdateSourcesInfo(this); + + setApplicationDirectory( QCoreApplication::applicationDirPath() ); + + ApplicationData::instance = this; +} + +/*! + Destructor +*/ +Application::~Application() +{ + if( this == ApplicationData::instance ) + ApplicationData::instance = 0; + delete d; +} + +/*! + Returns a previousle created Application instance. + */ +Application* Application::instance() +{ + return ApplicationData::instance; +} + +/*! + Changes the applicationDirPath directory to \c dir. Packages.xml and UpdateSources.xml found in the new + application directory will be used. +*/ +void Application::setApplicationDirectory(const QString& dir) +{ + if( d->applicationDirectory == dir ) + return; + + QDir dirObj(dir); + + // FIXME: Perhaps we should check whether dir exists on the local file system or not + d->applicationDirectory = dirObj.absolutePath(); + setPackagesXMLFileName( QString::fromLatin1( "%1/Packages.xml" ).arg(dir) ); + setUpdateSourcesXMLFileName( QString::fromLatin1( "%1/UpdateSources.xml" ).arg(dir) ); +} + +/*! + Returns path to the application directory. +*/ +QString Application::applicationDirectory() const +{ + return d->applicationDirectory; +} + +/*! + Returns the application name. +*/ +QString Application::applicationName() const +{ + if( d->packagesInfo->isValid() ) + return d->packagesInfo->applicationName(); + + return QCoreApplication::applicationName(); +} + +/*! + Returns the application version. +*/ +QString Application::applicationVersion() const +{ + if( d->packagesInfo->isValid() ) + return d->packagesInfo->applicationVersion(); + + return QString(); +} + +const SignatureVerifier* Application::signatureVerifier( SignatureTarget target ) const +{ + return d->verifiers.value( target ); +} + +void Application::setSignatureVerifier( SignatureTarget target, const SignatureVerifier* v ) +{ + delete d->verifiers.value( target ); + d->verifiers.remove( target ); + if ( v ) + d->verifiers.insert( target, v->clone() ); +} + +/*! + Returns the compat level that this application is in. +*/ +int Application::compatLevel() const +{ + if(d->packagesInfo->isValid()) + return d->packagesInfo->compatLevel(); + + return -1; +} + +void Application::addUpdateSource( const QString& name, const QString& title, + const QString& description, const QUrl& url, int priority ) +{ + UpdateSourceInfo info; + info.name = name; + info.title = title; + info.description = description; + info.url = url; + info.priority = priority; + d->updateSourcesInfo->addUpdateSourceInfo( info ); +} + + +/*! + Sets the file name of the Package XML file for this application. By default this is assumed to be + Packages.xml in the application directory. + + \sa KDUpdater::PackagesInfo::setFileName() +*/ +void Application::setPackagesXMLFileName(const QString& fileName) +{ + d->packagesInfo->setFileName( fileName ); +} + +/*! + Returns the Package XML file name. +*/ +QString Application::packagesXMLFileName() const +{ + return d->packagesInfo->fileName(); +} + +/*! + Returns the \ref PackagesInfo object associated with this application. +*/ +PackagesInfo* Application::packagesInfo() const +{ + return d->packagesInfo; +} + +/*! + Sets the file name of the Package XML file for this application. By default this is assumed to be + Packages.xml in the application directory. + + \sa KDUpdater::UpdateSourcesInfo::setFileName() +*/ +void Application::setUpdateSourcesXMLFileName(const QString& fileName) +{ + d->updateSourcesInfo->setFileName( fileName ); +} + +/*! + Returns the Update Sources XML file name. +*/ +QString Application::updateSourcesXMLFileName() const +{ + return d->updateSourcesInfo->fileName(); +} + +/*! + Returns the \ref UpdateSourcesInfo object associated with this application. +*/ +UpdateSourcesInfo* Application::updateSourcesInfo() const +{ + return d->updateSourcesInfo; +} + +void Application::printError( int errorCode, const QString& error ) +{ + qDebug() << errorCode << error; +} + +QStringList Application::filesForDelayedDeletion() const +{ + return d->filesForDelayedDeletion; +} + +void Application::addFilesForDelayedDeletion( const QStringList& files ) +{ + d->filesForDelayedDeletion << files; + d->configurationInterface->setValue( QLatin1String("FilesForDelayedDeletion"), d->filesForDelayedDeletion ); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h new file mode 100644 index 000000000..3970236d3 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_APPLICATION_H +#define KD_UPDATER_APPLICATION_H + +#include "kdupdater.h" +#include <QObject> + +class QUrl; + +namespace KDUpdater +{ + class PackagesInfo; + class SignatureVerifier; + class UpdateSourcesInfo; + + class ConfigurationInterface { + public: + virtual ~ConfigurationInterface(); + virtual QVariant value( const QString& key ) const = 0; + virtual void setValue( const QString& key, const QVariant& value ) = 0; + }; + + class KDTOOLS_UPDATER_EXPORT Application : public QObject + { + Q_OBJECT + + public: + enum SignatureTarget { + Metadata, + Packages + }; + + explicit Application( ConfigurationInterface* config=0, QObject* parent=0); + ~Application(); + + static Application* instance(); + + void setApplicationDirectory(const QString& dir); + QString applicationDirectory() const; + + QString applicationName() const; + QString applicationVersion() const; + int compatLevel() const; + + const SignatureVerifier* signatureVerifier( SignatureTarget target ) const; + void setSignatureVerifier( SignatureTarget target, const SignatureVerifier* verifier ); + + void setPackagesXMLFileName(const QString& fileName); + QString packagesXMLFileName() const; + PackagesInfo* packagesInfo() const; + + void addUpdateSource( const QString& name, const QString& title, + const QString& description, const QUrl& url, int priority = -1 ); + + void setUpdateSourcesXMLFileName(const QString& fileName); + QString updateSourcesXMLFileName() const; + UpdateSourcesInfo* updateSourcesInfo() const; + + QStringList filesForDelayedDeletion() const; + void addFilesForDelayedDeletion( const QStringList& files ); + + public Q_SLOTS: + void printError( int errorCode, const QString& error ); + + private: + struct ApplicationData; + ApplicationData* d; + }; + +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.cpp new file mode 100644 index 000000000..8e5832084 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.cpp @@ -0,0 +1,743 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdatercrypto.h" + +#include <openssl/ssl.h> +#include <openssl/rsa.h> + +#include <QCoreApplication> +#include <QCryptographicHash> +#include <QDebug> +#include <QStringList> +#include <QFile> +#include <QMutex> +#include <QLibrary> +#include <QDir> +#include <QTemporaryFile> + +//BEGIN code taken from qsslsocket_openssl_symbols.cpp + +#define DUMMYARG + +#define CLEARFUNC(func) \ + _kd_##func = 0; + +#define RESOLVEFUNC(func) \ + if (!(_kd_##func = _kd_PTR_##func(libs->resolve(#func)))) \ + qWarning("QSslSocket: cannot resolve "#func); + +#define DEFINEFUNC(ret, func, arg, a, err, funcret) \ + typedef ret (*_kd_PTR_##func)(arg); \ + _kd_PTR_##func _kd_##func; \ + ret kd_##func(arg) { \ + Q_ASSERT(_kd_##func); \ + funcret _kd_##func(a); \ + } + +#define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \ + typedef ret (*_kd_PTR_##func)(arg1, arg2, arg3); \ + _kd_PTR_##func _kd_##func; \ + ret kd_##func(arg1, arg2, arg3) { \ + Q_ASSERT(_kd_##func); \ + funcret _kd_##func(a, b, c); \ + } + +#define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \ + typedef ret (*_kd_PTR_##func)(arg1, arg2, arg3, arg4); \ + _kd_PTR_##func _kd_##func; \ + ret kd_##func(arg1, arg2, arg3, arg4) { \ + Q_ASSERT(_kd_##func); \ + funcret _kd_##func(a, b, c, d); \ + } + +#define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \ + typedef ret (*_kd_PTR_##func)(arg1, arg2, arg3, arg4, arg5); \ + _kd_PTR_##func _kd_##func; \ + ret kd_##func(arg1, arg2, arg3, arg4, arg5) { \ + Q_ASSERT(_kd_##func); \ + funcret _kd_##func(a, b, c, d, e); \ + } + +#define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \ + typedef ret (*_kd_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6); \ + _kd_PTR_##func _kd_##func; \ + ret kd_##func(arg1, arg2, arg3, arg4, arg5, arg6) { \ + Q_ASSERT(_kd_##func); \ + funcret _kd_##func(a, b, c, d, e, f); \ + } + + +# ifdef Q_OS_UNIX +static bool libGreaterThan(const QString &lhs, const QString &rhs) +{ + QStringList lhsparts = lhs.split(QLatin1Char('.')); + QStringList rhsparts = rhs.split(QLatin1Char('.')); + Q_ASSERT(lhsparts.count() > 1 && rhsparts.count() > 1); + + for (int i = 1; i < rhsparts.count(); ++i) { + if (lhsparts.count() <= i) + // left hand side is shorter, so it's less than rhs + return false; + + bool ok = false; + int b = 0; + int a = lhsparts.at(i).toInt(&ok); + if (ok) + b = rhsparts.at(i).toInt(&ok); + if (ok) { + // both toInt succeeded + if (a == b) + continue; + return a > b; + } else { + // compare as strings; + if (lhsparts.at(i) == rhsparts.at(i)) + continue; + return lhsparts.at(i) > rhsparts.at(i); + } + } + + // they compared strictly equally so far + // lhs cannot be less than rhs + return true; +} +static QStringList findAllLibSsl() +{ + QStringList paths; +# ifdef Q_OS_DARWIN + paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH")) + .split(QLatin1Char(':'), QString::SkipEmptyParts); +# else + paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH")) + .split(QLatin1Char(':'), QString::SkipEmptyParts); +# endif + paths << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib"); + + QStringList foundSsls; + Q_FOREACH (const QString &path, paths) { + QDir dir = QDir(path); + QStringList entryList = dir.entryList(QStringList() << QLatin1String("libssl.*"), QDir::Files); + + qSort(entryList.begin(), entryList.end(), libGreaterThan); + Q_FOREACH (const QString &entry, entryList) + foundSsls << path + QLatin1Char('/') + entry; + } + + return foundSsls; +} +#endif + +class KDLibraryLoader : public QObject +{ + static QMutex* mutex; +public: + KDLibraryLoader() + { + const QMutexLocker ml( mutex ); + if( tempDir.isEmpty() ) + { + QTemporaryFile file( QDir::temp().absoluteFilePath( QString::fromLatin1( "templibsXXXXXX" ) ) ); + file.open(); + tempDir = file.fileName(); + file.close(); + file.remove(); + } + QDir::temp().mkdir( QFileInfo( tempDir ).fileName() ); + } + + ~KDLibraryLoader() + { + const QMutexLocker ml( mutex ); + for( QVector< QLibrary* >::const_iterator it = loadedLibraries.begin(); it != loadedLibraries.end(); ++it ) + { + QLibrary* const lib = *it; + lib->unload(); + delete lib; + } + + for( QStringList::const_iterator it = temporaryFiles.begin(); it != temporaryFiles.end(); ++it ) + { + QFile file( *it ); + file.setPermissions( file.permissions() | QFile::WriteOwner | QFile::WriteUser ); + file.remove(); + } + + QDir::temp().rmdir( QFileInfo( tempDir ).fileName() ); + } + + bool load( const QString& filename ) + { + const QMutexLocker ml( mutex ); + // does it work out of the box? great! + QLibrary* const lib = new QLibrary; + loadedLibraries.push_back( lib ); + lib->setFileName( filename ); + if( lib->load() ) + return true; + + // if this failed, we copy the filename to a different place + // it might as well come from a resource + const QString realFilename = QFileInfo( QDir( tempDir ), QFileInfo( filename ).fileName() ).absoluteFilePath(); + + QFile::copy( filename, realFilename ); + temporaryFiles.push_back( realFilename ); + + lib->setFileName( realFilename ); + if( lib->load() ) + return true; + + // if all fails... sorry, we can't perform magic. Seriously! + QFile::remove( realFilename ); + temporaryFiles.pop_back(); + + delete lib; + loadedLibraries.pop_back(); + + return false; + } + + template< typename VERSION > + bool load( const QString& filename, VERSION version ) + { + const QMutexLocker ml( mutex ); + // does it work out of the box? great! + QLibrary* const lib = new QLibrary; + loadedLibraries.push_back( lib ); + lib->setFileNameAndVersion( filename, version ); + if( lib->load() ) + return true; + + // if this failed, we copy the filename to a different place + // it might as well come from a resource + const QString realFilename = QFileInfo( QDir( tempDir ), QFileInfo( filename ).fileName() ).absoluteFilePath(); + + QFile::copy( filename, realFilename ); + temporaryFiles.push_back( realFilename ); + + lib->setFileNameAndVersion( realFilename, version ); + if( lib->load() ) + return true; + + // if all fails... sorry, we can't perform magic. Seriously! + QFile::remove( realFilename ); + temporaryFiles.pop_back(); + + delete lib; + loadedLibraries.pop_back(); + + return false; + + } + + void* resolve( const char* symbol ) + { + const QMutexLocker ml( mutex ); + for( QVector< QLibrary* >::const_iterator it = loadedLibraries.begin(); it != loadedLibraries.end(); ++it ) + { + QLibrary* const lib = *it; + void* const ptr = lib->resolve( symbol ); + if( ptr != 0 ) + return ptr; + } + return 0; + } + +private: + QVector< QLibrary* > loadedLibraries; + QStringList temporaryFiles; + static QString tempDir; +}; + +QString KDLibraryLoader::tempDir; + +// TODO: this one get leaked +QMutex* KDLibraryLoader::mutex = new QMutex; + +static KDLibraryLoader* loadOpenSsl() +{ + KDLibraryLoader* result = new KDLibraryLoader; +#ifdef Q_OS_WIN + if( result->load( QLatin1String( ":/openssllibs/libeay32.dll" ) ) && result->load( QLatin1String( ":/openssllibs/libssl32.dll" ) ) ) + return result; + + delete result; + return 0; + +# elif defined(Q_OS_UNIX) + // Try to find the libssl library on the system. + // + // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that + // is, libssl.so on most Unix systems. However, the .so file isn't present in + // user installations because it's considered a development file. + // + // The right thing to do is to load the library at the major version we know how + // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h) + // + // However, OpenSSL is a well-known case of binary-compatibility breakage. To + // avoid such problems, many system integrators and Linux distributions change + // the soname of the binary, letting the full version number be the soname. So + // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that + // reason, we will search a few common paths (see findAllLibSsl() above) in hopes + // we find one that works. + // + // It is important, however, to try the canonical name and the unversioned name + // without going through the loop. By not specifying a path, we let the system + // dlopen(3) function determine it for us. This will include any DT_RUNPATH or + // DT_RPATH tags on our library header as well as other system-specific search + // paths. See the man page for dlopen(3) on your system for more information. + +#ifdef SHLIB_VERSION_NUMBER + // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER> + + if( result->load( QLatin1String( "ssl" ), QLatin1String( SHLIB_VERSION_NUMBER ) ) && + result->load( QLatin1String( "crypto" ), QLatin1String( SHLIB_VERSION_NUMBER ) ) ) { + // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found + return result; + } else { + delete result; + result = new KDLibraryLoader; + } +#endif + + // second attempt: find the development files libssl.so and libcrypto.so + if( result->load( QLatin1String( "ssl" ), -1 ) && + result->load( QLatin1String( "crypto" ), -1 ) ) { + // libssl.so.0 and libcrypto.so.0 found + return result; + } else { + delete result; + result = new KDLibraryLoader; + } + + // third attempt: loop on the most common library paths and find libssl + QStringList sslList = findAllLibSsl(); + Q_FOREACH (const QString &ssl, sslList) { + QString crypto = ssl; + crypto.replace(QLatin1String("ssl"), QLatin1String("crypto")); + if( result->load( ssl, -1 ) && + result->load( crypto ), -1 ) { + // libssl.so.0 and libcrypto.so.0 found + return result; + } else { + delete result; + result = new KDLibraryLoader; + } + } + + // failed to load anything + delete result; + return 0; + +# else + // not implemented for this platform yet + return 0; +# endif +} + +//END code taken from qsslsocket_openssl_symbols.cpp + +class KDUpdaterCrypto::Private +{ + public: + KDUpdaterCrypto *q; + + QByteArray m_privateKey; + QByteArray m_privatePassword; + RSA *m_private_key; + BIO *m_private_key_bio; + + QByteArray m_publicKey; + RSA *m_public_key; + BIO *m_public_key_bio; + + KDLibraryLoader* libLoader; + + const PasswordProvider* passwordProvider; + + DEFINEFUNC(int, SSL_library_init, void, DUMMYARG, return -1, return) + DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return) + DEFINEFUNC(BIO *, BIO_new, BIO_METHOD *a, a, return 0, return) + DEFINEFUNC(BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return) + DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return) + DEFINEFUNC(RSA*, RSA_new, void, DUMMYARG, return 0, return) + DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG) + DEFINEFUNC(int, RSA_size, RSA *a, a, return 0, return) + DEFINEFUNC5(int, RSA_public_encrypt, int flen, flen, unsigned char *from, from, unsigned char *to, to, RSA *rsa, rsa, int padding, padding, return -1, return) + DEFINEFUNC5(int, RSA_private_decrypt, int flen, flen, unsigned char *from, from, unsigned char *to, to, RSA *rsa, rsa, int padding, padding, return -1, return) + DEFINEFUNC6(int, RSA_sign, int type, type, const unsigned char *m, m, unsigned int m_len, m_len, unsigned char *sigret, sigret, unsigned int *siglen, siglen, RSA *rsa, rsa, return 0, return) + DEFINEFUNC6(int, RSA_verify, int type, type, const unsigned char *m, m, unsigned int m_len, m_len, unsigned char *sigret, sigret, unsigned int siglen, siglen, RSA *rsa, rsa, return 0, return) + DEFINEFUNC4(RSA*, PEM_read_bio_RSAPrivateKey, BIO *bp, bp, RSA **x, x, pem_password_cb *cb, cb, void *u, u, return 0, return) + DEFINEFUNC4(RSA*, PEM_read_bio_RSA_PUBKEY, BIO *bp, bp, RSA **x, x, pem_password_cb *cb, cb, void *u, u, return 0, return) + + explicit Private( KDUpdaterCrypto* q ) + : q( q ), + m_private_key( 0 ), + m_private_key_bio( 0 ), + m_public_key( 0 ), + m_public_key_bio( 0 ), + libLoader( 0 ), + passwordProvider( 0 ) + { + CLEARFUNC(SSL_library_init) + CLEARFUNC(BIO_free) + CLEARFUNC(BIO_new) + CLEARFUNC(BIO_s_mem) + CLEARFUNC(BIO_write) + CLEARFUNC(RSA_new) + CLEARFUNC(RSA_free) + CLEARFUNC(RSA_size) + CLEARFUNC(PEM_read_bio_RSAPrivateKey) + CLEARFUNC(PEM_read_bio_RSA_PUBKEY) + CLEARFUNC(RSA_public_encrypt) + CLEARFUNC(RSA_private_decrypt) + CLEARFUNC(RSA_sign) + CLEARFUNC(RSA_verify) + } + ~Private() + { + finish(); + CLEARFUNC(SSL_library_init) + CLEARFUNC(BIO_free) + CLEARFUNC(BIO_new) + CLEARFUNC(BIO_s_mem) + CLEARFUNC(BIO_write) + CLEARFUNC(RSA_new) + CLEARFUNC(RSA_free) + CLEARFUNC(RSA_size) + CLEARFUNC(PEM_read_bio_RSAPrivateKey) + CLEARFUNC(PEM_read_bio_RSA_PUBKEY) + CLEARFUNC(RSA_public_encrypt) + CLEARFUNC(RSA_private_decrypt) + CLEARFUNC(RSA_sign) + CLEARFUNC(RSA_verify) + delete libLoader; + } + + bool resolveOpenSslSymbols() + { + volatile bool symbolsResolved = false; + volatile bool triedToResolveSymbols = false; + //QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&kd_SSL_library_init)); + if (symbolsResolved) + return true; + if (triedToResolveSymbols) + return false; + if( libLoader != 0 ) + return true; + triedToResolveSymbols = true; + + KDLibraryLoader* const libs = loadOpenSsl(); + if( libs == 0 ) + // failed to load them + return false; + + RESOLVEFUNC(SSL_library_init) + RESOLVEFUNC(BIO_free) + RESOLVEFUNC(BIO_new) + RESOLVEFUNC(BIO_s_mem) + RESOLVEFUNC(BIO_write) + RESOLVEFUNC(RSA_new) + RESOLVEFUNC(RSA_free) + RESOLVEFUNC(RSA_size) + RESOLVEFUNC(PEM_read_bio_RSAPrivateKey) + RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY) + RESOLVEFUNC(RSA_public_encrypt) + RESOLVEFUNC(RSA_private_decrypt) + RESOLVEFUNC(RSA_sign) + RESOLVEFUNC(RSA_verify) + + symbolsResolved = true; + libLoader = libs; + return true; + } + + void init() + { + resolveOpenSslSymbols(); + const int inited = kd_SSL_library_init(); + Q_UNUSED( inited ); + Q_ASSERT(inited); + //OpenSSL_add_all_algorithms(); + } + + void finish() + { + finishPrivateKey(); + finishPublicKey(); + } + + void finishPrivateKey() + { + if( m_private_key ) { + kd_RSA_free(m_private_key); + m_private_key = 0; + } + if( m_private_key_bio ) { + kd_BIO_free(m_private_key_bio); + m_private_key_bio = 0; + } + } + + void finishPublicKey() + { + if( m_public_key ) { + kd_RSA_free(m_public_key); + m_public_key = 0; + } + if( m_public_key_bio ) { + kd_BIO_free(m_public_key_bio); + m_public_key_bio = 0; + } + } + + static int password_callback(char *buf, int bufsiz, int verify, void *userdata) + { + Q_UNUSED( verify ); + //qDebug()<<"KDUpdaterCrypto::password_callback verify="<<verify; + KDUpdaterCrypto *crypto = static_cast<KDUpdaterCrypto*>(userdata); + const QByteArray password = crypto->d->passwordProvider == 0 ? crypto->privatePassword() + : crypto->d->passwordProvider->password(); + int len = password.length(); + if (len <= 0) + return 0; + if (len > bufsiz) + len = bufsiz; + memcpy(buf, password.constData(), len); + return len; + } + + bool initPrivateKey() + { + finishPrivateKey(); + + m_private_key_bio = kd_BIO_new(kd_BIO_s_mem()); + Q_ASSERT(m_private_key_bio); + + Q_ASSERT( ! m_privateKey.isNull()); + const int priv_bio_size = kd_BIO_write(m_private_key_bio, m_privateKey.constData(), m_privateKey.length()); + Q_UNUSED( priv_bio_size ); + Q_ASSERT(priv_bio_size >= 1); + + m_private_key = kd_RSA_new(); + Q_ASSERT(m_private_key); + if( ! kd_PEM_read_bio_RSAPrivateKey(m_private_key_bio, &m_private_key, Private::password_callback, q)) { + qWarning() << "PEM_read_bio_RSAPrivateKey failed"; + kd_RSA_free( m_private_key ); + m_private_key = 0; + return false; + } + return true; + } + + bool initPublicKey() + { + finishPublicKey(); + + m_public_key_bio = kd_BIO_new(kd_BIO_s_mem()); + Q_ASSERT(m_public_key_bio); + + Q_ASSERT( ! m_publicKey.isNull()); + const int pub_bio_size = kd_BIO_write(m_public_key_bio, m_publicKey.constData(), m_publicKey.length()); + Q_UNUSED( pub_bio_size ); + Q_ASSERT(pub_bio_size >= 1); + + m_public_key = kd_RSA_new(); + Q_ASSERT(m_public_key); + if( ! kd_PEM_read_bio_RSA_PUBKEY(m_public_key_bio, &m_public_key, password_callback, q)) { + qWarning() << "PEM_read_bio_RSAPublicKey failed"; + kd_RSA_free( m_public_key ); + m_public_key = 0; + return false; + } + return true; + } +}; + +KDUpdaterCrypto::KDUpdaterCrypto() + : d(new Private(this)) +{ + d->init(); +} + +KDUpdaterCrypto::~KDUpdaterCrypto() +{ +} + +QByteArray KDUpdaterCrypto::privateKey() const +{ + return d->m_privateKey; +} + +void KDUpdaterCrypto::setPrivateKey(const QByteArray &key) +{ + d->m_privateKey = key; + d->finish(); +} + +QByteArray KDUpdaterCrypto::privatePassword() const +{ + return d->m_privatePassword; +} + +void KDUpdaterCrypto::setPrivatePassword(const QByteArray &passwd) +{ + d->m_privatePassword = passwd; + d->finish(); +} + +void KDUpdaterCrypto::setPrivatePasswordProvider( const PasswordProvider* provider ) +{ + d->passwordProvider = provider; +} + +QByteArray KDUpdaterCrypto::publicKey() const +{ + return d->m_publicKey; +} + +void KDUpdaterCrypto::setPublicKey(const QByteArray &key) +{ + d->m_publicKey = key; + d->finish(); +} + +QByteArray KDUpdaterCrypto::encrypt(const QByteArray &plaintext) +{ + if( !d->m_public_key && !d->initPublicKey() ) + return QByteArray(); + + Q_ASSERT(d->m_public_key); + unsigned char *encrypted = new unsigned char[ d->kd_RSA_size(d->m_public_key) ]; + const int encryptedlen = d->kd_RSA_public_encrypt(plaintext.length(), (unsigned char *) plaintext.constData(), encrypted, d->m_public_key, RSA_PKCS1_PADDING); + const QByteArray ret = encryptedlen>=0 ? QByteArray( (const char*) encrypted, encryptedlen ) : QByteArray(); + Q_ASSERT(!ret.isNull()); + delete [] encrypted; + return ret; +} + +QByteArray KDUpdaterCrypto::decrypt(const QByteArray &encryptedtext) +{ + if( !d->m_private_key && !d->initPrivateKey() ) + return QByteArray(); + + Q_ASSERT(d->m_private_key); + unsigned char *decrypted = new unsigned char[ d->kd_RSA_size(d->m_private_key) ]; + const int decryptedlen = d->kd_RSA_private_decrypt(encryptedtext.length(), (unsigned char *) encryptedtext.constData(), decrypted, d->m_private_key, RSA_PKCS1_PADDING); + const QByteArray ret = decryptedlen>=0 ? QByteArray( (const char*) decrypted, decryptedlen ) : QByteArray(); + delete [] decrypted; + return ret; +} + +bool KDUpdaterCrypto::verify(const QByteArray &data, const QByteArray &signature) +{ + if( !d->m_public_key && !d->initPublicKey() ) + return false; + + unsigned char *sigret = (unsigned char*) signature.constData(); + unsigned int siglen = signature.length(); + const int verifyresult = d->kd_RSA_verify(NID_sha1, (const unsigned char*) data.constData(), data.length(), sigret, siglen, d->m_public_key); + return verifyresult == 1; +} + +static QByteArray hash( QIODevice* dev, QCryptographicHash::Algorithm method ) +{ + QByteArray buffer; + buffer.resize( 8192 ); + QCryptographicHash h( method ); + while( !dev->atEnd() ) + { + const int read = dev->read( buffer.data(), buffer.length() ); + h.addData( buffer.constData(), read ); + } + return h.result(); +} + +bool KDUpdaterCrypto::verify( QIODevice* dev, const QByteArray& signature ) +{ + const bool wasOpen = dev->isOpen(); + if( !wasOpen && !dev->open( QIODevice::ReadOnly ) ) + { + qWarning() << "KDUpdaterCrypto::verify: could not open the device"; + return false; + } + + const qint64 pos = dev->pos(); + const bool result = verify( hash( dev, QCryptographicHash::Sha1 ), signature ); + dev->seek( pos ); + if( !wasOpen ) + dev->close(); + return result; + +} + +bool KDUpdaterCrypto::verify( const QString& dataPath, const QByteArray& signature ) +{ + QFile dFile( dataPath ); + return verify( &dFile, signature ); +} + +bool KDUpdaterCrypto::verify( const QString& dataPath, const QString& signaturePath ) +{ + QFile sFile( signaturePath ); + if( !sFile.open( QIODevice::ReadOnly ) ) + { + qWarning() << "KDUpdaterCrypto::veryfi: could not open the signature file"; + return false; + } + + return verify( dataPath, sFile.readAll() ); +} + +QByteArray KDUpdaterCrypto::sign( QIODevice* dev ) +{ + const bool wasOpen = dev->isOpen(); + if( !wasOpen && !dev->open( QIODevice::ReadOnly ) ) + return QByteArray(); + + const qint64 pos = dev->pos(); + const QByteArray signature = sign( hash( dev, QCryptographicHash::Sha1 ) ); + dev->seek( pos ); + if( !wasOpen ) + dev->close(); + return signature; +} + +QByteArray KDUpdaterCrypto::sign( const QString& path ) +{ + QFile file( path ); + return sign( &file ); +} + +QByteArray KDUpdaterCrypto::sign(const QByteArray &data) +{ + if( !d->m_private_key && !d->initPrivateKey() ) + return QByteArray(); + + const char *msg = data.constData(); + unsigned char *sigret = new unsigned char[ d->kd_RSA_size(d->m_private_key) ]; + unsigned int siglen; + const int signresult = d->kd_RSA_sign(NID_sha1, (const unsigned char*) msg, strlen(msg), sigret, &siglen, d->m_private_key); + const QByteArray ret = signresult == 1 ? QByteArray( (const char*) sigret, siglen) : QByteArray(); + delete [] sigret; + return ret; +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h new file mode 100644 index 000000000..15d0011a0 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_KDUPDATERCRYPTO_H__ +#define __KDTOOLS_KDUPDATERCRYPTO_H__ + +#include "kdupdater.h" + +class QByteArray; +class QIODevice; + +#include <KDToolsCore/pimpl_ptr.h> + +/** + * Class that provides cryptographic functionality like signing and verifying + * or encrypting and decrypting content. + */ +class KDTOOLS_UPDATER_EXPORT KDUpdaterCrypto { + public: + class PasswordProvider + { + public: + virtual ~PasswordProvider() {} + virtual QByteArray password() const = 0; + }; + + KDUpdaterCrypto(); + virtual ~KDUpdaterCrypto(); + + /** + * The private key. + */ + QByteArray privateKey() const; + void setPrivateKey(const QByteArray &key); + + /** + * The password for the private key. + */ + QByteArray privatePassword() const; + void setPrivatePassword(const QByteArray &passwd); + + void setPrivatePasswordProvider( const PasswordProvider* provider ); + + /** + * The public key. + */ + QByteArray publicKey() const; + void setPublicKey(const QByteArray &key); + + /** + * Encrypt content using the public key. + */ + QByteArray encrypt(const QByteArray &plaintext); + + /** + * Decript encrypted content using the private key. + */ + QByteArray decrypt(const QByteArray &encryptedtext); + + /** + * Sign content with the private key. + */ + QByteArray sign(const QByteArray &data); + QByteArray sign( const QString& path ); + QByteArray sign( QIODevice* dev ); + + /** + * Verify signed content with the public key. + */ + bool verify(const QByteArray &data, const QByteArray &signature); + bool verify( const QString& dataPath, const QString& signaturePath ); + bool verify( const QString& dataPath, const QByteArray& signature ); + bool verify( QIODevice* dev, const QByteArray& signature ); + + private: + class Private; + kdtools::pimpl_ptr< Private > d; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader.cpp new file mode 100644 index 000000000..c23badb5b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader.cpp @@ -0,0 +1,1165 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterfiledownloader_p.h" +#include "kdupdaterfiledownloaderfactory.h" +#include "kdupdatersignatureverifier.h" +#include "kdupdatersignatureverificationresult.h" + +#include <KDToolsCore/KDAutoPointer> + +#include <QFile> +#include <QFtp> +#include <QNetworkAccessManager> +#include <QNetworkProxyFactory> +#include <QPointer> +#include <QUrl> +#include <QTemporaryFile> +#include <QFileInfo> +#include <QCryptographicHash> +#include <QThreadPool> +#include <QDebug> + +using namespace KDUpdater; + +static double calcProgress(qint32 done, qint32 total) +{ + return total ? (double(done) / double(total)) : 0 ; +} + +QByteArray KDUpdater::calculateHash( QIODevice* device, QCryptographicHash::Algorithm algo ) { + Q_ASSERT( device ); + QCryptographicHash hash( algo ); + QByteArray buffer; + buffer.resize( 512 * 1024 ); + while ( true ) { + const qint64 numRead = device->read( buffer.data(), buffer.size() ); + if ( numRead <= 0 ) + return hash.result(); + hash.addData( buffer.constData(), numRead ); + } + return QByteArray(); // never reached +} + +QByteArray KDUpdater::calculateHash( const QString& path, QCryptographicHash::Algorithm algo ) { + QFile file( path ); + if ( !file.open( QIODevice::ReadOnly ) ) + return QByteArray(); + return calculateHash( &file, algo ); +} + +class HashVerificationJob::Private { +public: + Private() : hash( QCryptographicHash::Sha1 ), error( HashVerificationJob::ReadError ), timerId( -1 ) { + } + + QPointer<QIODevice> device; + QByteArray sha1Sum; + QCryptographicHash hash; + HashVerificationJob::Error error; + int timerId; +}; + +HashVerificationJob::HashVerificationJob( QObject* parent ) : QObject( parent ), d( new Private ) +{ +} + +HashVerificationJob::~HashVerificationJob() +{ +} + +void HashVerificationJob::setDevice( QIODevice* dev ) +{ + d->device = dev; +} + +void HashVerificationJob::setSha1Sum( const QByteArray& sum ) +{ + d->sha1Sum = sum; +} + +int HashVerificationJob::error() const +{ + return d->error; +} + +bool HashVerificationJob::hasError() const +{ + return d->error != NoError; +} + +void HashVerificationJob::start() +{ + Q_ASSERT( d->device ); + d->timerId = startTimer( 0 ); +} + +void HashVerificationJob::emitFinished() +{ + emit finished( this ); + deleteLater(); +} + +void HashVerificationJob::timerEvent( QTimerEvent* ) +{ + Q_ASSERT( d->timerId >= 0 ); + if ( d->sha1Sum.isEmpty() ) { + killTimer( d->timerId ); + d->timerId = -1; + d->error = NoError; + d->device->close(); + emitFinished(); + return; + } + + QByteArray buf; + buf.resize( 128 * 1024 ); + const qint64 read = d->device->read( buf.data(), buf.size() ); + if ( read > 0 ) { + d->hash.addData( buf.constData(), read ); + return; + } + + d->error = d->hash.result() == d->sha1Sum ? NoError : SumsDifferError; + killTimer( d->timerId ); + d->timerId = -1; + emitFinished(); +} + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::FileDownloader +//////////////////////////////////////////////////////////////////////////// + +/*! + \internal + \ingroup kdupdater + \class KDUpdater::FileDownloader kdupdaterfiledownloader.h + + Base class for file downloaders used in KDUpdater. File downloaders are used by + the KDUpdater::Update class to download update files. Each subclass of FileDownloader + can download file from a specific category of sources (eg. local, ftp, http etc). + + This is an internal class, not a part of the public API. Currently we have three + subclasses of FileDownloader + \li LocalFileDownloader - downloads from the local file system + \li FtpDownloader - downloads from a FTP site + \li HttpDownloader - downloads from a HTTP site + + Usage + + \code + KDUpdater::FileDownloader* downloader = new KDUpdater::(some subclass name) + + downloader->setUrl( url ); + downloader->download(); + +// wait for downloadCompleted() signal + +QString downloadedFile = downloader->downloadedFileName(); +\endcode +*/ + +struct KDUpdater::FileDownloader::FileDownloaderData +{ + FileDownloaderData() : autoRemove( true ) { + } + + QUrl url; + QString scheme; + QByteArray sha1Sum; + QString errorString; + bool autoRemove; + bool followRedirect; +}; + +KDUpdater::FileDownloader::FileDownloader(const QString& scheme, QObject* parent) + : QObject(parent), + d( new FileDownloaderData ) +{ + d->scheme = scheme; + d->followRedirect = false; +} + +KDUpdater::FileDownloader::~FileDownloader() +{ +} + +void KDUpdater::FileDownloader::setUrl(const QUrl& url) +{ + d->url = url; +} + +QUrl KDUpdater::FileDownloader::url() const +{ + return d->url; +} + +void KDUpdater::FileDownloader::setSha1Sum( const QByteArray& sum ) +{ + d->sha1Sum = sum; +} + +QByteArray KDUpdater::FileDownloader::sha1Sum() const +{ + return d->sha1Sum; +} + +QString FileDownloader::errorString() const +{ + return d->errorString; +} + +void FileDownloader::setDownloadAborted( const QString& error ) +{ + d->errorString = error; + emit downloadAborted( error ); +} + +void KDUpdater::FileDownloader::setDownloadCompleted( const QString& path ) +{ + KDAutoPointer<HashVerificationJob> job( new HashVerificationJob ); + QFile* file = new QFile( path, job.get() ); + if ( !file->open( QIODevice::ReadOnly ) ) { + emit downloadProgress( 1 ); + onError(); + setDownloadAborted( tr("Could not reopen downloaded file %1 for reading: %2").arg( path, file->errorString() ) ); + return; + } + + job->setDevice( file ); + job->setSha1Sum( d->sha1Sum ); + connect( job.get(), SIGNAL(finished(KDUpdater::HashVerificationJob*)), this, SLOT(sha1SumVerified(KDUpdater::HashVerificationJob*)) ); + job.release()->start(); +} + +void KDUpdater::FileDownloader::sha1SumVerified( KDUpdater::HashVerificationJob* job ) +{ + if ( job->hasError() ) { + onError(); + setDownloadAborted( tr("Cryptographic hashes do not match.") ); + } + else { + onSuccess(); + emit downloadCompleted(); + } +} + +QString KDUpdater::FileDownloader::scheme() const +{ + return d->scheme; +} + +void KDUpdater::FileDownloader::setAutoRemoveDownloadedFile(bool val) +{ + d->autoRemove = val; +} + +void KDUpdater::FileDownloader::setFollowRedirects( bool val ) +{ + d->followRedirect = val; +} + +bool KDUpdater::FileDownloader::followRedirects() const +{ + return d->followRedirect; +} + +bool KDUpdater::FileDownloader::isAutoRemoveDownloadedFile() const +{ + return d->autoRemove; +} + +void KDUpdater::FileDownloader::download() { + QMetaObject::invokeMethod( this, "doDownload", Qt::QueuedConnection ); +} + +void KDUpdater::FileDownloader::cancelDownload() +{ + // Do nothing +} + + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::FileDownloader +//////////////////////////////////////////////////////////////////////////// + +/* + Even though QFile::copy() does the task of copying local files from one place + to another, I prefer to use the timer and copy one block of data per unit time. + + This is because, it is possible that the user of KDUpdater is simultaneously + downloading several files. Sometimes in tandem with other file downloaders. + If the local file that is being downloaded takes a long time; then that will + hang the other downloads. + + On the otherhand, local downloads need not actually download the file. It can + simply pass on the source file as destination file. At this moment however, + I think the user of LocalFileDownloader will assume that the downloaded file + can be fiddled around with without worrying about whether it would mess up + the original source or not. +*/ + +struct KDUpdater::LocalFileDownloader::LocalFileDownloaderData +{ + LocalFileDownloaderData() : source(0), destination(0), + downloaded(false), timerId(-1) { } + + QFile* source; + QTemporaryFile* destination; + QString destFileName; + bool downloaded; + int timerId; +}; + +KDUpdater::LocalFileDownloader::LocalFileDownloader(QObject* parent) + :KDUpdater::FileDownloader(QLatin1String( "file" ), parent), + d ( new LocalFileDownloaderData ) +{ +} + +KDUpdater::LocalFileDownloader::~LocalFileDownloader() +{ + if( this->isAutoRemoveDownloadedFile() && !d->destFileName.isEmpty() ) + QFile::remove(d->destFileName); + + delete d; +} + +bool KDUpdater::LocalFileDownloader::canDownload() const +{ + const QString localFile = url().toLocalFile(); + QFileInfo fi( localFile ); + return fi.exists() && fi.isReadable(); +} + +bool KDUpdater::LocalFileDownloader::isDownloaded() const +{ + return d->downloaded; +} + +void KDUpdater::LocalFileDownloader::doDownload() +{ + // Already downloaded + if( d->downloaded ) + return; + + // Already started downloading + if( d->timerId >= 0 ) + return; + + // Open source and destination files + QString localFile = this->url().toLocalFile(); + d->source = new QFile(localFile, this); + d->destination = new QTemporaryFile(this); + + if( !d->source->open(QFile::ReadOnly) ) + { + onError(); + setDownloadAborted(tr("Cannot open source file for reading.")); + return; + } + + if( !d->destination->open() ) + { + onError(); + setDownloadAborted(tr("Cannot open destination file for writing.")); + return; + } + + // Start a timer and kickoff the copy process + d->timerId = startTimer(0); // as fast as possible + emit downloadStarted(); + emit downloadProgress(0); +} + +QString KDUpdater::LocalFileDownloader::downloadedFileName() const +{ + return d->destFileName; +} + +KDUpdater::LocalFileDownloader* KDUpdater::LocalFileDownloader::clone( QObject* parent ) const +{ + return new LocalFileDownloader( parent ); +} + +void KDUpdater::LocalFileDownloader::cancelDownload() +{ + if( d->timerId < 0 ) + return; + + killTimer( d->timerId ); + d->timerId = -1; + + onError(); + emit downloadCanceled(); +} + +void KDUpdater::LocalFileDownloader::timerEvent(QTimerEvent*) +{ + if( !d->source || !d->destination ) + return; + + const qint64 blockSize = 32768; + QByteArray buffer; + buffer.resize( blockSize ); + const qint64 numRead = d->source->read( buffer.data(), buffer.size() ); + qint64 toWrite = numRead; + while ( toWrite > 0 ) { + const qint64 numWritten = d->destination->write( buffer.constData() + numRead - toWrite, toWrite ); + if ( numWritten < 0 ) { + killTimer( d->timerId ); + d->timerId = -1; + onError(); + setDownloadAborted( tr("Writing to %1 failed: %2").arg( d->destination->fileName(), d->destination->errorString() ) ); + return; + } + toWrite -= numWritten; + } + + if( numRead > 0 ) { + emit downloadProgress( calcProgress(d->source->pos(), d->source->size()) ); + return; + } + + d->destination->flush(); + + killTimer( d->timerId ); + d->timerId = -1; + + setDownloadCompleted( d->destination->fileName() ); +} + +void LocalFileDownloader::onSuccess() +{ + d->downloaded = true; + d->destFileName = d->destination->fileName(); + d->destination->setAutoRemove( false ); + d->destination->close(); + delete d->destination; + d->destination = 0; + delete d->source; + d->source = 0; +} + +void LocalFileDownloader::onError() +{ + d->downloaded = false; + d->destFileName.clear(); + delete d->destination; + d->destination = 0; + delete d->source; + d->source = 0; +} + +struct KDUpdater::ResourceFileDownloader::ResourceFileDownloaderData +{ + ResourceFileDownloaderData() + : downloaded( false ), + timerId( -1 ) + { + } + + QString destFileName; + bool downloaded; + int timerId; +}; + +KDUpdater::ResourceFileDownloader::ResourceFileDownloader(QObject* parent) + :KDUpdater::FileDownloader(QLatin1String( "resource" ), parent), + d ( new ResourceFileDownloaderData ) +{ +} + +KDUpdater::ResourceFileDownloader::~ResourceFileDownloader() +{ + delete d; +} + +bool KDUpdater::ResourceFileDownloader::canDownload() const +{ + QUrl url = this->url(); + url.setScheme( QString::fromLatin1( "file" ) ); + QString localFile = QString::fromLatin1( ":%1" ).arg( url.toLocalFile() ); + QFileInfo fi(localFile); + return fi.exists() && fi.isReadable(); +} + +bool KDUpdater::ResourceFileDownloader::isDownloaded() const +{ + return d->downloaded; +} + +void KDUpdater::ResourceFileDownloader::doDownload() +{ + // Already downloaded + if( d->downloaded ) + return; + + // Already started downloading + if( d->timerId >= 0 ) + return; + + // Open source and destination files + QUrl url = this->url(); + url.setScheme( QString::fromLatin1( "file" ) ); + d->destFileName = QString::fromLatin1( ":%1" ).arg( url.toLocalFile() ); + + // Start a timer and kickoff the copy process + d->timerId = startTimer(0); // as fast as possible + emit downloadStarted(); + emit downloadProgress(0); +} + +QString KDUpdater::ResourceFileDownloader::downloadedFileName() const +{ + return d->destFileName; +} + +KDUpdater::ResourceFileDownloader* KDUpdater::ResourceFileDownloader::clone( QObject* parent ) const +{ + return new ResourceFileDownloader( parent ); +} + +void KDUpdater::ResourceFileDownloader::cancelDownload() +{ + if( d->timerId < 0 ) + return; + + killTimer( d->timerId ); + d->timerId = -1; + + emit downloadCanceled(); +} + +void KDUpdater::ResourceFileDownloader::timerEvent(QTimerEvent*) +{ + killTimer( d->timerId ); + d->timerId = -1; + setDownloadCompleted( d->destFileName ); +} + +void KDUpdater::ResourceFileDownloader::onSuccess() +{ + d->downloaded = true; +} + +void KDUpdater::ResourceFileDownloader::onError() +{ + d->downloaded = false; +} + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::FileDownloader +//////////////////////////////////////////////////////////////////////////// + +struct KDUpdater::FtpDownloader::FtpDownloaderData +{ + FtpDownloaderData() : ftp(0), destination(0), + downloaded(false), ftpCmdId(-1), aborted(false) { } + + QFtp* ftp; + QTemporaryFile* destination; + QString destFileName; + bool downloaded; + int ftpCmdId; + bool aborted; +}; + +KDUpdater::FtpDownloader::FtpDownloader(QObject* parent) + : KDUpdater::FileDownloader(QLatin1String( "ftp" ), parent), + d ( new FtpDownloaderData ) +{ +} + +KDUpdater::FtpDownloader::~FtpDownloader() +{ + if( this->isAutoRemoveDownloadedFile() && !d->destFileName.isEmpty() ) + QFile::remove(d->destFileName); + + delete d; +} + +bool KDUpdater::FtpDownloader::canDownload() const +{ + // TODO: Check whether the ftp file actually exists or not. + return true; +} + +bool KDUpdater::FtpDownloader::isDownloaded() const +{ + return d->downloaded; +} + +void KDUpdater::FtpDownloader::doDownload() +{ + if( d->downloaded ) + return; + + if( d->ftp ) + return; + + d->ftp = new QFtp(this); + connect(d->ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool))); + connect(d->ftp, SIGNAL(commandStarted(int)), this, SLOT(ftpCmdStarted(int))); + connect(d->ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(ftpCmdFinished(int,bool))); + connect(d->ftp, SIGNAL(stateChanged(int)), this, SLOT(ftpStateChanged(int))); + connect(d->ftp, SIGNAL(dataTransferProgress(qint64,qint64)), this, SLOT(ftpDataTransferProgress(qint64,qint64))); + + d->ftp->connectToHost( url().host(), url().port(21) ); + d->ftp->login(); +} + +QString KDUpdater::FtpDownloader::downloadedFileName() const +{ + return d->destFileName; +} + +KDUpdater::FtpDownloader* KDUpdater::FtpDownloader::clone( QObject* parent ) const +{ + return new FtpDownloader( parent ); +} + + +void KDUpdater::FtpDownloader::cancelDownload() +{ + if( d->ftp ) + { + d->aborted = true; + d->ftp->abort(); + } +} + +void KDUpdater::FtpDownloader::ftpDone(bool error) +{ + if( error ) + { + d->ftp->deleteLater(); + d->ftp = 0; + d->ftpCmdId = -1; + + onError(); + + if( d->aborted ) + { + d->aborted = false; + emit downloadCanceled(); + } + else + setDownloadAborted( d->ftp->errorString() ); + } + //PENDING what about the non-error case?? +} + +void KDUpdater::FtpDownloader::ftpCmdStarted(int id) +{ + if( id != d->ftpCmdId ) + return; + + emit downloadStarted(); + emit downloadProgress(0); +} + +void KDUpdater::FtpDownloader::ftpCmdFinished(int id, bool error) +{ + if( id != d->ftpCmdId || error ) // PENDING why error -> return?? + return; + + disconnect(d->ftp, 0, this, 0); + d->ftp->deleteLater(); + d->ftp = 0; + d->ftpCmdId = -1; + d->destination->flush(); + + setDownloadCompleted( d->destination->fileName() ); +} + +void FtpDownloader::onSuccess() +{ + d->downloaded = true; + d->destFileName = d->destination->fileName(); + d->destination->setAutoRemove( false ); + delete d->destination; + d->destination = 0; + +} + +void FtpDownloader::onError() +{ + d->downloaded = false; + d->destFileName.clear(); + delete d->destination; + d->destination = 0; + +} + +void KDUpdater::FtpDownloader::ftpStateChanged(int state) +{ + switch(state) + { + case QFtp::Connected: + // begin the download + d->destination = new QTemporaryFile(this); + d->destination->open(); //PENDING handle error + d->ftpCmdId = d->ftp->get( url().path(), d->destination ); + break; + case QFtp::Unconnected: + // download was unconditionally aborted + disconnect(d->ftp, 0, this, 0); + d->ftp->deleteLater(); + d->ftp = 0; + d->ftpCmdId = -1; + onError(); + setDownloadAborted(tr("Download was aborted due to network errors.")); + break; + } +} + +void KDUpdater::FtpDownloader::ftpDataTransferProgress(qint64 done, qint64 total) +{ + emit downloadProgress( calcProgress(done, total) ); +} + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::FileDownloader +//////////////////////////////////////////////////////////////////////////// + +struct KDUpdater::HttpDownloader::HttpDownloaderData +{ + explicit HttpDownloaderData( HttpDownloader* qq ) : q( qq ), http(0), destination(0), downloaded(false), + aborted(false), retrying(false) { } + + HttpDownloader* const q; + QNetworkAccessManager manager; + QNetworkReply* http; + QTemporaryFile* destination; + QString destFileName; + bool downloaded; + bool aborted; + bool retrying; + + void shutDown() { + disconnect( http, SIGNAL( finished() ), q, SLOT( httpReqFinished() ) ); + http->deleteLater(); + http = 0; + destination->close(); + destination->deleteLater(); + destination = 0; + + } +}; + +KDUpdater::HttpDownloader::HttpDownloader(QObject* parent) + : KDUpdater::FileDownloader(QLatin1String( "http" ), parent), + d ( new HttpDownloaderData( this ) ) +{ +} + +KDUpdater::HttpDownloader::~HttpDownloader() +{ + if( this->isAutoRemoveDownloadedFile() && !d->destFileName.isEmpty() ) + QFile::remove(d->destFileName); + delete d; +} + +bool KDUpdater::HttpDownloader::canDownload() const +{ + // TODO: Check whether the ftp file actually exists or not. + return true; +} + +bool KDUpdater::HttpDownloader::isDownloaded() const +{ + return d->downloaded; +} + +void KDUpdater::HttpDownloader::doDownload() +{ + if( d->downloaded ) + return; + + if( d->http ) + return; + + d->http = d->manager.get( QNetworkRequest( url() ) ); + + connect( d->http, SIGNAL( readyRead() ), this, SLOT( httpReadyRead() ) ); + connect( d->http, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( httpReadProgress( qint64, qint64) ) ); + connect( d->http, SIGNAL( finished() ), this, SLOT( httpReqFinished() ) ); + connect( d->http, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( httpError( QNetworkReply::NetworkError ) ) ); + + /* + // In a future update, authentication should also be supported. + + connect(d->http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(httpProxyAuth(QNetworkProxy,QAuthenticator*))); + connect(d->http, SIGNAL(authenticationRequired(QString,QAuthenticator*)), + this, SLOT(httpAuth(QString,QAuthenticator*))); + */ + + // Begin the download + d->destination = new QTemporaryFile(this); + if ( !d->destination->open() ) { + const QString err = d->destination->errorString(); + d->shutDown(); + setDownloadAborted( tr("Cannot download %1: Could not create temporary file: %2").arg( url().toString(), err ) ); + return; + } +} + +QString KDUpdater::HttpDownloader::downloadedFileName() const +{ + return d->destFileName; +} + +KDUpdater::HttpDownloader* KDUpdater::HttpDownloader::clone( QObject* parent ) const +{ + return new HttpDownloader( parent ); +} + +void KDUpdater::HttpDownloader::httpReadyRead() +{ + static QByteArray buffer( 16384, '\0' ); + while( d->http->bytesAvailable() ) + { + const qint64 read = d->http->read( buffer.data(), buffer.size() ); + qint64 written = 0; + while( written < read ) { + const qint64 numWritten = d->destination->write( buffer.data() + written, read - written ); + if ( numWritten < 0 ) { + const QString err = d->destination->errorString(); + d->shutDown(); + setDownloadAborted( tr("Cannot download %1: Writing to temporary file failed: %2").arg( url().toString(), err ) ); + return; + } + written += numWritten; + } + } +} + +void KDUpdater::HttpDownloader::httpError( QNetworkReply::NetworkError ) +{ + static bool setProxySettings = false; + if( !d->retrying && !setProxySettings ) + { + d->shutDown(); + d->retrying = true; + setProxySettings = true; + + // silently force retry with global proxy settings + QNetworkProxyFactory::setUseSystemConfiguration( true ); + + doDownload(); + return; + } + httpDone( true ); +} + +void KDUpdater::HttpDownloader::cancelDownload() +{ + d->aborted = true; + if( d->http ) + { + d->http->abort(); + httpDone( true ); + } +} + +void KDUpdater::HttpDownloader::httpDone( bool error ) +{ + if( error ) + { + QString err; + if( d->http ) + { + err = d->http->errorString(); + d->http->deleteLater(); + d->http = 0; + onError(); + } + + if( d->aborted ) + { + d->aborted = false; + emit downloadCanceled(); + } + else + setDownloadAborted( err ); + } + //PENDING: what about the non-error case?? +} + +void KDUpdater::HttpDownloader::onError() +{ + d->downloaded = false; + d->destFileName.clear(); + delete d->destination; + d->destination = 0; +} + +void KDUpdater::HttpDownloader::onSuccess() +{ + d->downloaded = true; + d->destFileName = d->destination->fileName(); + d->destination->setAutoRemove( false ); + delete d->destination; + d->destination = 0; +} + +void KDUpdater::HttpDownloader::httpReqFinished() +{ + const QVariant redirect = d->http == 0 ? QVariant() : d->http->attribute( QNetworkRequest::RedirectionTargetAttribute ); + const QUrl redirectUrl = redirect.toUrl(); + //if ( redirect.isValid() ) + // redirectUrl = redirect.toUrl(); + if ( followRedirects() && redirectUrl.isValid() ) + { + // clean the previous download + d->http->deleteLater(); + d->http = 0; + d->destination->close(); + d->destination->deleteLater(); + d->destination = 0; + + d->http = d->manager.get( QNetworkRequest( redirectUrl ) ); + + connect( d->http, SIGNAL( readyRead() ), this, SLOT( httpReadyRead() ) ); + connect( d->http, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( httpReadProgress( qint64, qint64) ) ); + connect( d->http, SIGNAL( finished() ), this, SLOT( httpReqFinished() ) ); + connect( d->http, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( httpError( QNetworkReply::NetworkError ) ) ); + + // Begin the download + d->destination = new QTemporaryFile(this); + d->destination->open(); //PENDING handle error + } + else + { + if( d->http == 0 ) + return; + httpReadyRead(); + d->destination->flush(); + setDownloadCompleted( d->destination->fileName() ); + d->http->deleteLater(); + d->http = 0; + } +} + +void KDUpdater::HttpDownloader::httpReadProgress( qint64 done, qint64 total) +{ + emit downloadProgress( calcProgress( done, total ) ); +} + +class SignatureVerificationDownloader::Private +{ + SignatureVerificationDownloader* const q; +public: + explicit Private( FileDownloader* dl, SignatureVerificationDownloader* qq ) : q( qq ), verifier( 0 ), downloader( dl ), sigDownloader( 0 ), actualDownloadDone( false ) + { + Q_ASSERT( downloader ); + q->connect( downloader.get(), SIGNAL( downloadProgress( double ) ), q, SIGNAL( downloadProgress( double ) ) ); + q->connect( downloader.get(), SIGNAL(downloadStarted()), q, SLOT(dataDownloadStarted()) ); + q->connect( downloader.get(), SIGNAL(downloadCompleted()), q, SLOT(dataDownloadCompleted()) ); + q->connect( downloader.get(), SIGNAL(downloadCanceled()), q, SLOT(dataDownloadCanceled()) ); + q->connect( downloader.get(), SIGNAL(downloadAborted(QString)), q, SLOT(dataDownloadAborted(QString)) ); + } + + ~Private() + { + delete verifier; + } + + const SignatureVerifier* verifier; + KDAutoPointer< FileDownloader > downloader; + KDAutoPointer< FileDownloader > sigDownloader; + QUrl signatureUrl; + SignatureVerificationResult result; + QString downloadedFileName; + bool actualDownloadDone : 1; +}; + +SignatureVerificationDownloader::SignatureVerificationDownloader( FileDownloader* downloader, QObject* parent ) : FileDownloader( downloader->scheme(), parent ), d( new Private( downloader, this ) ) +{ +} + +SignatureVerificationDownloader::~SignatureVerificationDownloader() +{ +} + +QUrl SignatureVerificationDownloader::signatureUrl() const +{ + return d->signatureUrl; +} + +void SignatureVerificationDownloader::setSignatureUrl( const QUrl& url ) +{ + d->signatureUrl = url; +} + +const SignatureVerifier* SignatureVerificationDownloader::signatureVerifier() const { + return d->verifier; +} + +void SignatureVerificationDownloader::setSignatureVerifier( const SignatureVerifier* verifier ) { + delete d->verifier; + d->verifier = verifier ? verifier->clone() : 0; +} + +SignatureVerificationResult SignatureVerificationDownloader::result() const +{ + return d->result; +} + +bool SignatureVerificationDownloader::canDownload() const +{ + return d->downloader->canDownload(); +} + +bool SignatureVerificationDownloader::isDownloaded() const +{ + return d->downloader->isDownloaded(); +} + +QString SignatureVerificationDownloader::downloadedFileName() const +{ + return d->downloadedFileName; +} + +FileDownloader* SignatureVerificationDownloader::clone( QObject* parent ) const +{ + return new SignatureVerificationDownloader( d->downloader->clone(), parent ); +} + +void SignatureVerificationDownloader::onError() +{ + d->sigDownloader.reset(); + if ( QFile::exists( d->downloadedFileName ) ) + QFile::remove( d->downloadedFileName ); +} + +void SignatureVerificationDownloader::onSuccess() +{ + d->sigDownloader.reset(); +} + +void SignatureVerificationDownloader::cancelDownload() +{ + if ( !d->actualDownloadDone ) { + d->downloader->cancelDownload(); + return; + } + if ( d->sigDownloader ) { + d->sigDownloader->cancelDownload(); + } +} + +void SignatureVerificationDownloader::doDownload() +{ + Q_ASSERT( d->verifier ); + Q_ASSERT( d->downloader ); + d->downloader->setUrl( url() ); + d->downloader->setSha1Sum( sha1Sum() ); + d->downloader->download(); +} + +void SignatureVerificationDownloader::dataDownloadStarted() +{ + emit downloadStarted(); +} + +void SignatureVerificationDownloader::dataDownloadAborted( const QString& err ) +{ + setDownloadAborted( err ); +} + +void SignatureVerificationDownloader::dataDownloadCanceled() +{ + emit downloadCanceled(); +} + +static QUrl suggestSignatureUrl( const QUrl& url ) { + return url.toString() + QLatin1String(".sig"); +} + +void SignatureVerificationDownloader::dataDownloadCompleted() +{ + d->downloadedFileName = d->downloader->downloadedFileName(); + d->actualDownloadDone = true; + + QUrl url = d->signatureUrl; + if ( url.isEmpty() ) + url = suggestSignatureUrl( d->downloader->url() ); + d->sigDownloader.reset( FileDownloaderFactory::instance().create( url.scheme(), this ) ); + if ( !d->sigDownloader ) { + setDownloadAborted( tr("Could not download signature: scheme %1 not supported").arg( url.scheme() ) ); + return; + } + d->sigDownloader->setUrl( url ); + connect( d->sigDownloader.get(), SIGNAL(downloadCompleted()), this, SLOT(signatureDownloadCompleted()) ); + connect( d->sigDownloader.get(), SIGNAL(downloadCanceled()), this, SLOT(signatureDownloadCanceled()) ); + connect( d->sigDownloader.get(), SIGNAL(downloadAborted(QString)), this, SLOT(signatureDownloadAborted(QString)) ); + d->sigDownloader->download(); +} + +void SignatureVerificationDownloader::signatureDownloadAborted( const QString& err ) +{ + setDownloadAborted( tr("Downloading signature: %1").arg( err ) ); +} + +void SignatureVerificationDownloader::signatureDownloadCanceled() +{ + emit downloadCanceled(); +} + +void SignatureVerificationDownloader::signatureDownloadCompleted() +{ + QFile sigFile( d->sigDownloader->downloadedFileName() ); + if ( !sigFile.open( QIODevice::ReadOnly ) ) { + setDownloadAborted( tr("Could not open signature file: %1").arg( sigFile.errorString() ) ); + return; + } + + const QByteArray signature = sigFile.readAll(); + + QFile dataFile( d->downloadedFileName ); + if ( !dataFile.open( QIODevice::ReadOnly ) ) { + setDownloadAborted( tr("Could not open file for verification: %1").arg( dataFile.errorString() ) ); + return; + } + const QByteArray dataHash = calculateHash(&dataFile, QCryptographicHash::Sha1); + + //const QString sigPath = d->sigDownloader->downloadedFileName(); + d->result = d->verifier->verify( dataHash, signature ); + if( ! d->result.isValid() ) { + setDownloadAborted( d->result.errorString() ); + return; + } + setDownloadCompleted( d->downloadedFileName ); + +#if 0 + SignatureVerificationRunnable* runnable = new SignatureVerificationRunnable; + runnable->setSignature( signature ); + runnable->setData( dataFile.release() ); + runnable->setVerifier( d->verifier ); + runnable->addResultListener( this, "verificationResult" ); + QThreadPool::globalInstance()->start( runnable ); +#endif +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader.h new file mode 100644 index 000000000..754917aa8 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_FILE_DOWNLOADER_H +#define KD_UPDATER_FILE_DOWNLOADER_H + +#include "kdupdater.h" +#include <KDToolsCore/pimpl_ptr.h> + +#include <QtCore/QObject> +#include <QtCore/QUrl> +#include <QtCore/QCryptographicHash> + +namespace KDUpdater +{ + KDTOOLS_UPDATER_EXPORT QByteArray calculateHash( QIODevice* device, QCryptographicHash::Algorithm algo ); + KDTOOLS_UPDATER_EXPORT QByteArray calculateHash( const QString& path, QCryptographicHash::Algorithm algo ); + + class HashVerificationJob; + + class KDTOOLS_UPDATER_EXPORT FileDownloader : public QObject + { + Q_OBJECT + Q_PROPERTY( bool autoRemoveDownloadedFile READ isAutoRemoveDownloadedFile WRITE setAutoRemoveDownloadedFile ) + Q_PROPERTY( QUrl url READ url WRITE setUrl ) + Q_PROPERTY( QString scheme READ scheme ) + + public: + explicit FileDownloader(const QString& scheme, QObject* parent=0); + ~FileDownloader(); + + void setUrl(const QUrl& url); + QUrl url() const; + + void setSha1Sum( const QByteArray& sha1 ); + QByteArray sha1Sum() const; + + QString errorString() const; + QString scheme() const; + + virtual bool canDownload() const = 0; + virtual bool isDownloaded() const = 0; + virtual QString downloadedFileName() const = 0; + virtual FileDownloader* clone( QObject* parent=0 ) const = 0; + + void download(); + + void setAutoRemoveDownloadedFile(bool val); + bool isAutoRemoveDownloadedFile() const; + + void setFollowRedirects( bool val ); + bool followRedirects() const; + + public Q_SLOTS: + virtual void cancelDownload(); + void sha1SumVerified( KDUpdater::HashVerificationJob* job ); + + protected: + virtual void onError() = 0; + virtual void onSuccess() = 0; + + Q_SIGNALS: + void downloadProgress(double); + void downloadStarted(); + void downloadCanceled(); + +#ifndef Q_MOC_RUN + private: +#endif + void downloadCompleted(); + void downloadAborted(const QString& errorMessage); + + protected: + void setDownloadCompleted( const QString& filepath ); + void setDownloadAborted( const QString& error ); + + private Q_SLOTS: + virtual void doDownload() = 0; + + private: + struct FileDownloaderData; + kdtools::pimpl_ptr<FileDownloaderData> d; + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h new file mode 100644 index 000000000..516bc3c3d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h @@ -0,0 +1,243 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_FILE_DOWNLOADER_P_H +#define KD_UPDATER_FILE_DOWNLOADER_P_H + +#include "kdupdaterfiledownloader.h" +#include <KDToolsCore/pimpl_ptr.h> + +#include <QtCore/QCryptographicHash> +#include <QtNetwork/QNetworkReply> + +class QIODevice; + +// these classes are not a part of the public API + +namespace KDUpdater +{ + + //TODO make it a KDJob once merged + class HashVerificationJob : public QObject + { + Q_OBJECT + public: + enum Error { + NoError=0, + ReadError=128, + SumsDifferError + }; + + explicit HashVerificationJob( QObject* parent=0 ); + ~HashVerificationJob(); + + void setDevice( QIODevice* dev ); + void setSha1Sum( const QByteArray& data ); + + bool hasError() const; + int error() const; + + void start(); + + Q_SIGNALS: + void finished( KDUpdater::HashVerificationJob* ); + + private: + void emitFinished(); + /* reimp */ void timerEvent( QTimerEvent* te ); + + private: + class Private; + kdtools::pimpl_ptr<Private> d; + }; + + class LocalFileDownloader : public FileDownloader + { + Q_OBJECT + + public: + explicit LocalFileDownloader(QObject* parent=0); + ~LocalFileDownloader(); + + bool canDownload() const; + bool isDownloaded() const; + QString downloadedFileName() const; + /* reimp */ LocalFileDownloader* clone( QObject* parent=0 ) const; + + public Q_SLOTS: + void cancelDownload(); + + protected: + void timerEvent(QTimerEvent* te); + /* reimp */ void onError(); + /* reimp */ void onSuccess(); + + private Q_SLOTS: + /* reimp */ void doDownload(); + + private: + struct LocalFileDownloaderData; + LocalFileDownloaderData* d; + }; + + class ResourceFileDownloader : public FileDownloader + { + Q_OBJECT + + public: + explicit ResourceFileDownloader(QObject* parent=0); + ~ResourceFileDownloader(); + + bool canDownload() const; + bool isDownloaded() const; + QString downloadedFileName() const; + /* reimp */ ResourceFileDownloader* clone( QObject* parent=0 ) const; + + public Q_SLOTS: + void cancelDownload(); + + protected: + void timerEvent(QTimerEvent* te); + /* reimp */ void onError(); + /* reimp */ void onSuccess(); + + private Q_SLOTS: + /* reimp */ void doDownload(); + + private: + struct ResourceFileDownloaderData; + ResourceFileDownloaderData* d; + }; + + class FtpDownloader : public FileDownloader + { + Q_OBJECT + + public: + explicit FtpDownloader(QObject* parent=0); + ~FtpDownloader(); + + bool canDownload() const; + bool isDownloaded() const; + QString downloadedFileName() const; + /* reimp */ FtpDownloader* clone( QObject* parent=0 ) const; + + public Q_SLOTS: + void cancelDownload(); + + protected: + /* reimp */ void onError(); + /* reimp */ void onSuccess(); + + private Q_SLOTS: + /* reimp */ void doDownload(); + void ftpDone(bool error); + void ftpCmdStarted(int id); + void ftpCmdFinished(int id, bool error); + void ftpStateChanged(int state); + void ftpDataTransferProgress(qint64 done, qint64 total); + + private: + struct FtpDownloaderData; + FtpDownloaderData* d; + }; + + class HttpDownloader : public FileDownloader + { + Q_OBJECT + + public: + explicit HttpDownloader(QObject* parent=0); + ~HttpDownloader(); + + bool canDownload() const; + bool isDownloaded() const; + QString downloadedFileName() const; + /* reimp */ HttpDownloader* clone( QObject* parent=0 ) const; + + public Q_SLOTS: + void cancelDownload(); + + protected: + /* reimp */ void onError(); + /* reimp */ void onSuccess(); + + private Q_SLOTS: + /* reimp */ void doDownload(); + void httpReadyRead(); + void httpReadProgress( qint64 done, qint64 total ); + void httpError( QNetworkReply::NetworkError ); + void httpDone( bool error ); + void httpReqFinished(); + + private: + struct HttpDownloaderData; + HttpDownloaderData* d; + }; + + class SignatureVerificationResult; + class SignatureVerifier; + + class SignatureVerificationDownloader : public FileDownloader + { + Q_OBJECT + public: + explicit SignatureVerificationDownloader( FileDownloader* downloader, QObject* parent=0 ); + ~SignatureVerificationDownloader(); + + QUrl signatureUrl() const; + void setSignatureUrl( const QUrl& url ); + + const SignatureVerifier* signatureVerifier() const; + void setSignatureVerifier( const SignatureVerifier* verifier ); + + SignatureVerificationResult result() const; + + /* reimp */ bool canDownload() const; + /* reimp */ bool isDownloaded() const; + /* reimp */ QString downloadedFileName() const; + /* reimp */ FileDownloader* clone( QObject* parent=0 ) const; + + public Q_SLOTS: + /* reimp */ void cancelDownload(); + + protected: + /* reimp */ void onError(); + /* reimp */ void onSuccess(); + + private Q_SLOTS: + /* reimp */ void doDownload(); + void dataDownloadStarted(); + void dataDownloadCanceled(); + void dataDownloadCompleted(); + void dataDownloadAborted(const QString& errorMessage); + void signatureDownloadCanceled(); + void signatureDownloadCompleted(); + void signatureDownloadAborted(const QString& errorMessage); + + private: + class Private; + kdtools::pimpl_ptr<Private> d; + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.cpp new file mode 100644 index 000000000..cba271e96 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterfiledownloaderfactory.h" +#include "kdupdaterfiledownloader_p.h" + +#include <cassert> + +/*! + \internal + \ingroup kdupdater + \class KDUpdater::FileDownloaderFactory kdupdaterfiledownloaderfactory.h + \brief Factory for \ref KDUpdater::FileDownloader + + This class acts as a factory for \ref KDUpdater::FileDownloader. You can register + one or more file downloaders with this factory and query them based on their scheme. + + This class follows the singleton design pattern. Only one instance of this class can + be created and its reference can be fetched from the \ref instance() method. +*/ + +using namespace KDUpdater; + +struct FileDownloaderFactory::FileDownloaderFactoryData +{ + bool m_followRedirects; +}; + +FileDownloaderFactory& FileDownloaderFactory::instance() +{ + static KDUpdater::FileDownloaderFactory theFactory; + return theFactory; +} + +/*! + Constructor +*/ +FileDownloaderFactory::FileDownloaderFactory() + : d ( new FileDownloaderFactoryData ) +{ + // Register the default file downloader set + registerFileDownloader< LocalFileDownloader >( QLatin1String( "file" ) ); + registerFileDownloader< FtpDownloader >( QLatin1String( "ftp" ) ); + registerFileDownloader< HttpDownloader >( QLatin1String( "http" ) ); + registerFileDownloader< ResourceFileDownloader >( QLatin1String( "resource" ) ); + d->m_followRedirects = false; +} + +void FileDownloaderFactory::setFollowRedirects( bool val ) +{ + FileDownloaderFactory::instance().d->m_followRedirects = val; +} + +bool FileDownloaderFactory::followRedirects() +{ + return FileDownloaderFactory::instance().d->m_followRedirects; +} + +FileDownloaderFactory::~FileDownloaderFactory() +{ +} + +/*! + Returns a new instance to the \ref KDUpdater::FileDownloader based whose scheme is equal to the string + passed as parameter to this function. + \note Ownership of this object remains to the programmer. +*/ +FileDownloader* FileDownloaderFactory::create( const QString& scheme, QObject* parent ) const +{ + return create( scheme, 0, QUrl(), parent ); +} + +FileDownloader* FileDownloaderFactory::create( const QString& scheme, const SignatureVerifier* verifier, const QUrl& signatureUrl, QObject* parent ) const +{ + FileDownloader* const downloader = KDGenericFactory< FileDownloader >::create( scheme ); + if( downloader != 0 ) { + downloader->setFollowRedirects( d->m_followRedirects ); + downloader->setParent( parent ); + } + if( !verifier ) + return downloader; + + SignatureVerificationDownloader* const svdl = new SignatureVerificationDownloader( downloader, parent ); + svdl->setSignatureVerifier( verifier ); + svdl->setSignatureUrl( signatureUrl ); + return svdl; +} + +/*! + KDUpdater::FileDownloaderFactory::registerFileDownlooader + Registers a new file downloader with the factory. If there is already a downloader with the same scheme, + the downloader is replaced. The ownership of the downloader is transfered to the factory. +*/ + +/*! + Returns the number of file downloaders in the factory. +*/ +int FileDownloaderFactory::fileDownloaderCount() const +{ + return productCount(); +} + +/*! + Returns a list of schemes supported by this factory, i.e. for which a + FileDownloader was registered. +*/ +QStringList FileDownloaderFactory::supportedSchemes() const +{ + return availableProducts(); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h new file mode 100644 index 000000000..b4c284640 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_FILE_DOWNLOADER_FACTORY_H +#define KD_UPDATER_FILE_DOWNLOADER_FACTORY_H + +#include "kdupdater.h" +#include <KDToolsCore/pimpl_ptr.h> +#include <KDToolsCore/kdgenericfactory.h> + +#include <QtCore/QStringList> +#include <QtCore/QUrl> + +class QObject; + +namespace KDUpdater +{ + class FileDownloader; + class SignatureVerifier; + + class KDTOOLS_UPDATER_EXPORT FileDownloaderFactory : public KDGenericFactory< FileDownloader > + { + Q_DISABLE_COPY( FileDownloaderFactory ) + public: + static FileDownloaderFactory& instance(); + ~FileDownloaderFactory(); + + template< typename T > + void registerFileDownloader( const QString& scheme ) + { + registerProduct< T >( scheme ); + } + QStringList supportedSchemes() const; + + int fileDownloaderCount() const; + FileDownloader* create( const QString& scheme, QObject* parent ) const; + FileDownloader* create( const QString& scheme, const SignatureVerifier* verifier = 0, const QUrl& signatureUrl = QUrl(), QObject* parent = 0 ) const; + static void setFollowRedirects( bool val ); + static bool followRedirects(); + + private: + FileDownloaderFactory(); + + private: + struct FileDownloaderFactoryData; + kdtools::pimpl_ptr<FileDownloaderFactoryData> d; + }; +} + + +#endif + diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesinfo.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesinfo.cpp new file mode 100644 index 000000000..c6ce195ea --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesinfo.cpp @@ -0,0 +1,566 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterpackagesinfo.h" +#include "kdupdaterapplication.h" + +#include <QFileInfo> +#include <QDomDocument> +#include <QDomElement> +#include <QVector> + +using namespace KDUpdater; + +/*! + \ingroup kdupdater + \class KDUpdater::PackagesInfo kdupdaterpackagesinfo.h KDUpdaterPackagesInfo + \brief Provides access to information about packages installed on the application side. + + This class parses the XML package file specified via the setFileName() method and + provides access to the the information defined within the package file through an + easy to use API. You can: + \li get application name via the \ref applicationName() method + \li get application version via the \ref applicationVersion() method + \li get information about the number of packages installed and their meta-data via the + \ref packageInfoCount() and \ref packageInfo() methods. + + Instances of this class cannot be created. Each instance of \ref KDUpdater::Application + has one instance of this class associated with it. You can fetch a pointer to an instance + of this class for an application via the \ref KDUpdater::Application::packagesInfo() + method. +*/ + +/*! \enum UpdatePackagesInfo::Error + * Error codes related to retrieving update sources + */ + +/*! \var UpdatePackagesInfo::Error UpdatePackagesInfo::NoError + * No error occurred + */ + +/*! \var UpdatePackagesInfo::Error UpdatePackagesInfo::NotYetReadError + * The package information was not parsed yet from the XML file + */ + +/*! \var UpdatePackagesInfo::Error UpdatePackagesInfo::CouldNotReadPackageFileError + * the specified update source file could not be read (does not exist or not readable) + */ + +/*! \var UpdatePackagesInfo::Error UpdatePackagesInfo::InvalidXmlError + * The source file contains invalid XML. + */ + +/*! \var UpdatePackagesInfo::Error UpdatePackagesInfo::InvalidContentError + * The source file contains valid XML, but does not match the expected format for package descriptions + */ + +struct PackagesInfo::PackagesInfoData +{ + PackagesInfoData( PackagesInfo* qq ) : + q( qq ), + application(0), + error(PackagesInfo::NotYetReadError), + compatLevel(-1), + modified( false ) + {} + PackagesInfo* q; + Application* application; + QString errorMessage; + PackagesInfo::Error error; + QString fileName; + QString applicationName; + QString applicationVersion; + int compatLevel; + bool modified; + + QVector<PackageInfo> packageInfoList; + + void addPackageFrom(const QDomElement& packageE); + void setInvalidContentError( const QString& detail ); +}; + +void PackagesInfo::PackagesInfoData::setInvalidContentError(const QString& detail) +{ + error = PackagesInfo::InvalidContentError; + errorMessage = tr("%1 contains invalid content: %2").arg(fileName, detail); +} + +/*! + \internal +*/ +PackagesInfo::PackagesInfo(Application* application) + : QObject(application), + d( new PackagesInfoData( this ) ) +{ + d->application = application; +} + +/*! + \internal +*/ +PackagesInfo::~PackagesInfo() +{ + writeToDisk(); + delete d; +} + +/*! + Returns a pointer to the application, whose package information this class provides + access to. +*/ +Application* PackagesInfo::application() const +{ + return d->application; +} + +/*! + Returns true if the PackagesInfo are valid else false is returned in which case + the \a errorString() method can be used to receive a describing error message. +*/ +bool PackagesInfo::isValid() const +{ + return d->error == NoError; +} + +/*! + Returns a human-readable error message. +*/ +QString PackagesInfo::errorString() const +{ + return d->errorMessage; +} + +PackagesInfo::Error PackagesInfo::error() const +{ + return d->error; +} + +/*! + Sets the complete file name of the Packages.xml file. The function also issues a call to + \ref refresh() to reload package information from the XML file. + + \sa KDUpdater::Application::setPackagesXMLFileName() +*/ +void PackagesInfo::setFileName(const QString& fileName) +{ + if( d->fileName == fileName ) + return; + + d->fileName = fileName; + refresh(); +} + +/*! + Returns the name of the Packages.xml file that this class referred to. +*/ +QString PackagesInfo::fileName() const +{ + return d->fileName; +} + +/*! + Sets the application name. By default this is the name specified in + the ApplicationName XML element of the Packages.xml file. +*/ +void PackagesInfo::setApplicationName(const QString& name) +{ + d->applicationName = name; + d->modified = true; +} + +/*! + Returns the application name. +*/ +QString PackagesInfo::applicationName() const +{ + return d->applicationName; +} + +/*! + Sets the application version. By default this is the version specified + in the ApplicationVersion XML element of Packages.xml. +*/ +void PackagesInfo::setApplicationVersion(const QString& version) +{ + d->applicationVersion = version; + d->modified = true; +} + +/*! + Returns the application version. +*/ +QString PackagesInfo::applicationVersion() const +{ + return d->applicationVersion; +} + +/*! + Returns the number of \ref KDUpdater::PackageInfo objects contained in this class. +*/ +int PackagesInfo::packageInfoCount() const +{ + return d->packageInfoList.count(); +} + +/*! + Returns the package info structure (\ref KDUpdater::PackageInfo) at index. If index is + out of range then an empty package info structure is returned. +*/ +PackageInfo PackagesInfo::packageInfo(int index) const +{ + if( index < 0 || index >= d->packageInfoList.count() ) + return PackageInfo(); + + return d->packageInfoList[index]; +} + +/*! + Returns the compat level of the application. +*/ +int PackagesInfo::compatLevel() const +{ + return d->compatLevel; +} + +/*! + This function returns the index of the package whose name is \c pkgName. If no such + package was found, this function returns -1. +*/ +int PackagesInfo::findPackageInfo(const QString& pkgName) const +{ + for(int i=0; i<d->packageInfoList.count(); i++) + { + if( d->packageInfoList[i].name == pkgName ) + return i; + } + + return -1; +} + +/*! + Returns all package info structures. +*/ +QVector<PackageInfo> PackagesInfo::packageInfos() const +{ + return d->packageInfoList; +} + +/*! + This function re-reads the Packages.xml file and updates itself. Changes to \ref applicationName() + and \ref applicationVersion() are lost after this function returns. The function emits a reset() + signal after completion. +*/ +void PackagesInfo::refresh() +{ + // First clear internal variables + d->applicationName.clear(); + d->applicationVersion.clear(); + d->packageInfoList.clear(); + d->modified = false; + + QFile file( d->fileName ); + + // if the file does not exist then we just skip the reading + if( !file.exists() ) + { + d->error = NoError; + d->errorMessage.clear(); + emit reset(); + return; + } + + // Open Packages.xml + if( !file.open(QFile::ReadOnly) ) + { + d->error = CouldNotReadPackageFileError; + d->errorMessage = tr("Could not read \"%1\"").arg(d->fileName); + emit reset(); + return; + } + + // Parse the XML document + QDomDocument doc; + QString parseErrorMessage; + int parseErrorLine; + int parseErrorColumn; + if( !doc.setContent( &file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn ) ) + { + d->error = InvalidXmlError; + d->errorMessage = tr("Parse error in %1 at %2, %3: %4") + .arg(d->fileName, + QString::number(parseErrorLine), + QString::number(parseErrorColumn), + parseErrorMessage); + emit reset(); + return; + } + file.close(); + + // Now populate information from the XML file. + QDomElement rootE = doc.documentElement(); + if( rootE.tagName() != QLatin1String( "Packages" ) ) + { + d->setInvalidContentError(tr("root element %1 unexpected, should be \"Packages\"").arg(rootE.tagName())); + emit reset(); + return; + } + + QDomNodeList childNodes = rootE.childNodes(); + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.item(i); + QDomElement childNodeE = childNode.toElement(); + if( childNodeE.isNull() ) + continue; + + if( childNodeE.tagName() == QLatin1String( "ApplicationName" ) ) + d->applicationName = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "ApplicationVersion" ) ) + d->applicationVersion = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Package" ) ) + d->addPackageFrom( childNodeE ); + else if( childNodeE.tagName() == QLatin1String( "CompatLevel" ) ) + d->compatLevel = childNodeE.text().toInt(); + } + + d->error = NoError; + d->errorMessage.clear(); + emit reset(); +} + +/*! + Sets the application compat level. +*/ +void PackagesInfo::setCompatLevel(int level) +{ + d->compatLevel = level; + d->modified = true; +} + +/*! + Marks the package with \a name as installed in \a version. + */ +bool PackagesInfo::installPackage( const QString& name, const QString& version, const QString& title, const QString& description + , const QStringList& dependencies, bool forcedInstallation, bool virtualComp, quint64 uncompressedSize ) +{ + if( findPackageInfo( name ) != -1 ) + return updatePackage( name, version, QDate::currentDate() ); + + PackageInfo info; + info.name = name; + info.version = version; + info.installDate = QDate::currentDate(); + info.title = title; + info.description = description; + info.dependencies = dependencies; + info.forcedInstallation = forcedInstallation; + info.virtualComp = virtualComp; + info.uncompressedSize = uncompressedSize; + d->packageInfoList.push_back( info ); + d->modified = true; + return true; +} + +/*! + Update the package. +*/ +bool PackagesInfo::updatePackage(const QString &name, + const QString &version, + const QDate &date) +{ + int index = findPackageInfo(name); + + if (index==-1) return false; + + d->packageInfoList[index].version = version; + d->packageInfoList[index].lastUpdateDate = date; + d->modified = true; + return true; +} + +/*! + Remove the package with \a name. + */ +bool PackagesInfo::removePackage( const QString& name ) +{ + const int index = findPackageInfo( name ); + if( index == -1 ) + return false; + + d->packageInfoList.remove( index ); + d->modified = true; + return true; +} + +static void addTextChildHelper(QDomNode *node, + const QString &tag, + const QString &text) +{ + QDomElement domElement = node->ownerDocument().createElement(tag); + QDomText domText = node->ownerDocument().createTextNode(text); + + domElement.appendChild(domText); + node->appendChild(domElement); +} + +void PackagesInfo::writeToDisk() +{ + if( d->modified && ( !d->packageInfoList.isEmpty() || QFile::exists( d->fileName ) ) ) + { + QDomDocument doc; + QDomElement root = doc.createElement(QLatin1String( "Packages") ) ; + doc.appendChild(root); + + addTextChildHelper(&root, QLatin1String( "ApplicationName" ), d->applicationName); + addTextChildHelper(&root, QLatin1String( "ApplicationVersion" ), d->applicationVersion); + if (d->compatLevel!=-1) { + addTextChildHelper(&root, QLatin1String( "CompatLevel" ), QString::number(d->compatLevel)); + } + + Q_FOREACH (const PackageInfo &info, d->packageInfoList) { + QDomElement package = doc.createElement( QLatin1String( "Package" ) ); + + addTextChildHelper( &package, QLatin1String( "Name" ), info.name ); + addTextChildHelper( &package, QLatin1String( "Pixmap" ), info.pixmap ); + addTextChildHelper( &package, QLatin1String( "Title" ), info.title ); + addTextChildHelper( &package, QLatin1String( "Description" ), info.description ); + addTextChildHelper( &package, QLatin1String( "Version" ), info.version ); + addTextChildHelper( &package, QLatin1String( "LastUpdateDate" ), info.lastUpdateDate.toString( Qt::ISODate ) ); + addTextChildHelper( &package, QLatin1String( "InstallDate" ), info.installDate.toString( Qt::ISODate) ); + addTextChildHelper( &package, QLatin1String( "Size" ), QString::number( info.uncompressedSize ) ); + QString assembledDependencies = QLatin1String( "" ); + Q_FOREACH( const QString & val, info.dependencies ){ + assembledDependencies += val + QLatin1String( "," ); + } + if ( info.dependencies.count() > 0 ) + assembledDependencies.chop( 1 ); + addTextChildHelper( &package, QLatin1String( "Dependencies" ), assembledDependencies ); + if ( info.forcedInstallation ) + addTextChildHelper( &package, QLatin1String( "ForcedInstallation" ), QLatin1String( "true" ) ); + if ( info.virtualComp ) + addTextChildHelper( &package, QLatin1String( "Virtual" ), QLatin1String( "true" ) ); + + root.appendChild(package); + } + + // Open Packages.xml + QFile file( d->fileName ); + if( !file.open(QFile::WriteOnly) ) { + return; + } + + file.write(doc.toByteArray(4)); + file.close(); + d->modified = false; + } +} + +void PackagesInfo::PackagesInfoData::addPackageFrom(const QDomElement& packageE) +{ + if( packageE.isNull() ) + return; + + QDomNodeList childNodes = packageE.childNodes(); + if(childNodes.count() == 0) + return; + + PackageInfo info; + info.forcedInstallation = false; + info.virtualComp = false; + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.item(i); + QDomElement childNodeE = childNode.toElement(); + if( childNodeE.isNull() ) + continue; + + if( childNodeE.tagName() == QLatin1String( "Name" ) ) + info.name = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Pixmap" ) ) + info.pixmap = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Title" ) ) + info.title = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Description" ) ) + info.description = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Version" ) ) + info.version = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Virtual" ) ) + info.virtualComp = childNodeE.text().toLower() == QLatin1String( "true" ) ? true : false; + else if( childNodeE.tagName() == QLatin1String( "Size" ) ) + info.uncompressedSize = childNodeE.text().toULongLong(); + else if( childNodeE.tagName() == QLatin1String( "Dependencies" ) ) + info.dependencies = childNodeE.text().split( QLatin1String( "," ) ); + else if( childNodeE.tagName() == QLatin1String( "ForcedInstallation" ) ) + info.forcedInstallation = childNodeE.text().toLower() == QLatin1String( "true" ) ? true : false; + else if( childNodeE.tagName() == QLatin1String( "LastUpdateDate" ) ) + info.lastUpdateDate = QDate::fromString(childNodeE.text(), Qt::ISODate); + else if( childNodeE.tagName() == QLatin1String( "InstallDate" ) ) + info.installDate = QDate::fromString(childNodeE.text(), Qt::ISODate); + } + + this->packageInfoList.append( info ); +} + +/*! + \fn void KDUpdater::PackagesInfo::reset() + + This signal is emitted whenever the contents of this class is refreshed, usually from within + the \ref refresh() slot. +*/ + +/*! + \ingroup kdupdater + \struct KDUpdater::PackageInfo kdupdaterpackagesinfo.h KDUpdaterPackageInfo + \brief Describes a single installed package in the application. + + This structure contains information about a single installed package in the application. + The information contained in this structure corresponds to the information described + by the Package XML element in Packages.xml +*/ + +/*! + \var QString KDUpdater::PackageInfo::name +*/ + +/*! + \var QString KDUpdater::PackageInfo::pixmap +*/ + +/*! + \var QString KDUpdater::PackageInfo::title +*/ + +/*! + \var QString KDUpdater::PackageInfo::description +*/ + +/*! + \var QString KDUpdater::PackageInfo::version +*/ + +/*! + \var QDate KDUpdater::PackageInfo::lastUpdateDate +*/ + +/*! + \var QDate KDUpdater::PackageInfo::installDate +*/ diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesinfo.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesinfo.h new file mode 100644 index 000000000..8b38dd8d2 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesinfo.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_PACKAGES_INFO_H +#define KD_UPDATER_PACKAGES_INFO_H + +#include "kdupdater.h" +#include <QObject> +#include <QDate> +#include <QString> +#include <QStringList> +#include <QVariant> + +namespace KDUpdater +{ + class Application; + class UpdateInstaller; + + struct KDTOOLS_UPDATER_EXPORT PackageInfo + { + QString name; + QString pixmap; + QString title; + QString description; + QString version; + QStringList dependencies; + QStringList translations; + QDate lastUpdateDate; + QDate installDate; + bool forcedInstallation; + bool virtualComp; + quint64 uncompressedSize; + }; + + class KDTOOLS_UPDATER_EXPORT PackagesInfo : public QObject + { + Q_OBJECT + + public: + ~PackagesInfo(); + + enum Error + { + NoError=0, + NotYetReadError, + CouldNotReadPackageFileError, + InvalidXmlError, + InvalidContentError + }; + + Application* application() const; + + bool isValid() const; + QString errorString() const; + Error error() const; + + void setFileName(const QString& fileName); + QString fileName() const; + + void setApplicationName(const QString& name); + QString applicationName() const; + + void setApplicationVersion(const QString& version); + QString applicationVersion() const; + + int packageInfoCount() const; + PackageInfo packageInfo(int index) const; + int findPackageInfo(const QString& pkgName) const; + QVector<KDUpdater::PackageInfo> packageInfos() const; + void writeToDisk(); + + int compatLevel() const; + void setCompatLevel(int level); + + bool installPackage( const QString& pkgName, const QString& version, const QString& title = QString(), const QString& description = QString() + , const QStringList& dependencies = QStringList(), bool forcedInstallation = false, bool virtualComp = false, quint64 uncompressedSize = 0 ); + bool updatePackage(const QString &pkgName, const QString &version, const QDate &date ); + bool removePackage( const QString& pkgName ); + + public Q_SLOTS: + void refresh(); + + Q_SIGNALS: + void reset(); + + protected: + explicit PackagesInfo( Application * application=0 ); + + private: + friend class Application; + friend class UpdateInstaller; + struct PackagesInfoData; + PackagesInfoData* d; + }; + +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesview.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesview.cpp new file mode 100644 index 000000000..4943c7b72 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesview.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterpackagesview.h" +#include "kdupdaterpackagesinfo.h" + +/*! + \ingroup kdupdater + \class KDUpdater::PackagesView kdupdaterpackagesview.h KDUpdaterPackagesView + \brief A widget that can show packages contained in \ref KDUpdater::PackagesInfo + + \ref KDUpdater::PackagesInfo, associated with \ref KDUpdater::Application, contains + information about all the packages installed in the application. This widget helps view the packages + in a list. + + \image html packagesview.jpg + + To use this widget, just create an instance and pass to \ref setPackageInfo() a pointer to + \ref KDUpdater::PackagesInfo whose information you want this widget to show. +*/ + +struct KDUpdater::PackagesView::PackagesViewData +{ + PackagesViewData( PackagesView* qq ) : + q( qq ), + packagesInfo(0) + {} + + PackagesView* q; + PackagesInfo* packagesInfo; +}; + +/*! + Constructor. +*/ +KDUpdater::PackagesView::PackagesView(QWidget* parent) + : QTreeWidget(parent), + d ( new PackagesViewData( this ) ) +{ + + setColumnCount(5); + setHeaderLabels( QStringList() << tr("Name") << tr("Title") + << tr("Description") << tr("Version") + << tr("Last Updated") ); + setRootIsDecorated(false); +} + +/*! + Destructor +*/ +KDUpdater::PackagesView::~PackagesView() +{ + delete d; +} + +/*! + Sets the package info whose information this widget should show. + + \code + KDUpdater::Application application; + + KDUpdater::PackagesView packageView; + packageView.setPackageInfo( application.packagesInfo() ); + packageView.show(); + \endcode + +*/ +void KDUpdater::PackagesView::setPackageInfo(KDUpdater::PackagesInfo* packagesInfo) +{ + if( d->packagesInfo == packagesInfo ) + return; + + if(d->packagesInfo) + disconnect(d->packagesInfo, 0, this, 0); + + d->packagesInfo = packagesInfo; + if(d->packagesInfo) + connect(d->packagesInfo, SIGNAL(reset()), this, SLOT(refresh())); + + refresh(); +} + +/*! + Returns a pointer to the package info whose information this widget is showing. +*/ +KDUpdater::PackagesInfo* KDUpdater::PackagesView::packagesInfo() const +{ + return d->packagesInfo; +} + +/*! + This slot reloads package information from the \ref KDUpdater::PackagesInfo associated + with this widget. + + \note By default, this slot is connected to the \ref KDUpdater::PackagesInfo::reset() + signal in \ref setPackageInfo() +*/ +void KDUpdater::PackagesView::refresh() +{ + this->clear(); + if( !d->packagesInfo ) + return; + + Q_FOREACH(const KDUpdater::PackageInfo& info, d->packagesInfo->packageInfos()) + { + QTreeWidgetItem* item = new QTreeWidgetItem(this); + item->setText(0, info.name); + item->setText(1, info.title); + item->setText(2, info.description); + item->setText(3, info.version); + item->setText(4, info.lastUpdateDate.toString()); + } + + resizeColumnToContents(0); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesview.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesview.h new file mode 100644 index 000000000..8f42b1e19 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterpackagesview.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_PACKAGES_VIEW_H +#define KD_UPDATER_PACKAGES_VIEW_H + +#include "kdupdater.h" +#include <QTreeWidget> + +namespace KDUpdater +{ + class PackagesInfo; + + class KDTOOLS_UPDATER_EXPORT PackagesView : public QTreeWidget + { + Q_OBJECT + + public: + explicit PackagesView(QWidget* parent=0); + ~PackagesView(); + + void setPackageInfo(PackagesInfo* packageInfo); + PackagesInfo* packagesInfo() const; + + public Q_SLOTS: + void refresh(); + + private: + struct PackagesViewData; + PackagesViewData* d; + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.cpp new file mode 100644 index 000000000..0b1f61a57 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdatersignatureverificationresult.h" + +#include <QSharedData> +#include <QString> + +#include <algorithm> + +using namespace KDUpdater; + +class SignatureVerificationResult::Private : public QSharedData { +public: + Private() : QSharedData(), validity( SignatureVerificationResult::UnknownValidity ) { + } + Private( const Private& other ) : QSharedData( other ), validity( other.validity ), errorString( other.errorString ) { + } + + bool operator==( const Private& other ) const { + return validity == other.validity && errorString == other.errorString; + } + + SignatureVerificationResult::Validity validity; + QString errorString; +}; + +SignatureVerificationResult::SignatureVerificationResult( Validity validity ) + : d( new Private ) +{ + setValidity( validity ); +} + +SignatureVerificationResult::SignatureVerificationResult( const SignatureVerificationResult& other ) : d( other.d ) { +} + +SignatureVerificationResult::~SignatureVerificationResult() { +} + +SignatureVerificationResult& SignatureVerificationResult::operator=( const SignatureVerificationResult& other ) { + SignatureVerificationResult copy( other ); + std::swap( d, copy.d ); + return *this; +} + +bool SignatureVerificationResult::operator==( const SignatureVerificationResult& other ) const { + return *d == *other.d; +} + +bool SignatureVerificationResult::isValid() const { + return d->validity == ValidSignature; +} + +SignatureVerificationResult::Validity SignatureVerificationResult::validity() const { + return d->validity; +} + +void SignatureVerificationResult::setValidity( Validity validity ) { + d->validity = validity; +} + +QString SignatureVerificationResult::errorString() const { + return d->errorString; +} + +void SignatureVerificationResult::setErrorString( const QString& errorString ) { + d->errorString = errorString; +} + diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h new file mode 100644 index 000000000..5319d35f3 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_SIGNATUREVERIFICATIONRESULT_H +#define KD_UPDATER_SIGNATUREVERIFICATIONRESULT_H + +#include "kdupdater.h" + +#include <QtCore/QMetaType> +#include <QtCore/QSharedDataPointer> + +class QString; + +namespace KDUpdater { + class KDTOOLS_UPDATER_EXPORT SignatureVerificationResult { + public: + enum Validity { + ValidSignature=0, + UnknownValidity, + InvalidSignature, + BadSignature + }; + + explicit SignatureVerificationResult( Validity validity = UnknownValidity ); + SignatureVerificationResult( const SignatureVerificationResult& other ); + ~SignatureVerificationResult(); + + SignatureVerificationResult& operator=( const SignatureVerificationResult& other ); + bool operator==( const SignatureVerificationResult& other ) const; + + bool isValid() const; + Validity validity() const; + void setValidity( Validity validity ); + + QString errorString() const; + void setErrorString( const QString& errorString ); + + private: + class Private; + QSharedDataPointer<Private> d; + }; +} + +Q_DECLARE_METATYPE( KDUpdater::SignatureVerificationResult ) + +#endif // KD_UPDATER_SIGNATUREVERIFICATIONRESULT_H diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.cpp new file mode 100644 index 000000000..19c6337e4 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdatersignatureverificationrunnable.h" +#include "kdupdatersignatureverifier.h" +#include "kdupdatersignatureverificationresult.h" + +#include <QByteArray> +#include <QIODevice> +#include <QMetaObject> +#include <QObject> +#include <QPointer> +#include <QThreadPool> +#include <QVariant> +#include <QVector> + +#include <cassert> + +using namespace KDUpdater; + +class Runnable::Private { +public: + QVector<QObject*> receivers; + QVector<QByteArray> methods; +}; + +Runnable::Runnable() : QRunnable(), d( new Private ) { +} + +Runnable::~Runnable() { +} + + +void Runnable::addResultListener( QObject* receiver, const char* method ) { + d->receivers.push_back( receiver ); + d->methods.push_back( QByteArray( method ) ); +} + +void Runnable::emitResult( const QGenericArgument& arg0, + const QGenericArgument& arg1, + const QGenericArgument& arg2, + const QGenericArgument& arg3, + const QGenericArgument& arg4, + const QGenericArgument& arg5, + const QGenericArgument& arg6, + const QGenericArgument& arg7, + const QGenericArgument& arg8, + const QGenericArgument& arg9 ) { + assert( d->receivers.size() == d->methods.size() ); + for ( int i = 0; i < d->receivers.size(); ++i ) { + QMetaObject::invokeMethod( d->receivers[i], + d->methods[i].constData(), + Qt::QueuedConnection, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9 ); + } +} + +class SignatureVerificationRunnable::Private { +public: + Private() : verifier( 0 ) {} + const SignatureVerifier* verifier; + QPointer<QIODevice> device; + QByteArray signature; +}; + +SignatureVerificationRunnable::SignatureVerificationRunnable() : Runnable(), d( new Private ) { +} + +SignatureVerificationRunnable::~SignatureVerificationRunnable() { +} + +const SignatureVerifier* SignatureVerificationRunnable::verifier() const { + return d->verifier; +} + +void SignatureVerificationRunnable::setVerifier( const SignatureVerifier* verifier ) { + delete d->verifier; + d->verifier = verifier ? verifier->clone() : 0; +} + +QByteArray SignatureVerificationRunnable::signature() const { + return d->signature; +} + +void SignatureVerificationRunnable::setSignature( const QByteArray& sig ) { + d->signature = sig; +} + +QIODevice* SignatureVerificationRunnable::data() const { + return d->device; +} + +void SignatureVerificationRunnable::setData( QIODevice* device ) { + d->device = device; +} + + +void SignatureVerificationRunnable::run() { + QThreadPool::globalInstance()->releaseThread(); + const SignatureVerificationResult result = d->verifier->verify( d->device->readAll(), d->signature ); + QThreadPool::globalInstance()->reserveThread(); + delete d->verifier; + delete d->device; + emitResult( Q_ARG( KDUpdater::SignatureVerificationResult, result ) ); +} + + diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h new file mode 100644 index 000000000..afc201bea --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KDUPDATERSIGNATUREVERIFICATIONJOB_H +#define KDUPDATERSIGNATUREVERIFICATIONJOB_H + +#include <KDToolsCore/pimpl_ptr.h> +#include <QtCore/QGenericArgument> +#include <QtCore/QRunnable> + +class QByteArray; +class QIODevice; +class QObject; +template <typename T> class QVector; + +namespace KDUpdater { + class SignatureVerifier; + class SignatureVerificationResult; + + class Runnable : public QRunnable { + public: + Runnable(); + ~Runnable(); + + void addResultListener( QObject* receiver, const char* method ); + + protected: + void emitResult( const QGenericArgument& arg0=QGenericArgument( 0 ), + const QGenericArgument& arg1=QGenericArgument(), + const QGenericArgument& arg2=QGenericArgument(), + const QGenericArgument& arg3=QGenericArgument(), + const QGenericArgument& arg4=QGenericArgument(), + const QGenericArgument& arg5=QGenericArgument(), + const QGenericArgument& arg6=QGenericArgument(), + const QGenericArgument& arg7=QGenericArgument(), + const QGenericArgument& arg8=QGenericArgument(), + const QGenericArgument& arg9=QGenericArgument() ); + + private: + class Private; + kdtools::pimpl_ptr<Private> d; + }; + + class SignatureVerificationRunnable : public Runnable { + public: + explicit SignatureVerificationRunnable(); + ~SignatureVerificationRunnable(); + + const SignatureVerifier* verifier() const; + void setVerifier( const SignatureVerifier* verifier ); + + QByteArray signature() const; + void setSignature( const QByteArray& sig ); + + QIODevice* data() const; + void setData( QIODevice* device ); + + /* reimp */ void run(); + + private: + class Private; + kdtools::pimpl_ptr<Private> d; + }; +} + +#endif // KDUPDATERSIGNATUREVERIFICATIONJOB_H diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.cpp new file mode 100644 index 000000000..28cba7098 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdatersignatureverifier.h" +#include "kdupdatersignatureverificationresult.h" + +#include <QFile> + +using namespace KDUpdater; + +SignatureVerifier::~SignatureVerifier() +{ +} + +SignatureVerificationResult SignatureVerifier::verify( const QString& dataFile, const QString& signatureFile ) const +{ + QFile dFile( dataFile ); + QFile sFile( signatureFile ); + + if( !dFile.open( QIODevice::ReadOnly ) ) + return SignatureVerificationResult(); + + if( !sFile.open( QIODevice::ReadOnly ) ) + return SignatureVerificationResult( SignatureVerificationResult::BadSignature ); + + return verify( dFile.readAll(), sFile.readAll() ); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h new file mode 100644 index 000000000..dfb8cbddb --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_SIGNATUREVERIFIER_H +#define KD_UPDATER_SIGNATUREVERIFIER_H + +#include "kdupdater.h" + +class QByteArray; +class QIODevice; +class QString; + +namespace KDUpdater { + + class SignatureVerificationResult; + + class KDTOOLS_UPDATER_EXPORT SignatureVerifier { + public: + virtual ~SignatureVerifier(); + virtual SignatureVerifier* clone() const = 0; + virtual SignatureVerificationResult verify( const QByteArray &data, const QByteArray& signature ) const = 0; + virtual SignatureVerificationResult verify( const QString& dataFile, const QString& signatureFile ) const; + virtual QString type() const = 0; + }; +} + +#endif // KD_UPDATER_SIGNATUREVERIFIER_H diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatertask.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatertask.cpp new file mode 100644 index 000000000..ee8d5aca8 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatertask.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdatertask.h" + +/*! + \ingroup kdupdater + \class KDUpdater::Task kdupdatertask.h KDUpdaterTask + \brief Base class for all task classes in KDUpdater + + This class is the base class for all task classes in KDUpdater. Task is an activity that + occupies certain amount of execution time. It can be started, stopped (or canceled), paused and + resumed. Tasks can report progress and error messages which an application can show in any + sort of UI. The KDUpdater::Task class provides a common interface for dealing with all kinds of + tasks in KDUpdater. The class diagram show in this class documentation will help in pointing out + the task classes in KDUpdater. + + User should be carefull of these points: + \li Instances of this class cannot be created. Only instance of the subclasses can be created + \li Task classes can be started only once. +*/ + +struct KDUpdater::Task::TaskData +{ + TaskData( Task* qq) : + q( qq ) + { + caps = KDUpdater::Task::NoCapability; + errorCode = 0; + started = false; + finished = false; + paused = false; + stopped = false; + progressPc = 0; + } + + Task* q; + int caps; + QString name; + int errorCode; + QString errorText; + bool started; + bool finished; + bool paused; + bool stopped; + int progressPc; + QString progressText; +}; + +/*! + \internal +*/ +KDUpdater::Task::Task(const QString& name, int caps, QObject* parent) + : QObject(parent), + d( new TaskData( this ) ) +{ + d->caps = caps; + d->name = name; +}; + +/*! + \internal +*/ +KDUpdater::Task::~Task() +{ + delete d; +} + +/*! + Returns the name of the task. +*/ +QString KDUpdater::Task::name() const +{ + return d->name; +} + +/*! + Returns the capabilities of the task. It is a combination of one or more + Capability flags. Defined as follows + \code + enum KDUpdater::Task::Capability + { + NoCapability = 0, + Pausable = 1, + Stoppable = 2 + }; + \endcode +*/ +int KDUpdater::Task::capabilities() const +{ + return d->caps; +} + +/*! + Returns the last reported error code. +*/ +int KDUpdater::Task::error() const +{ + return d->errorCode; +} + +/*! + Returns the last reported error message text. +*/ +QString KDUpdater::Task::errorString() const +{ + return d->errorText; +} + +/*! + Returns whether the task has started and is running or not. +*/ +bool KDUpdater::Task::isRunning() const +{ + return d->started; +} + +/*! + Returns whether the task has finished or not. + + \note Stopped (or canceled) tasks are not finished tasks. +*/ +bool KDUpdater::Task::isFinished() const +{ + return d->finished; +} + +/*! + Returns whether the task is paused or not. +*/ +bool KDUpdater::Task::isPaused() const +{ + return d->paused; +} + +/*! + Returns whether the task is stopped or not. + + \note Finished tasks are not stopped classes. +*/ +bool KDUpdater::Task::isStopped() const +{ + return d->stopped; +} + +/*! + Returns the progress in percentage made by this task. +*/ +int KDUpdater::Task::progressPercent() const +{ + return d->progressPc; +} + +/*! + Returns a string that describes the progress made by this task as a string. +*/ +QString KDUpdater::Task::progressText() const +{ + return d->progressText; +} + +/*! + Starts the task. +*/ +void KDUpdater::Task::run() +{ + if(d->started) + { + qDebug("Trying to start an already started task"); + return; + } + + if(d->finished || d->stopped) + { + qDebug("Trying to start a finished or canceled task"); + return; + } + + d->stopped = false; + d->finished = false; // for the sake of completeness + d->started = true; + emit started(); + reportProgress(0, tr("%1 started").arg(d->name)); + + doRun(); +} + +/*! + Stops the task, provided the task has \ref Stoppable capability. + + \note Once the task is stopped, it cannot be restarted. +*/ +void KDUpdater::Task::stop() +{ + if( !(d->caps & Stoppable) ) + { + const QString errorMsg = tr("'%1' cannot be stopped").arg(d->name); + reportError(KDUpdater::ECannotStopTask, errorMsg); + return; + } + + if(!d->started) + { + qDebug("Trying to stop an unstarted task"); + return; + } + + if(d->finished || d->stopped) + { + qDebug("Trying to stop a finished or canceled task"); + return; + } + + d->stopped = doStop(); + if(!d->stopped) + { + const QString errorMsg = tr("Cannot stop task '%1'").arg(d->name); + reportError(KDUpdater::ECannotStopTask, errorMsg); + return; + } + + d->started = false; // the task is not running + d->finished = false; // the task is not finished, but was canceled half-way through + + emit stopped(); + deleteLater(); +} + +/*! + Paused the task, provided the task has \ref Pausable capability. +*/ +void KDUpdater::Task::pause() +{ + if( !(d->caps & Pausable) ) + { + const QString errorMsg = tr("'%1' cannot be paused").arg(d->name); + reportError(KDUpdater::ECannotPauseTask, errorMsg); + return; + } + + if(!d->started) + { + qDebug("Trying to pause an unstarted task"); + return; + } + + if(d->finished || d->stopped) + { + qDebug("Trying to pause a finished or canceled task"); + return; + } + + d->paused = doPause(); + if(!d->paused) + { + const QString errorMsg = tr("Cannot pause task '%1'").arg(d->name); + reportError(KDUpdater::ECannotPauseTask, errorMsg); + return; + } + + // The task state has to be started, paused but not finished or stopped. + // We need not set the flags below, but just in case. + // Perhaps we should do Q_ASSERT() ??? + d->started = true; + d->finished = false; + d->stopped = false; + + emit paused(); +} + +/*! + Resumes the task if it was paused. +*/ +void KDUpdater::Task::resume() +{ + if(!d->paused) + { + qDebug("Trying to resume an unpaused task"); + return; + } + + const bool val = doResume(); + if(!val) + { + const QString errorMsg = tr("Cannot resume task '%1'").arg(d->name); + reportError(KDUpdater::ECannotResumeTask, errorMsg); + return; + } + + // The task state should be started, but not paused, finished or stopped. + // We need not set the flags below, but just in case. + // Perhaps we should do Q_ASSERT() ??? + d->started = true; + d->paused = false; + d->finished = false; + d->stopped = false; + + emit resumed(); +} + +/*! + \internal +*/ +void KDUpdater::Task::reportProgress(int percent, const QString& text) +{ + if(d->progressPc == percent) + return; + + d->progressPc = percent; + d->progressText = text; + emit progressValue( d->progressPc ); + emit progressText( d->progressText ); +} + +/*! + \internal +*/ +void KDUpdater::Task::reportError(int errorCode, const QString& errorText) +{ + d->errorCode = errorCode; + d->errorText = errorText; + + emit error(d->errorCode, d->errorText); + deleteLater(); +} + +/*! + \internal +*/ +void KDUpdater::Task::reportDone() +{ + QString msg = tr("%1 done"); + reportProgress(100, msg); + + // State should be finished, but not started, paused or stopped. + d->finished = true; + d->started = false; + d->paused = false; + d->stopped = false; + d->errorCode = 0; + d->errorText.clear(); + + emit finished(); + deleteLater(); +} + +/*! + \fn virtual bool KDUpdater::Task::doStart() = 0; +*/ + +/*! + \fn virtual bool KDUpdater::Task::doStop() = 0; +*/ + +/*! + \fn virtual bool KDUpdater::Task::doPause() = 0; +*/ + +/*! + \fn virtual bool KDUpdater::Task::doResume() = 0; +*/ + +/*! + \signal void KDUpdater::Task::error(int code, const QString& errorText) + + This signal is emitted to notify an error during the execution of this task. + \param code Error code + \param errorText A string describing the error. + + Error codes are just integers, there are however built in errors represented + by the KDUpdater::Error enumeration + \code + enum Error + { + ECannotStartTask, + ECannotPauseTask, + ECannotResumeTask, + ECannotStopTask, + EUnknown + }; + \endcode +*/ + +/*! + \signal void KDUpdater::Task::progress(int percent, const QString& progressText) + + This signal is emitted to nofity progress made by the task. + + \param percent Percentage of progress made + \param progressText A string describing the progress made +*/ + +/*! + \signal void KDUpdater::Task::started() + + This signal is emitted when the task has started. +*/ + +/*! + \signal void KDUpdater::Task::paused() + + This signal is emitted when the task has paused. +*/ + +/*! + \signal void KDUpdater::Task::resumed() + + This signal is emitted when the task has resumed. +*/ + +/*! + \signal void KDUpdater::Task::stopped() + + This signal is emitted when the task has stopped (or canceled). +*/ + +/*! + \signal void KDUpdater::Task::finished() + + This signal is emitted when the task has finished. +*/ diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatertask.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatertask.h new file mode 100644 index 000000000..84dada516 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatertask.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_TASK_H +#define KD_UPDATER_TASK_H + +#include "kdupdater.h" +#include <QObject> + +namespace KDUpdater +{ + class KDTOOLS_UPDATER_EXPORT Task : public QObject + { + Q_OBJECT + + public: + enum Capability + { + NoCapability = 0, + Pausable = 1, + Stoppable = 2 + }; + + virtual ~Task(); + + QString name() const; + int capabilities() const; + + int error() const; + QString errorString() const; + + bool isRunning() const; + bool isFinished() const; + bool isPaused() const; + bool isStopped() const; + + int progressPercent() const; + QString progressText() const; + + public Q_SLOTS: + void run(); + void stop(); + void pause(); + void resume(); + + Q_SIGNALS: + void error(int code, const QString& errorText); + void progressValue(int percent); + void progressText(const QString& progressText); + void started(); + void paused(); + void resumed(); + void stopped(); + void finished(); + + protected: + explicit Task(const QString& name, int caps=NoCapability, QObject* parent=0); + void reportProgress(int percent, const QString& progressText); + void reportError(int errorCode, const QString& errorText); + void reportDone(); + + void reportError(const QString& errorText) + { + reportError(EUnknown, errorText); + } + + protected: + // Task interface + virtual void doRun() = 0; + virtual bool doStop() = 0; + virtual bool doPause() = 0; + virtual bool doResume() = 0; + + private: + struct TaskData; + TaskData* d; + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon.cpp new file mode 100644 index 000000000..4a93b92c2 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterufcompresscommon_p.h" + +#include <QCryptographicHash> +#include <QDataStream> + +using namespace KDUpdater; + +bool UFHeader::isValid() const +{ + return magic == QLatin1String( KD_UPDATER_UF_HEADER_MAGIC ) && + fileList.count() == permList.count() && + fileList.count() == isDirList.count(); +} + +void UFHeader::addToHash(QCryptographicHash& hash) const +{ + QByteArray data; + QDataStream stream( &data, QIODevice::WriteOnly ); + stream << *this; + hash.addData(data); +} + +UFEntry::UFEntry() + : permissions( 0 ) +{ +} + +bool UFEntry::isValid() const +{ + return !fileName.isEmpty(); +} + +void UFEntry::addToHash(QCryptographicHash& hash) const +{ + QByteArray data; + QDataStream stream( &data, QIODevice::WriteOnly ); + stream.setVersion( QDataStream::Qt_4_2 ); + stream << *this; + hash.addData(data); +} + +namespace KDUpdater +{ + +QDataStream& operator<<( QDataStream& stream, const UFHeader& hdr ) +{ + stream << hdr.magic; + stream << hdr.fileList; + stream << hdr.permList; + stream << hdr.isDirList; + return stream; +} + +QDataStream& operator>>( QDataStream& stream, UFHeader& hdr ) +{ + const QDataStream::Status oldStatus = stream.status(); + stream >> hdr.magic; + if( stream.status() == QDataStream::Ok && hdr.magic != QLatin1String( KD_UPDATER_UF_HEADER_MAGIC ) ) + stream.setStatus( QDataStream::ReadCorruptData ); + + if( stream.status() == QDataStream::Ok ) + stream >> hdr.fileList; + + if( stream.status() == QDataStream::Ok ) + stream >> hdr.permList; + + if( stream.status() == QDataStream::Ok ) + stream >> hdr.isDirList; + + if( stream.status() == QDataStream::Ok && ( hdr.fileList.count() != hdr.permList.count() || hdr.permList.count() != hdr.isDirList.count() ) ) + stream.setStatus( QDataStream::ReadCorruptData ); + + if( stream.status() != QDataStream::Ok ) + hdr = UFHeader(); + + if( oldStatus != QDataStream::Ok ) + stream.setStatus( oldStatus ); + + return stream; +} + +QDataStream& operator<<( QDataStream& stream, const UFEntry& entry ) +{ + stream << entry.fileName; + stream << entry.permissions; + stream << entry.fileData; + return stream; +} + +QDataStream& operator>>( QDataStream& stream, UFEntry& entry ) +{ + const QDataStream::Status oldStatus = stream.status(); + if( stream.status() == QDataStream::Ok ) + stream >> entry.fileName; + if( stream.status() == QDataStream::Ok ) + stream >> entry.permissions; + if( stream.status() == QDataStream::Ok ) + stream >> entry.fileData; + + if( stream.status() != QDataStream::Ok ) + entry = UFEntry(); + + if( oldStatus != QDataStream::Ok ) + stream.setStatus( oldStatus ); + + return stream; +} + +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h new file mode 100644 index 000000000..65f6ea5cb --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_KDUPDATE_UFCOMPRESSCOMMON_P_H__ +#define __KDTOOLS_KDUPDATE_UFCOMPRESSCOMMON_P_H__ + +#define KD_UPDATER_UF_HEADER_MAGIC "KDVCLZ" + +#include <KDToolsCore/kdtoolsglobal.h> + +#include <QtCore/QStringList> +#include <QtCore/QByteArray> +#include <QtCore/QVector> + +class QCryptographicHash; +class QDataStream; + +namespace KDUpdater +{ + struct KDTOOLS_UPDATER_EXPORT UFHeader + { + QString magic; + QStringList fileList; + QVector<quint64> permList; + QList<bool> isDirList; + + bool isValid() const; + + void addToHash( QCryptographicHash& hash ) const; + }; + + struct KDTOOLS_UPDATER_EXPORT UFEntry + { + QString fileName; + quint64 permissions; + QByteArray fileData; + + UFEntry(); + + bool isValid() const; + + void addToHash(QCryptographicHash& hash) const; + }; + + KDTOOLS_UPDATER_EXPORT QDataStream& operator<<( QDataStream& stream, const UFHeader& hdr ); + KDTOOLS_UPDATER_EXPORT QDataStream& operator>>( QDataStream& stream, UFHeader& hdr ); + + KDTOOLS_UPDATER_EXPORT QDataStream& operator<<( QDataStream& stream, const UFEntry& entry ); + KDTOOLS_UPDATER_EXPORT QDataStream& operator>>( QDataStream& stream, UFEntry& entry ); +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor.cpp new file mode 100644 index 000000000..f5c36e44f --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterufuncompressor_p.h" +#include "kdupdaterufcompresscommon_p.h" + +#include <QCryptographicHash> +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QFSFileEngine> +#include <QDebug> + +using namespace KDUpdater; + +class UFUncompressor::Private +{ +public: + QString ufFileName; + QString destination; + QString errorMessage; + + void setError(const QString& msg); +}; + +void UFUncompressor::Private::setError(const QString& msg) +{ + errorMessage = msg; +} + +UFUncompressor::UFUncompressor() +{ +} + +UFUncompressor::~UFUncompressor() +{ +} + +QString UFUncompressor::errorString() const +{ + return d->errorMessage; +} + +void UFUncompressor::setFileName(const QString& fileName) +{ + d->ufFileName = fileName; +} + +QString UFUncompressor::fileName() const +{ + return d->ufFileName; +} + +void UFUncompressor::setDestination(const QString& dest) +{ + d->destination = dest; +} + +QString UFUncompressor::destination() const +{ + return d->destination; +} + +bool UFUncompressor::uncompress() +{ + d->errorMessage.clear(); + + // First open the uf file for reading + QFile ufFile( d->ufFileName ); + if( !ufFile.open(QFile::ReadOnly) ) { + d->setError(tr("Couldn't open file for reading: %1").arg( ufFile.errorString() )); + return false; + } + + QDataStream ufDS( &ufFile ); + ufDS.setVersion( QDataStream::Qt_4_2 ); + QCryptographicHash hash( QCryptographicHash::Md5 ); + + // Now read the header. + UFHeader header; + ufDS >> header; + if( ufDS.status() != QDataStream::Ok || !header.isValid() ) + { + d->setError( tr( "Couldn't read the file header." ) ); + return false; + } + header.addToHash(hash); + + // Some basic checks. + if( header.magic != QLatin1String( KD_UPDATER_UF_HEADER_MAGIC ) ) { + d->setError(tr("Wrong file format (magic number not found)")); + return false; + } + + // Lets get to the destination directory + const QDir dir(d->destination); + QFSFileEngine fileEngine; + + // Lets create the required directory structure + int numExpectedFiles = 0; + for(int i=0; i<header.fileList.count(); i++) + { + const QString fileName = header.fileList[i]; + // qDebug("ToUncompress %s", qPrintable(fileName)); + if( header.isDirList[i] ) + { + if ( !dir.mkpath( fileName ) ) + { + d->setError(tr("Could not create folder: %1/%2").arg( d->destination, fileName )); + return false; + } + fileEngine.setFileName( QString(QLatin1String( "%1/%2" )).arg(d->destination, fileName) ); + fileEngine.setPermissions( header.permList[i] | QAbstractFileEngine::ExeOwnerPerm ); + } else { + ++numExpectedFiles; + } + } + + // Lets now create files within these directories + int numActualFiles = 0; + while( !ufDS.atEnd() && numActualFiles < numExpectedFiles ) + { + UFEntry ufEntry; + ufDS >> ufEntry; + if( ufDS.status() != QDataStream::Ok || !ufEntry.isValid() ) + { + d->setError( tr( "Could not read information for entry %1." ).arg( numActualFiles ) ); + return false; + } + ufEntry.addToHash(hash); + + const QString completeFileName = QString(QLatin1String( "%1/%2" )).arg(d->destination, ufEntry.fileName); + + const QByteArray ba = qUncompress( ufEntry.fileData ); + // check the size + QDataStream stream( ufEntry.fileData ); + stream.setVersion( QDataStream::Qt_4_2 ); + qint32 length = 0; + stream >> length; + if( ba.length() != length ) // uncompress failed + { + d->setError(tr("Could not uncompress entry %1, corrupt data").arg( ufEntry.fileName ) ); + return false; + + } + + + QFile ufeFile( completeFileName ); + if ( !ufeFile.open( QFile::WriteOnly ) ) + { + d->setError(tr("Could not open file %1 for writing: %2").arg( completeFileName, ufeFile.errorString() )); + return false; + } + + + const char* const data = ba.constData(); + const qint64 total = ba.size(); + qint64 written = 0; + + while ( written < total ) + { + const qint64 num = ufeFile.write( data+written, total-written ); + if ( num == -1 ) + { + d->setError( tr("Failed writing uncompressed data to %1: %2").arg( completeFileName, ufeFile.errorString() ) ); + return false; + } + written += num; + } + + ufeFile.close(); + + const QFile::Permissions perm = static_cast< QFile::Permissions >( ufEntry.permissions ); + ufeFile.setPermissions( perm ); + + if ( ufeFile.error() != QFile::NoError ) + { + ufeFile.remove(); + d->setError( tr("Failed writing uncompressed data to %1: %2").arg( completeFileName, ufeFile.errorString() ) ); + return false; + } + + qDebug("Uncompressed %s", qPrintable(completeFileName)); + ++numActualFiles; + } + + if( numExpectedFiles != numActualFiles ) { + d->errorMessage = tr("Corrupt file (wrong number of files)"); + return false; + } + + QByteArray hashdata; + ufDS >> hashdata; + + if( hashdata != hash.result() ) { + d->errorMessage = tr("Corrupt file (wrong hash)"); + return false; + } + + return true; +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h new file mode 100644 index 000000000..5800887fc --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef __KDTOOLS_KDUPDATERUFUNCOMPRESSOR_P_H__ +#define __KDTOOLS_KDUPDATERUFUNCOMPRESSOR_P_H__ + +#include <KDToolsCore/pimpl_ptr.h> + +#include <QtCore/QCoreApplication> + +class QString; + +namespace KDUpdater +{ + class KDTOOLS_UPDATER_EXPORT UFUncompressor + { + Q_DECLARE_TR_FUNCTIONS(KDUpdater::UFUncompressor) + + public: + UFUncompressor(); + ~UFUncompressor(); + + QString errorString() const; + + void setFileName(const QString& fileName); + QString fileName() const; + + void setDestination(const QString& dest); + QString destination() const; + + bool uncompress(); + + private: + class Private; + kdtools::pimpl_ptr< Private > d; + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdate.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdate.cpp new file mode 100644 index 000000000..a84f3799c --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdate.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdate.h" +#include "kdupdaterapplication.h" +#include "kdupdaterupdatesourcesinfo.h" +#include "kdupdaterfiledownloader_p.h" +#include "kdupdaterfiledownloaderfactory.h" +#include "kdupdaterupdateoperations.h" +#include "kdupdaterupdateoperationfactory.h" + +#include <QFile> + +/*! + \ingroup kdupdater + \class KDUpdater::Update kdupdaterupdate.h KDUpdaterUpdate + \brief Represents a single update + + The KDUpdater::Update class contains information and mechanisms to download one update. It is + created by KDUpdater::UpdateFinder and is used by KDUpdater::UpdateInstaller to download the UpdateFile + corresponding to the update. + + The class makes use of appropriate network protocols (HTTP, HTTPS, FTP, or Local File Copy) to + download the UpdateFile. + + The constructor of the KDUpdater::Update class is made protected, because it can be instantiated only by + KDUpdater::UpdateFinder (which is a friend class). The destructor however is public. +*/ + +struct KDUpdater::Update::UpdateData +{ + UpdateData( Update* qq ) : + q( qq ), + application( 0 ), + compressedSize( 0 ), + uncompressedSize( 0 ) + {} + + Update* q; + Application* application; + KDUpdater::UpdateSourceInfo sourceInfo; + QMap<QString, QVariant> data; + QUrl updateUrl; + UpdateType type; + QList<UpdateOperation*> operations; + QByteArray sha1sum; + + quint64 compressedSize; + quint64 uncompressedSize; + + KDUpdater::FileDownloader* fileDownloader; +}; + + +/*! + \internal +*/ +KDUpdater::Update::Update(KDUpdater::Application* application, const KDUpdater::UpdateSourceInfo& sourceInfo, + UpdateType type, const QUrl& updateUrl, const QMap<QString, QVariant>& data, quint64 compressedSize, quint64 uncompressedSize, const QByteArray& sha1sum ) + : KDUpdater::Task(QLatin1String( "Update" ), Stoppable, application), + d( new UpdateData( this ) ) +{ + d->application = application; + d->sourceInfo = sourceInfo; + d->data = data; + d->updateUrl = updateUrl; + d->type = type; + + d->compressedSize = compressedSize; + d->uncompressedSize = uncompressedSize; + d->sha1sum = sha1sum; + + const SignatureVerifier* verifier = d->application->signatureVerifier( Application::Packages ); + + d->fileDownloader = FileDownloaderFactory::instance().create( updateUrl.scheme(), verifier, QUrl(), this); + if(d->fileDownloader) + { + d->fileDownloader->setUrl(d->updateUrl); + d->fileDownloader->setSha1Sum( d->sha1sum ); + connect(d->fileDownloader, SIGNAL(downloadProgress(double)), this, SLOT(downloadProgress(double))); + connect(d->fileDownloader, SIGNAL(downloadCanceled()), this, SIGNAL(stopped())); + connect(d->fileDownloader, SIGNAL(downloadCompleted()), this, SIGNAL(finished())); + } + + switch( type ) { + case NewPackage: + case PackageUpdate: + { + KDUpdater::UpdateOperation* packageOperation = UpdateOperationFactory::instance().create( QLatin1String( "UpdatePackage" ) ); + QStringList args; + args << data.value( QLatin1String( "Name" ) ).toString() + << data.value( QLatin1String( "Version" ) ).toString() + << data.value( QLatin1String( "ReleaseDate" ) ).toString(); + packageOperation->setArguments(args); + packageOperation->setApplication( application ); + d->operations.append( packageOperation ); + break; + } + case CompatUpdate: + { + KDUpdater::UpdateOperation* compatOperation = UpdateOperationFactory::instance().create( QLatin1String( "UpdateCompatLevel" ) ); + QStringList args; + args << data.value( QLatin1String( "CompatLevel" ) ).toString(); + compatOperation->setArguments(args); + compatOperation->setApplication( application ); + d->operations.append( compatOperation ); + break; + } + default: + break; + } +} + +/*! + Destructor +*/ +KDUpdater::Update::~Update() +{ + const QString fileName = this->downloadedFileName(); + if( !fileName.isEmpty() ) + QFile::remove( fileName ); + qDeleteAll( d->operations ); + d->operations.clear(); + delete d; +} + +/*! + Returns the application for which this class is downloading the UpdateFile +*/ +KDUpdater::Application* KDUpdater::Update::application() const +{ + return d->application; +} + +/*! + Returns the release date of the update downloaded by this class +*/ +QDate KDUpdater::Update::releaseDate() const +{ + return d->data.value( QLatin1String( "ReleaseDate" ) ).toDate(); +} + +/*! + Returns data whose name is given in parameter, or an invalid QVariant if the data doesn't exist. +*/ +QVariant KDUpdater::Update::data( const QString& name ) const +{ + if ( d->data.contains( name ) ) + return d->data.value( name ); + return QVariant(); +} + +/*! + Returns the complete URL of the UpdateFile downloaded by this class. +*/ +QUrl KDUpdater::Update::updateUrl() const +{ + return d->updateUrl; +} + +/*! + Returns the update source info on which this update was created. +*/ +KDUpdater::UpdateSourceInfo KDUpdater::Update::sourceInfo() const +{ + return d->sourceInfo; +} + +/*! + * Returns the type of update + */ +KDUpdater::UpdateType KDUpdater::Update::type() const +{ + return d->type; +} + +/*! + Returns true of the update can be downloaded, false otherwise. The function + returns false if the URL scheme is not supported by this class. +*/ +bool KDUpdater::Update::canDownload() const +{ + return d->fileDownloader && d->fileDownloader->canDownload(); +} + +/*! + Returns true of the update has been downloaded. If this function returns true + the you can use the \ref downloadedFileName() method to get the complete name + of the downloaded UpdateFile. + + \note: The downloaded UpdateFile will be deleted when this class is destroyed +*/ +bool KDUpdater::Update::isDownloaded() const +{ + return d->fileDownloader && d->fileDownloader->isDownloaded(); +} + +/*! + Returns the name of the downloaded UpdateFile after the download is complete, ie + when \ref isDownloaded() returns true. +*/ +QString KDUpdater::Update::downloadedFileName() const +{ + if(d->fileDownloader) + return d->fileDownloader->downloadedFileName(); + + return QString(); +} + +/*! + \internal +*/ +void KDUpdater::Update::downloadProgress(double value) +{ + Q_ASSERT(value <= 1); + reportProgress(value * 100, tr("Downloading update...")); +} + +/*! + \internal +*/ +void KDUpdater::Update::downloadCompleted() +{ + reportProgress(100, tr("Update downloaded")); + reportDone(); +} + +/*! + \internal +*/ +void KDUpdater::Update::downloadAborted(const QString& msg) +{ + reportError(msg); +} + +/*! + \internal +*/ +void KDUpdater::Update::doRun() +{ + if(d->fileDownloader) + d->fileDownloader->download(); +} + +/*! + \internal +*/ +bool KDUpdater::Update::doStop() +{ + if(d->fileDownloader) + d->fileDownloader->cancelDownload(); + return true; +} + +/*! + \internal +*/ +bool KDUpdater::Update::doPause() +{ + return false; +} + +/*! + \internal +*/ +bool KDUpdater::Update::doResume() +{ + return false; +} + +/*! + Returns a list of operations needed by this update. For example, package update needs to change + the package version, compat update needs to change the compat level... + */ +QList<KDUpdater::UpdateOperation*> KDUpdater::Update::operations() const +{ + return d->operations; +} + +/*! + * Returns the compressed size of this update's data file. + */ +quint64 KDUpdater::Update::compressedSize() const +{ + return d->compressedSize; +} + +/*! + * Returns the uncompressed size of this update's data file. + */ +quint64 KDUpdater::Update::uncompressedSize() const +{ + return d->uncompressedSize; +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdate.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdate.h new file mode 100644 index 000000000..8ea4728b9 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdate.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_H +#define KD_UPDATER_UPDATE_H + +#include "kdupdater.h" +#include "kdupdatertask.h" +#include <QUrl> +#include <QDate> +#include <QMap> +#include <QVariant> +#include <QList> + +namespace KDUpdater +{ + class Application; + struct UpdateSourceInfo; + class UpdateFinder; + class UpdateOperation; + + class KDTOOLS_UPDATER_EXPORT Update : public Task + { + Q_OBJECT + + public: + ~Update(); + + Application* application() const; + + UpdateType type() const; + QUrl updateUrl() const; + QDate releaseDate() const; + QVariant data( const QString& name ) const; + UpdateSourceInfo sourceInfo() const; + + bool canDownload() const; + bool isDownloaded() const; + void download() { run(); } + QString downloadedFileName() const; + + QList<UpdateOperation*> operations() const; + + quint64 compressedSize() const; + quint64 uncompressedSize() const; + + private Q_SLOTS: + void downloadProgress(double); + void downloadAborted(const QString& msg); + void downloadCompleted(); + + private: + friend class UpdateFinder; + struct UpdateData; + UpdateData* d; + + void doRun(); + bool doStop(); + bool doPause(); + bool doResume(); + + Update(Application* application, const UpdateSourceInfo& sourceInfo, + UpdateType type, const QUrl& updateUrl, const QMap<QString, QVariant>& data, quint64 compressedSize, quint64 uncompressedSize, const QByteArray& sha1sum ); + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.cpp new file mode 100644 index 000000000..8d34586e8 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.cpp @@ -0,0 +1,892 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdatefinder.h" +#include "kdupdaterapplication.h" +#include "kdupdaterupdatesourcesinfo.h" +#include "kdupdaterpackagesinfo.h" +#include "kdupdaterupdate.h" +#include "kdupdaterfiledownloader_p.h" +#include "kdupdaterfiledownloaderfactory.h" +#include "kdupdaterupdatesinfo_p.h" +#include "kdupdatersignatureverifier.h" + +#include <QCoreApplication> +#include <QDebug> + +using namespace KDUpdater; + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateFinder kdupdaterupdatefinder KDUpdaterUpdateFinder + \brief Finds updates applicable for a \ref KDUpdater::Application + + The KDUpdater::UpdateFinder class helps in searching for updates and installing it on the application. The + class basically processes the application's \ref KDUpdater::PackagesInfo and the UpdateXMLs it aggregates + from all the update sources described in KDUpdater::UpdateSourcesInfo and populates a list of + \ref KDUpdater::Update objects. This list can then be passed to \ref KDUpdater::UpdateInstaller for + actually downloading and installing the updates. + + + Usage: + \code + KDUpdater::UpdateFinder updateFinder( application ); + QProgressDialog finderProgressDlg; + + QObject::connect( &updateFinder, SIGNAL(progressValue(int)), + &finderProgressDlg, SLOT(setValue(int))); + QObject::connect( &updateFinder, SIGNAL(computeUpdatesCompleted()), + &finderProgressDlg, SLOT(accept())); + QObject::connect( &updateFinder, SIGNAL(computeUpdatesCanceled()), + &finderProgressDlg, SLOT(reject())); + + QObject::connect( &finderProgressDlg, SIGNAL(canceled()), + &updateFinder, SLOT(cancelComputeUpdates())); + + updateFinder.run(); + finderProgressDlg.exec(); + +// Control comes here after update finding is done or canceled. + +QList<KDUpdater::Update*> updates = updateFinder.updates(); +KDUpdater::UpdateInstaller updateInstaller; +updateInstaller.installUpdates( updates ); + +\endcode +*/ + + +// +// Private +// +class KDUpdater::UpdateFinder::Private +{ +public: + Private( UpdateFinder* qq ) : + q( qq ), + application(0), + updateType(KDUpdater::PackageUpdate) + {} + + ~Private() + { + qDeleteAll( updates ); + qDeleteAll( updatesInfoList ); + qDeleteAll( updateXmlFDList ); + } + + UpdateFinder* q; + KDUpdater::Application* application; + QList<KDUpdater::Update*> updates; + UpdateTypes updateType; + + // Temporary structure that notes down information about updates. + bool cancel; + int downloadCompleteCount; + QList<KDUpdater::UpdateSourceInfo> updateSourceInfoList; + QList<KDUpdater::UpdatesInfo*> updatesInfoList; + QList<KDUpdater::FileDownloader*> updateXmlFDList; + + void clear(); + void computeUpdates(); + void cancelComputeUpdates(); + bool downloadUpdateXMLFiles(); + bool computeApplicableUpdates(); + + QList<KDUpdater::UpdateInfo> applicableUpdates(KDUpdater::UpdatesInfo* updatesInfo, bool addNewPackages = false ); + void createUpdateObjects(const KDUpdater::UpdateSourceInfo& sourceInfo, + const QList<KDUpdater::UpdateInfo>& updateInfoList); + bool checkForUpdatePriority(const KDUpdater::UpdateSourceInfo& sourceInfo, + const KDUpdater::UpdateInfo& updateInfo); + int pickUpdateFileInfo(const QList<KDUpdater::UpdateFileInfo>& updateFiles); + void slotDownloadDone(); +}; + + +static int computeProgressPercentage(int min, int max, int percent) +{ + return min + qint64(max-min) * percent / 100; +} + +static int computePercent(int done, int total) +{ + return total ? done * Q_INT64_C(100) / total : 0 ; +} + +/*! + \internal + + Releases all internal resources consumed while downloading and computing updates. +*/ +void KDUpdater::UpdateFinder::Private::clear() +{ + qDeleteAll( updates ); + updates.clear(); + qDeleteAll( updatesInfoList ); + updatesInfoList.clear(); + qDeleteAll( updateXmlFDList ); + updateXmlFDList.clear(); + updateSourceInfoList.clear(); + + downloadCompleteCount = 0; +} + +/*! + \internal + + This method computes the updates that can be applied on the application by + studying the application's \ref KDUpdater::PackagesInfo object and the UpdateXML files + from each of the update sources described in \ref KDUpdater::UpdateSourcesInfo. + + This function can take a long time to complete. The following signals are emitted + during the execution of this function + + The function creates \ref KDUpdater::Update objects on the stack. All KDUpdater::Update objects + are made children of the application associated with this finder. + + The update sources are fetched from the \ref KDUpdater::UpdateSourcesInfo object associated with + the application. Package information is extracted from the \ref KDUpdater::PackagesInfo object + associated with the application. + + \note Each time this function is called, all the previously computed updates are discarded +and its resources are freed. +*/ +void KDUpdater::UpdateFinder::Private::computeUpdates() +{ + // Computing updates is done in two stages + // 1. Downloading Update XML files from all the update sources + // 2. Matching updates with Package XML and figuring out available updates + + cancel = false; + clear(); + + // First do some quick sanity checks on the packages info + KDUpdater::PackagesInfo* packages = application->packagesInfo(); + if( !packages ) { + q->reportError(tr("Could not access the package information of this application")); + return; + } + if( !packages->isValid() ) { + q->reportError(packages->errorString()); + return; + } + + // Now do some quick sanity checks on the update sources info + KDUpdater::UpdateSourcesInfo* sources = application->updateSourcesInfo(); + if( !sources ) { + q->reportError(tr("Could not access the update sources information of this application")); + return; + } + if( !sources->isValid() ) { + q->reportError(sources->errorString()); + return; + } + + // Now we can start... + + // Step 1: 0 - 49 percent + if(!downloadUpdateXMLFiles() || cancel) + { + clear(); + return; + } + + // Step 2: 50 - 100 percent + if(!computeApplicableUpdates() || cancel) + { + clear(); + return; + } + + // All done + q->reportProgress( 100, tr("%1 updates found").arg(updates.count()) ); + q->reportDone(); +} + +/*! + \internal + + Cancels the computation of updates. + + \sa \ref computeUpdates() +*/ +void KDUpdater::UpdateFinder::Private::cancelComputeUpdates() +{ + cancel = true; +} + +/*! + \internal + + This function downloads Updates.xml from all the update sources. A single application can potentially + have several update sources, hence we need to be asynchronous in downloading updates from different + sources. + + The function basically does this for each update source + a) Create a KDUpdater::FileDownloader and KDUpdater::UpdatesInfo for each update + b) Triggers the download of Updates.xml from each file downloader. + c) The downloadCompleted(), downloadCanceled() and downloadAborted() signals are connected + in each of the downloaders. Once all the downloads are complete and/or aborted, the next stage + would be done. + + The function gets into an event loop until all the downloads are complete. +*/ +bool KDUpdater::UpdateFinder::Private::downloadUpdateXMLFiles() +{ + if( !application ) + return false; + + KDUpdater::UpdateSourcesInfo* updateSources = application->updateSourcesInfo(); + if( !updateSources ) + return false; + + // Create KDUpdater::FileDownloader and KDUpdater::UpdatesInfo for each update + for(int i=0; i<updateSources->updateSourceInfoCount(); i++) + { + KDUpdater::UpdateSourceInfo info = updateSources->updateSourceInfo(i); + QUrl updateXmlUrl = QString::fromLatin1("%1/Updates.xml").arg(info.url.toString()); + + const SignatureVerifier* verifier = application->signatureVerifier( Application::Metadata ); + KDUpdater::FileDownloader* downloader = FileDownloaderFactory::instance().create(updateXmlUrl.scheme(), verifier, QUrl(), q); + if( !downloader ) + continue; + + downloader->setUrl(updateXmlUrl); + downloader->setAutoRemoveDownloadedFile(true); + + KDUpdater::UpdatesInfo* updatesInfo = new KDUpdater::UpdatesInfo; + updateSourceInfoList.append(info); + updateXmlFDList.append(downloader); + updatesInfoList.append(updatesInfo); + + connect(downloader, SIGNAL(downloadCompleted()), + q, SLOT(slotDownloadDone())); + connect(downloader, SIGNAL(downloadCanceled()), + q, SLOT(slotDownloadDone())); + connect(downloader, SIGNAL(downloadAborted(QString)), + q, SLOT(slotDownloadDone())); + } + + // Trigger download of Updates.xml file + downloadCompleteCount = 0; + for(int i=0; i<updateXmlFDList.count(); i++) + { + KDUpdater::FileDownloader* downloader = updateXmlFDList[i]; + downloader->download(); + } + + // Wait until all downloaders have completed their downloads. + while(1) + { + QCoreApplication::processEvents(); + if( cancel ) + return false; + if( downloadCompleteCount == updateXmlFDList.count()) + break; + + int pc = computePercent(downloadCompleteCount, updateXmlFDList.count()); + q->reportProgress(pc, tr("Downloading Updates.xml from update-sources")); + } + + // All the downloaders have now either downloaded or aborted the + // donwload of update XML files. + + // Lets now get rid of update sources whose Updates.xml could not be downloaded + for(int i=0; i<updateXmlFDList.count(); i++) + { + KDUpdater::FileDownloader* downloader = updateXmlFDList[i]; + if( downloader->isDownloaded() ) + continue; + + KDUpdater::UpdateSourceInfo info = updateSourceInfoList[i]; + QString msg = tr("Could not download updates from %1 ('%2')").arg(info.name, info.url.toString()); + q->reportError(msg); + + delete updatesInfoList[i]; + delete downloader; + updateXmlFDList.removeAt(i); + updatesInfoList.removeAt(i); + updateSourceInfoList.removeAt(i); + --i; + } + + if (updatesInfoList.isEmpty()) { + return false; + } + + // Lets parse the downloaded update XML files and get rid of the downloaders. + for(int i=0; i<updateXmlFDList.count(); i++) + { + KDUpdater::FileDownloader* downloader = updateXmlFDList[i]; + KDUpdater::UpdatesInfo* updatesInfo = updatesInfoList[i]; + + updatesInfo->setFileName( downloader->downloadedFileName() ); + + if (!updatesInfo->isValid()) { + QString msg = updatesInfo->errorString(); + q->reportError(msg); + + delete updatesInfoList[i]; + delete downloader; + updateXmlFDList.removeAt(i); + updatesInfoList.removeAt(i); + --i; + } + } + qDeleteAll( updateXmlFDList ); + updateXmlFDList.clear(); + + if (updatesInfoList.isEmpty()) { + return false; + } + + q->reportProgress( 49, tr("Updates.xml file(s) downloaded from update sources") ); + return true; +} + +/*! + \internal + + This function runs through all the KDUpdater::UpdatesInfo objects created during + the downloadUpdateXMLFiles() method and compares it with the data contained in + KDUpdater::PackagesInfo. There by figures out whether an update is applicable for + this application or not. +*/ +bool KDUpdater::UpdateFinder::Private::computeApplicableUpdates() +{ + if( updateType & KDUpdater::CompatUpdate ) + { + KDUpdater::UpdateInfo compatUpdateInfo; + KDUpdater::UpdateSourceInfo compatUpdateSourceInfo; + + // Required compat level + int reqCompatLevel = application->compatLevel()+1; + + q->reportProgress(60, tr("Looking for compatibility update...")); + + // We are only interested in compat updates. + for(int i=0; i<updatesInfoList.count(); i++) + { + KDUpdater::UpdatesInfo* info = updatesInfoList[i]; + KDUpdater::UpdateSourceInfo updateSource = updateSourceInfoList[i]; + + // If we already have a compat update, just check if the source currently being + // considered has a higher priority or not. + if(compatUpdateInfo.data.contains( QLatin1String( "CompatLevel" ) ) && updateSource.priority < compatUpdateSourceInfo.priority) + continue; + + // Lets look for comapt updates that provide compat level one-higher than + // the application's current compat level. + QList<KDUpdater::UpdateInfo> updatesInfo = info->updatesInfo( KDUpdater::CompatUpdate, reqCompatLevel ); + + if( updatesInfo.count() == 0 ) + continue; + + compatUpdateInfo = updatesInfo.at( 0 ); + compatUpdateSourceInfo = updateSource; + } + + bool found = (compatUpdateInfo.data.contains( QLatin1String( "CompatLevel" ) )); + if(found) + { + q->reportProgress(80, tr("Found compatibility update..")); + + // Lets create an update for this compat update. + QString updateName = tr("Compatibility level %1 update").arg(reqCompatLevel); + QUrl url; + + // Pick a update file based on arch and OS. + int pickUpdateFileIndex = pickUpdateFileInfo(compatUpdateInfo.updateFiles); + if(pickUpdateFileIndex < 0) + { + q->reportError(tr("Compatibility update for the required architecture and hardware configuration was not found")); + q->reportProgress(100, tr("Compatibility update not found")); + return false; + } + + KDUpdater::UpdateFileInfo fileInfo = compatUpdateInfo.updateFiles.at( pickUpdateFileIndex ); + + // Create an update for this entry + url = QString::fromLatin1( "%1/%2" ).arg( compatUpdateSourceInfo.url.toString(), fileInfo.fileName ); + KDUpdater::Update* update = q->constructUpdate(application, + compatUpdateSourceInfo, + KDUpdater::CompatUpdate, url, + compatUpdateInfo.data, fileInfo.compressedSize, fileInfo.uncompressedSize, fileInfo.sha1sum ); + + // Register the update + updates.append(update); + + // Done + q->reportProgress(100, tr("Compatibility update found")); + } + else + q->reportProgress(100, tr("No compatibility updates found")); + } + if ( updateType & PackageUpdate ) + { + // We are not looking for normal updates, not compat ones. + for(int i=0; i<updatesInfoList.count(); i++) + { + // Fetch updates applicable to this application. + KDUpdater::UpdatesInfo* info = updatesInfoList[i]; + QList<KDUpdater::UpdateInfo> updates = applicableUpdates(info , updateType & NewPackage ); + if( !updates.count() ) + continue; + + if( cancel ) + return false; + KDUpdater::UpdateSourceInfo updateSource = updateSourceInfoList[i]; + + // Create KDUpdater::Update objects for updates that have a valid + // UpdateFile + createUpdateObjects(updateSource, updates); + if( cancel ) + return false; + + // Report progress + int pc = computePercent(i, updatesInfoList.count()); + pc = computeProgressPercentage(51, 100, pc); + q->reportProgress( pc, tr("Computing applicable updates") ); + } + } + + q->reportProgress( 99, tr("Application updates computed") ); + return true; +} + +QList<KDUpdater::UpdateInfo> KDUpdater::UpdateFinder::Private::applicableUpdates( KDUpdater::UpdatesInfo* updatesInfo, bool addNewPackages ) +{ + QList<KDUpdater::UpdateInfo> retList; + + if( !updatesInfo || updatesInfo->updateInfoCount( PackageUpdate ) == 0 ) + return retList; + + KDUpdater::PackagesInfo* packages = this->application->packagesInfo(); + if( !packages ) + return retList; + + // Check to see if the updates info contains updates for any application + bool anyApp = updatesInfo->applicationName() == QLatin1String( "{AnyApplication}" ); + int appNameIndex = -1; + + if( !anyApp ) + { + // updatesInfo->applicationName() describes one application or a series of + // application names separated by commas. + QString appName = updatesInfo->applicationName(); + appName = appName.replace(QLatin1String( ", " ), + QLatin1String( "," )); + appName = appName.replace(QLatin1String( " ," ), + QLatin1String( "," )); + + // Catch hold of app names contained updatesInfo->applicationName() + QStringList apps = appName.split(QLatin1String( "," ), QString::SkipEmptyParts); + appNameIndex = apps.indexOf(this->application->applicationName()); + + // If the application appName isnt one of the app names, then + // the updates are not applicable. + if( appNameIndex < 0 ) + return retList; + } + +#if 0 //Nokia-SDK: ignore ApplicationVersion, it has no purpose and just causes problems if someone bumps the config.xml application version accidentally + // Check to see if the update repository versions match with app version + if( !anyApp ) + { + QString appVersion = updatesInfo->applicationVersion(); + appVersion = appVersion.replace(QLatin1String( ", " ), QLatin1String( "," )); + appVersion = appVersion.replace(QLatin1String( " ," ), QLatin1String( "," )); + QStringList versions = appVersion.split(QLatin1String( "," ), QString::SkipEmptyParts); + + if( appNameIndex >= versions.count() ) + return retList; // please give us well formatted Updates.xml files. + + QString version = versions[appNameIndex]; + if( KDUpdater::compareVersion(this->application->applicationVersion(), version) != 0 ) + return retList; + } +#endif + + // Check to see if version numbers match. This means that the version + // number of the update should be greater than the version number of + // the package that is currently installed. + QList<KDUpdater::UpdateInfo> updateList = updatesInfo->updatesInfo( KDUpdater::PackageUpdate ); + for(int i=0; i<updatesInfo->updateInfoCount( PackageUpdate ); i++) + { + KDUpdater::UpdateInfo updateInfo = updateList.at( i ); + if( !addNewPackages ) + { + int pkgInfoIdx = packages->findPackageInfo( updateInfo.data.value( QLatin1String( "Name" ) ).toString() ); + if( pkgInfoIdx < 0 ) + continue; + + KDUpdater::PackageInfo pkgInfo = packages->packageInfo( pkgInfoIdx ); + + // First check to see if the update version is more than package version + QString updateVersion = updateInfo.data.value( QLatin1String( "Version" ) ).toString(); + QString pkgVersion = pkgInfo.version; + if( KDUpdater::compareVersion(updateVersion, pkgVersion) <= 0 ) + continue; + + // It is quite possible that we may have already installed the update. + // Lets check the last update date of the package and the release date + // of the update. This way we can compare and figure out if the update + // has been installed or not. + QDate pkgDate = pkgInfo.lastUpdateDate; + QDate updateDate = updateInfo.data.value( QLatin1String( "ReleaseDate" ) ).toDate(); + if( pkgDate > updateDate ) + continue; + } + + // Bingo!, we found an update :-) + retList.append(updateInfo); + } + + return retList; +} + +void KDUpdater::UpdateFinder::Private::createUpdateObjects(const KDUpdater::UpdateSourceInfo& sourceInfo, const QList<KDUpdater::UpdateInfo>& updateInfoList) +{ + for(int i=0; i<updateInfoList.count(); i++) + { + KDUpdater::UpdateInfo info = updateInfoList[i]; + // Compat level checks + if( info.data.contains( QLatin1String( "RequiredCompatLevel" ) ) && + info.data.value( QLatin1String( "RequiredCompatLevel" ) ).toInt() != application->compatLevel() ) + { + qDebug() << "Update \"" << info.data.value( QLatin1String( "Name" ) ).toString() << "\" at \"" + << sourceInfo.name << "\"(\"" << sourceInfo.url.toString() << "\") requires a different compat level"; + continue; // Compatibility level mismatch + } + + // If another update of the same name exists, then use the update coming from + // a higher priority. + if( !checkForUpdatePriority(sourceInfo, info) ) + { + qDebug() << "Skipping Update \"" + << info.data.value( QLatin1String( "Name" ) ).toString() + << "\" from \"" + << sourceInfo.name + << "\"(\"" + << sourceInfo.url.toString() + << "\") because an update with the same name was found from a higher priority location"; + + continue; + } + + // Pick a update file based on arch and OS. + int pickUpdateFileIndex = this->pickUpdateFileInfo(info.updateFiles); + if(pickUpdateFileIndex < 0) + continue; + + KDUpdater::UpdateFileInfo fileInfo = info.updateFiles.at( pickUpdateFileIndex ); + + // Create an update for this entry + QUrl url( QString::fromLatin1("%1/%2").arg( sourceInfo.url.toString(), fileInfo.fileName ) ); + KDUpdater::Update* update = q->constructUpdate(application, sourceInfo, KDUpdater::PackageUpdate, url, info.data, fileInfo.compressedSize, fileInfo.uncompressedSize, fileInfo.sha1sum ); + + // Register the update + this->updates.append(update); + } +} + +bool KDUpdater::UpdateFinder::Private::checkForUpdatePriority(const KDUpdater::UpdateSourceInfo& sourceInfo, const KDUpdater::UpdateInfo& updateInfo) +{ + for(int i=0; i<this->updates.count(); i++) + { + KDUpdater::Update* update = this->updates[i]; + if( update->data( QLatin1String( "Name" ) ).toString() != updateInfo.data.value( QLatin1String( "Name" ) ).toString() ) + continue; + + // Bingo, update was previously found elsewhere. + + // If the existing update comes from a higher priority server, then cool :) + if( update->sourceInfo().priority > sourceInfo.priority ) + return false; + + // If the existing update has a higher version number, keep it + if ( KDUpdater::compareVersion(update->data( QLatin1String( "Version" ) ).toString(), + updateInfo.data.value( QLatin1String( "Version" ) ).toString()) > 0) + return false; + + // Otherwise the old update must be deleted. + this->updates.removeAll(update); + delete update; + + return true; + } + + // No update by that name was found, so what we have is a priority update. + return true; +} + +int KDUpdater::UpdateFinder::Private::pickUpdateFileInfo(const QList<KDUpdater::UpdateFileInfo>& updateFiles) +{ +#ifdef Q_WS_MAC + QString os = QLatin1String( "MacOSX" ); +#endif +#ifdef Q_WS_WIN + QString os = QLatin1String( "Windows" ); +#endif +#ifdef Q_WS_X11 + QString os = QLatin1String( "Linux" ); +#endif + + QString arch = QLatin1String( "i386" ); // only one architecture considered for now. + + for(int i=0; i<updateFiles.count(); i++) + { + KDUpdater::UpdateFileInfo fileInfo = updateFiles[i]; + + if( fileInfo.arch != arch ) + continue; + + if( fileInfo.os != QLatin1String( "Any" ) && fileInfo.os != os ) + continue; + + return i; + } + + return -1; +} + + + +// +// UpdateFinder +// + +/*! + Constructs a update finder for a given \ref KDUpdater::Application. +*/ +KDUpdater::UpdateFinder::UpdateFinder(KDUpdater::Application* application) + : KDUpdater::Task(QLatin1String( "UpdateFinder" ), Stoppable, application), + d( new Private( this ) ) +{ + d->application = application; +} + +/*! + Destructor +*/ +KDUpdater::UpdateFinder::~UpdateFinder() +{ + delete d; +} + +/*! + Returns a pointer to the update application for which this function computes all + the updates. +*/ +KDUpdater::Application* KDUpdater::UpdateFinder::application() const +{ + return d->application; +} + +/*! + Returns a list of KDUpdater::Update objects. The update objects returned in this list + are made children of the \ref KDUpdater::Application object associated with this class. +*/ +QList<KDUpdater::Update*> KDUpdater::UpdateFinder::updates() const +{ + return d->updates; +} + +/*! + Looks only for a certain type of update. By default, only package update +*/ +void KDUpdater::UpdateFinder::setUpdateType(UpdateTypes type) +{ + d->updateType = type; +} + +/*! + Returns the type of updates searched +*/ +KDUpdater::UpdateTypes KDUpdater::UpdateFinder::updateType() const +{ + return d->updateType; +} + +/*! + \internal + + Implemented from \ref KDUpdater::Task::doStart(). +*/ +void KDUpdater::UpdateFinder::doRun() +{ + d->computeUpdates(); +} + +/*! + \internal + + Implemented form \ref KDUpdater::Task::doStop() +*/ +bool KDUpdater::UpdateFinder::doStop() +{ + d->cancelComputeUpdates(); + + // Wait until the cancel has actually happened, and then return. + // Thinking of using QMutex for this. Frank/Till any suggestions? + + return true; +} + +/*! + \internal + + Implemented form \ref KDUpdater::Task::doStop() +*/ +bool KDUpdater::UpdateFinder::doPause() +{ + // Not a pausable task + return false; +} + +/*! + \internal + + Implemented form \ref KDUpdater::Task::doStop() +*/ +bool KDUpdater::UpdateFinder::doResume() +{ + // Not a pausable task, hence it is not resumable as well + return false; +} + +/*! + \internal +*/ +void KDUpdater::UpdateFinder::Private::slotDownloadDone() +{ + ++downloadCompleteCount; + + int pc = computePercent(downloadCompleteCount, updateXmlFDList.count()); + pc = computeProgressPercentage(0, 45, pc); + q->reportProgress( pc, tr("Downloading Updates.xml from update sources") ); +} + +/*! + \internal + */ +KDUpdater::Update* KDUpdater::UpdateFinder::constructUpdate( Application* application, const UpdateSourceInfo& sourceInfo, + UpdateType type, const QUrl& updateUrl, const QMap< QString, QVariant >& data, quint64 compressedSize, quint64 uncompressedSize, const QByteArray& sha1sum ) +{ + return new Update( application, sourceInfo, type, updateUrl, data, compressedSize, uncompressedSize, sha1sum ); +} + + +/*! + \ingroup kdupdater + + This function compares two version strings \c v1 and \c v2 and returns + -1, 0 or +1 based on the following rule + + \li Returns 0 if v1 == v2 + \li Returns -1 if v1 < v2 + \li Returns +1 if v1 > v2 + + The function is very similar to \c strcmp(), except that it works on version strings. + + Example: + \code + + KDUpdater::compareVersion("2.0", "2.1"); // Returns -1 + KDUpdater::compareVersion("2.1", "2.0"); // Returns +1 + KDUpdater::compareVersion("2.0", "2.0"); // Returns 0 + KDUpdater::compareVersion("2.1", "2.1"); // Returns 0 + + KDUpdater::compareVersion("2.0", "2.x"); // Returns 0 + KDUpdater::compareVersion("2.x", "2.0"); // Returns 0 + + KDUpdater::compareVersion("2.0.12.4", "2.1.10.4"); // Returns -1 + KDUpdater::compareVersion("2.0.12.x", "2.0.x"); // Returns 0 + KDUpdater::compareVersion("2.1.12.x", "2.0.x"); // Returns +1 + KDUpdater::compareVersion("2.1.12.x", "2.x"); // Returns 0 + KDUpdater::compareVersion("2.x", "2.1.12.x"); // Returns 0 + + \endcode +*/ +int KDUpdater::compareVersion(const QString& v1, const QString& v2) +{ + // For tests refer VersionCompareFnTest testcase. + + // Check for equality + if( v1 == v2 ) + return 0; + + // Split version numbers across . + const QStringList v1_comps = v1.split( QRegExp( QLatin1String( "\\.|-" ) ) ); + const QStringList v2_comps = v2.split( QRegExp( QLatin1String( "\\.|-" ) ) ); + + // Check each component of the version + int index = 0; + while(1) + { + if( index == v1_comps.count() && index < v2_comps.count() ) + return -1; + else if( index < v1_comps.count() && index == v2_comps.count() ) + return +1; + else if( index >= v1_comps.count() || index >= v2_comps.count() ) + break; + + bool v1_ok, v2_ok; + int v1_comp = v1_comps[index].toInt(&v1_ok); + int v2_comp = v2_comps[index].toInt(&v2_ok); + + if(!v1_ok) + { + if(v1_comps[index] == QLatin1String( "x" ) ) + return 0; + } + if(!v2_ok) + { + if(v2_comps[index] == QLatin1String( "x") ) + return 0; + } + if( !v1_ok && !v2_ok ) + { + return v1_comps[ index ].compare( v2_comps[ index ] ); + } + + if( v1_comp < v2_comp ) + return -1; + + if( v1_comp > v2_comp ) + return +1; + + // v1_comp == v2_comp + ++index; + } + + if( index < v2_comps.count() ) + return +1; + + if( index < v1_comps.count() ) + return -1; + + // Controversial return. I hope this never happens. + return 0; +} + +#include "moc_kdupdaterupdatefinder.cpp" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h new file mode 100644 index 000000000..14ebb9c97 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_FINDER_H +#define KD_UPDATER_UPDATE_FINDER_H + +#include "kdupdater.h" +#include "kdupdatertask.h" +#include <QList> +#include <QMap> + +class QUrl; + +namespace KDUpdater +{ + class Application; + class Update; + struct UpdateSourceInfo; + + class KDTOOLS_UPDATER_EXPORT UpdateFinder : public Task + { + Q_OBJECT + + public: + explicit UpdateFinder(Application* application); + ~UpdateFinder(); + + Application* application() const; + QList<Update*> updates() const; + + void setUpdateType( UpdateTypes type ); + UpdateTypes updateType() const; + + private: + void doRun(); + bool doStop(); + bool doPause(); + bool doResume(); + + Update* constructUpdate( Application* application, const UpdateSourceInfo& sourceInfo, + UpdateType type, const QUrl& updateUrl, const QMap< QString, QVariant >& data, quint64 compressedSize, quint64 uncompressedSize, const QByteArray& sha1sum ); + + + private: + class Private; + Private* const d; + Q_PRIVATE_SLOT( d, void slotDownloadDone() ) + }; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateinstaller.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateinstaller.cpp new file mode 100644 index 000000000..3b8d2dbd4 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateinstaller.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdateinstaller.h" +#include "kdupdaterpackagesinfo.h" +#include "kdupdaterapplication.h" +#include "kdupdaterupdate.h" +#include "kdupdaterupdateoperationfactory.h" +#include "kdupdaterupdateoperation.h" +#include "kdupdaterufuncompressor_p.h" + +#include <QCoreApplication> +#include <QFileInfo> +#include <QDir> +#include <QDomDocument> +#include <QDomElement> +#include <QDate> + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateInstaller kdupdaterupdateinstaller.h KDUpdaterUpdateInstaller + \brief Installs updates, given a list of \ref KDUpdater::Update objects + + This class installs updates, given a list of \ref KDUpdater::Update objects via the + \ref installUpdates() method. To install the updates this class performs the following + for each update + + \li Downloads the update files from its source + \li Unpacks update files into a temporary directory + \li Parses and executes UpdateInstructions.xml by making use of \ref KDUpdater::UpdateOperation + objects sourced via \ref KDUpdater::UpdateOperationFactory + + \note All temporary files created during the installation of the update will be destroyed + immediately after the installation is complete. +*/ +class KDUpdater::UpdateInstaller::Private +{ + public: + Private( UpdateInstaller* qq ) : + q( qq ) + {} + + UpdateInstaller* q; + + KDUpdater::Application* application; + int updateDownloadDoneCount; + int updateDownloadProgress; + int totalUpdates; + QStringList toRemoveDirs; + + int totalProgressPc; + int currentProgressPc; + QList<KDUpdater::Update*> updates; + + void resolveArguments(QStringList& args); + + void removeDirectory(const QDir & dir); + void slotUpdateDownloadProgress(int percent); + void slotUpdateDownloadDone(); +}; + +// next two are duplicated from kdupdaterupdatefinder.cpp: + +static int computeProgressPercentage(int min, int max, int percent) +{ + return min + qint64(max-min) * percent / 100 ; +} + +static int computePercent(int done, int total) +{ + return total ? done * Q_INT64_C(100) / total : 0 ; +} + +/*! + Constructs an instance of this class for the \ref KDUpdater::Application passed as + parameter. Only updates meant for the specified application will be installed by this class. +*/ +KDUpdater::UpdateInstaller::UpdateInstaller(KDUpdater::Application* application) + : KDUpdater::Task(QLatin1String( "UpdateInstaller" ), NoCapability, application), + d( new Private( this ) ) +{ + d->application = application; +} + +/*! + Destructor +*/ +KDUpdater::UpdateInstaller::~UpdateInstaller() +{ + delete d; +} + +/*! + Returns the update application for which the update is being installed +*/ +KDUpdater::Application* KDUpdater::UpdateInstaller::application() const +{ + return d->application; +} + +/*! + Use this function to let the installer know what updates are to be installed. The + updates are actually installed when the \ref start() method is called on this class. +*/ +void KDUpdater::UpdateInstaller::setUpdatesToInstall(const QList<KDUpdater::Update*>& updates) +{ + d->updates = updates; +} + +/*! + Returns the updates that would be installed when the next time \ref the start) method is called. +*/ +QList<KDUpdater::Update*> KDUpdater::UpdateInstaller::updatesToInstall() const +{ + return d->updates; +} + +/*! + \internal +*/ +void KDUpdater::UpdateInstaller::doRun() +{ + QList<KDUpdater::Update*>& updates = d->updates; + + // First download all the updates + d->updateDownloadDoneCount = 0; + d->totalUpdates = updates.count(); + + for(int i=0; i<updates.count(); i++) + { + KDUpdater::Update* update = updates[i]; + if( update->application() != d->application ) + continue; + + update->setProperty("_ProgressPc_", 0); + connect(update, SIGNAL(progressValue(int)), this, SLOT(slotUpdateDownloadProgress(int))); + connect(update, SIGNAL(finished()), this, SLOT(slotUpdateDownloadDone())); + connect(update, SIGNAL(stopped()), this, SLOT(slotUpdateDownloadDone())); + update->download(); + } + + d->totalProgressPc = updates.count() * 100; + d->currentProgressPc = 0; + + // Wait until all updates have been downloaded + while(d->updateDownloadDoneCount != updates.count()) + { + QCoreApplication::processEvents(); + + // Normalized progress + int progressPc = computePercent(d->currentProgressPc, d->totalProgressPc); + + // Bring the progress to within 50 percent + progressPc = (progressPc>>1); + + // Report the progress + reportProgress(progressPc, tr("Downloading updates...")); + } + + // Global progress + reportProgress(50, tr("Updates downloaded...")); + + // Save the current working directory of the application + QDir oldCWD = QDir::current(); + + int pcDiff = computePercent(1, updates.count()); + pcDiff = computeProgressPercentage(50, 95, pcDiff) - 50; + + // Now install one update after another. + for(int i=0; i<updates.count(); i++) + { + KDUpdater::Update* update = updates[i]; + + // Global progress + QString msg = tr("Installing %1..").arg(update->name()); + int minPc = pcDiff*i + 50; + int maxPc = minPc + pcDiff; + reportProgress(minPc, msg); + + if( update->application() != d->application ) + continue; + + QDir::setCurrent(oldCWD.absolutePath()); + if (!installUpdate(update, minPc, maxPc)) { + d->application->packagesInfo()->writeToDisk(); + return; + } + } + + d->application->packagesInfo()->writeToDisk(); + + // Global progress + reportProgress(95, tr("Finished installing updates. Now removing temporary files and directories..")); + + // Restore the current working directory of the application + QDir::setCurrent(oldCWD.absolutePath()); + + // Remove all the toRemoveDirs + for(int i=0; i<d->toRemoveDirs.count(); i++) + { + QDir dir( d->toRemoveDirs[i] ); + d->removeDirectory( dir ); + + QString dirName = dir.dirName(); + dir.cdUp(); + dir.rmdir( dirName ); + } + d->toRemoveDirs.clear(); + + // Global progress + reportProgress(100, tr("Removed temporary files and directories")); + reportDone(); +} + +/*! + \internal +*/ +bool KDUpdater::UpdateInstaller::doStop() +{ + return false; +} + +/*! + \internal +*/ +bool KDUpdater::UpdateInstaller::doPause() +{ + return false; +} + +/*! + \internal +*/ +bool KDUpdater::UpdateInstaller::doResume() +{ + return false; +} + +bool KDUpdater::UpdateInstaller::installUpdate(KDUpdater::Update* update, int minPc, int maxPc) +{ + QString updateName( update->name() ); + + // Sanity checks + if( !update->isDownloaded() ) + { + QString msg = tr("Could not download update '%1'").arg(update->name()); + reportError(msg); + return false; + } + + // Step 1: Prepare a directory into which the UpdateFile will be unpacked. + // If update file is C:/Users/PRASHA~1/AppData/Local/Temp/qt_temp.Hp1204 and + // the applicationn name "MyApplication" + // Then the directory would be %USERDIR%/AppData/Local/Temp/MyApplication_Update1 + static int count = 0; + QString dirName = QString::fromLatin1("%1_Update%2").arg(d->application->applicationName(), QString::number(count++)); + QString updateFile = update->downloadedFileName(); + QFileInfo fi(updateFile); + QDir dir( fi.absolutePath() ); + dir.mkdir( dirName ); + dir.cd( dirName ); + d->toRemoveDirs << dir.absolutePath(); + + // Step 2: Unpack the update file into the update directory + KDUpdater::UFUncompressor uncompressor; + uncompressor.setFileName( updateFile ); + uncompressor.setDestination( dir.absolutePath() ); + + if (!uncompressor.uncompress()) { + reportError(tr("Couldn't uncompress update: %1") + .arg(uncompressor.errorString())); + return false; + } + + // Step 3: Find out the directory in which UpdateInstructions.xml can be found + QDir updateDir = dir; + while( !updateDir.exists(QLatin1String( "UpdateInstructions.xml" )) ) + { + QString path = updateDir.absolutePath(); + QFileInfoList fiList = updateDir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot); + if( !fiList.count() ) // || fiList.count() >= 2 ) + { + QString msg = tr("Could not find UpdateInstructions.xml for %1").arg(update->name()); + reportError(msg); + return false; + } + + updateDir.cd(fiList.first().fileName()); + } + + // Set the application's current working directory as updateDir + QDir::setCurrent(updateDir.absolutePath()); + + // Step 4: Now load the UpdateInstructions.xml file + QDomDocument doc; + QFile file(updateDir.absoluteFilePath(QLatin1String( "UpdateInstructions.xml" ))); + if( !file.open(QFile::ReadOnly) ) + { + QString msg = tr("Could not read UpdateInstructions.xml of %1").arg(update->name()); + reportError(msg); + return false; + } + if( !doc.setContent(&file) ) + { + QString msg = tr("Could not read UpdateInstructions.xml of %1").arg(update->name()); + reportError(msg); + return false; + } + + // Now parse and execute update operations + QDomNodeList operEList = doc.elementsByTagName(QLatin1String( "UpdateOperation" )); + QString msg = tr("Installing %1").arg(updateName); + + for(int i=0; i<operEList.count(); i++) + { + int pc = computePercent(i+1, operEList.count()); + pc = computeProgressPercentage(minPc, maxPc, pc); + reportProgress(pc, msg); + + // Fetch the important XML elements in UpdateOperation + QDomElement operE = operEList.at(i).toElement(); + QDomElement nameE = operE.firstChildElement(QLatin1String( "Name" )); + QDomElement errorE = operE.firstChildElement(QLatin1String( "OnError" )); + QDomElement argE = operE.firstChildElement(QLatin1String( "Arg" )); + + // Figure out information about the update operation to perform + QString operName = nameE.text(); + QString onError = errorE.attribute(QLatin1String( "Action" ), QLatin1String( "Abort" ) ); + QStringList args; + while( !argE.isNull() ) + { + args << argE.text(); + argE = argE.nextSiblingElement(QLatin1String( "Arg" )); + } + + //QString operSignature = QString::fromLatin1("%1(%2)").arg(operName, args.join( QLatin1String( ", ") ) ); + + // Fetch update operation + KDUpdater::UpdateOperation* const updateOperation = KDUpdater::UpdateOperationFactory::instance().create(operName); + if( !updateOperation ) + { + QString errMsg = tr("Update operation %1 not supported").arg(operName); + reportError(errMsg); + + if( onError == QLatin1String( "Continue" ) ) + continue; + + if( onError == QLatin1String( "Abort" ) ) + return false; + + if( onError == QLatin1String( "AskUser" ) ) + { + // TODO: + continue; + } + } + + // Now resolve special fields in arguments + d->resolveArguments(args); + + // Now set the arguments to the update operation and execute the update operation + updateOperation->setArguments(args); + updateOperation->setApplication( d->application ); + const bool success = updateOperation->performOperation(); + + updateOperation->clear(); + + if( !success ) + { + QString errMsg = tr("Cannot execute '%1'").arg(updateOperation->operationCommand()); + reportError(errMsg); + + if( onError == QLatin1String( "Continue" ) ) + continue; + + if( onError == QLatin1String( "Abort" ) ) + return false; + + if( onError == QLatin1String( "AskUser" ) ) + { + // TODO: + continue; + } + } + delete updateOperation; + } + + Q_FOREACH( UpdateOperation* updateOperation, update->operations() ) { + updateOperation->performOperation(); + } + + msg = tr("Finished installing update %1").arg(update->name()); + reportProgress(maxPc, msg); + return true; +} + +/*! + \internal +*/ +void KDUpdater::UpdateInstaller::Private::slotUpdateDownloadProgress(int percent) +{ + // 0-49 percent progress is dedicated for the download of updates + KDUpdater::Update* update = qobject_cast<KDUpdater::Update*>(q->sender()); + if( !update ) + return; + + int oldPc = update->property("_ProgressPc_").toInt(); + int diffPc = percent-oldPc; + if(diffPc <= 0) + return; + + currentProgressPc += diffPc; + update->setProperty("_ProgressPc_", percent); +} + +/*! + \internal +*/ +void KDUpdater::UpdateInstaller::Private::slotUpdateDownloadDone() +{ + ++updateDownloadDoneCount; +} + +void KDUpdater::UpdateInstaller::Private::resolveArguments(QStringList& args) +{ + for(int i=0; i<args.count(); i++) + { + QString arg = args[i]; + + arg = arg.replace(QLatin1String( "{APPDIR}" ), application->applicationDirectory()); + arg = arg.replace(QLatin1String( "{HOME}" ), QDir::homePath()); + arg = arg.replace(QLatin1String( "{APPNAME}" ), application->applicationName()); + arg = arg.replace(QLatin1String( "{APPVERSION}" ), application->applicationVersion()); + arg = arg.replace(QLatin1String( "{CURPATH}" ), QDir::currentPath()); + arg = arg.replace(QLatin1String( "{ROOT}" ), QDir::rootPath()); + arg = arg.replace(QLatin1String( "{TEMP}" ), QDir::tempPath()); + + args[i] = arg; + } +} + +void KDUpdater::UpdateInstaller::Private::removeDirectory(const QDir & dir) +{ + QFileInfoList fiList = dir.entryInfoList(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot); + if( !fiList.count() ) + return; + + for(int i=0; i<fiList.count(); i++) + { + QFileInfo fi = fiList[i]; + if( fi.isDir() ) + { + QDir childDir = fi.absoluteFilePath(); + removeDirectory( childDir ); + dir.rmdir( childDir.dirName() ); + } + else if( fi.isFile() ) + QFile::remove( fi.absoluteFilePath() ); + } +} + +#include "moc_kdupdaterupdateinstaller.cpp" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateinstaller.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateinstaller.h new file mode 100644 index 000000000..dc3e58e48 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateinstaller.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_INSTALLER_H +#define KD_UPDATER_UPDATE_INSTALLER_H + +#include "kdupdater.h" +#include "kdupdatertask.h" +#include <QList> + +namespace KDUpdater +{ + class Application; + class Update; + + class KDTOOLS_UPDATER_EXPORT UpdateInstaller : public Task + { + Q_OBJECT + + public: + explicit UpdateInstaller(Application* application); + ~UpdateInstaller(); + + Application* application() const; + + void setUpdatesToInstall(const QList<Update*>& updates); + QList<Update*> updatesToInstall() const; + + private: + void doRun(); + bool doStop(); + bool doPause(); + bool doResume(); + + bool installUpdate(Update* update, int minPc, int maxPc); + + class Private; + Private * const d; + + Q_PRIVATE_SLOT( d, void slotUpdateDownloadProgress(int) ) + Q_PRIVATE_SLOT( d, void slotUpdateDownloadDone() ) + }; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperation.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperation.cpp new file mode 100644 index 000000000..7c4121e8e --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperation.cpp @@ -0,0 +1,417 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdateoperation.h" + +#include "kdupdaterapplication.h" + +#include <QDebug> +#include <QDir> +#include <QFileInfo> +#include <QTemporaryFile> + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateOperation kdupdaterupdateoperation.h KDUpdaterUpdateOperation + \brief Abstract base class for update operations. + + The \ref KDUpdater::UpdateOperation is an abstract class that specifies an interface for + update operations. Concrete implementations of this class must perform a single update + operation like copy, move, delete etc. + + \note Two seperate threads cannot be using a single instance of KDUpdater::UpdateOperation + at the same time. +*/ + +/* + * \internal + * Returns a filename for a temporary file based on \a templateName + */ +static QString backupFileName( const QString& templateName = QString() ) +{ + const QFileInfo templ( templateName ); + QTemporaryFile file( QDir::temp().absoluteFilePath( templ.fileName() ) ); + file.open(); + const QString name = file.fileName(); + file.close(); + file.remove(); + return name; +} + +using namespace KDUpdater; + +struct UpdateOperation::UpdateOperationData +{ + UpdateOperationData( UpdateOperation* qq ) : + q( qq ), + error( 0 ), + application(0) + {} + + UpdateOperation* q; + QString name; + QStringList args; + QString errorString; + int error; + Application* application; + QVariantMap values; + QStringList delayedDeletionFiles; +}; + + +/*! + Constructor +*/ +UpdateOperation::UpdateOperation() + : d ( new UpdateOperationData( this ) ) +{ +} + +/*! + Destructor +*/ +UpdateOperation::~UpdateOperation() +{ + Application* const app = Application::instance(); + if( app ) + app->addFilesForDelayedDeletion( filesForDelayedDeletion() ); + delete d; +} + +/*! + Returns the update operation name. + + \sa setName() +*/ +QString UpdateOperation::name() const +{ + return d->name; +} + +/*! + Returns a command line string that describes the update operation. The returned + string would be of the form + + <name> <arg1> <arg2> <arg3> .... +*/ +QString UpdateOperation::operationCommand() const +{ + QString argsStr = d->args.join(QLatin1String( " " )); + return QString::fromLatin1( "%1 %2" ).arg(d->name, argsStr); +} + +/*! + Returns true if there exists a setting called \a name. Otherwise returns false. +*/ +bool UpdateOperation::hasValue( const QString& name ) const +{ + return d->values.contains( name ); +} + +/*! + Clears the value of setting \a name and removes it. + \post hasValue( \a name ) returns false. +*/ +void UpdateOperation::clearValue( const QString& name ) +{ + d->values.remove( name ); +} + +/*! + Returns the value of setting \a name. If the setting does not exists, + this returns an empty QVariant. +*/ +QVariant UpdateOperation::value( const QString& name ) const +{ + return hasValue( name ) ? d->values[ name ] : QVariant(); +} + +/*! + Sets the value of setting \a name to \a value. +*/ +void UpdateOperation::setValue( const QString& name, const QVariant& value ) +{ + d->values[ name ] = value; +} + +/*! + Sets a update operation name. Subclasses will have to provide a unique + name to describe this operation. +*/ +void UpdateOperation::setName(const QString& name) +{ + d->name = name; +} + +/*! + Through this function, arguments to the update operation can be specified + to the update operation. +*/ +void UpdateOperation::setArguments(const QStringList& args) +{ + d->args = args; +} + +/*! + Sets the Application for this operation. + This may be used by some operations +*/ +void UpdateOperation::setApplication( Application* application ) +{ + d->application = application; +} + +/*! + Returns the last set function arguments. +*/ +QStringList UpdateOperation::arguments() const +{ + return d->args; +} + +/*! + Returns error details in case performOperation() failed. +*/ +QString UpdateOperation::errorString() const +{ + return d->errorString; +} + +/*! + * Can be used by subclasses to report more detailed error codes (optional). + * To check if an operation was successful, use the return value of performOperation(). + */ +int UpdateOperation::error() const +{ + return d->error; +} + +/*! + * Used by subclasses to set the error string. + */ +void UpdateOperation::setErrorString( const QString& str ) +{ + d->errorString = str; +} + +/*! + * Used by subclasses to set the error code. + */ +void UpdateOperation::setError( int error, const QString& errorString ) +{ + d->error = error; + if( !errorString.isNull() ) + d->errorString = errorString; +} + +/*! + Clears the previously set argument list and application +*/ +void UpdateOperation::clear() +{ + d->args.clear(); + d->application = 0; +} + +QStringList UpdateOperation::filesForDelayedDeletion() const +{ + return d->delayedDeletionFiles; +} + +/*! + Registers a file to be deleted later, once the application was restarted + (and the file isn't used anymore for sure). + @param files the files to be registered +*/ +void UpdateOperation::registerForDelayedDeletion( const QStringList& files ) +{ + d->delayedDeletionFiles << files; +} + +/*! + Tries to delete \a file. If \a file can't be deleted, it gets registered for delayed deletion. +*/ +bool UpdateOperation::deleteFileNowOrLater( const QString& file, QString* errorString ) +{ + if( file.isEmpty() || QFile::remove( file ) ) + return true; + + if( !QFile::exists( file ) ) + return true; + + const QString backup = backupFileName( file ); + QFile f( file ); + if( !f.rename( backup ) ) + { + if ( errorString ) + *errorString = f.errorString(); + return false; + } + registerForDelayedDeletion( QStringList( backup ) ); + return true; +} + +/*! + Returns a pointer to the current Application +*/ +Application* UpdateOperation::application() const +{ + return d->application; +} + +/*! + \fn virtual void KDUpdater::UpdateOperation::backup() = 0; + + Subclasses must implement this function to backup any data before performing the action. +*/ + +/*! + \fn virtual bool KDUpdater::UpdateOperation::performOperation() = 0; + + Subclasses must implement this function to perform the update operation +*/ + +/*! + \fn virtual bool KDUpdater::UpdateOperation::undoOperation() = 0; + + Subclasses must implement this function to perform the reverse of the operation. +*/ + +/*! + \fn virtual bool KDUpdater::UpdateOperation::testOperation() = 0; + + Subclasses must implement this function to perform the test operation. +*/ + +/*! + \fn virtual bool KDUpdater::UpdateOperation::clone() = 0; + + Subclasses must implement this function to clone the current operation. +*/ + +/*! + Saves this UpdateOperation in XML. You can override this method to store your own extra-data. + The default implementation is taking care of arguments and values set via setValue. +*/ +QDomDocument UpdateOperation::toXml() const +{ + QDomDocument doc; + QDomElement root = doc.createElement( QLatin1String("operation") ); + doc.appendChild( root ); + QDomElement args = doc.createElement( QLatin1String("arguments") ); + Q_FOREACH( const QString &s, arguments() ) { + QDomElement arg = doc.createElement( QLatin1String("argument") ); + arg.appendChild( doc.createTextNode(s) ); + args.appendChild( arg ); + } + root.appendChild( args ); + if( d->values.isEmpty() ) + return doc; + + // append all values set with setValue + QDomElement values = doc.createElement( QLatin1String( "values" ) ); + for( QVariantMap::const_iterator it = d->values.begin(); it != d->values.end(); ++it ) + { + QDomElement value = doc.createElement( QLatin1String( "value" ) ); + const QVariant& variant = it.value(); + value.setAttribute( QLatin1String( "name" ), it.key() ); + value.setAttribute( QLatin1String( "type" ), QLatin1String( QVariant::typeToName( variant.type() ) ) ); + + if( variant.type() != QVariant::List && variant.type() != QVariant::StringList && qVariantCanConvert< QString >( variant ) ) + { + // it can convert to string? great! + value.appendChild( doc.createTextNode( variant.toString() ) ); + } + else + { + // no? then we have to go the hard way... + QByteArray data; + QDataStream stream( &data, QIODevice::WriteOnly ); + stream << variant; + value.appendChild( doc.createTextNode( QLatin1String( data.toBase64().data() ) ) ); + } + values.appendChild( value ); + } + root.appendChild( values ); + return doc; +} + +/*! + Restores UpdateOperation's arguments and values from the XML document \a doc. + Returns true on success, otherwise false. +*/ +bool UpdateOperation::fromXml( const QDomDocument &doc ) +{ + QStringList args; + const QDomElement root = doc.documentElement(); + const QDomElement argsElem = root.firstChildElement( QLatin1String("arguments") ); + Q_ASSERT( ! argsElem.isNull() ); + for( QDomNode n = argsElem.firstChild(); ! n.isNull(); n = n.nextSibling() ) { + const QDomElement e = n.toElement(); + if( !e.isNull() && e.tagName() == QLatin1String("argument") ) + args << e.text(); + } + setArguments(args); + + d->values.clear(); + const QDomElement values = root.firstChildElement( QLatin1String( "values" ) ); + for( QDomNode n = values.firstChild(); !n.isNull(); n = n.nextSibling() ) + { + const QDomElement v = n.toElement(); + if( v.isNull() || v.tagName() != QLatin1String( "value" ) ) + continue; + + const QString name = v.attribute( QLatin1String( "name" ) ); + const QString type = v.attribute( QLatin1String( "type" ) ); + const QString value = v.text(); + + const QVariant::Type t = QVariant::nameToType( type.toLatin1().data() ); + QVariant var = qVariantFromValue( value ); + if( t == QVariant::List || t == QVariant::StringList || !var.convert( t ) ) + { + QDataStream stream( QByteArray::fromBase64( value.toLatin1() ) ); + stream >> var; + } + + d->values[ name ] = var; + } + + return true; +} + +/*! + Restores UpdateOperation's arguments and values from the XML document at path \a xml. + Returns true on success, otherwise false. + \overload +*/ +bool UpdateOperation::fromXml( const QString &xml ) +{ + QDomDocument doc; + QString errorMsg; + int errorLine; + int errorColumn; + if ( ! doc.setContent( xml, &errorMsg, &errorLine, &errorColumn ) ) { + qWarning() << "Error parsing xml error=" << errorMsg << "line=" << errorLine << "column=" << errorColumn; + return false; + } + return fromXml(doc); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperation.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperation.h new file mode 100644 index 000000000..53111d23a --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperation.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_OPERATION_H +#define KD_UPDATER_UPDATE_OPERATION_H + +#include "kdupdater.h" + +#include <QCoreApplication> +#include <QStringList> +#include <QVariant> +#include <QDomDocument> + +namespace KDUpdater +{ + class Application; + + class KDTOOLS_UPDATER_EXPORT UpdateOperation + { + Q_DECLARE_TR_FUNCTIONS(UpdateOperation) + + public: + enum Error { + NoError=0, + InvalidArguments=1, + UserDefinedError=128 + }; + + UpdateOperation(); + virtual ~UpdateOperation(); + + QString name() const; + QString operationCommand() const; + + bool hasValue( const QString& name ) const; + void clearValue( const QString& name ); + QVariant value( const QString& name ) const; + void setValue( const QString& name, const QVariant &value ); + + void setArguments(const QStringList& args); + void setApplication( Application* application ); + QStringList arguments() const; + void clear(); + QString errorString() const; + int error() const; + QStringList filesForDelayedDeletion() const; + + virtual void backup() = 0; + virtual bool performOperation() = 0; + virtual bool undoOperation() = 0; + virtual bool testOperation() = 0; + virtual UpdateOperation* clone() const = 0; + + virtual QDomDocument toXml() const; + virtual bool fromXml( const QString &xml ); + virtual bool fromXml( const QDomDocument &doc ); + + protected: + void setName(const QString& name); + Application* application() const; + void setErrorString( const QString& errorString ); + void setError( int error, const QString& errorString = QString() ); + void registerForDelayedDeletion( const QStringList& files ); + bool deleteFileNowOrLater( const QString& file, QString* errorString=0 ); + + private: + struct UpdateOperationData; + UpdateOperationData* d; + }; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperationfactory.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperationfactory.cpp new file mode 100644 index 000000000..076af5273 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperationfactory.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdateoperationfactory.h" +#include "kdupdaterupdateoperations.h" + +#include <QHash> + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateOperationFactory kdupdaterupdateoperationfactory.h KDUpdaterUpdateOperationFactory + \brief Factory for \ref KDUpdater::UpdateOperation + + This class acts as a factory for \ref KDUpdater::UpdateOperation. You can register + one or more update operations with this factory and query operations based on their name. + + This class follows the singleton design pattern. Only one instance of this class can + be created and its reference can be fetched from the \ref instance() method. +*/ + +/*! + \fn KDUpdater::UpdateOperationFactory::registerUpdateOperation( const QString& name ) + + Registers T as new UpdateOperation with \a name. When create() is called with that \a name, + T is constructed using its default constructor. +*/ + +using namespace KDUpdater; + +struct UpdateOperationFactory::UpdateOperationFactoryData +{ +}; + +/*! + Returns the UpdateOperationFactory instance. The instance is created if needed. +*/ +UpdateOperationFactory& UpdateOperationFactory::instance() +{ + static UpdateOperationFactory theFactory; + return theFactory; +} + +/*! + Constructor +*/ +UpdateOperationFactory::UpdateOperationFactory() + : d ( new UpdateOperationFactoryData ) +{ + // Register the default update operation set + registerUpdateOperation< CopyOperation >( QLatin1String( "Copy" ) ); + registerUpdateOperation< MoveOperation >( QLatin1String( "Move" ) ); + registerUpdateOperation< DeleteOperation >( QLatin1String( "Delete" ) ); + registerUpdateOperation< MkdirOperation >( QLatin1String( "Mkdir" ) ); + registerUpdateOperation< RmdirOperation >( QLatin1String( "Rmdir" ) ); + registerUpdateOperation< AppendFileOperation >( QLatin1String( "AppendFile" ) ); + registerUpdateOperation< PrependFileOperation >( QLatin1String( "PrependFile" ) ); + registerUpdateOperation< ExecuteOperation >( QLatin1String( "Execute" ) ); + registerUpdateOperation< UpdatePackageOperation >( QLatin1String( "UpdatePackage" ) ); + registerUpdateOperation< UpdateCompatOperation >( QLatin1String( "UpdateCompat" ) ); +} + +UpdateOperationFactory::~UpdateOperationFactory() +{ +} + +/*! + Returns the number of update operations in the factory. +*/ +int UpdateOperationFactory::updateOperationCount() const +{ + return productCount(); +} + +/*! + Returns a list containing the names of all available UpdateOperations. +*/ +QStringList UpdateOperationFactory::availableUpdateOperations() const +{ + return availableProducts(); +} + +/* + Unregisters the update operation previously registered with \a name. +*/ +void UpdateOperationFactory::unregisterUpdateOperation( const QString& name ) +{ + unregisterProduct( name ); +} + +/*! + Registers \a create to be a factory function to create an UpdateOperation with \a name. + \sa registerUpdateOperation +*/ +void UpdateOperationFactory::registerUpdateOperationFactory( const QString& name, UpdateOperationFactoryFunction create ) +{ + registerProductionFunction( name, create ); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperationfactory.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperationfactory.h new file mode 100644 index 000000000..d42a871c3 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperationfactory.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_OPERATION_FACTORY_H +#define KD_UPDATER_UPDATE_OPERATION_FACTORY_H + +#include <KDToolsCore/kdgenericfactory.h> + +#include "kdupdater.h" +#include <KDToolsCore/pimpl_ptr.h> + +namespace KDUpdater +{ + class UpdateOperation; + + typedef KDGenericFactory< UpdateOperation >::FactoryFunction UpdateOperationFactoryFunction; + + class KDTOOLS_UPDATER_EXPORT UpdateOperationFactory : public KDGenericFactory< UpdateOperation > + { + Q_DISABLE_COPY( UpdateOperationFactory ) + public: + static UpdateOperationFactory& instance(); + ~UpdateOperationFactory(); + + template< class T > + void registerUpdateOperation( const QString& name ) + { + registerProduct< T >( name ); + } + void registerUpdateOperationFactory( const QString& name, UpdateOperationFactoryFunction create ); + + void unregisterUpdateOperation( const QString& name ); + + int updateOperationCount() const; + QStringList availableUpdateOperations() const; + + protected: + UpdateOperationFactory(); + + private: + struct UpdateOperationFactoryData; + kdtools::pimpl_ptr<UpdateOperationFactoryData> d; + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperations.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperations.cpp new file mode 100644 index 000000000..a1486d34d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperations.cpp @@ -0,0 +1,1120 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdateoperations.h" +#include "kdupdaterapplication.h" +#include "kdupdaterpackagesinfo.h" +#include "environment.h" + +#include <QFile> +#include <QDir> +#include <QDirIterator> +#include <QProcess> +#include <QTextStream> +#include <QDebug> +#include <QTemporaryFile> + + +#include <cerrno> + +#define SUPPORT_DETACHED_PROCESS_EXECUTION + +#ifdef SUPPORT_DETACHED_PROCESS_EXECUTION +#ifdef Q_WS_WIN +#include <windows.h> +#endif +#endif + +using namespace KDUpdater; + +static bool removeDirectory( const QString& path, QString* errorString ) +{ + Q_ASSERT( errorString ); + const QFileInfoList entries = QDir( path ).entryInfoList( QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden ); + for( QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it ) + { + if( it->isDir() && !it->isSymLink() ) + { + removeDirectory( it->filePath(), errorString ); + } + else + { + QFile f( it->filePath() ); + if( !f.remove() ) + return false; + } + } + + errno = 0; + const bool success = QDir().rmdir( path ); + if ( errno ) + *errorString = QLatin1String( strerror(errno) ); + return success; +} +/* + * \internal + * Returns a filename for a temporary file based on \a templateName + */ +static QString backupFileName( const QString& templateName = QString() ) +{ + QTemporaryFile file( templateName ); + file.open(); + const QString name = file.fileName(); + file.close(); + file.remove(); + return name; +} + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::CopyOperation +//////////////////////////////////////////////////////////////////////////// + +CopyOperation::CopyOperation() +{ + setName(QLatin1String( "Copy" )); +} + +CopyOperation::~CopyOperation() +{ + deleteFileNowOrLater( value( QLatin1String( "backupOfExistingDestination" ) ).toString() ); +} + +void CopyOperation::backup() +{ + const QString dest = arguments().last(); + if( !QFile::exists( dest ) ) + { + clearValue( QLatin1String( "backupOfExistingDestination" ) ); + return; + } + + setValue( QLatin1String( "backupOfExistingDestination" ), backupFileName( dest ) ); + + // race condition: The backup file could get created + // by another process right now. But this is the same + // in QFile::copy... + const bool success = QFile::rename( dest, value( QLatin1String( "backupOfExistingDestination" ) ).toString() ); + if(!success) + setError( UserDefinedError, tr("Could not backup file %1").arg(dest) ); +} + +bool CopyOperation::performOperation() +{ + // We need two args to complete the copy operation. + // First arg provides the complete file name of source + // Second arg provides the complete file name of dest + QStringList args = this->arguments(); + if( args.count() != 2 ) { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 2 expected.").arg( args.count() ) ); + return false; + } + QString source = args.first(); + QString dest = args.last(); + + // If destination file exists, then we cannot use QFile::copy() + // because it does not overwrite an existing file. So we remove + // the destination file. + if( QFile::exists(dest) ) + { + QFile file( dest ); + if( !file.remove() ) { + setError( UserDefinedError ); + setErrorString( tr("Could not remove destination file %1: %2.").arg( dest, file.errorString() ) ); + return false; + } + } + + QFile file( source ); + const bool copied = file.copy( dest ); + if ( !copied ) { + setError( UserDefinedError ); + setErrorString( tr("Could not copy %1 to %2: %3.").arg( source, dest, file.errorString() ) ); + } + return copied; +} + +bool CopyOperation::undoOperation() +{ + const QString dest = arguments().last(); + + QFile destF( dest ); + // first remove the dest + if( !destF.remove() ) + { + setError( UserDefinedError, tr("Could not delete file %1: %2").arg(dest, destF.errorString()) ); + return false; + } + + // no backup was done: + // the copy destination file wasn't existing yet - that's no error + if( !hasValue( QLatin1String( "backupOfExistingDestination" ) ) ) + return true; + + QFile backupF( value( QLatin1String( "backupOfExistingDestination" ) ).toString() ); + // otherwise we have to copy the backup back: + const bool success = backupF.rename( dest ); + if(!success) { + setError( UserDefinedError, tr("Could not restore backup file into %1: %2").arg(dest, backupF.errorString()) ); + } + return success; +} + +/*! + \reimp + */ +QDomDocument CopyOperation::toXml() const +{ + // we don't want to save the backupOfExistingDestination + if( !hasValue( QLatin1String( "backupOfExistingDestination" ) ) ) + return UpdateOperation::toXml(); + + CopyOperation* const me = const_cast< CopyOperation* >( this ); + + const QVariant v = value( QLatin1String( "backupOfExistingDestination" ) ); + me->clearValue( QLatin1String( "backupOfExistingDestination" ) ); + const QDomDocument xml = UpdateOperation::toXml(); + me->setValue( QLatin1String( "backupOfExistingDestination" ), v ); + return xml; +} + +bool CopyOperation::testOperation() +{ + // TODO + return true; +} + +CopyOperation* CopyOperation::clone() const +{ + return new CopyOperation(); +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::MoveOperation +//////////////////////////////////////////////////////////////////////////// + +MoveOperation::MoveOperation() +{ + setName(QLatin1String( "Move" )); +} + +MoveOperation::~MoveOperation() +{ + deleteFileNowOrLater( value( QLatin1String( "backupOfExistingDestination" ) ).toString() ); +} + +void MoveOperation::backup() +{ + const QString dest = arguments().last(); + if( !QFile::exists( dest ) ) + { + clearValue( QLatin1String( "backupOfExistingDestination" ) ); + return; + } + + setValue( QLatin1String( "backupOfExistingDestination" ), backupFileName( dest ) ); + + // race condition: The backup file could get created + // by another process right now. But this is the same + // in QFile::copy... + const bool success = QFile::rename( dest, value( QLatin1String( "backupOfExistingDestination" ) ).toString() ); + if(!success) + setError( UserDefinedError, tr("Could not backup file %1").arg(dest) ); +} + +bool MoveOperation::performOperation() +{ + // We need two args to complete the copy operation. + // First arg provides the complete file name of source + // Second arg provides the complete file name of dest + QStringList args = this->arguments(); + if( args.count() != 2 ) { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 2 expected.").arg( args.count() ) ); + return false; + } + + QString source = args.first(); + QString dest = args.last(); + + // If destination file exists, then we cannot use QFile::copy() + // because it does not overwrite an existing file. So we remove + // the destination file. + if( QFile::exists(dest) ) + { + QFile file( dest ); + if( !file.remove(dest) ) { + setError( UserDefinedError ); + setErrorString( tr("Could not remove destination file %1: %2.").arg( dest, file.errorString() ) ); + return false; + } + } + + // Copy source to destination. + QFile file( source ); + const bool copied = file.copy( source, dest ); + if ( !copied ) { + setError( UserDefinedError ); + setErrorString( tr("Could not copy %1 to %2: %3.").arg( source, dest, file.errorString() ) ); + return false; + } + + return deleteFileNowOrLater( source ); +} + +bool MoveOperation::undoOperation() +{ + const QStringList args = arguments(); + const QString& source = args.first(); + const QString& dest = args.last(); + + // first: copy back the destination to source + QFile destF( dest ); + if( !destF.copy( source ) ) + { + setError( UserDefinedError, tr("Cannot copy %1 to %2: %3").arg( dest, source, destF.errorString() ) ); + return false; + } + + // second: delete the move destination + if( !deleteFileNowOrLater( dest ) ) + { + setError( UserDefinedError, tr( "Cannot remove file %1" ) ); + return false; + } + + // no backup was done: + // the move destination file wasn't existing yet - that's no error + if( !hasValue( QLatin1String( "backupOfExistingDestination" ) ) ) + return true; + + // otherwise we have to copy the backup back: + QFile backupF( value( QLatin1String( "backupOfExistingDestination" ) ).toString() ); + const bool success = backupF.rename( dest ); + if(!success) + setError( UserDefinedError, tr("Cannot restore backup file for %1: %2").arg(dest, backupF.errorString()) ); + + return success; +} + +bool MoveOperation::testOperation() +{ + // TODO + return true; +} + +MoveOperation* MoveOperation::clone() const +{ + return new MoveOperation; +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::DeleteOperation +//////////////////////////////////////////////////////////////////////////// + +DeleteOperation::DeleteOperation() +{ + setName(QLatin1String( "Delete" )); +} + +DeleteOperation::~DeleteOperation() +{ + deleteFileNowOrLater( value( QLatin1String( "backupOfExistingFile" ) ).toString() ); +} + +void DeleteOperation::backup() +{ + const QString fileName = arguments().first(); + setValue( QLatin1String( "backupOfExistingFile" ), backupFileName( fileName ) ); + QFile file( fileName ); + const bool success = file.copy( value( QLatin1String( "backupOfExistingFile" ) ).toString() ); + if(!success) + setError( UserDefinedError, tr("Cannot create backup of %1: %2").arg(fileName, file.errorString()) ); +} + +bool DeleteOperation::performOperation() +{ + // Requires only one parameter. That is the name of + // the file to remove. + QStringList args = this->arguments(); + if( args.count() != 1 ) { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 1 expected.").arg( args.count() ) ); + return false; + } + + const QString fName = args.first(); + return deleteFileNowOrLater( fName ); +} + +bool DeleteOperation::undoOperation() +{ + if( !hasValue( QLatin1String( "backupOfExistingFile" ) ) ) + return true; + + const QString fileName = arguments().first(); + QFile backupF( value( QLatin1String( "backupOfExistingFile" ) ).toString() ); + const bool success = backupF.copy( fileName ) && deleteFileNowOrLater( backupF.fileName() ); + if(!success) + setError( UserDefinedError, tr("Cannot restore backup file for %1: %2").arg(fileName, backupF.errorString()) ); + + return success; +} + +bool DeleteOperation::testOperation() +{ + // TODO + return true; +} + +DeleteOperation* DeleteOperation::clone() const +{ + return new DeleteOperation; +} + +/*! + \reimp + */ +QDomDocument DeleteOperation::toXml() const +{ + // we don't want to save the backupOfExistingFile + if( !hasValue( QLatin1String( "backupOfExistingFile" ) ) ) + return UpdateOperation::toXml(); + + DeleteOperation* const me = const_cast< DeleteOperation* >( this ); + + const QVariant v = value( QLatin1String( "backupOfExistingFile" ) ); + me->clearValue( QLatin1String( "backupOfExistingFile" ) ); + const QDomDocument xml = UpdateOperation::toXml(); + me->setValue( QLatin1String( "backupOfExistingFile" ), v ); + return xml; +} + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::MkdirOperation +//////////////////////////////////////////////////////////////////////////// + +MkdirOperation::MkdirOperation() +{ + setName(QLatin1String( "Mkdir" )); +} + +MkdirOperation::~MkdirOperation() +{ + +} + +void MkdirOperation::backup() +{ + static const QRegExp re( QLatin1String( "\\\\|/" ) ); + static const QLatin1String sep( "/" ); + + QString path = arguments().first(); + path.replace( re, sep ); + + QDir createdDir = QDir::root(); + + // find out, which part of the path is the first one we actually need to create + int end = 0; + while( true ) + { + QString p = path.section( sep, 0, ++end ); + createdDir = QDir( p ); + if( !createdDir.exists() ) + break; + else if( p == path ) + { + // everything did already exist -> nothing to do for us (nothing to revert then, either) + createdDir = QDir::root(); + break; + } + } + + setValue( QLatin1String( "createddir" ), createdDir.absolutePath() ); +} + +bool MkdirOperation::performOperation() +{ + // Requires only one parameter. That is the name of + // the file to remove. + QStringList args = this->arguments(); + if( args.count() != 1 ) { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 1 expected.").arg( args.count() ) ); + return false; + } + QString dirName = args.first(); + const bool created = QDir::root().mkpath(dirName); + if ( !created ) { + setError( UserDefinedError ); + setErrorString( tr("Could not create folder %1: Unknown error.").arg( dirName ) ); + } + return created; +} + +bool MkdirOperation::undoOperation() +{ + Q_ASSERT( arguments().count() == 1 ); + QString dirName = arguments().first(); + + const QDir createdDir = QDir( value( QLatin1String( "createddir" ) ).toString() ); + const bool forceremoval = QVariant( value( QLatin1String( "forceremoval" ) ) ).toBool(); + + if( createdDir == QDir::root() ) + return true; + + QString errorString; + if( forceremoval ) + { + return removeDirectory( createdDir.path(), &errorString ); + } + + // even remove some hidden, OS-created files in there +#if defined Q_WS_MAC + QFile::remove( createdDir.path() + QLatin1String( "/.DS_Store" ) ); +#elif defined Q_WS_WIN + QFile::remove( createdDir.path() + QLatin1String( "/Thumbs.db" ) ); +#endif + + errno = 0; + const bool result = QDir::root().rmdir( createdDir.path() ); + if ( !result ) { + if ( errorString.isEmpty() ) + setError( UserDefinedError, tr("Cannot remove directory %1: %2").arg( createdDir.path(), errorString ) ); + else + setError( UserDefinedError, tr("Cannot remove directory %1: %2").arg( createdDir.path(), QLatin1String(strerror(errno)) ) ); + } + return result; +} + +bool KDUpdater::MkdirOperation::testOperation() +{ + // TODO + return true; +} + +MkdirOperation* MkdirOperation::clone() const +{ + return new MkdirOperation; +} + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::RmdirOperation +//////////////////////////////////////////////////////////////////////////// + +RmdirOperation::RmdirOperation() +{ + setValue( QLatin1String( "removed" ), false ); + setName(QLatin1String( "Rmdir" )); +} + +RmdirOperation::~RmdirOperation() +{ + +} + +void RmdirOperation::backup() +{ + // nothing to backup - rollback will just create the directory +} + +bool RmdirOperation::performOperation() +{ + // Requires only one parameter. That is the name of + // the file to remove. + QStringList args = this->arguments(); + if( args.count() != 1 ) { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 1 expected.").arg( args.count() ) ); + return false; + } + + QString dirName = args.first(); + QDir dir( dirName ); + if( !dir.exists() ) { + setError( UserDefinedError ); + setErrorString( tr("Could not remove folder %1: The folder does not exist.").arg( dirName ) ); + return false; + } + + errno = 0; + const bool removed = dir.rmdir( dirName ); + setValue( QLatin1String( "removed" ), removed ); + if ( !removed ) { + setError( UserDefinedError ); + setErrorString( tr("Could not remove folder %1: %2.").arg( dirName, QLatin1String(strerror(errno)) ) ); + } + return removed; +} + +bool RmdirOperation::undoOperation() +{ + if( !value( QLatin1String( "removed" ) ).toBool() ) + return true; + + const QFileInfo fi( arguments().first() ); + errno = 0; + const bool success = fi.dir().mkdir( fi.fileName() ); + if(!success) + setError( UserDefinedError, tr("Cannot recreate directory %1: %2").arg( fi.fileName(), QLatin1String(strerror(errno)) ) ); + + return success; +} + +bool RmdirOperation::testOperation() +{ + // TODO + return true; +} + +RmdirOperation* RmdirOperation::clone() const +{ + return new RmdirOperation; +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::AppendFileOperation +//////////////////////////////////////////////////////////////////////////// + +AppendFileOperation::AppendFileOperation() +{ + setName(QLatin1String( "AppendFile" )); +} + +AppendFileOperation::~AppendFileOperation() +{ + +} + +void AppendFileOperation::backup() +{ + const QString filename = arguments().first(); + + QFile file( filename ); + if( !file.exists() ) + return; // nothing to backup + + setValue( QLatin1String( "backupOfFile" ), backupFileName( filename ) ); + if( !file.copy( value( QLatin1String( "backupOfFile" ) ).toString() ) ) + { + setError( UserDefinedError, tr("Cannot backup file %1: %2").arg(filename, file.errorString()) ); + clearValue( QLatin1String( "backupOfFile" ) ); + } +} + +bool AppendFileOperation::performOperation() +{ + // This operation takes two arguments. First argument is the name + // of the file into which a text has to be appended. Second argument + // is the text to append. + QStringList args = this->arguments(); + if( args.count() != 2 ) { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 2 expected.").arg( args.count() ) ); + return false; + } + + QString fName = args.first(); + QString text = args.last(); + + QFile file(fName); + if( !file.open(QFile::Append) ) + { + // first we rename the file, then we copy it to the real target and open the copy - the renamed original is then marked for deletion + const QString newName = backupFileName( fName ); + if( !QFile::rename( fName, newName ) && QFile::copy( newName, fName ) && file.open( QFile::Append ) ) + { + QFile::rename( newName, fName ); + setError( UserDefinedError ); + setErrorString( tr("Could not open file %1 for writing: %2.").arg( file.fileName(), file.errorString() ) ); + return false; + } + deleteFileNowOrLater( newName ); + } + + QTextStream ts(&file); + ts << text; + file.close(); + + return true; +} + +bool AppendFileOperation::undoOperation() +{ + // backupOfFile being empty -> file didn't exist before -> no error + const QString filename = arguments().first(); + const QString backupOfFile = value( QLatin1String( "backupOfFile" ) ).toString(); + if( !backupOfFile.isEmpty() && !QFile::exists( backupOfFile ) ) + { + setError( UserDefinedError, tr("Cannot find backup file for %1").arg(filename) ); + return false; + } + + const bool removed = deleteFileNowOrLater( filename ); + if ( !removed ) { + setError( UserDefinedError, tr("Could not restore backup file for %1.").arg( filename ) ); + return false; + } + + // got deleted? We might be done, if it didn't exist before + if( backupOfFile.isEmpty() ) + return true; + + QFile backupFile( backupOfFile ); + const bool success = backupFile.rename( filename ); + if ( !success ) + setError( UserDefinedError, tr("Could not restore backup file for %1: %2").arg(filename, backupFile.errorString()) ); + return success; +} + +bool AppendFileOperation::testOperation() +{ + // TODO + return true; +} + +AppendFileOperation* AppendFileOperation::clone() const +{ + return new AppendFileOperation; +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::PrependFileOperation +//////////////////////////////////////////////////////////////////////////// + +PrependFileOperation::PrependFileOperation() +{ + setName(QLatin1String( "PrependFile" )); +} + +PrependFileOperation::~PrependFileOperation() +{ + +} + +void PrependFileOperation::backup() +{ + const QString filename = arguments().first(); + + QFile file( filename ); + if( !file.exists() ) + return; // nothing to backup + + setValue( QLatin1String( "backupOfFile" ), backupFileName( filename ) ); + if( !file.copy( value( QLatin1String( "backupOfFile" ) ).toString() ) ) + { + setError( UserDefinedError, tr("Cannot backup file %1: %2").arg(filename, file.errorString()) ); + clearValue( QLatin1String( "backupOfFile" ) ); + } +} + +bool PrependFileOperation::performOperation() +{ + // This operation takes two arguments. First argument is the name + // of the file into which a text has to be appended. Second argument + // is the text to append. + QStringList args = this->arguments(); + if( args.count() != 2 ) {\ + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 2 expected.").arg( args.count() ) ); + return false; + } + + QString fName = args.first(); + QString text = args.last(); + + // Load the file first. + QFile file(fName); + if( !file.open(QFile::ReadOnly) ) { + setError( UserDefinedError ); + setErrorString( tr("Could not open file %1 for reading: %2.").arg( file.fileName(), file.errorString() ) ); + return false; + } + QString fContents( QLatin1String( file.readAll() ) ); + file.close(); + + // Prepend text to the file text + fContents = text + fContents; + + // Now re-open the file in write only mode. + if( !file.open(QFile::WriteOnly) ) { + // first we rename the file, then we copy it to the real target and open the copy - the renamed original is then marked for deletion + const QString newName = backupFileName( fName ); + if( !QFile::rename( fName, newName ) && QFile::copy( newName, fName ) && file.open( QFile::WriteOnly ) ) + { + QFile::rename( newName, fName ); + setError( UserDefinedError ); + setErrorString( tr("Could not open file %1 for writing: %2.").arg( file.fileName(), file.errorString() ) ); + return false; + } + deleteFileNowOrLater( newName ); + } + QTextStream ts(&file); + ts << fContents; + file.close(); + + return true; +} + +bool PrependFileOperation::undoOperation() +{ + // bockupOfFile being empty -> file didn't exist before -> no error + const QString filename = arguments().first(); + const QString backupOfFile = value( QLatin1String( "backupOfFile" ) ).toString(); + if( !backupOfFile.isEmpty() && !QFile::exists( backupOfFile ) ) + { + setError( UserDefinedError, tr("Cannot find backup file for %1").arg(filename) ); + return false; + } + + if( !deleteFileNowOrLater( filename ) ) + { + setError( UserDefinedError, tr("Cannot restore backup file for %1").arg( filename ) ); + return false; + } + + // got deleted? We might be done, if it didn't exist before + if( backupOfFile.isEmpty() ) + return true; + + QFile backupF( backupOfFile ); + const bool success = backupF.rename( filename ); + if(!success) + setError( UserDefinedError, tr("Cannot restore backup file for %1: %2").arg(filename, backupF.errorString()) ); + + return success; +} + +bool PrependFileOperation::testOperation() +{ + // TODO + return true; +} + +PrependFileOperation* PrependFileOperation::clone() const +{ + return new PrependFileOperation; +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::ExecuteOperation +//////////////////////////////////////////////////////////////////////////// + +ExecuteOperation::ExecuteOperation() + : QObject() +{ + setName(QLatin1String( "Execute" )); +} + +ExecuteOperation::~ExecuteOperation() +{ + +} + +void ExecuteOperation::backup() +{ + // this is not possible, since the process can do whatever... +} + +#if defined( SUPPORT_DETACHED_PROCESS_EXECUTION ) && defined( Q_WS_WIN ) +// stolen from qprocess_win.cpp +static QString qt_create_commandline(const QString &program, const QStringList &arguments) +{ + QString args; + if (!program.isEmpty()) { + QString programName = program; + if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' '))) + programName = QLatin1Char('\"') + programName + QLatin1Char('\"'); + programName.replace(QLatin1Char('/'), QLatin1Char('\\')); + + // add the prgram as the first arg ... it works better + args = programName + QLatin1Char(' '); + } + + for (int i=0; i<arguments.size(); ++i) { + QString tmp = arguments.at(i); + // in the case of \" already being in the string the \ must also be escaped + tmp.replace( QLatin1String("\\\""), QLatin1String("\\\\\"") ); + // escape a single " because the arguments will be parsed + tmp.replace( QLatin1Char('\"'), QLatin1String("\\\"") ); + if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { + // The argument must not end with a \ since this would be interpreted + // as escaping the quote -- rather put the \ behind the quote: e.g. + // rather use "foo"\ than "foo\" + QString endQuote(QLatin1Char('\"')); + int i = tmp.length(); + while (i>0 && tmp.at(i-1) == QLatin1Char('\\')) { + --i; + endQuote += QLatin1Char('\\'); + } + args += QLatin1String(" \"") + tmp.left(i) + endQuote; + } else { + args += QLatin1Char(' ') + tmp; + } + } + return args; +} +#endif + +bool ExecuteOperation::performOperation() +{ + // This operation receives only one argument. It is the complete + // command line of the external program to execute. + QStringList args = this->arguments(); + if( args.isEmpty() ) + { + setError( InvalidArguments ); + setErrorString( tr("Invalid arguments: %1 arguments given, 2 expected.").arg( args.count() ) ); + return false; + } + + QList< int > allowedExitCodes; + + QRegExp re( QLatin1String( "^\\{((-?\\d+,)*-?\\d+)\\}$" ) ); + if( re.exactMatch( args.first() ) ) + { + const QStringList numbers = re.cap( 1 ).split( QLatin1Char( ',' ) ); + for( QStringList::const_iterator it = numbers.begin(); it != numbers.end(); ++it ) + allowedExitCodes.push_back( it->toInt() ); + args.pop_front(); + } + else + { + allowedExitCodes.push_back( 0 ); + } + + bool success = false; +#ifdef SUPPORT_DETACHED_PROCESS_EXECUTION + // unix style: when there's an ampersand after the command, it's started detached + if( args.count() >= 2 && args.last() == QLatin1String( "&" ) ) + { + args.pop_back(); +#ifdef Q_WS_WIN + QString arguments = qt_create_commandline( args.front(), args.mid( 1 ) ); + + PROCESS_INFORMATION pinfo; + + STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, + static_cast< ulong >( CW_USEDEFAULT ), static_cast< ulong >( CW_USEDEFAULT ), + static_cast< ulong >( CW_USEDEFAULT ), static_cast< ulong >( CW_USEDEFAULT ), + 0, 0, 0, STARTF_USESHOWWINDOW, SW_HIDE, 0, 0, 0, 0, 0 + }; + success = CreateProcess( 0, const_cast< wchar_t* >( static_cast< const wchar_t* >( arguments.utf16() ) ), + 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0, + 0, + &startupInfo, &pinfo ); + +#else + success = QProcess::startDetached( args.front(), args.mid( 1 ) ); +#endif + } + else +#endif + { + Environment::instance()->applyTo( &process ); //apply non-persistent variables + process.start( args.front(), args.mid( 1 ) ); + + QEventLoop loop; + QObject::connect( &process, SIGNAL( finished( int, QProcess::ExitStatus ) ), &loop, SLOT( quit() ) ); + QObject::connect( &process, SIGNAL(readyRead()), this, SLOT(readProcessOutput())); + success = process.waitForStarted( -1 ); + if( success ) + { + loop.exec(); + setValue( QLatin1String( "ExitCode" ), process.exitCode() ); + success = allowedExitCodes.contains( process.exitCode() ); + } + } + if(!success) + { + setError( UserDefinedError ); + setErrorString( tr("Execution failed: \"%1\"").arg( args.join( QLatin1String( " " ) ) ) ); + } + + return success; +} + +/*! + Cancels the ExecuteOperation. This methods tries to terminate the process + gracefully by calling QProcess::terminate. After 10 seconds, the process gets killed. + */ +void ExecuteOperation::cancelOperation() +{ + if( process.state() == QProcess::Running ) + process.terminate(); + if( !process.waitForFinished( 10000 ) ) + process.kill(); +} + +void ExecuteOperation::readProcessOutput() +{ + QByteArray output = process.readAll(); + if (!output.isEmpty()) + emit outputTextChanged(QString::fromLocal8Bit(output)); +} + +bool ExecuteOperation::undoOperation() +{ + // this is not possible, since the process can do whatever... + return false; +} + +bool ExecuteOperation::testOperation() +{ + // TODO + return true; +} + +ExecuteOperation* ExecuteOperation::clone() const +{ + return new ExecuteOperation; +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::UpdatePackageOperation +//////////////////////////////////////////////////////////////////////////// + +UpdatePackageOperation::UpdatePackageOperation() +{ + setName(QLatin1String( "UpdatePackage" )); +} + +UpdatePackageOperation::~UpdatePackageOperation() +{ + +} + +void UpdatePackageOperation::backup() +{ + const PackageInfo info = application()->packagesInfo()->packageInfo( application()->packagesInfo()->findPackageInfo( arguments().first() ) ); + setValue( QLatin1String( "oldVersion" ), info.version ); + setValue( QLatin1String( "oldDate" ), info.lastUpdateDate ); +} + +bool UpdatePackageOperation::performOperation() +{ + // This operation receives three arguments : the name of the package + // the new version and the release date + const QStringList args = this->arguments(); + if( args.count() != 3 ) + { + setError( InvalidArguments, tr("Invalid arguments: %1 arguments given, 3 expected.").arg( args.count() ) ); + return false; + } + + const QString& packageName = args.at( 0 ); + const QString& version = args.at( 1 ); + const QDate date = QDate::fromString( args.at( 2 ) ); + const bool success = application()->packagesInfo()->updatePackage( packageName, version, date ); + if(!success) + setError( UserDefinedError, tr("Cannot update %1-%2").arg( packageName, version ) ); + + return success; +} + +bool UpdatePackageOperation::undoOperation() +{ + const QString packageName = arguments().first(); + const QString version = arguments().at( 1 ); + const QString oldVersion = value( QLatin1String( "oldVersion" ) ).toString(); + const QDate oldDate = value( QLatin1String( "oldDate" ) ).toDate(); + const bool success = application()->packagesInfo()->updatePackage( packageName, oldVersion, oldDate ); + if(!success) + setError( UserDefinedError, tr("Cannot restore %1-%2").arg( packageName, version ) ); + + return success; +} + +bool UpdatePackageOperation::testOperation() +{ + // TODO + return true; +} + +UpdatePackageOperation* UpdatePackageOperation::clone() const +{ + return new UpdatePackageOperation; +} + + +//////////////////////////////////////////////////////////////////////////// +// KDUpdater::UpdateCompatOperation +//////////////////////////////////////////////////////////////////////////// + +UpdateCompatOperation::UpdateCompatOperation() +{ + setName(QLatin1String( "UpdateCompatLevel" )); +} + +UpdateCompatOperation::~UpdateCompatOperation() +{ + +} + +void UpdateCompatOperation::backup() +{ + setValue( QLatin1String( "oldCompatLevel" ), application()->packagesInfo()->compatLevel() ); +} + +bool UpdateCompatOperation::performOperation() +{ + // This operation receives one argument : the new compat level + const QStringList args = this->arguments(); + if( args.count() != 1 ) + { + setError( InvalidArguments, tr("Invalid arguments: %1 arguments given, 1 expected.").arg( args.count() ) ); + return false; + } + + const int level = args.first().toInt(); + application()->packagesInfo()->setCompatLevel( level ); + return true; +} + +bool UpdateCompatOperation::undoOperation() +{ + if( !hasValue( QLatin1String( "oldCompatLevel" ) ) ) + { + setError( UserDefinedError, tr("Cannot restore previous compat-level") ); + return false; + } + + application()->packagesInfo()->setCompatLevel( value( QLatin1String( "oldCompatLevel" ) ).toInt() ); + return true; +} + +bool UpdateCompatOperation::testOperation() +{ + // TODO + return true; +} + +UpdateCompatOperation* UpdateCompatOperation::clone() const +{ + return new UpdateCompatOperation; +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperations.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperations.h new file mode 100644 index 000000000..4f1a2563e --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdateoperations.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_OPERATIONS_H +#define KD_UPDATER_UPDATE_OPERATIONS_H + +#include "kdupdaterupdateoperation.h" + +#include <QDir> +#include <QObject> +#include <QProcess> + +namespace KDUpdater +{ + + class KDTOOLS_UPDATER_EXPORT CopyOperation : public UpdateOperation + { + public: + CopyOperation(); + ~CopyOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + CopyOperation* clone() const; + + QDomDocument toXml() const; + }; + + class KDTOOLS_UPDATER_EXPORT MoveOperation : public UpdateOperation + { + public: + MoveOperation(); + ~MoveOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + MoveOperation* clone() const; + }; + + class KDTOOLS_UPDATER_EXPORT DeleteOperation : public UpdateOperation + { + public: + DeleteOperation(); + ~DeleteOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + DeleteOperation* clone() const; + + QDomDocument toXml() const; + }; + + class KDTOOLS_UPDATER_EXPORT MkdirOperation : public UpdateOperation + { + public: + MkdirOperation(); + ~MkdirOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + MkdirOperation* clone() const; + }; + + class KDTOOLS_UPDATER_EXPORT RmdirOperation : public UpdateOperation + { + public: + RmdirOperation(); + ~RmdirOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + RmdirOperation* clone() const; + }; + + class KDTOOLS_UPDATER_EXPORT AppendFileOperation : public UpdateOperation + { + public: + AppendFileOperation(); + ~AppendFileOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + AppendFileOperation* clone() const; + }; + + class KDTOOLS_UPDATER_EXPORT PrependFileOperation : public UpdateOperation + { + public: + PrependFileOperation(); + ~PrependFileOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + PrependFileOperation* clone() const; + }; + + class KDTOOLS_UPDATER_EXPORT ExecuteOperation : public QObject, public UpdateOperation + { + Q_OBJECT + public: + ExecuteOperation(); + ~ExecuteOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + ExecuteOperation* clone() const; + + public Q_SLOTS: + void cancelOperation(); + + private Q_SLOTS: + void readProcessOutput(); + + Q_SIGNALS: + void outputTextChanged(const QString &text); + + private: + QProcess process; + }; + + class KDTOOLS_UPDATER_EXPORT UpdatePackageOperation : public UpdateOperation + { + public: + UpdatePackageOperation(); + ~UpdatePackageOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + UpdatePackageOperation* clone() const; + }; + + class KDTOOLS_UPDATER_EXPORT UpdateCompatOperation : public UpdateOperation + { + public: + UpdateCompatOperation(); + ~UpdateCompatOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + UpdateCompatOperation* clone() const; + }; + +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesdialog.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesdialog.cpp new file mode 100644 index 000000000..2b8d54a6b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesdialog.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdatesdialog.h" +#include "kdupdaterpackagesinfo.h" +#include "kdupdaterupdate.h" +#include "kdupdaterapplication.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QHash> +#include <QtCore/QSet> + +#if defined( KDUPDATERGUIWEBVIEW ) +#include <QtWebKit/QWebView> +#elif defined( KDUPDATERGUITEXTBROWSER ) +#include <QtGui/QTextBrowser> +#endif + +#include "ui_updatesdialog.h" + +/*! + \ingroup kdupdater + \class KDUpdater::UpdatesDialog kdupdaterupdatesdialog.h KDUpdaterUpdatesDialog + \brief A dialog that let the user chooses which updates he wants to install + + After \ref KDUpdater::UpdateFinder class finds all updates available for an application, + this dialog can be used to help the user select which update he wants to install. + + Usage: + \code + QList<KDUpdater::Update*> updates = updateFinder.updates(); + + KDUpdater::UpdatesDialog updatesDialog(this); + updatesDialog.setUpdates(updates); + + if( updatesDialog.exec() != QDialog::Accepted ) + { + qDeleteAll(updates); + updates.clear(); + return; + } + + QList<KDUpdater::Update*> reqUpdates; + for(int i=0; i<updates.count(); i++) + { + if( !updatesDialog.isUpdateAllowed(updates[i]) ) + continue; + reqUpdates.append(updates[i]); + } + \endcode +*/ + +class KDUpdater::UpdatesDialog::Private +{ + Q_DECLARE_TR_FUNCTIONS(KDUpdater::Private) + +public: + explicit Private( UpdatesDialog* qq ) : + q( qq ) + {} + + UpdatesDialog* q; + + Ui::UpdatesDialog ui; + + int currentUpdate; + QList<Update*> updates; + QSet<const Update*> status; + + void setCurrentUpdate(int index); + + QString packageDescription( Update* update ); + QString compatDescription( Update* update ); + void slotStateChanged(); + void slotPreviousClicked(); + void slotNextClicked(); +}; + +/*! + Constructor. +*/ +KDUpdater::UpdatesDialog::UpdatesDialog(QWidget *parent) + : QDialog(parent), + d( new Private( this ) ) +{ + d->ui.setupUi(this); + d->currentUpdate = -1; + + connect(d->ui.packageUpdateCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(slotStateChanged())); + connect(d->ui.nextPackageButton, SIGNAL(clicked()), + this, SLOT(slotNextClicked())); + connect(d->ui.previousPackageButton, SIGNAL(clicked()), + this, SLOT(slotPreviousClicked())); +} + + +/*! + Destructor. +*/ +KDUpdater::UpdatesDialog::~UpdatesDialog() +{ + delete d; +} + + +/*! + Sets the list of updates available to the user. +*/ +void KDUpdater::UpdatesDialog::setUpdates(const QList<Update*> &updates) +{ + d->updates = updates; + d->status.clear(); + + d->ui.packageSwitchBar->setVisible( d->updates.size()>1 ); + + if (d->updates.isEmpty()) { + d->ui.descriptionLabel->setText(tr("<b>No update available...</b>")); + d->ui.descriptionLabel->setFixedSize(d->ui.descriptionLabel->sizeHint()); + d->ui.releaseNotesGroup->hide(); + d->ui.pixmapLabel->hide(); + } else if (d->updates.size()==1) { + //Only one update, so pre-accept it. + //OK/Cancel will do from the user POV + d->status.insert( d->updates.front() ); + } + + d->ui.totalPackageLabel->setText(QString::number(d->updates.size())); + d->setCurrentUpdate(0); +} + + +/*! + returns the list of updates available to the user. +*/ +QList<KDUpdater::Update*> KDUpdater::UpdatesDialog::updates() const +{ + return d->updates; +} + + +/*! + Returns true if the update needs to be installed. +*/ +bool KDUpdater::UpdatesDialog::isUpdateAllowed(const KDUpdater::Update *update) const +{ + return d->status.contains( update ); +} + +void KDUpdater::UpdatesDialog::Private::slotStateChanged() +{ + if (currentUpdate<0 || currentUpdate>=updates.size()) { + return; + } + + if ( ui.packageUpdateCheckBox->isChecked() ) + status.insert( updates[currentUpdate] ); + else + status.remove( updates[currentUpdate] ); +} + +void KDUpdater::UpdatesDialog::Private::slotPreviousClicked() +{ + setCurrentUpdate(currentUpdate-1); +} + +void KDUpdater::UpdatesDialog::Private::slotNextClicked() +{ + setCurrentUpdate(currentUpdate+1); +} + +void KDUpdater::UpdatesDialog::Private::setCurrentUpdate(int index) +{ + if (updates.isEmpty()) { + if (currentUpdate == -1) + return; + + currentUpdate = -1; + return; + } + + if (index<0 || index>=updates.size()) { + return; + } + + currentUpdate = index; + + KDUpdater::Update *update = updates.at( index ); + + QString description; + + switch ( update->type() ) { + case PackageUpdate: + case NewPackage: + description = packageDescription( update ); + break; + case CompatUpdate: + description = compatDescription( update ); + break; + default: + description = tr( "<unkown>" ); + } + + ui.descriptionLabel->setText(description); + ui.descriptionLabel->setMinimumHeight(ui.descriptionLabel->heightForWidth(400)); + + ui.packageUpdateCheckBox->setChecked( status.contains( update ) ); + + ui.currentPackageLabel->setText(QString::number(index+1)); + ui.nextPackageButton->setEnabled( index!=(updates.size()-1) ); + ui.previousPackageButton->setEnabled( index!=0 ); + + QDir appdir(update->application()->applicationDirectory()); + if (update->data( QLatin1String( "ReleaseNotes" ) ).isValid()) { + ui.releaseNotesGroup->show(); +#if defined( KDUPDATERGUIWEBVIEW ) + ui.releaseNotesView->setUrl( update->data( QLatin1String( "ReleaseNotes" ) ).toUrl() ); +#elif defined( KDUPDATERGUITEXTBROWSER ) + ui.releaseNotesView->setSource( update->data( QLatin1String( "ReleaseNotes" ) ).toUrl()); +#endif + } + else { + ui.releaseNotesGroup->hide(); + } +} + + +QString KDUpdater::UpdatesDialog::Private::packageDescription( KDUpdater::Update* update ) +{ + KDUpdater::PackagesInfo *packages = update->application()->packagesInfo(); + KDUpdater::PackageInfo info = packages->packageInfo( + packages->findPackageInfo(update->data( QLatin1String( "Name" ) ).toString())); + + QDir appdir(update->application()->applicationDirectory()); + QPixmap pixmap(appdir.filePath(info.pixmap)); + if (!pixmap.isNull()) { + ui.pixmapLabel->setPixmap(pixmap.scaled(96, 96)); + } + + + QString description = tr("<b>A new package update is available for %1!</b><br/><br/>" + "The package %2 %3 is now available -- you have version %4") + .arg(packages->applicationName(), + update->data( QLatin1String( "Name" ) ).toString(), + update->data( QLatin1String( "Version" ) ).toString(), + info.version); + + if (!info.title.isEmpty() || !info.description.isEmpty() ) { + description += QLatin1String( "<br/><br/>" ); + description += tr("<b>Package Details:</b>" ); + if ( !info.title.isEmpty() ) { + description += tr( "<br/><i>Title:</i> %1" ).arg( info.title ); + } + if ( !info.description.isEmpty() ) { + description += tr( "<br/><i>Description:</i> %1" ).arg( info.description ); + } + } + + if ( update->data( QLatin1String( "Description" ) ).isValid() ) { + description += QLatin1String( "<br/><br/>" ); + description += tr( "<b>Update description:</b><br/>%1" ) + .arg( update->data( QLatin1String( "Description" ) ).toString() ); + } + return description; +} + +QString KDUpdater::UpdatesDialog::Private::compatDescription( Update* update ) +{ + KDUpdater::PackagesInfo *packages = update->application()->packagesInfo(); + + QString description = tr("<b>A new compatibility update is available for %1!</b><br/><br/>" + "The compatibility level %2 is now available -- you have level %3") + .arg(packages->applicationName(), + QString::number(update->data( QLatin1String( "CompatLevel" ) ).toInt()), + QString::number(packages->compatLevel())); + + if ( update->data( QLatin1String( "Description" ) ).isValid() ) { + description += QLatin1String( "<br/><br/>" ); + description += tr( "<b>Update description:</b> %1" ) + .arg( update->data( QLatin1String( "Description" ) ).toString() ); + } + return description; +} + +#include "moc_kdupdaterupdatesdialog.cpp" diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesdialog.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesdialog.h new file mode 100644 index 000000000..85a90a595 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesdialog.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATES_DIALOG_H +#define KD_UPDATER_UPDATES_DIALOG_H + +#include "kdupdater.h" +#include <QtCore/QList> +#include <QtGui/QDialog> + +namespace KDUpdater +{ + class Update; + + class KDTOOLS_UPDATER_EXPORT UpdatesDialog : public QDialog + { + Q_OBJECT + + public: + explicit UpdatesDialog(QWidget *parent = 0); + ~UpdatesDialog(); + + void setUpdates(const QList<Update*> &updates); + QList<Update*> updates() const; + + bool isUpdateAllowed( const Update * update ) const; + + private: + class Private; + Private * const d; + + Q_PRIVATE_SLOT( d, void slotStateChanged() ) + Q_PRIVATE_SLOT( d, void slotPreviousClicked() ) + Q_PRIVATE_SLOT( d, void slotNextClicked() ) + }; +} + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesinfo.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesinfo.cpp new file mode 100644 index 000000000..4e9f60195 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesinfo.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdatesinfo_p.h" + +#include <QCoreApplication> +#include <QDomDocument> +#include <QDomElement> +#include <QFile> +#include <QSharedData> + +// +// KDUpdater::UpdatesInfo::UpdatesInfoData +// +struct KDUpdater::UpdatesInfo::UpdatesInfoData : public QSharedData +{ + Q_DECLARE_TR_FUNCTIONS(KDUpdater::UpdatesInfoData) + +public: + UpdatesInfoData() : error(UpdatesInfo::NotYetReadError), compatLevel(-1) { } + + QString errorMessage; + UpdatesInfo::Error error; + QString updateXmlFile; + QString applicationName; + QString applicationVersion; + int compatLevel; + QList<KDUpdater::UpdateInfo> updateInfoList; + + void parseFile(const QString& updateXmlFile); + bool parsePackageUpdateElement(const QDomElement & updateE); + bool parseCompatUpdateElement(const QDomElement & updateE); + + void setInvalidContentError( const QString& detail ); +}; + +void KDUpdater::UpdatesInfo::UpdatesInfoData::setInvalidContentError(const QString& detail) +{ + error = UpdatesInfo::InvalidContentError; + errorMessage = tr("Updates.Xml contains invalid content: %1").arg(detail); +} + +void KDUpdater::UpdatesInfo::UpdatesInfoData::parseFile(const QString& updateXmlFile) +{ + QFile file( updateXmlFile ); + if( !file.open(QFile::ReadOnly) ) + { + error = UpdatesInfo::CouldNotReadUpdateInfoFileError; + errorMessage = tr("Could not read \"%1\"").arg(updateXmlFile); + return; + } + + QDomDocument doc; + QString parseErrorMessage; + int parseErrorLine; + int parseErrorColumn; + if( !doc.setContent( &file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn ) ) + { + error = UpdatesInfo::InvalidXmlError; + errorMessage = tr("Parse error in %1 at %2, %3: %4") + .arg( updateXmlFile, + QString::number( parseErrorLine ), + QString::number( parseErrorColumn ), + parseErrorMessage ); + return; + } + + QDomElement rootE = doc.documentElement(); + if( rootE.tagName() != QLatin1String( "Updates" ) ) + { + setInvalidContentError(tr("root element %1 unexpected, should be \"Updates\"").arg(rootE.tagName())); + return; + } + + QDomNodeList childNodes = rootE.childNodes(); + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.at(i); + QDomElement childE = childNode.toElement(); + if( childE.isNull() ) + continue; + + if( childE.tagName() == QLatin1String( "ApplicationName" ) ) + applicationName = childE.text(); + else if( childE.tagName() == QLatin1String( "ApplicationVersion" ) ) + applicationVersion = childE.text(); + else if( childE.tagName() == QLatin1String( "RequiredCompatLevel" ) ) + compatLevel = childE.text().toInt(); + else if( childE.tagName() == QLatin1String( "PackageUpdate" ) ) { + const bool res = parsePackageUpdateElement( childE ); + if (!res) { + //error handled in subroutine + return; + } + } else if( childE.tagName() == QLatin1String( "CompatUpdate" ) ) { + const bool res = parseCompatUpdateElement( childE ); + if (!res) { + //error handled in subroutine + return; + } + } + } + + if (applicationName.isEmpty()) + { + setInvalidContentError(tr("ApplicationName element is missing")); + return; + } + + if (applicationVersion.isEmpty()) + { + setInvalidContentError(tr("ApplicationVersion element is missing")); + return; + } + + error = UpdatesInfo::NoError; + errorMessage.clear(); +} + +bool KDUpdater::UpdatesInfo::UpdatesInfoData::parsePackageUpdateElement(const QDomElement & updateE) +{ + if( updateE.isNull() ) + return false; + + KDUpdater::UpdateInfo info; + info.type = KDUpdater::PackageUpdate; + + QDomNodeList childNodes = updateE.childNodes(); + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.at(i); + QDomElement childE = childNode.toElement(); + if( childE.isNull() ) + continue; + + if( childE.tagName() == QLatin1String( "ReleaseNotes" ) ) { + info.data[childE.tagName()] = QUrl(childE.text()); + } + else if( childE.tagName() == QLatin1String( "UpdateFile" ) ) + { + KDUpdater::UpdateFileInfo ufInfo; + ufInfo.arch = childE.attribute(QLatin1String( "Arch" ), QLatin1String( "i386" )); + ufInfo.os = childE.attribute(QLatin1String( "OS" )); + ufInfo.compressedSize = childE.attribute( QLatin1String( "CompressedSize" ) ).toLongLong(); + ufInfo.uncompressedSize = childE.attribute( QLatin1String( "UncompressedSize" ) ).toLongLong(); + ufInfo.sha1sum = QByteArray::fromHex( childE.attribute( QLatin1String( "sha1sum" ) ).toAscii() ); + ufInfo.fileName = childE.text(); + info.updateFiles.append(ufInfo); + } + else if (childE.tagName() == QLatin1String("Licenses")) { + QHash<QString, QVariant> licenseHash; + const QDomNodeList licenseNodes = childE.childNodes(); + for (int i = 0; i < licenseNodes.count(); ++i) { + const QDomNode licenseNode = licenseNodes.at(i); + if (licenseNode.nodeName() == QLatin1String("License")) { + QDomElement element = licenseNode.toElement(); + licenseHash.insert(element.attributeNode(QLatin1String("name")).value(), + element.attributeNode(QLatin1String("file")).value()); + } + } + if (!licenseHash.isEmpty()) + info.data.insert(QLatin1String("Licenses"), licenseHash); + } + else { + info.data[childE.tagName()] = childE.text(); + } + } + + if (!info.data.contains( QLatin1String( "Name" ) )) + { + setInvalidContentError(tr("PackageUpdate element without Name")); + return false; + } + else if (!info.data.contains( QLatin1String( "Version" ) )) + { + setInvalidContentError(tr("PackageUpdate element without Version")); + return false; + } + else if (!info.data.contains( QLatin1String( "ReleaseDate" ) )) + { + setInvalidContentError(tr("PackageUpdate element without ReleaseDate")); + return false; + } + else if (info.updateFiles.isEmpty()) + { + setInvalidContentError(tr("PackageUpdate element without UpdateFile")); + return false; + } + + updateInfoList.append(info); + return true; +} + +bool KDUpdater::UpdatesInfo::UpdatesInfoData::parseCompatUpdateElement(const QDomElement & updateE) +{ + if( updateE.isNull() ) + return false; + + KDUpdater::UpdateInfo info; + info.type = KDUpdater::CompatUpdate; + + QDomNodeList childNodes = updateE.childNodes(); + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.at(i); + QDomElement childE = childNode.toElement(); + if( childE.isNull() ) + continue; + + if( childE.tagName() == QLatin1String( "ReleaseNotes" ) ) { + info.data[childE.tagName()] = QUrl(childE.text()); + } + else if( childE.tagName() == QLatin1String( "UpdateFile" ) ) + { + KDUpdater::UpdateFileInfo ufInfo; + ufInfo.arch = childE.attribute(QLatin1String( "Arch" ), QLatin1String( "i386" )); + ufInfo.os = childE.attribute(QLatin1String( "OS" )); + ufInfo.fileName = childE.text(); + info.updateFiles.append(ufInfo); + } + else { + info.data[childE.tagName()] = childE.text(); + } + } + + if (!info.data.contains( QLatin1String( "CompatLevel" ) )) + { + setInvalidContentError(tr("CompatUpdate element without CompatLevel")); + return false; + } + + if (!info.data.contains( QLatin1String( "ReleaseDate" ) )) + { + setInvalidContentError(tr("CompatUpdate element without ReleaseDate")); + return false; + } + + if (info.updateFiles.isEmpty()) + { + setInvalidContentError(tr("CompatUpdate element without UpdateFile")); + return false; + } + + updateInfoList.append(info); + return true; +} + + +// +// KDUpdater::UpdatesInfo +// +KDUpdater::UpdatesInfo::UpdatesInfo() + : d(new KDUpdater::UpdatesInfo::UpdatesInfoData) +{ +} + +KDUpdater::UpdatesInfo::~UpdatesInfo() +{ +} + +bool KDUpdater::UpdatesInfo::isValid() const +{ + return d->error == NoError; +} + +QString KDUpdater::UpdatesInfo::errorString() const +{ + return d->errorMessage; +} + +void KDUpdater::UpdatesInfo::setFileName(const QString& updateXmlFile) +{ + if( d->updateXmlFile == updateXmlFile ) + return; + + d->applicationName.clear(); + d->applicationVersion.clear(); + d->updateInfoList.clear(); + + d->updateXmlFile = updateXmlFile; + d->parseFile( d->updateXmlFile ); +} + +QString KDUpdater::UpdatesInfo::fileName() const +{ + return d->updateXmlFile; +} + +QString KDUpdater::UpdatesInfo::applicationName() const +{ + return d->applicationName; +} + +QString KDUpdater::UpdatesInfo::applicationVersion() const +{ + return d->applicationVersion; +} + +int KDUpdater::UpdatesInfo::compatLevel() const +{ + return d->compatLevel; +} + +int KDUpdater::UpdatesInfo::updateInfoCount( int type) const +{ + if ( type == KDUpdater::AllUpdate ) { + return d->updateInfoList.count(); + } + int count = 0; + for ( int i=0; i<d->updateInfoList.count(); ++i ) { + if ( d->updateInfoList.at( i ).type == type ) + ++count; + } + return count; +} + +KDUpdater::UpdateInfo KDUpdater::UpdatesInfo::updateInfo(int index) const +{ + if(index < 0 || index >= d->updateInfoList.count()) + return KDUpdater::UpdateInfo(); + + return d->updateInfoList.at( index ); +} + +QList<KDUpdater::UpdateInfo> KDUpdater::UpdatesInfo::updatesInfo( int type, int compatLevel ) const +{ + QList<KDUpdater::UpdateInfo> list; + if ( compatLevel == -1 ) { + if ( type == KDUpdater::AllUpdate ) { + return d->updateInfoList; + } + for ( int i=0; i<d->updateInfoList.count(); ++i ) { + if ( d->updateInfoList.at( i ).type == type ) + list.append( d->updateInfoList.at( i ) ); + } + } + else { + for ( int i=0; i<d->updateInfoList.count(); ++i ) { + UpdateInfo updateInfo = d->updateInfoList.at( i ); + if ( updateInfo.type == type ) { + if ( updateInfo.type == CompatUpdate ) { + if ( updateInfo.data.value( QLatin1String( "CompatLevel" ) ) == compatLevel ) + list.append( updateInfo ); + } + else { + if ( updateInfo.data.value( QLatin1String( "RequiredCompatLevel" ) ) == compatLevel ) + list.append( updateInfo ); + } + } + } + } + return list; +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesinfo_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesinfo_p.h new file mode 100644 index 000000000..4179e3d8d --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesinfo_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_PACKAGES_INFO_H +#define KD_UPDATER_UPDATE_PACKAGES_INFO_H + +#include "kdupdater.h" +#include <QSharedDataPointer> +#include <QString> +#include <QDate> +#include <QList> +#include <QStringList> +#include <QUrl> +#include <QMap> +#include <QVariant> + +// Classes and structures in this header file are for internal use only. +// They are not a part of the public API + +namespace KDUpdater +{ + struct UpdateFileInfo + { + UpdateFileInfo() + : compressedSize( 0 ), + uncompressedSize( 0 ) + { + } + QString arch; + QString os; + QString fileName; + QByteArray sha1sum; + quint64 compressedSize; + quint64 uncompressedSize; + }; + + struct UpdateInfo + { + int type; + QMap<QString, QVariant> data; + QList<UpdateFileInfo> updateFiles; + }; + + class UpdatesInfo + { + public: + enum Error + { + NoError=0, + NotYetReadError, + CouldNotReadUpdateInfoFileError, + InvalidXmlError, + InvalidContentError + }; + + UpdatesInfo(); + ~UpdatesInfo(); + + bool isValid() const; + QString errorString() const; + Error error() const; + + void setFileName(const QString& updateXmlFile); + QString fileName() const; + + QString applicationName() const; + QString applicationVersion() const; + int compatLevel() const; + + int updateInfoCount( int type=AllUpdate ) const; + UpdateInfo updateInfo(int index) const; + QList<UpdateInfo> updatesInfo( int type=AllUpdate, int compatLevel=-1 ) const; + + private: + struct UpdatesInfoData; + QSharedDataPointer<UpdatesInfoData> d; + }; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp new file mode 100644 index 000000000..14a765a5b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp @@ -0,0 +1,511 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdatesourcesinfo.h" +#include "kdupdaterapplication.h" + +#include <QDomElement> +#include <QDomDocument> +#include <QDomText> +#include <QDomCDATASection> +#include <QFileInfo> +#include <QFile> +#include <QTextStream> + + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateSourcesInfo kdupdaterupdatesourcesinfo.h KDUpdaterUpdateSourcesInfo + \brief Provides access to information about the update sources set for the application. + + An update source is a repository that contains updates applicable for the application. + Applications can download updates from the update source and install them locally. + + Each application can have one or more update sources from which it can download updates. + Information about update source is stored in a file called UpdateSources.xml. This class helps + access and modify the UpdateSources.xml file. + + The complete file name of the UpdateSources.xml file can be specified via the \ref setFileName() + method. The class then parses the XML file and makes available information contained in + that XML file through an easy to use API. You can + + \li Get update sources information via the \ref updateSourceInfoCount() and \ref updateSourceInfo() + methods. + \li You can add/remove/change update source information via the \ref addUpdateSourceInfo(), + \ref removeUpdateSource(), \ref setUpdateSourceAt() methods. + + The class emits appropriate signals to inform listeners about changes in the update application. +*/ + +/*! \enum UpdateSourcesInfo::Error + * Error codes related to retrieving update sources + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::NoError + * No error occurred + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::NotYetReadError + * The package information was not parsed yet from the XML file + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::CouldNotReadSourceFileError + * the specified update source file could not be read (does not exist or not readable) + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::InvalidXmlError + * The source file contains invalid XML. + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::InvalidContentError + * The source file contains valid XML, but does not match the expected format for source descriptions + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::CouldNotSaveChangesError + * Changes made to the object could be saved back to the source file + */ + +namespace KDUpdater +{ +struct UpdateSourceInfoPriorityHigherThan +{ + bool operator()( const UpdateSourceInfo& lhs, const UpdateSourceInfo& rhs ) const + { + return lhs.priority > rhs.priority; + } +}; +} + +struct KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData +{ + UpdateSourcesInfoData( UpdateSourcesInfo* qq ) : + q( qq ), + error(UpdateSourcesInfo::NotYetReadError), + application(0), + modified(false) + {} + + UpdateSourcesInfo* q; + + QString errorMessage; + UpdateSourcesInfo::Error error; + KDUpdater::Application* application; + bool modified; + QString fileName; + QList<KDUpdater::UpdateSourceInfo> updateSourceInfoList; + + void addUpdateSourceFrom( const QDomElement & element ); + void addChildElement( QDomDocument & doc, QDomElement & parentE, const QString & tagName, const QString & text, bool htmlText=false ); + void setInvalidContentError( const QString& detail ); + void clearError(); + void saveChanges(); +}; + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::setInvalidContentError(const QString& detail) +{ + error = UpdateSourcesInfo::InvalidContentError; + errorMessage = tr("%1 contains invalid content: %2").arg(fileName, detail); +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::clearError() +{ + error = UpdateSourcesInfo::NoError; + errorMessage.clear(); +} + +/*! + \internal +*/ +KDUpdater::UpdateSourcesInfo::UpdateSourcesInfo(Application* application) + : QObject(application), + d( new KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData( this ) ) +{ + d->application = application; +} + +/*! + \internal +*/ +KDUpdater::UpdateSourcesInfo::~UpdateSourcesInfo() +{ + d->saveChanges(); + delete d; +} + +/*! + Returns a pointer to the update application for which this class manages update sources. +*/ +KDUpdater::Application* KDUpdater::UpdateSourcesInfo::application() const +{ + return d->application; +} + +/*! + \internal +*/ +bool KDUpdater::UpdateSourcesInfo::isValid() const +{ + return d->error == NoError; +} + +/*! + returns a human-readable description of the error + */ +QString KDUpdater::UpdateSourcesInfo::errorString() const +{ + return d->errorMessage; +} + +/*! + returns the last error + */ +KDUpdater::UpdateSourcesInfo::Error KDUpdater::UpdateSourcesInfo::error() const +{ + return d->error; +} + +bool KDUpdater::UpdateSourcesInfo::isModified() const +{ + return d->modified; +} + +void KDUpdater::UpdateSourcesInfo::setModified(bool modified) +{ + d->modified = modified; +} + +/*! + Sets the complete file name of the UpdateSources.xml file. The function also issues a call + to refresh() to reload package information from the XML file. + + \sa KDUpdater::Application::setUpdateSourcesXMLFileName() +*/ +void KDUpdater::UpdateSourcesInfo::setFileName(const QString& fileName) +{ + if( d->fileName == fileName ) + return; + + d->fileName = fileName; + refresh(); // load new file +} + +/*! + Returns the name of the UpdateSources.xml file that this class referred to. +*/ +QString KDUpdater::UpdateSourcesInfo::fileName() const +{ + return d->fileName; +} + +/*! + Returns the number of update source info structures contained in this class. +*/ +int KDUpdater::UpdateSourcesInfo::updateSourceInfoCount() const +{ + return d->updateSourceInfoList.count(); +} + +/*! + Returns the update source info structure at \c index. If an invalid index is passed + the function returns a dummy constructor. +*/ +KDUpdater::UpdateSourceInfo KDUpdater::UpdateSourcesInfo::updateSourceInfo(int index) const +{ + if( index < 0 || index >= d->updateSourceInfoList.count() ) + return KDUpdater::UpdateSourceInfo(); + + return d->updateSourceInfoList[index]; +} + +/*! + Adds an update source info to this class. Upon successful addition, the class emits a + \ref updateSourceInfoAdded() signal. +*/ +void KDUpdater::UpdateSourcesInfo::addUpdateSourceInfo(const KDUpdater::UpdateSourceInfo& info) +{ + if( d->updateSourceInfoList.contains( info ) ) + return; + d->updateSourceInfoList.push_back( info ); + qSort( d->updateSourceInfoList.begin(), d->updateSourceInfoList.end(), KDUpdater::UpdateSourceInfoPriorityHigherThan() ); + emit updateSourceInfoAdded(info); + d->modified = true; +} + +/*! + Removes an update source info from this class. Upon successful removal, the class emits a + \ref updateSourceInfoRemoved() signal. +*/ +void KDUpdater::UpdateSourcesInfo::removeUpdateSourceInfo(const KDUpdater::UpdateSourceInfo& info) +{ + if( !d->updateSourceInfoList.contains(info) ) + return; + d->updateSourceInfoList.removeAll(info); + emit updateSourceInfoRemoved(info); + d->modified = true; +} + +/*! + Removes an update source info at \index in this class. Upon successful removal, the class emits a + \ref updateSourceInfoRemoved() signal. +*/ +void KDUpdater::UpdateSourcesInfo::removeUpdateSourceInfoAt(int index) +{ + if( index < 0 || index >= d->updateSourceInfoList.count() ) + return; + KDUpdater::UpdateSourceInfo info = d->updateSourceInfoList[index]; + d->updateSourceInfoList.removeAt(index); + emit updateSourceInfoRemoved(info); + d->modified = true; +} + +/*! + Changes the update source info at \c index to \c info. If \c index is equal to the number of + source info structures in this class (\ref updateSourceInfoCount()) then \c info is appended; + otherwise the existing info at \c index will be changed. + + Depending on what the function does \ref updateSourceInfoAdded() or \ref updateSourceInfoChanged() + signal is emitted. +*/ +void KDUpdater::UpdateSourcesInfo::setUpdateSourceInfoAt(int index, const KDUpdater::UpdateSourceInfo& info) +{ + if( index < 0 || index > d->updateSourceInfoList.count() ) + return; + + if( index == d->updateSourceInfoList.count() ) + { + d->updateSourceInfoList.append(info); + emit updateSourceInfoAdded(info); + } + else + { + KDUpdater::UpdateSourceInfo oldInfo = d->updateSourceInfoList[index]; + if( info == oldInfo ) + return; + + d->updateSourceInfoList[index] = info; + emit updateSourceInfoChanged(info, oldInfo); + } + d->modified = true; +} + +/*! + This slot reloads the update source information from UpdateSources.xml. +*/ +void KDUpdater::UpdateSourcesInfo::refresh() +{ + d->saveChanges(); // save changes done in the previous file + d->updateSourceInfoList.clear(); + + QFile file( d->fileName ); + + // if the file does not exist then we just skip the reading + if( !file.exists() ) + { + d->clearError(); + emit reset(); + return; + } + + // Open the XML file + if( !file.open(QFile::ReadOnly) ) + { + d->errorMessage = tr("Could not read \"%1\"").arg(d->fileName); + d->error = CouldNotReadSourceFileError; + emit reset(); + return; + } + + QDomDocument doc; + QString parseErrorMessage; + int parseErrorLine; + int parseErrorColumn; + if( !doc.setContent( &file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn ) ) + { + d->error = InvalidXmlError; + d->errorMessage = tr("XML Parse error in %1 at %2, %3: %4") + .arg( d->fileName, + QString::number( parseErrorLine ), + QString::number( parseErrorColumn ), + parseErrorMessage ); + emit reset(); + return; + } + + // Now parse the XML file. + QDomElement rootE = doc.documentElement(); + if( rootE.tagName() != QLatin1String( "UpdateSources" ) ) + { + d->setInvalidContentError(tr("Root element %1 unexpected, should be \"UpdateSources\"").arg(rootE.tagName())); + emit reset(); + return; + } + + QDomNodeList childNodes = rootE.childNodes(); + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.item(i); + QDomElement childNodeE = childNode.toElement(); + if( childNodeE.isNull() ) + continue; + + if( childNodeE.tagName() == QLatin1String( "UpdateSource" ) ) + d->addUpdateSourceFrom(childNodeE); + } + + d->clearError(); + emit reset(); +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::saveChanges() +{ + if( !modified || fileName.isEmpty() ) + return; + + const bool hadSaveError = error == UpdateSourcesInfo::CouldNotSaveChangesError; + + QDomDocument doc; + + QDomElement rootE = doc.createElement( QLatin1String( "UpdateSources") ); + doc.appendChild(rootE); + + for(int i=0; i<updateSourceInfoList.count(); i++) + { + KDUpdater::UpdateSourceInfo info = updateSourceInfoList[i]; + + QDomElement infoE = doc.createElement( QLatin1String( "UpdateSource" ) ); + rootE.appendChild(infoE); + addChildElement(doc, infoE, QLatin1String( "Name" ), info.name); + addChildElement(doc, infoE, QLatin1String( "Title" ), info.title); + addChildElement(doc, infoE, QLatin1String( "Description" ), info.description, + (info.description.length() && info.description[0] == QLatin1Char( '<' ) ) ); + addChildElement(doc, infoE, QLatin1String( "Url" ), info.url.toString()); + } + + QFile file( fileName ); + if ( !file.open( QFile::WriteOnly ) ) + { + error = UpdateSourcesInfo::CouldNotSaveChangesError; + errorMessage = tr("Could not save changes to \"%1\": %2").arg(fileName, file.errorString()); + return; + } + + QTextStream stream( &file ); + doc.save( stream, 2 ); + stream.flush(); + file.close(); + + if ( file.error() != QFile::NoError ) + { + error = UpdateSourcesInfo::CouldNotSaveChangesError; + errorMessage = tr("Could not save changes to \"%1\": %2").arg(fileName, file.errorString()); + return; + } + + //if there was a write error before, clear the error, as the write was successful now + if ( hadSaveError ) + clearError(); + + modified = false; +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::addUpdateSourceFrom( const QDomElement & element ) +{ + if( element.tagName() != QLatin1String( "UpdateSource" ) ) + return; + + QDomNodeList childNodes = element.childNodes(); + if(!childNodes.count()) + return; + + KDUpdater::UpdateSourceInfo info; + + for(int i=0; i<childNodes.count(); i++) + { + QDomNode childNode = childNodes.item(i); + QDomElement childNodeE = childNode.toElement(); + if( childNodeE.isNull() ) + continue; + + if( childNodeE.tagName() == QLatin1String( "Name" ) ) + info.name = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Title" ) ) + info.title = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Description" ) ) + info.description = childNodeE.text(); + else if( childNodeE.tagName() == QLatin1String( "Url" ) ) + info.url = childNodeE.text(); + } + + this->updateSourceInfoList.append(info); +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::addChildElement( QDomDocument & doc, QDomElement & parentE, const QString & tagName, const QString & text, bool htmlText ) +{ + QDomElement childE = doc.createElement(tagName); + parentE.appendChild(childE); + + if( htmlText ) + { + QDomCDATASection textE = doc.createCDATASection(text); + childE.appendChild(textE); + } + else + { + QDomText textE = doc.createTextNode(text); + childE.appendChild(textE); + } +} + +/*! + \ingroup kdupdater + \struct KDUpdater::UpdateSourceInfo kdupdaterupdatesourcesinfo.h KDUpdaterUpdateSourcesInfo + \brief Describes a single update source + + An update source is a repository that contains updates applicable for the application. + This structure describes a single update source in terms of name, title, description, url and priority. +*/ + +/*! + \var QString KDUpdater::UpdateSourceInfo::name +*/ + +/*! + \var QString KDUpdater::UpdateSourceInfo::title +*/ + +/*! + \var QString KDUpdater::UpdateSourceInfo::description +*/ + +/*! + \var QUrl KDUpdater::UpdateSourceInfo::url +*/ + +/*! + \var QUrl KDUpdater::UpdateSourceInfo::priority +*/ + +bool KDUpdater::operator==( const UpdateSourceInfo & lhs, const UpdateSourceInfo & rhs ) +{ + return (lhs.name == rhs.name) && (lhs.title == rhs.title) && + (lhs.description == rhs.description) && (lhs.url == rhs.url); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.h new file mode 100644 index 000000000..231002ee0 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_SOURCES_INFO_H +#define KD_UPDATER_UPDATE_SOURCES_INFO_H + +#include "kdupdater.h" + +#include <QObject> +#include <QVariant> +#include <QUrl> + +namespace KDUpdater +{ + class Application; + + struct KDTOOLS_UPDATER_EXPORT UpdateSourceInfo + { + UpdateSourceInfo() : priority(-1) { } + + QString name; + QString title; + QString description; + QUrl url; + int priority; + + }; + + KDTOOLS_UPDATER_EXPORT bool operator==( const UpdateSourceInfo & lhs, const UpdateSourceInfo & rhs ); + inline bool operator!= ( const UpdateSourceInfo & lhs, const UpdateSourceInfo & rhs ) { + return !operator==( lhs, rhs ); + } + + class KDTOOLS_UPDATER_EXPORT UpdateSourcesInfo : public QObject + { + Q_OBJECT + + public: + ~UpdateSourcesInfo(); + + enum Error + { + NoError=0, + NotYetReadError, + CouldNotReadSourceFileError, + InvalidXmlError, + InvalidContentError, + CouldNotSaveChangesError + }; + + Application* application() const; + + bool isValid() const; + QString errorString() const; + Error error() const; + + bool isModified() const; + void setModified(bool modified); + + void setFileName(const QString& fileName); + QString fileName() const; + + int updateSourceInfoCount() const; + UpdateSourceInfo updateSourceInfo(int index) const; + + void addUpdateSourceInfo(const UpdateSourceInfo& info); + void removeUpdateSourceInfo(const UpdateSourceInfo& info); + void removeUpdateSourceInfoAt(int index); + void setUpdateSourceInfoAt(int index, const UpdateSourceInfo& info); + + protected: + explicit UpdateSourcesInfo(Application* application); + + public Q_SLOTS: + void refresh(); + + Q_SIGNALS: + void reset(); + void updateSourceInfoAdded(const UpdateSourceInfo& info); + void updateSourceInfoRemoved(const UpdateSourceInfo& info); + void updateSourceInfoChanged(const UpdateSourceInfo& newInfo, + const UpdateSourceInfo& oldInfo); + + private: + friend class Application; + struct UpdateSourcesInfoData; + UpdateSourcesInfoData* d; + }; +} + +Q_DECLARE_METATYPE(KDUpdater::UpdateSourceInfo) + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesview.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesview.cpp new file mode 100644 index 000000000..aec942614 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesview.cpp @@ -0,0 +1,375 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdatesourcesview.h" +#include "kdupdaterupdatesourcesinfo.h" +#include "ui_addupdatesourcedialog.h" + +#include <QMessageBox> +#include <QContextMenuEvent> +#include <QAction> +#include <QMenu> + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateSourcesView kdupdaterupdatesourcesview.h KDUpdaterUpdateSourcesView + \brief A widget that helps view and/or edit \ref KDUpdater::UpdateSourcesInfo + + \ref KDUpdater::UpdateSourcesInfo, associated with \ref KDUpdater::Application, contains information + about all the update sources from which the application can download and install updates. + This widget helps view and edit update sources information. + + \image html updatesourcesview.jpg + + The widget provides the following slots for editing update sources information + \ref addNewSource() + \ref editCurrentSource() + \ref removeCurrentSource() + + You can include this widget within another form or dialog and connect to these slots which make + use of an inbuilt dialog box to add/edit update sources. Shown below is a screenshot of the + inbuilt dialog box. + + \image html editupdatesource.jpg + + Alternatively you can also use your own dialog box and directly update \ref KDUpdater::UpdateSourcesInfo. + This widget connects to \ref KDUpdater::UpdateSourcesInfo signals and ensures that the data it displays + is always kept updated. + + The widget provides a context menu using which you can add/remove/edit update sources. Shown below is a + screenshot of the context menu. + + \image html updatesourcesview_contextmenu.jpg +*/ + +struct KDUpdater::UpdateSourcesView::UpdateSourcesViewData +{ + UpdateSourcesViewData( UpdateSourcesView* qq ) : + q( qq ), + updateSourcesInfo(0) + {} + + UpdateSourcesView* q; + UpdateSourcesInfo* updateSourcesInfo; +}; + +/*! + Constructor +*/ +KDUpdater::UpdateSourcesView::UpdateSourcesView(QWidget* parent) + : QTreeWidget(parent), + d(new KDUpdater::UpdateSourcesView::UpdateSourcesViewData( this ) ) +{ + setColumnCount(3); + setHeaderLabels( QStringList() << tr("Name") << tr("Title") << tr("URL") ); + setRootIsDecorated(false); + + connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(editCurrentSource())); +} + +/*! + Destructor +*/ +KDUpdater::UpdateSourcesView::~UpdateSourcesView() +{ + delete d; +} + +/*! + Sets the \ref KDUpdater::UpdateSourcesInfo object whose information this widget should show. + + \code + KDUpdater::Application application; + + KDUpdater::UpdateSourcesView updatesView; + updatesView.setUpdateSourcesInfo( application.updateSourcesInfo() ); + updatesView.show(); + \endcode +*/ +void KDUpdater::UpdateSourcesView::setUpdateSourcesInfo(KDUpdater::UpdateSourcesInfo* info) +{ + if( d->updateSourcesInfo == info ) + return; + + if(d->updateSourcesInfo) + disconnect(d->updateSourcesInfo, 0, this, 0); + + d->updateSourcesInfo = info; + if(d->updateSourcesInfo) + { + connect(d->updateSourcesInfo, SIGNAL(reset()), this, SLOT(refresh())); + connect(d->updateSourcesInfo, SIGNAL(updateSourceInfoAdded(UpdateSourceInfo)), + this, SLOT(slotUpdateSourceInfoAdded(UpdateSourceInfo))); + connect(d->updateSourcesInfo, SIGNAL(updateSourceInfoRemoved(UpdateSourceInfo)), + this, SLOT(slotUpdateSourceInfoRemoved(UpdateSourceInfo))); + connect(d->updateSourcesInfo, SIGNAL(updateSourceInfoChanged(UpdateSourceInfo,UpdateSourceInfo)), + this, SLOT(slotUpdateSourceInfoChanged(UpdateSourceInfo,UpdateSourceInfo))); + } + + refresh(); +} + +/*! + Returns a pointer to the \ref KDUpdater::UpdateSourcesInfo object whose information this + widget is showing. +*/ +KDUpdater::UpdateSourcesInfo* KDUpdater::UpdateSourcesView::updateSourcesInfo() const +{ + return d->updateSourcesInfo; +} + +/*! + Returns the index of the currently selected update source in the widget. You can use this + index along with \ref KDUpdater::UpdateSourcesInfo::updateSourceInfo() method to get hold + of the update source info. +*/ +int KDUpdater::UpdateSourcesView::currentUpdateSourceInfoIndex() const +{ + if( !d->updateSourcesInfo ) + return -1; + + QTreeWidgetItem* item = this->currentItem(); + if( !item ) + return -1; + + int index = this->indexOfTopLevelItem(item); + if( index < 0 ) + return -1; + + return index; +} + +/*! + Call this slot to reload the updates information. By default this slot is connected to + \ref KDUpdater::UpdateSourcesInfo::reset() signal in \ref setUpdateSourcesInfo(). +*/ +void KDUpdater::UpdateSourcesView::refresh() +{ + this->clear(); + + if( !d->updateSourcesInfo ) + return; + + for(int i=0; i<d->updateSourcesInfo->updateSourceInfoCount(); i++) + { + KDUpdater::UpdateSourceInfo info = d->updateSourcesInfo->updateSourceInfo(i); + QTreeWidgetItem* item = new QTreeWidgetItem(this); + item->setText(0, info.name); + item->setText(1, info.title); + item->setText(2, info.url.toString()); + item->setData(0, Qt::UserRole, qVariantFromValue<KDUpdater::UpdateSourceInfo>(info)); + } + + resizeColumnToContents(0); +} + +/*! + Call this slot to make use of the in-built dialog box to add a new update source. Shown + below is a screenshot of the in-built dialog box. + + \image html addupdatesource.jpg +*/ +void KDUpdater::UpdateSourcesView::addNewSource() +{ + if( !d->updateSourcesInfo ) + return; + + QDialog dialog(this); + Ui::AddUpdateSourceDialog ui; + ui.setupUi(&dialog); + + while(1) + { + if( dialog.exec() == QDialog::Rejected ) + return; + + if(ui.txtName->text().isEmpty() || ui.txtUrl->text().isEmpty()) + { + QMessageBox::information(this, tr("Invalid Update Source Info"), + tr("A valid update source name and url has to be provided")); + continue; + } + + break; + } + + KDUpdater::UpdateSourceInfo newInfo; + newInfo.name = ui.txtName->text(); + newInfo.title = ui.txtTitle->text(); + newInfo.description = ui.txtDescription->toPlainText(); // FIXME: This should perhaps be toHtml + newInfo.url = QUrl(ui.txtUrl->text()); + + d->updateSourcesInfo->addUpdateSourceInfo(newInfo); +} + +/*! + Call this slot to delete the currently selected update source. +*/ +void KDUpdater::UpdateSourcesView::removeCurrentSource() +{ + if( !d->updateSourcesInfo ) + return; + + QTreeWidgetItem* item = this->currentItem(); + if( !item ) + return; + + int index = this->indexOfTopLevelItem(item); + if( index < 0 ) + return; + + d->updateSourcesInfo->removeUpdateSourceInfoAt(index); +} + +/*! + Call this slot to edit the currently selected update source, using the in-built edit + update source dialog box. Shown below is a screenshot of the edit update source dialog + box. + + \image html editupdatesource.jpg +*/ +void KDUpdater::UpdateSourcesView::editCurrentSource() +{ + if( !d->updateSourcesInfo ) + return; + + QTreeWidgetItem* item = this->currentItem(); + if( !item ) + return; + + int index = this->indexOfTopLevelItem(item); + if( index < 0 ) + return; + + KDUpdater::UpdateSourceInfo info = item->data(0, Qt::UserRole).value<KDUpdater::UpdateSourceInfo>(); + + QDialog dialog(this); + Ui::AddUpdateSourceDialog ui; + ui.setupUi(&dialog); + ui.txtName->setText(info.name); + ui.txtTitle->setText(info.title); + ui.txtDescription->setPlainText(info.description); // FIXME: This should perhaps be setHtml + ui.txtUrl->setText(info.url.toString()); + dialog.setWindowTitle(tr("Edit Update Source")); + + if( dialog.exec() == QDialog::Rejected ) + return; + + KDUpdater::UpdateSourceInfo newInfo; + newInfo.name = ui.txtName->text(); + newInfo.title = ui.txtTitle->text(); + newInfo.description = ui.txtDescription->toPlainText(); // FIXME: This should perhaps be setHtml + newInfo.url = QUrl(ui.txtUrl->text()); + + d->updateSourcesInfo->setUpdateSourceInfoAt(index, newInfo); +} + +/*! + \internal +*/ +void KDUpdater::UpdateSourcesView::slotUpdateSourceInfoAdded(const KDUpdater::UpdateSourceInfo &info) +{ + if( !d->updateSourcesInfo ) + return; + + QTreeWidgetItem* item = new QTreeWidgetItem(this); + item->setText(0, info.name); + item->setText(1, info.title); + item->setText(2, info.url.toString()); + item->setData(0, Qt::UserRole, qVariantFromValue<KDUpdater::UpdateSourceInfo>(info)); +} + +/*! + \internal +*/ +void KDUpdater::UpdateSourcesView::slotUpdateSourceInfoRemoved(const KDUpdater::UpdateSourceInfo &info) +{ + if( !d->updateSourcesInfo ) + return; + + QTreeWidgetItem* item = 0; + for(int i=0; i<topLevelItemCount(); i++) + { + item = topLevelItem(i); + KDUpdater::UpdateSourceInfo itemInfo = item->data(0, Qt::UserRole).value<KDUpdater::UpdateSourceInfo>(); + if(itemInfo == info) + break; + item = 0; + } + + if( !item ) + return; + + delete item; +} + +/*! + \internal +*/ +void KDUpdater::UpdateSourcesView::slotUpdateSourceInfoChanged (const KDUpdater::UpdateSourceInfo &newInfo, + const KDUpdater::UpdateSourceInfo &oldInfo) +{ + if( !d->updateSourcesInfo ) + return; + + QTreeWidgetItem* item = 0; + for(int i=0; i<topLevelItemCount(); i++) + { + item = topLevelItem(i); + KDUpdater::UpdateSourceInfo itemInfo = item->data(0, Qt::UserRole).value<KDUpdater::UpdateSourceInfo>(); + if(itemInfo == oldInfo) + break; + item = 0; + } + + if( !item ) + return; + + item->setText(0, newInfo.name); + item->setText(1, newInfo.title); + item->setText(2, newInfo.url.toString()); + item->setData(0, Qt::UserRole, qVariantFromValue<KDUpdater::UpdateSourceInfo>(newInfo)); +} + +/*! + \internal +*/ +void KDUpdater::UpdateSourcesView::contextMenuEvent(QContextMenuEvent* e) +{ + QTreeWidgetItem* item = this->itemAt( e->pos() ); + + QMenu menu; + QAction* addAction = menu.addAction(tr("&Add Source")); + QAction* editAction = item ? menu.addAction(tr("&Edit Source")) : 0; + QAction* remAction = item ? menu.addAction(tr("&Remove Source")) : 0; + + QAction* result = menu.exec( QCursor::pos() ); + if( !result ) + return; + + if( result == addAction ) + this->addNewSource(); + else if( result == remAction ) + this->removeCurrentSource(); + else if( result == editAction ) + this->editCurrentSource(); +} diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesview.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesview.h new file mode 100644 index 000000000..c2c840d72 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesview.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#ifndef KD_UPDATER_UPDATE_SOURCES_VIEW_H +#define KD_UPDATER_UPDATE_SOURCES_VIEW_H + +#include "kdupdater.h" +#include <QTreeWidget> + +namespace KDUpdater +{ + struct UpdateSourceInfo; + class UpdateSourcesInfo; + + class KDTOOLS_UPDATER_EXPORT UpdateSourcesView : public QTreeWidget + { + Q_OBJECT + + public: + explicit UpdateSourcesView(QWidget* parent=0); + ~UpdateSourcesView(); + + void setUpdateSourcesInfo(UpdateSourcesInfo* info); + UpdateSourcesInfo* updateSourcesInfo() const; + + int currentUpdateSourceInfoIndex() const; + + public Q_SLOTS: + void refresh(); + void addNewSource(); + void removeCurrentSource(); + void editCurrentSource(); + + protected: + void contextMenuEvent(QContextMenuEvent* e); + + private Q_SLOTS: + void slotUpdateSourceInfoAdded(const UpdateSourceInfo &info); + void slotUpdateSourceInfoRemoved(const UpdateSourceInfo &info); + void slotUpdateSourceInfoChanged(const UpdateSourceInfo &newInfo, + const UpdateSourceInfo &oldInfo); + + private: + struct UpdateSourcesViewData; + UpdateSourcesViewData* d; + }; +}; + +#endif diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/updatesdialog.ui b/installerbuilder/libinstaller/kdtools/KDUpdater/updatesdialog.ui new file mode 100644 index 000000000..52162109e --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/updatesdialog.ui @@ -0,0 +1,245 @@ +<ui version="4.0" > + <class>UpdatesDialog</class> + <widget class="QDialog" name="UpdatesDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>555</width> + <height>478</height> + </rect> + </property> + <property name="windowTitle" > + <string>Update</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <property name="sizeConstraint" > + <enum>QLayout::SetMinAndMaxSize</enum> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="pixmapLabel" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Minimum" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize" > + <size> + <width>96</width> + <height>96</height> + </size> + </property> + <property name="text" > + <string/> + </property> + <property name="alignment" > + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + <item row="0" column="2" colspan="2" > + <widget class="QLabel" name="descriptionLabel" > + <property name="minimumSize" > + <size> + <width>400</width> + <height>96</height> + </size> + </property> + <property name="text" > + <string/> + </property> + <property name="textFormat" > + <enum>Qt::RichText</enum> + </property> + <property name="alignment" > + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="2" colspan="2" > + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QWidget" native="1" name="releaseNotesGroup" > + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label" > + <property name="text" > + <string><b>Release Notes:</b></string> + </property> + <property name="textFormat" > + <enum>Qt::RichText</enum> + </property> + </widget> + </item> + <item> + <widget class="KDUPDATERVIEW" native="1" name="releaseNotesView" > + <property name="minimumSize" > + <size> + <width>400</width> + <height>200</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" native="1" name="packageSwitchBar" > + <layout class="QHBoxLayout" name="horizontalLayout" > + <property name="spacing" > + <number>0</number> + </property> + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="packageUpdateCheckBox" > + <property name="text" > + <string>Update the current package</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>296</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="previousPackageButton" > + <property name="text" > + <string/> + </property> + <property name="iconSize" > + <size> + <width>8</width> + <height>8</height> + </size> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + <property name="arrowType" > + <enum>Qt::LeftArrow</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="currentPackageLabel" > + <property name="text" > + <string>N</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>/</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="totalPackageLabel" > + <property name="text" > + <string>M</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="nextPackageButton" > + <property name="text" > + <string/> + </property> + <property name="iconSize" > + <size> + <width>8</width> + <height>8</height> + </size> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + <property name="arrowType" > + <enum>Qt::RightArrow</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item row="2" column="3" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KDUPDATERVIEW</class> + <extends>QWidget</extends> + <header>qwidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>UpdatesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>UpdatesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/installerbuilder/libinstaller/kdtools/LICENSE.LGPL b/installerbuilder/libinstaller/kdtools/LICENSE.LGPL new file mode 100644 index 000000000..ea164db15 --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/LICENSE.LGPL @@ -0,0 +1,488 @@ + + The KD Tools Library is Copyright (C) 2001-2009 Klarälvdalens Datakonsult AB. + + You may use, distribute and copy the KD Tools Library under the terms of + GNU Library General Public License version 2, which is displayed below. + +------------------------------------------------------------------------- + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! |