1 /*
2     SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "akonadi-singlefileresource_export.h"
10 #include <Akonadi/ResourceBase>
11 
12 #include <QStringList>
13 #include <QUrl>
14 
15 namespace KIO
16 {
17 class FileCopyJob;
18 class Job;
19 }
20 
21 namespace Akonadi
22 {
23 /**
24  * Base class for single file based resources.
25  * @see SingleFileResource
26  */
27 class AKONADI_SINGLEFILERESOURCE_EXPORT SingleFileResourceBase : public ResourceBase, public AgentBase::Observer
28 {
29     Q_OBJECT
30 public:
31     explicit SingleFileResourceBase(const QString &id);
32 
33     /**
34      * Set the mimetypes supported by this resource and an optional icon for the collection.
35      */
36     void setSupportedMimetypes(const QStringList &mimeTypes, const QString &icon = QString());
37 
38     void collectionChanged(const Akonadi::Collection &collection) override;
39 
40 public Q_SLOTS:
41     void reloadFile();
42 
43     /*
44      * Read the current state from a file. This can happen
45      * from direct callers, or as part of a scheduled task.
46      * @p taskContext specifies whether the method is being
47      * called from within a task or not.
48      */
49     virtual void readFile(bool taskContext = false) = 0;
50     /*
51      * Writes the current state out to a file. This can happen
52      * from direct callers, or as part of a scheduled task.
53      * @p taskContext specifies whether the method is being
54      * called from within a task or not.
55      */
56     virtual void writeFile(bool taskContext = false) = 0;
57 
58     /*
59      * Same method as above, but uses a QVariant so it can
60      * be called from Akonadi::ResourceScheduler.
61      */
62     virtual void writeFile(const QVariant &taskContext) = 0;
63 
64 protected:
65     /**
66      * Implement in derived classes to do things when the configuration changes
67      * before reload file is called.
68      */
69     virtual void applyConfigurationChanges();
70 
71     /**
72      * Returns a pointer to the KConfig object which is used to store runtime
73      * information of the resource.
74      */
75     KSharedConfig::Ptr runtimeConfig() const;
76 
77     /**
78      * Handles everything needed when the hash of a file has changed between the
79      * last write and the first read. This stores the new hash in a config file
80      * and notifies implementing resources to handle a hash change if the
81      * previous known hash was not empty. Finally this method clears the cache
82      * and calls synchronize.
83      * Returns true on success, false otherwise.
84      */
85     bool readLocalFile(const QString &fileName);
86 
87     /**
88      * Reimplement to read your data from the given file.
89      * The file is always local, loading from the network is done
90      * automatically if needed.
91      */
92     virtual bool readFromFile(const QString &fileName) = 0;
93 
94     /**
95      * Reimplement to write your data to the given file.
96      * The file is always local, storing back to the network url is done
97      * automatically when needed.
98      */
99     virtual bool writeToFile(const QString &fileName) = 0;
100 
101     /**
102      * It is not always needed to parse the file when a resources is started.
103      * (e.g. When the hash of the file is the same as the last time the resource
104      * has written changes to the file). In this case setActualFileName is
105      * called so that the implementing resource does know which file to read
106      * when it actually needs to read the file.
107      *
108      * The default implementation will just call readFromFile( fileName ), so
109      * implementing resources will have to explicitly reimplement this method to
110      * actually get any profit of this.
111      *
112      * @p fileName This will always be a path to a local file.
113      */
114     virtual void setLocalFileName(const QString &fileName);
115 
116     /**
117      * Generates the full path for the cache file in the case that a remote file
118      * is used.
119      */
120     QString cacheFile() const;
121 
122     /**
123      * Calculates an MD5 hash for given file. If the file does not exists
124      * or the path is empty, this will return an empty QByteArray.
125      */
126     QByteArray calculateHash(const QString &fileName) const;
127 
128     /**
129      * This method is called when the hash of the file has changed between the
130      * last writeFile() and a readFile() call. This means that the file was
131      * changed by another program.
132      *
133      * Note: This method is <em>not</em> called when the last known hash is
134      *       empty. In that case it is assumed that the file is loaded for the
135      *       first time.
136      */
137     virtual void handleHashChange();
138 
139     /**
140      * Returns the hash that was stored to a cache file.
141      */
142     QByteArray loadHash() const;
143 
144     /**
145      * Stores the given hash into a cache file.
146      */
147     void saveHash(const QByteArray &hash) const;
148 
149     /**
150      * Returns whether the resource can be written to.
151      */
152     virtual bool readOnly() const = 0;
153 
154     /**
155      * Returns the collection of this resource.
156      */
157     virtual Collection rootCollection() const = 0;
158 
159 protected:
160     QUrl mCurrentUrl;
161     QStringList mSupportedMimetypes;
162     QString mCollectionIcon;
163     KIO::FileCopyJob *mDownloadJob = nullptr;
164     KIO::FileCopyJob *mUploadJob = nullptr;
165     QByteArray mCurrentHash;
166 
167 protected Q_SLOTS:
168     void scheduleWrite(); /// Called when changes are added to the ChangeRecorder.
169     void handleProgress(KJob *, unsigned long);
170     void fileChanged(const QString &fileName);
171     void slotDownloadJobResult(KJob *);
172     void slotUploadJobResult(KJob *);
173 };
174 }
175 
176