1 /*
2     SPDX-FileCopyrightText: 2007 Henrique Pinto <henrique.pinto@kdemail.net>
3     SPDX-FileCopyrightText: 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
4     SPDX-FileCopyrightText: 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
5     SPDX-FileCopyrightText: 2016 Vladyslav Batyrenko <mvlabat@gmail.com>
6 
7     SPDX-License-Identifier: BSD-2-Clause
8 */
9 
10 #ifndef ARCHIVEINTERFACE_H
11 #define ARCHIVEINTERFACE_H
12 
13 #include "archive_kerfuffle.h"
14 #include "kerfuffle_export.h"
15 #include "archiveentry.h"
16 
17 #include <KPluginMetaData>
18 
19 #include <QObject>
20 #include <QStringList>
21 #include <QString>
22 #include <QVariantList>
23 
24 namespace Kerfuffle
25 {
26 class Query;
27 
28 enum {
29     PossiblyMaliciousArchiveError = KJob::UserDefinedError + 1,
30     DestinationNotWritableError
31 };
32 
33 
34 class KERFUFFLE_EXPORT ReadOnlyArchiveInterface: public QObject
35 {
36     Q_OBJECT
37 public:
38     explicit ReadOnlyArchiveInterface(QObject *parent, const QVariantList &args);
39     ~ReadOnlyArchiveInterface() override;
40 
41     /**
42      * Returns the filename of the archive currently being handled.
43      */
44     QString filename() const;
45 
46     /**
47      * Returns the comment of the archive.
48      */
49     QString comment() const;
50 
51     /**
52      * @return The password of the archive, if any.
53      */
54     QString password() const;
55 
56     bool isMultiVolume() const;
57     int numberOfVolumes() const;
58 
59     /**
60      * Returns whether the file can only be read.
61      *
62      * @return @c true  The file cannot be written.
63      * @return @c false The file can be read and written.
64      */
65     virtual bool isReadOnly() const;
66 
67     virtual bool open();
68 
69     /**
70      * List archive contents.
71      * This runs the process of reading archive contents.
72      * When subclassing, you can block as long as you need (unless you called setWaitForFinishedSignal(true)).
73      * @returns whether the listing succeeded.
74      * @note If returning false, make sure to emit the error() signal beforewards to notify
75      * the user of the error condition.
76      */
77     virtual bool list() = 0;
78     virtual bool testArchive() = 0;
79     void setPassword(const QString &password);
80     void setHeaderEncryptionEnabled(bool enabled);
81 
82     /**
83      * Extracts the given @p files to the given @p destinationDirectory.
84      * If @p files is empty, the whole archive will be extracted.
85      * When subclassing, you can block as long as you need (unless you called setWaitForFinishedSignal(true)).
86      * @returns whether the extraction succeeded.
87      * @note If returning false, make sure to emit the error() signal beforewards to notify
88      * the user of the error condition.
89      */
90     virtual bool extractFiles(const QVector<Archive::Entry*> &files, const QString &destinationDirectory, const ExtractionOptions &options) = 0;
91 
92     /**
93      * @return Whether the plugins do NOT run the functions in their own thread.
94      * @see setWaitForFinishedSignal()
95      */
96     bool waitForFinishedSignal();
97 
98     /**
99      * Returns count of required finish signals for a job to be finished.
100      *
101      * These two methods are used by move and copy jobs, which in some plugins implementations have to call
102      * several processes sequentially. For instance, moving entries in zip archive is only possible if
103      * extracting the entries, deleting them, recreating destination folder structure and adding them back again.
104      */
105     virtual int moveRequiredSignals() const;
106     virtual int copyRequiredSignals() const;
107 
108     /**
109      * Returns the list of filenames retrieved from the list of entries.
110      */
111     static QStringList entryFullPaths(const QVector<Archive::Entry*> &entries, PathFormat format = WithTrailingSlash);
112 
113     /**
114      * Returns the list of the entries, excluding their children.
115      *
116      * This method relies on entries paths so doesn't require parents to be set.
117      */
118     static QVector<Archive::Entry*> entriesWithoutChildren(const QVector<Archive::Entry*> &entries);
119 
120     /**
121      * Returns the string list of entry paths, which will be a result of adding/moving/copying entries.
122      *
123      * @param entries The entries which will be added/moved/copied.
124      * @param destination Destination path within the archive to which entries have to be added. For renaming an entry
125      * the path has to contain a new filename too.
126      * @param entriesWithoutChildren Entries count, excluding their children. For AddJob or CopyJob 0 MUST be passed.
127      *
128      * @return For entries
129      *  some/dir/
130      *  some/dir/entry
131      *  some/dir/some/entry
132      *  some/another/entry
133      * and destination
134      *  some/destination
135      * will return
136      *  some/destination/dir/
137      *  some/destination/dir/entry
138      *  some/destination/dir/some/enty
139      *  some/destination/entry
140      */
141     static QStringList entryPathsFromDestination(QStringList entries, const Archive::Entry *destination, int entriesWithoutChildren);
142 
143     /**
144      * @return true if the interface has killed the job.
145      * Otherwise returns false if the interface is not able to instantly kill the operation.
146      */
147     virtual bool doKill();
148 
149     bool isHeaderEncryptionEnabled() const;
150     virtual QString multiVolumeName() const;
151     void setMultiVolume(bool value);
152     uint numberOfEntries() const;
153     QMimeType mimetype() const;
154 
155     /**
156      * @return Whether the interface supports progress reporting for BatchExtractJobs.
157      */
158     virtual bool hasBatchExtractionProgress() const;
159 
160     /**
161      * @return Whether the archive is locked (RAR feature).
162      */
163     virtual bool isLocked() const;
164 
165 Q_SIGNALS:
166 
167     /**
168      * Emitted when the user cancels the operation. Examples:
169      * - the user cancels the password dialog
170      * - the user cancels the overwrite dialog
171      */
172     void cancelled();
173     void error(const QString &message, const QString &details = QString(), int errorCode = KJob::UserDefinedError);
174     void entry(Archive::Entry *archiveEntry);
175     void progress(double progress);
176     void info(const QString &info);
177     void finished(bool result);
178     void testSuccess();
179     void compressionMethodFound(const QString &method);
180     void encryptionMethodFound(const QString &method);
181 
182     /**
183      * Emitted when @p query needs to be executed on the GUI thread.
184      */
185     void userQuery(Kerfuffle::Query *query);
186 
187 protected:
188 
189     /**
190      * Setting this option to true will NOT run the functions in their own thread.
191      * Instead it will be necessary to call finished(bool) when the operation is actually finished.
192      */
193     void setWaitForFinishedSignal(bool value);
194 
195     void setCorrupt(bool isCorrupt);
196     bool isCorrupt() const;
197     QString m_comment;
198     int m_numberOfVolumes;
199     uint m_numberOfEntries;
200     KPluginMetaData m_metaData;
201 
202 private:
203     QString m_filename;
204     QMimeType m_mimetype;
205     QString m_password;
206     bool m_waitForFinishedSignal;
207     bool m_isHeaderEncryptionEnabled;
208     bool m_isCorrupt;
209     bool m_isMultiVolume;
210 
211 private Q_SLOTS:
212     void onEntry(Archive::Entry *archiveEntry);
213 };
214 
215 class KERFUFFLE_EXPORT ReadWriteArchiveInterface: public ReadOnlyArchiveInterface
216 {
217     Q_OBJECT
218 public:
219     enum OperationMode  {
220         NoOperation,
221         List,
222         Extract,
223         Add,
224         Move,
225         Copy,
226         Delete,
227         Comment,
228         Test
229     };
230 
231     explicit ReadWriteArchiveInterface(QObject *parent, const QVariantList &args);
232     ~ReadWriteArchiveInterface() override;
233 
234     bool isReadOnly() const override;
235 
236     /**
237      * Adds the given @p files under the given @p destination.
238      * If @p destination is null, the files will be added under the root of the archive.
239      * @param options The compression options that must be respected.
240      * @param numberOfEntriesToAdd The total number of entries the will be added.
241      * @return Whether the operation succeeded.
242      * @note If returning false, make sure to emit the error() signal beforewards to notify
243      * the user of the error condition.
244      */
245     virtual bool addFiles(const QVector<Archive::Entry*> &files, const Archive::Entry *destination, const CompressionOptions& options, uint numberOfEntriesToAdd = 0) = 0;
246     virtual bool moveFiles(const QVector<Archive::Entry*> &files, Archive::Entry *destination, const CompressionOptions& options) = 0;
247     virtual bool copyFiles(const QVector<Archive::Entry*> &files, Archive::Entry *destination, const CompressionOptions& options) = 0;
248     virtual bool deleteFiles(const QVector<Archive::Entry*> &files) = 0;
249     virtual bool addComment(const QString &comment) = 0;
250 
251 Q_SIGNALS:
252     void entryRemoved(const QString &path);
253 
254 protected:
255     OperationMode m_operationMode = NoOperation;
256 
257 private Q_SLOTS:
258     void onEntryRemoved(const QString &path);
259 };
260 
261 } // namespace Kerfuffle
262 
263 #endif // ARCHIVEINTERFACE_H
264