diff options
Diffstat (limited to 'src/libs/installer/createshortcutoperation.cpp')
-rw-r--r-- | src/libs/installer/createshortcutoperation.cpp | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/libs/installer/createshortcutoperation.cpp b/src/libs/installer/createshortcutoperation.cpp new file mode 100644 index 000000000..bd0608233 --- /dev/null +++ b/src/libs/installer/createshortcutoperation.cpp @@ -0,0 +1,219 @@ +/************************************************************************** +** +** This file is part of Installer Framework +** +** Copyright (c) 2011-2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#include "createshortcutoperation.h" + +#include "errors.h" +#include "fileutils.h" + +#include "kdupdaterapplication.h" +#include "kdupdaterpackagesinfo.h" + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QTemporaryFile> + +#include <algorithm> +#include <cerrno> + +#ifdef Q_WS_WIN +# include <windows.h> +# include <shlobj.h> +#endif + +using namespace QInstaller; + +static bool createLink(QString fileName, QString linkName, QString workingDir, QString arguments = QString()) +{ +#ifdef Q_WS_WIN + bool ret = false; + fileName = QDir::toNativeSeparators(fileName); + linkName = QDir::toNativeSeparators(linkName); + if (workingDir.isEmpty()) + workingDir = QFileInfo(fileName).absolutePath(); + workingDir = QDir::toNativeSeparators(workingDir); + + //### assume that they add .lnk + + IShellLink *psl; + bool neededCoInit = false; + + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); + + if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized + neededCoInit = true; + CoInitialize(NULL); + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); + } + + if (SUCCEEDED(hres)) { + hres = psl->SetPath((wchar_t *)fileName.utf16()); + if (SUCCEEDED(hres) && !arguments.isNull()) + hres = psl->SetArguments((wchar_t*)arguments.utf16()); + if (SUCCEEDED(hres)) { + hres = psl->SetWorkingDirectory((wchar_t *)workingDir.utf16()); + if (SUCCEEDED(hres)) { + IPersistFile *ppf; + hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); + if (SUCCEEDED(hres)) { + hres = ppf->Save((wchar_t*)linkName.utf16(), TRUE); + if (SUCCEEDED(hres)) + ret = true; + ppf->Release(); + } + } + } + psl->Release(); + } + + if (neededCoInit) + CoUninitialize(); + + return ret; +#else + Q_UNUSED(workingDir) + Q_UNUSED(arguments) + return QFile::link(fileName, linkName); +#endif +} + +/* +TRANSLATOR QInstaller::CreateShortcutOperation +*/ + +CreateShortcutOperation::CreateShortcutOperation() +{ + setName(QLatin1String("CreateShortcut")); +} + +static bool isWorkingDirOption(const QString &s) +{ + return s.startsWith(QLatin1String("workingDirectory=")); +} + +static QString takeWorkingDirArgument(QStringList &args) +{ + QString workingDir; + // if the args contain an option in the form "workingDirectory=...", find it and consume it + QStringList::iterator wdiropt = std::find_if(args.begin(), args.end(), isWorkingDirOption); + if (wdiropt != args.end()) { + workingDir = wdiropt->mid(QString::fromLatin1("workingDirectory=").size()); + args.erase(wdiropt); + } + return workingDir; +} + +void CreateShortcutOperation::backup() +{ +} + +bool CreateShortcutOperation::performOperation() +{ + QStringList args = arguments(); + const QString workingDir = takeWorkingDirArgument(args); + + if (args.count() != 2 && args.count() != 3) { + setError(InvalidArguments); + setErrorString(QObject::tr("Invalid arguments: %1 arguments given, 2 or 3 expected (optional: " + "\"workingDirectory=...\").").arg(args.count())); + return false; + } + + const QString& linkTarget = args.at(0); + const QString& linkLocation = args.at(1); + const QString targetArguments = args.value(2); //used value because it could be not existing + + const QString linkPath = QFileInfo(linkLocation).absolutePath(); + + const bool linkPathAlreadyExists = QDir(linkPath).exists(); + const bool created = linkPathAlreadyExists || QDir::root().mkpath(linkPath); + + if (!created) { + setError(UserDefinedError); + setErrorString(tr("Could not create folder %1: %2.").arg(QDir::toNativeSeparators(linkPath), + QLatin1String(strerror(errno)))); + return false; + } + + + //remove a possible existing older one + QString errorString; + if (QFile::exists(linkLocation) && !deleteFileNowOrLater(linkLocation, &errorString)) { + setError(UserDefinedError); + setErrorString(QObject::tr("Failed to overwrite %1: %2").arg(QDir::toNativeSeparators(linkLocation), + errorString)); + return false; + } + + const bool linked = createLink(linkTarget, linkLocation, workingDir, targetArguments); + if (!linked) { + setError(UserDefinedError); + setErrorString(tr("Could not create link %1: %2").arg(QDir::toNativeSeparators(linkLocation), + qt_error_string())); + return false; + } + return true; +} + +bool CreateShortcutOperation::undoOperation() +{ + const QStringList args = arguments(); + + const QString& linkLocation = args.at(1); + + // first remove the link + if (!deleteFileNowOrLater(linkLocation)) + qDebug() << "Can't delete:" << linkLocation; + + const QString linkPath = QFileInfo(linkLocation).absolutePath(); + + QStringList pathParts = QString(linkPath).remove(QDir::homePath()).split(QLatin1String("/")); + for (int i = pathParts.count(); i > 0; --i) { + QString possibleToDeleteDir = QDir::homePath() + QStringList(pathParts.mid(0, i)).join(QLatin1String("/")); + removeSystemGeneratedFiles(possibleToDeleteDir); + if (!possibleToDeleteDir.isEmpty() && QDir().rmdir(possibleToDeleteDir)) + qDebug() << "Deleted directory:" << possibleToDeleteDir; + else + break; + } + + return true; +} + +bool CreateShortcutOperation::testOperation() +{ + return true; +} + +Operation *CreateShortcutOperation::clone() const +{ + return new CreateShortcutOperation(); +} |