krarchandler.cpp 27.4 KB
Newer Older
Rafi Yanai's avatar
Rafi Yanai committed
1
/***************************************************************************
2 3 4 5
                                krarchandler.cpp
                            -------------------
   copyright            : (C) 2001 by Shie Erlich & Rafi Yanai
   email                : krusader@users.sourceforge.net
Fathi Boudra's avatar
Fathi Boudra committed
6
   web site   : http://krusader.sourceforge.net
7
---------------------------------------------------------------------------
8
 Description
9 10
***************************************************************************

11
 A
12

13 14 15 16 17 18
    db   dD d8888b. db    db .d8888.  .d8b.  d8888b. d88888b d8888b.
    88 ,8P' 88  `8D 88    88 88'  YP d8' `8b 88  `8D 88'     88  `8D
    88,8P   88oobY' 88    88 `8bo.   88ooo88 88   88 88ooooo 88oobY'
    88`8b   88`8b   88    88   `Y8b. 88~~~88 88   88 88~~~~~ 88`8b
    88 `88. 88 `88. 88b  d88 db   8D 88   88 88  .8D 88.     88 `88.
    YP   YD 88   YD ~Y8888P' `8888Y' YP   YP Y8888D' Y88888P 88   YD
19

20
                                                    S o u r c e    F i l e
21 22 23 24 25 26 27 28

***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
Fathi Boudra's avatar
Fathi Boudra committed
29
***************************************************************************/
Fathi Boudra's avatar
Fathi Boudra committed
30 31 32

#include "krarchandler.h"

33 34 35 36 37 38
// QtCore
#include <QDebug>
#include <QDir>
#include <QFile>
// QtWidgets
#include <QApplication>
Fathi Boudra's avatar
Fathi Boudra committed
39

40
#include <KArchive/KTar>
41
#include <KConfigCore/KSharedConfig>
Simon Persson's avatar
Simon Persson committed
42
#include <KI18n/KLocalizedString>
43
#include <KIO/Global>
44
#include <KWallet/KWallet>
45
#include <KWidgetsAddons/KMessageBox>
46
#include <KWidgetsAddons/KPasswordDialog>
Fathi Boudra's avatar
Fathi Boudra committed
47

48
#include "kr7zencryptionchecker.h"
49
#include "../krglobal.h"
Rafi Yanai's avatar
Rafi Yanai committed
50
#include "../defaults.h"
51
#include "../krservices.h"
52
#include "../Dialogs/krpleasewait.h"
53
#include "../../krArc/krlinecountingprocess.h"
Rafi Yanai's avatar
Rafi Yanai committed
54

55
#if 0
56 57 58
class DefaultKRarcObserver : public KRarcObserver
{
public:
Fathi Boudra's avatar
Fathi Boudra committed
59 60 61
    DefaultKRarcObserver() {}
    virtual ~DefaultKRarcObserver() {}

62
    virtual void processEvents() Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
63 64 65 66
        usleep(1000);
        qApp->processEvents();
    }

67
    virtual void subJobStarted(const QString & jobTitle, int count) Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
68 69 70
        krApp->startWaiting(jobTitle, count, true);
    }

71
    virtual void subJobStopped() Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
72 73 74
        krApp->stopWait();
    }

75
    virtual bool wasCancelled() Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
76 77 78
        return krApp->wasWaitingCancelled();
    }

79
    virtual void error(const QString & error) Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
80 81 82
        KMessageBox::error(krApp, error, i18n("Error"));
    }

83
    virtual void detailedError(const QString & error, const QString & details) Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
84 85 86
        KMessageBox::detailedError(krApp, error, details, i18n("Error"));
    }

87
    virtual void incrementProgress(int c) Q_DECL_OVERRIDE {
Fathi Boudra's avatar
Fathi Boudra committed
88 89
        krApp->plzWait->incProgress(c);
    }
90
};
91
#endif
92

93
static QStringList arcProtocols = QString("tar;bzip;bzip2;lzma;xz;gzip;krarc;zip").split(';');
94 95

KWallet::Wallet * KRarcHandler::wallet = 0;
96

Fathi Boudra's avatar
Fathi Boudra committed
97 98 99 100 101 102 103 104 105
QStringList KRarcHandler::supportedPackers()
{
    QStringList packers;

    // we will simply try to find the packers here..
    if (KrServices::cmdExist("tar")) packers.append("tar");
    if (KrServices::cmdExist("gzip")) packers.append("gzip");
    if (KrServices::cmdExist("bzip2")) packers.append("bzip2");
    if (KrServices::cmdExist("lzma")) packers.append("lzma");
106
    if (KrServices::cmdExist("xz")) packers.append("xz");
Fathi Boudra's avatar
Fathi Boudra committed
107 108
    if (KrServices::cmdExist("unzip")) packers.append("unzip");
    if (KrServices::cmdExist("zip")) packers.append("zip");
Davide Gianforte's avatar
Davide Gianforte committed
109
    if (KrServices::cmdExist("zip")) packers.append("cbz");
Fathi Boudra's avatar
Fathi Boudra committed
110 111 112 113
    if (KrServices::cmdExist("lha")) packers.append("lha");
    if (KrServices::cmdExist("cpio")) packers.append("cpio");
    if (KrServices::cmdExist("unrar")) packers.append("unrar");
    if (KrServices::cmdExist("rar")) packers.append("rar");
Davide Gianforte's avatar
Davide Gianforte committed
114
    if (KrServices::cmdExist("rar")) packers.append("cbr");
Fathi Boudra's avatar
Fathi Boudra committed
115 116 117 118 119 120
    if (KrServices::cmdExist("arj")) packers.append("arj");
    if (KrServices::cmdExist("unarj")) packers.append("unarj");
    if (KrServices::cmdExist("unace")) packers.append("unace");
    if (KrServices::cmdExist("dpkg")) packers.append("dpkg");
    if (KrServices::cmdExist("7z") || KrServices::cmdExist("7za")) packers.append("7z");
    if (KrServices::cmdExist("rpm") && KrServices::cmdExist("rpm2cpio")) packers.append("rpm");
121
    // qDebug() << "Supported Packers:";
Fathi Boudra's avatar
Fathi Boudra committed
122 123
    //QStringList::Iterator it;
    //for( it = packers.begin(); it != packers.end(); ++it )
124
    // qDebug() << *it;
Fathi Boudra's avatar
Fathi Boudra committed
125 126 127 128 129 130 131

    return packers;
}

bool KRarcHandler::arcSupported(QString type)
{
    // lst will contain the supported unpacker list...
132 133
    const KConfigGroup group(krConfig, "Archives");
    const QStringList lst = group.readEntry("Supported Packers", QStringList());
Fathi Boudra's avatar
Fathi Boudra committed
134

135 136 137 138 139 140
    // Let's notice that in some cases the QString `type` that arrives here
    // represents a mimetype, and in some other cases it represents
    // a short identifier.
    // If `type` is not a short identifier then it's supposed that `type` is a mime type
    if (type.length() > maxLenType) {
        type = getShortTypeFromMime(type);
141 142
    }

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
    return (type == "zip" && lst.contains("unzip"))
           || (type == "tar" && lst.contains("tar"))
           || (type == "tbz" && lst.contains("tar"))
           || (type == "tgz" && lst.contains("tar"))
           || (type == "tlz" && lst.contains("tar"))
           || (type == "txz" && lst.contains("tar"))
           || (type == "tarz" && lst.contains("tar"))
           || (type == "gzip" && lst.contains("gzip"))
           || (type == "bzip2" && lst.contains("bzip2"))
           || (type == "lzma" && lst.contains("lzma"))
           || (type == "xz" && lst.contains("xz"))
           || (type == "lha" && lst.contains("lha"))
           || (type == "ace" && lst.contains("unace"))
           || (type == "rpm" && lst.contains("cpio"))
           || (type == "cpio" && lst.contains("cpio"))
           || (type == "rar" && (lst.contains("unrar") || lst.contains("rar")))
           || (type == "arj" && (lst.contains("unarj") || lst.contains("arj")))
           || (type == "deb" && (lst.contains("dpkg") && lst.contains("tar")))
           || (type == "7z" && lst.contains("7z"));
Fathi Boudra's avatar
Fathi Boudra committed
162 163 164 165 166 167 168
}

long KRarcHandler::arcFileCount(QString archive, QString type, QString password, KRarcObserver *observer)
{
    int divideWith = 1;

    // first check if supported
169 170
    if (!arcSupported(type))
        return 0;
Fathi Boudra's avatar
Fathi Boudra committed
171

172 173 174
    // bzip2, gzip, etc. archives contain only one file
    if (type == "bzip2" || type == "gzip" || type == "lzma" || type == "xz")
        return 1L;
Fathi Boudra's avatar
Fathi Boudra committed
175 176 177 178

    // set the right lister to do the job
    QStringList lister;

179 180 181
    if (type == "zip") lister << KrServices::fullPathName("unzip") << "-ZTs";
    else if (type == "tar") lister << KrServices::fullPathName("tar") << "-tvf";
    else if (type == "tgz") lister << KrServices::fullPathName("tar") << "-tvzf";
Fathi Boudra's avatar
Fathi Boudra committed
182
    else if (type == "tarz") lister << KrServices::fullPathName("tar") << "-tvzf";
183 184 185 186 187 188 189
    else if (type == "tbz") lister << KrServices::fullPathName("tar") << "-tjvf";
    else if (type == "tlz") lister << KrServices::fullPathName("tar") << "--lzma" << "-tvf";
    else if (type == "txz") lister << KrServices::fullPathName("tar") << "--xz" << "-tvf";
    else if (type == "lha") lister << KrServices::fullPathName("lha") << "l";
    else if (type == "rar") lister << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "l" << "-v";
    else if (type == "ace") lister << KrServices::fullPathName("unace") << "l";
    else if (type == "arj") {
Fathi Boudra's avatar
Fathi Boudra committed
190 191 192 193 194
        if (KrServices::cmdExist("arj"))
            lister << KrServices::fullPathName("arj") << "v" << "-y" << "-v",
            divideWith = 4;
        else
            lister << KrServices::fullPathName("unarj") << "l";
195 196 197
    } else if (type == "rpm") lister << KrServices::fullPathName("rpm") << "--dump" << "-lpq";
    else if (type == "deb") lister << KrServices::fullPathName("dpkg") << "-c";
    else if (type == "7z")  lister << KrServices::fullPathName("7z") << "-y" << "l";
Fathi Boudra's avatar
Fathi Boudra committed
198 199 200
    else return 0L;

    if (!password.isNull()) {
201
        if (type == "arj")
Fathi Boudra's avatar
Fathi Boudra committed
202
            lister << QString("-g%1").arg(password);
203
        if (type == "ace" || type == "rar" || type == "7z")
Fathi Boudra's avatar
Fathi Boudra committed
204
            lister << QString("-p%1").arg(password);
205
    }
Fathi Boudra's avatar
Fathi Boudra committed
206 207 208 209 210 211 212 213

    // tell the user to wait
    observer->subJobStarted(i18n("Counting files in archive"), 0);

    // count the number of files in the archive
    long count = 1;
    KProcess list;
    list << lister << archive;
214
    if (type == "ace" && QFile("/dev/ptmx").exists())     // Don't remove, unace crashes if missing!!!
Fathi Boudra's avatar
Fathi Boudra committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
        list.setStandardInputFile("/dev/ptmx");
    list.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect
    list.start();
    // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking
    // it would be better to connect to started(), error() and finished()
    if (list.waitForStarted()) while (list.state() == QProcess::Running) {
            observer->processEvents();
            if (observer->wasCancelled())
                list.kill();
        }
    ; // busy wait - need to find something better...

    observer->subJobStopped();

    if (list.exitStatus() != QProcess::NormalExit || !checkStatus(type, list.exitCode())) {
Pino Toscano's avatar
Pino Toscano committed
230
        observer->detailedError(i18n("Failed to list the content of the archive (%1).", archive),
Fathi Boudra's avatar
Fathi Boudra committed
231 232
                                QString::fromLocal8Bit(list.readAllStandardError()));
        return 0;
233 234
    }

Fathi Boudra's avatar
Fathi Boudra committed
235 236 237 238 239 240 241 242 243 244 245 246 247
    count = list.readAllStandardOutput().count('\n');

    //make sure you call stopWait after this function return...
    //  observer->subJobStopped();

    return count / divideWith;
}

bool KRarcHandler::unpack(QString archive, QString type, QString password, QString dest, KRarcObserver *observer)
{
    KConfigGroup group(krConfig, "Archives");
    if (group.readEntry("Test Before Unpack", _TestBeforeUnpack)) {
        // test first - or be sorry later...
248
        if (type != "rpm" && type != "deb" && !test(archive, type, password, observer, 0)) {
Pino Toscano's avatar
Pino Toscano committed
249
            observer->error(i18n("Failed to unpack %1.", archive));
Fathi Boudra's avatar
Fathi Boudra committed
250 251
            return false;
        }
252
    }
Fathi Boudra's avatar
Fathi Boudra committed
253 254 255

    // count the files in the archive
    long count = arcFileCount(archive, type, password, observer);
256 257 258 259
    if (count == 0)
        return false;   // not supported
    if (count == 1)
        count = 0;
Fathi Boudra's avatar
Fathi Boudra committed
260 261 262 263 264 265

    // choose the right packer for the job
    QString cpioName;
    QStringList packer;

    // set the right packer to do the job
266
    if (type == "zip") packer << KrServices::fullPathName("unzip") << "-o";
267 268
    else if (type == "tar") packer << KrServices::fullPathName("tar") << "-xvf";
    else if (type == "tgz") packer << KrServices::fullPathName("tar") << "-xvzf";
Fathi Boudra's avatar
Fathi Boudra committed
269
    else if (type == "tarz") packer << KrServices::fullPathName("tar") << "-xvzf";
270 271 272
    else if (type == "tbz") packer << KrServices::fullPathName("tar") << "-xjvf";
    else if (type == "tlz") packer << KrServices::fullPathName("tar") << "--lzma" << "-xvf";
    else if (type == "txz") packer << KrServices::fullPathName("tar") << "--xz" << "-xvf";
Fathi Boudra's avatar
Fathi Boudra committed
273
    else if (type == "gzip") packer << KrServices::fullPathName("gzip") << "-cd";
274
    else if (type == "bzip2") packer << KrServices::fullPathName("bzip2") << "-cdk";
Fathi Boudra's avatar
Fathi Boudra committed
275
    else if (type == "lzma") packer << KrServices::fullPathName("lzma") << "-cdk";
276 277 278 279 280
    else if (type == "xz")  packer << KrServices::fullPathName("xz") << "-cdk";
    else if (type == "lha") packer << KrServices::fullPathName("lha") << "xf";
    else if (type == "rar") packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "-y" << "x";
    else if (type == "ace") packer << KrServices::fullPathName("unace") << "x";
    else if (type == "arj") {
Fathi Boudra's avatar
Fathi Boudra committed
281 282 283 284
        if (KrServices::cmdExist("arj"))
            packer << KrServices::fullPathName("arj") << "-y" << "-v" << "x";
        else
            packer << KrServices::fullPathName("unarj") << "x";
285 286
    } else if (type == "7z")  packer << KrServices::fullPathName("7z") << "-y" << "x";
    else if (type == "rpm") {
287 288
        // TODO use QTemporaryFile (setAutoRemove(false) when asynchrone)
        cpioName = QDir::tempPath() + QStringLiteral("/contents.cpio");
Fathi Boudra's avatar
Fathi Boudra committed
289 290 291 292 293 294

        KrLinecountingProcess cpio;
        cpio << KrServices::fullPathName("rpm2cpio") << archive;
        cpio.setStandardOutputFile(cpioName); // TODO maybe no tmpfile but a pipe (setStandardOutputProcess(packer))
        cpio.start();
        if (!cpio.waitForFinished() || cpio.exitStatus() != QProcess::NormalExit || !checkStatus("cpio", cpio.exitCode())) {
Pino Toscano's avatar
Pino Toscano committed
295
            observer->detailedError(i18n("Failed to convert rpm (%1) to cpio.", archive), cpio.getErrorMsg());
Fathi Boudra's avatar
Fathi Boudra committed
296 297 298 299 300
            return 0;
        }

        archive = cpioName;
        packer << KrServices::fullPathName("cpio") << "--force-local" << "--no-absolute-filenames" <<  "-iuvdF";
301
    } else if (type == "deb") {
302 303
        // TODO use QTemporaryFile (setAutoRemove(false) when asynchrone)
        cpioName = QDir::tempPath() + QStringLiteral("/contents.tar");
Fathi Boudra's avatar
Fathi Boudra committed
304 305 306 307 308

        KrLinecountingProcess dpkg;
        dpkg << KrServices::fullPathName("dpkg") << "--fsys-tarfile" << archive;
        dpkg.setStandardOutputFile(cpioName); // TODO maybe no tmpfile but a pipe (setStandardOutputProcess(packer))
        dpkg.start();
309
        if (!dpkg.waitForFinished() || dpkg.exitStatus() != QProcess::NormalExit || !checkStatus("deb", dpkg.exitCode())) {
Pino Toscano's avatar
Pino Toscano committed
310
            observer->detailedError(i18n("Failed to convert deb (%1) to tar.", archive), dpkg.getErrorMsg());
Fathi Boudra's avatar
Fathi Boudra committed
311 312 313 314 315 316 317 318
            return 0;
        }

        archive = cpioName;
        packer << KrServices::fullPathName("tar") << "xvf";
    } else return false;

    if (!password.isNull()) {
319
        if (type == "zip")
Fathi Boudra's avatar
Fathi Boudra committed
320
            packer << "-P" << password;
321
        if (type == "arj")
Fathi Boudra's avatar
Fathi Boudra committed
322
            packer << QString("-g%1").arg(password);
323
        if (type == "ace" || type == "rar" || type == "7z")
Fathi Boudra's avatar
Fathi Boudra committed
324
            packer << QString("-p%1").arg(password);
325
    }
Fathi Boudra's avatar
Fathi Boudra committed
326 327 328 329

    // unpack the files
    KrLinecountingProcess proc;
    proc << packer << archive;
330
    if (type == "bzip2" || type == "gzip" || type == "lzma" || type == "xz") {
Fathi Boudra's avatar
Fathi Boudra committed
331 332
        QString arcname = archive.mid(archive.lastIndexOf("/") + 1);
        if (arcname.contains(".")) arcname = arcname.left(arcname.lastIndexOf("."));
333
            proc.setStandardOutputFile(dest + '/' + arcname);
334
    }
335
    if (type == "ace" && QFile("/dev/ptmx").exists())    // Don't remove, unace crashes if missing!!!
Fathi Boudra's avatar
Fathi Boudra committed
336 337 338 339 340 341 342 343 344
        proc.setStandardInputFile("/dev/ptmx");

    proc.setWorkingDirectory(dest);

    // tell the user to wait
    observer->subJobStarted(i18n("Unpacking File(s)"), count);
    if (count != 0) {
        connect(&proc, SIGNAL(newOutputLines(int)),
                observer, SLOT(incrementProgress(int)));
345
        if (type == "rpm")
Fathi Boudra's avatar
Fathi Boudra committed
346 347
            connect(&proc, SIGNAL(newErrorLines(int)),
                    observer, SLOT(incrementProgress(int)));
348
    }
Fathi Boudra's avatar
Fathi Boudra committed
349 350 351 352 353

    // start the unpacking process
    proc.start();
    // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking
    // it would be better to connect to started(), error() and finished()
354 355
    if (proc.waitForStarted())
        while (proc.state() == QProcess::Running) {
Fathi Boudra's avatar
Fathi Boudra committed
356 357 358 359 360 361 362 363 364 365 366 367
            observer->processEvents();
            if (observer->wasCancelled())
                proc.kill();
        }
    ; // busy wait - need to find something better...
    observer->subJobStopped();

    if (!cpioName.isEmpty())
        QFile(cpioName).remove();      /* remove the cpio file */

    // check the return value
    if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) {
Pino Toscano's avatar
Pino Toscano committed
368
        observer->detailedError(i18n("Failed to unpack %1.", archive),
Fathi Boudra's avatar
Fathi Boudra committed
369 370
                                observer->wasCancelled() ? i18n("User cancelled.") : proc.getErrorMsg());
        return false;
371
    }
Fathi Boudra's avatar
Fathi Boudra committed
372 373
    return true; // SUCCESS
}
374

375
bool KRarcHandler::test(QString archive, QString type, QString password, KRarcObserver *observer, long count)
Fathi Boudra's avatar
Fathi Boudra committed
376 377 378 379 380
{
    // choose the right packer for the job
    QStringList packer;

    // set the right packer to do the job
381 382 383
    if (type == "zip") packer << KrServices::fullPathName("unzip") << "-t";
    else if (type == "tar") packer << KrServices::fullPathName("tar") << "-tvf";
    else if (type == "tgz") packer << KrServices::fullPathName("tar") << "-tvzf";
Fathi Boudra's avatar
Fathi Boudra committed
384
    else if (type == "tarz") packer << KrServices::fullPathName("tar") << "-tvzf";
385 386 387
    else if (type == "tbz") packer << KrServices::fullPathName("tar") << "-tjvf";
    else if (type == "tlz") packer << KrServices::fullPathName("tar") << "--lzma" << "-tvf";
    else if (type == "txz") packer << KrServices::fullPathName("tar") << "--xz" << "-tvf";
Fathi Boudra's avatar
Fathi Boudra committed
388
    else if (type == "gzip") packer << KrServices::fullPathName("gzip") << "-tv";
389
    else if (type == "bzip2") packer << KrServices::fullPathName("bzip2") << "-tv";
Fathi Boudra's avatar
Fathi Boudra committed
390
    else if (type == "lzma") packer << KrServices::fullPathName("lzma") << "-tv";
391 392 393 394 395
    else if (type == "xz")  packer << KrServices::fullPathName("xz") << "-tv";
    else if (type == "rar") packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "t";
    else if (type == "ace") packer << KrServices::fullPathName("unace") << "t";
    else if (type == "lha") packer << KrServices::fullPathName("lha") << "t";
    else if (type == "arj") packer << KrServices::fullPathName(KrServices::cmdExist("arj") ? "arj" : "unarj") << "t";
Fathi Boudra's avatar
Fathi Boudra committed
396
    else if (type == "cpio") packer << KrServices::fullPathName("cpio") << "--only-verify-crc" << "-tvF";
397
    else if (type == "7z")  packer << KrServices::fullPathName("7z") << "-y" << "t";
Fathi Boudra's avatar
Fathi Boudra committed
398 399 400
    else return false;

    if (!password.isNull()) {
401
        if (type == "zip")
Fathi Boudra's avatar
Fathi Boudra committed
402
            packer << "-P" << password;
403
        if (type == "arj")
Fathi Boudra's avatar
Fathi Boudra committed
404
            packer << QString("-g%1").arg(password);
405
        if (type == "ace" || type == "rar" || type == "7z")
Fathi Boudra's avatar
Fathi Boudra committed
406 407
            packer << QString("-p%1").arg(password);
    }
408

Fathi Boudra's avatar
Fathi Boudra committed
409 410 411 412
    // unpack the files
    KrLinecountingProcess proc;
    proc << packer << archive;

413
    if (type == "ace" && QFile("/dev/ptmx").exists())    // Don't remove, unace crashes if missing!!!
Fathi Boudra's avatar
Fathi Boudra committed
414 415 416 417 418 419 420 421 422 423 424 425
        proc.setStandardInputFile("/dev/ptmx");

    // tell the user to wait
    observer->subJobStarted(i18n("Testing Archive"), count);
    if (count != 0)
        connect(&proc, SIGNAL(newOutputLines(int)),
                observer, SLOT(incrementProgress(int)));

    // start the unpacking process
    proc.start();
    // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking
    // it would be better to connect to started(), error() and finished()
426 427
    if (proc.waitForStarted())
        while (proc.state() == QProcess::Running) {
Fathi Boudra's avatar
Fathi Boudra committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
            observer->processEvents();
            if (observer->wasCancelled())
                proc.kill();
        }
    ; // busy wait - need to find something better...
    observer->subJobStopped();

    // check the return value
    if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode()))
        return false;

    return true; // SUCCESS
}

bool KRarcHandler::pack(QStringList fileNames, QString type, QString dest, long count, QMap<QString, QString> extraProps, KRarcObserver *observer)
{
    // set the right packer to do the job
    QStringList packer;

    if (type == "zip") {
448
        packer << KrServices::fullPathName("zip") << "-ry";
Davide Gianforte's avatar
Davide Gianforte committed
449
    } else if (type == "cbz") {
450 451
        packer << KrServices::fullPathName("zip") << "-ry";
        type = "zip";
Fathi Boudra's avatar
Fathi Boudra committed
452
    } else if (type == "tar") {
453
        packer << KrServices::fullPathName("tar") << "-cvf";
Fathi Boudra's avatar
Fathi Boudra committed
454
    } else if (type == "tar.gz") {
455 456
        packer << KrServices::fullPathName("tar") << "-cvzf";
        type = "tgz";
Fathi Boudra's avatar
Fathi Boudra committed
457
    } else if (type == "tar.bz2") {
458 459
        packer << KrServices::fullPathName("tar") << "-cvjf";
        type = "tbz";
Fathi Boudra's avatar
Fathi Boudra committed
460
    } else if (type == "tar.lzma") {
461 462
        packer << KrServices::fullPathName("tar") << "--lzma" << "-cvf";
        type = "tlz";
463
    } else if (type == "tar.xz") {
464 465
        packer << KrServices::fullPathName("tar") << "--xz" << "-cvf";
        type = "txz";
Fathi Boudra's avatar
Fathi Boudra committed
466
    } else if (type == "rar") {
467
        packer << KrServices::fullPathName("rar") << "-r" << "a";
Davide Gianforte's avatar
Davide Gianforte committed
468
    } else if (type == "cbr") {
469 470
        packer << KrServices::fullPathName("rar") << "-r" << "a";
        type = "rar";
Fathi Boudra's avatar
Fathi Boudra committed
471
    } else if (type == "lha") {
472
        packer << KrServices::fullPathName("lha") << "a";
Fathi Boudra's avatar
Fathi Boudra committed
473
    } else if (type == "arj") {
474
        packer << KrServices::fullPathName("arj") << "-r" << "-y" << "a";
Fathi Boudra's avatar
Fathi Boudra committed
475
    } else if (type == "7z") {
476
        packer << KrServices::fullPathName("7z") << "-y" << "a";
Fathi Boudra's avatar
Fathi Boudra committed
477 478
    } else return false;

Fathi Boudra's avatar
Fathi Boudra committed
479
    QString password;
Fathi Boudra's avatar
Fathi Boudra committed
480 481 482 483 484

    if (extraProps.count("Password") > 0) {
        password = extraProps[ "Password" ];

        if (!password.isNull()) {
485
            if (type == "zip")
Fathi Boudra's avatar
Fathi Boudra committed
486
                packer << "-P" << password;
487
            else if (type == "arj")
Fathi Boudra's avatar
Fathi Boudra committed
488
                packer << QString("-g%1").arg(password);
489
            else if (type == "ace" || type == "7z")
Fathi Boudra's avatar
Fathi Boudra committed
490
                packer << QString("-p%1").arg(password);
491
            else if (type == "rar") {
Fathi Boudra's avatar
Fathi Boudra committed
492 493 494 495 496
                if (extraProps.count("EncryptHeaders") > 0)
                    packer << QString("-hp%1").arg(password);
                else
                    packer << QString("-p%1").arg(password);
            } else
Fathi Boudra's avatar
Fathi Boudra committed
497
                password.clear();
Fathi Boudra's avatar
Fathi Boudra committed
498
        }
Csaba Karai's avatar
Csaba Karai committed
499
    }
Fathi Boudra's avatar
Fathi Boudra committed
500 501 502 503 504 505

    if (extraProps.count("VolumeSize") > 0) {
        QString sizeStr = extraProps[ "VolumeSize" ];
        KIO::filesize_t size = sizeStr.toLongLong();

        if (size >= 10000) {
506
            if (type == "arj" || type == "rar")
Fathi Boudra's avatar
Fathi Boudra committed
507 508
                packer << QString("-v%1b").arg(sizeStr);
        }
509 510
    }

Fathi Boudra's avatar
Fathi Boudra committed
511 512 513 514 515 516 517
    if (extraProps.count("CompressionLevel") > 0) {
        int level = extraProps[ "CompressionLevel" ].toInt() - 1;
        if (level < 0)
            level = 0;
        if (level > 8)
            level = 8;

518
        if (type == "rar") {
Fathi Boudra's avatar
Fathi Boudra committed
519 520
            static const int rarLevels[] = { 0, 1, 2, 2, 3, 3, 4, 4, 5 };
            packer << QString("-m%1").arg(rarLevels[ level ]);
521
        } else if (type == "arj") {
Fathi Boudra's avatar
Fathi Boudra committed
522 523
            static const int arjLevels[] = { 0, 4, 4, 3, 3, 2, 2, 1, 1 };
            packer << QString("-m%1").arg(arjLevels[ level ]);
524
        } else if (type == "zip") {
Fathi Boudra's avatar
Fathi Boudra committed
525 526
            static const int zipLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 };
            packer << QString("-%1").arg(zipLevels[ level ]);
527
        } else if (type == "7z") {
Fathi Boudra's avatar
Fathi Boudra committed
528 529 530
            static const int sevenZipLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 };
            packer << QString("-mx%1").arg(sevenZipLevels[ level ]);
        }
531 532
    }

Fathi Boudra's avatar
Fathi Boudra committed
533 534 535 536 537 538 539 540 541
    if (extraProps.count("CommandLineSwitches") > 0)
        packer << QString("%1").arg(extraProps[ "CommandLineSwitches" ]);

    // prepare to pack
    KrLinecountingProcess proc;
    proc << packer << dest;

    for (QStringList::Iterator file = fileNames.begin(); file != fileNames.end(); ++file) {
        proc << *file;
542 543
    }

Fathi Boudra's avatar
Fathi Boudra committed
544 545 546 547 548 549 550 551 552 553
    // tell the user to wait
    observer->subJobStarted(i18n("Packing File(s)"), count);
    if (count != 0)
        connect(&proc, SIGNAL(newOutputLines(int)),
                observer, SLOT(incrementProgress(int)));

    // start the packing process
    proc.start();
    // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking
    // it would be better to connect to started(), error() and finished()
554 555
    if (proc.waitForStarted())
        while (proc.state() == QProcess::Running) {
Fathi Boudra's avatar
Fathi Boudra committed
556 557 558 559 560 561 562 563 564
            observer->processEvents();
            if (observer->wasCancelled())
                proc.kill();
        }
    ; // busy wait - need to find something better...
    observer->subJobStopped();

    // check the return value
    if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) {
Pino Toscano's avatar
Pino Toscano committed
565
        observer->detailedError(i18n("Failed to pack %1.", dest),
Fathi Boudra's avatar
Fathi Boudra committed
566 567 568 569 570 571
                                observer->wasCancelled() ? i18n("User cancelled.") : proc.getErrorMsg());
        return false;
    }

    KConfigGroup group(krConfig, "Archives");
    if (group.readEntry("Test Archives", _TestArchives) &&
572
            !test(dest, type, password, observer, count)) {
Pino Toscano's avatar
Pino Toscano committed
573
        observer->error(i18n("Failed to pack %1.", dest));
Fathi Boudra's avatar
Fathi Boudra committed
574
        return false;
575
    }
Fathi Boudra's avatar
Fathi Boudra committed
576
    return true; // SUCCESS
Rafi Yanai's avatar
Rafi Yanai committed
577
}
578

579 580 581 582 583 584 585 586 587 588 589 590 591
bool KRarcHandler::openWallet()
{
    if (!wallet) {
        // find a suitable parent window
        QWidget *actWindow = QApplication::activeWindow();
        if (!actWindow)
            actWindow = (QWidget*) QApplication::desktop();

        wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), actWindow->effectiveWinId());
    }
    return (wallet != 0);
}

Fathi Boudra's avatar
Fathi Boudra committed
592 593 594 595 596 597 598 599 600 601 602
QString KRarcHandler::getPassword(QString path)
{
    QString password;

    QString key = "krarc-" + path;

    if (!KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder(), key)) {
        if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet())  && wallet != 0) {
            delete wallet;
            wallet = 0;
        }
603
        if (openWallet() && wallet->hasFolder(KWallet::Wallet::PasswordFolder())) {
Fathi Boudra's avatar
Fathi Boudra committed
604 605 606 607 608 609 610 611 612 613 614 615
            wallet->setFolder(KWallet::Wallet::PasswordFolder());
            QMap<QString, QString> map;
            if (wallet->readMap(key, map) == 0) {
                QMap<QString, QString>::const_iterator it = map.constFind("password");
                if (it != map.constEnd())
                    password = it.value();
            }
        }
    }

    bool keep = true;
    QString user = "archive";
616 617 618
    QPointer<KPasswordDialog> passDlg = new KPasswordDialog(0L, KPasswordDialog::ShowKeepPassword);
            passDlg->setPrompt(i18n("This archive is encrypted, please supply the password:") ),
            passDlg->setUsername(user);
619
    passDlg->setPassword(password);
620
    if (passDlg->exec() == KPasswordDialog::Accepted) {
621
        password = passDlg->password();
Fathi Boudra's avatar
Fathi Boudra committed
622 623 624 625 626
        if (keep) {
            if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet()) && wallet != 0) {
                delete wallet;
                wallet = 0;
            }
627
            if (openWallet()) {
Fathi Boudra's avatar
Fathi Boudra committed
628 629 630 631 632 633 634 635 636 637 638 639
                bool ok = true;
                if (!wallet->hasFolder(KWallet::Wallet::PasswordFolder()))
                    ok = wallet->createFolder(KWallet::Wallet::PasswordFolder());
                if (ok) {
                    wallet->setFolder(KWallet::Wallet::PasswordFolder());
                    QMap<QString, QString> map;
                    map.insert("login", "archive");
                    map.insert("password", password);
                    wallet->writeMap(key, map);
                }
            }
        }
Csaba Karai's avatar
Csaba Karai committed
640
        delete passDlg;
Fathi Boudra's avatar
Fathi Boudra committed
641 642
        return password;
    }
643
    delete passDlg;
Fathi Boudra's avatar
Fathi Boudra committed
644 645

    return "";
Rafi Yanai's avatar
Rafi Yanai committed
646
}
647

648
bool KRarcHandler::isArchive(const QUrl &url)
Fathi Boudra's avatar
Fathi Boudra committed
649
{
650
    QString protocol = url.scheme();
Fathi Boudra's avatar
Fathi Boudra committed
651 652 653
    if (arcProtocols.indexOf(protocol) != -1)
        return true;
    else return false;
Rafi Yanai's avatar
Rafi Yanai committed
654
}
655

656
QString KRarcHandler::getType(bool &encrypted, QString fileName, QString mime, bool checkEncrypted, bool fast)
Fathi Boudra's avatar
Fathi Boudra committed
657
{
658
    QString result = detectArchive(encrypted, fileName, checkEncrypted, fast);
659
    if (result.isNull()) {
660 661
        // Then the type is based on the mime type
        return getShortTypeFromMime(mime);
662
    }
663
    return result;
Fathi Boudra's avatar
Fathi Boudra committed
664 665 666 667
}

bool KRarcHandler::checkStatus(QString type, int exitCode)
{
668
    return KrArcBaseManager::checkStatus(type, exitCode);
Rafi Yanai's avatar
Rafi Yanai committed
669
}
670

671
void KRarcHandler::checkIf7zIsEncrypted(bool &encrypted, QString fileName)
Fathi Boudra's avatar
Fathi Boudra committed
672
{
673 674 675 676 677 678 679
    Kr7zEncryptionChecker proc;
    // TODO incorporate all this in Kr7zEncryptionChecker
    proc << KrServices::fullPathName("7z") << "-y" << "t";
    proc << fileName;
    proc.start();
    proc.waitForFinished();
    encrypted = proc.isEncrypted();
Rafi Yanai's avatar
Rafi Yanai committed
680 681
}